diff --git a/CMakeLists.txt b/CMakeLists.txt index e771f40..237854e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,22 +10,22 @@ set(SOURCES src/controller/loginController.hpp src/controller/songController.hpp src/database/base_repository.cpp - src/directory_manager.cpp src/dto/loginResultDto.hpp - src/imageFile.cpp src/main.cpp + src/managers/directory_manager.cpp src/managers/song_manager.cpp - src/metadata_retriever.cpp - src/token_manager.cpp + src/managers/token_manager.cpp + src/utilities/imageFile.cpp + src/utilities/metadata_retriever.cpp ) set(HEADERS include/database/base_repository.h - include/directory_manager.h - include/imageFile.h + include/managers/directory_manager.h include/managers/song_manager.h - include/metadata_retriever.h - include/models.h - include/token_manager.h + include/managers/token_manager.h + include/models/models.h + include/utilities/imageFile.h + include/utilities/metadata_retriever.h include/types/scopes.h ) diff --git a/include/database/base_repository.h b/include/database/base_repository.h index 110f29e..ea90788 100644 --- a/include/database/base_repository.h +++ b/include/database/base_repository.h @@ -1,11 +1,11 @@ #ifndef BASE_REPOSITORY_H_ #define BASE_REPOSITORY_H_ -#include +#include #include -#include "models.h" +#include "models/models.h" class base_repository { diff --git a/include/directory_manager.h b/include/directory_manager.h deleted file mode 100644 index a20d29a..0000000 --- a/include/directory_manager.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "models.h" - -#include - -std::string create_directory_process(Song, const char*); -std::string read_cover_art(const char*); - -bool delete_song(Song*); - -void copy_stock_to_root(const char*, const std::string); -void copy_song_to_path(const char*, const char*); -void delete_cover_art_file(const std::string); -void delete_directories(Song, const char*); -void delete_song(Song); diff --git a/include/managers/directory_manager.h b/include/managers/directory_manager.h new file mode 100644 index 0000000..ca44afc --- /dev/null +++ b/include/managers/directory_manager.h @@ -0,0 +1,26 @@ +#ifndef DIRECTORY_MANAGER_H_ +#define DIRECTORY_MANAGER_H_ + +#include + +#include "models/models.h" + +class directory_manager +{ +public: + + std::string create_directory_process(Song, const std::string&); + // Return Cover instead + std::string read_cover_art(const std::string&); + + + void copy_stock_to_root(const std::string&, const std::string&); + void copy_song_to_path(const std::string&, const std::string&); + void delete_cover_art_file(const std::string&, const std::string&); + void delete_directories(Song, const std::string&); + +private: + void delete_song(const Song); +}; + +#endif diff --git a/include/managers/song_manager.h b/include/managers/song_manager.h index 5cef72b..18cc8a8 100644 --- a/include/managers/song_manager.h +++ b/include/managers/song_manager.h @@ -4,7 +4,7 @@ #include #include -#include "models.h" +#include "models/models.h" class song_manager { diff --git a/include/token_manager.h b/include/managers/token_manager.h similarity index 53% rename from include/token_manager.h rename to include/managers/token_manager.h index 4b15d49..f8bcbec 100644 --- a/include/token_manager.h +++ b/include/managers/token_manager.h @@ -3,8 +3,12 @@ #include #include +#include +#include -#include "models.h" +#include + +#include "models/models.h" #include "types/scopes.h" class token_manager @@ -18,6 +22,11 @@ public: bool is_token_valid(std::string&, Scope); private: auth_credentials parse_auth_credentials(std::string_view); + + std::vector extract_scopes(const jwt::decoded_jwt&&); + std::pair> fetch_auth_header(const std::string&); + + bool token_supports_scope(const std::vector, const std::string&&); }; #endif diff --git a/include/metadata_retriever.h b/include/metadata_retriever.h deleted file mode 100644 index 80e3dd4..0000000 --- a/include/metadata_retriever.h +++ /dev/null @@ -1,3 +0,0 @@ -#include - -#include "models.h" diff --git a/include/models.h b/include/models.h index 4842e0a..3c40b64 100644 --- a/include/models.h +++ b/include/models.h @@ -6,22 +6,24 @@ struct Song { - int Id; - char Title[1024]; - char Artist[1024]; - char Album[1024]; - char Genre[1024]; - int Year; - int Duration; - char SongPath[1024]; + int id; + std::string title; + std::string artist; + std::string album; + std::string genre; + int year; + int duration; + std::string songPath; std::vector data; }; struct Cover { - int Id; - char SongTitle[1024]; - char ImagePath[1024]; + int id; + std::string songTitle; + std::string imagePath; + // Currently not being used but it should + std::vector data; }; struct LoginRes diff --git a/include/models/models.h b/include/models/models.h new file mode 100644 index 0000000..1d027da --- /dev/null +++ b/include/models/models.h @@ -0,0 +1,77 @@ +#ifndef MODELS_H_ +#define MODELS_H_ + +#include +#include + +struct Song +{ + int id; + std::string title; + std::string artist; + std::string album; + std::string genre; + int year; + int duration; + std::string songPath; + std::vector data; +}; + +struct Cover +{ + int id; + std::string songTitle; + std::string imagePath; + // Not being used but it should be + std::vector data; +}; + +struct LoginRes +{ + int UserId; + char Username[1024]; + char Token[1024]; + char TokenType[1024]; + char Message[1024]; + int Expiration; +}; + +struct loginResult +{ + int user_id; + std::string username; + std::string access_token; + std::string token_type; + std::string message; + int expiration; +}; + +struct auth_credentials +{ + std::string domain; + std::string api_identifier; + std::string client_id; + std::string client_secret; + std::string uri; + std::string endpoint; +}; + +struct database_connection +{ + std::string server; + std::string username; + std::string password; + std::string database; +}; + +struct TokenReq +{ + char ClientId[1024]; + char ClientSecret[1024]; + char Audience[1024]; + char GrantType[1024]; + char URI[1024]; + char Endpoint[1024]; +}; + +#endif diff --git a/include/imageFile.h b/include/utilities/imageFile.h similarity index 100% rename from include/imageFile.h rename to include/utilities/imageFile.h diff --git a/include/utilities/metadata_retriever.h b/include/utilities/metadata_retriever.h new file mode 100644 index 0000000..4d14a8c --- /dev/null +++ b/include/utilities/metadata_retriever.h @@ -0,0 +1,19 @@ +#ifndef METADATA_RETRIEVER_H_ +#define METADATA_RETRIEVER_H_ + +#include +#include + +#include "models/models.h" + +class metadata_retriever +{ +public: + Song retrieve_metadata(std::string&); + Cover update_cover_art(Cover, const Song, const std::string&); + + void update_metadata(Song updated_song, const Song old_song); +private: +}; + +#endif diff --git a/src/controller/loginController.hpp b/src/controller/loginController.hpp index 7c9e7ee..e17de5e 100644 --- a/src/controller/loginController.hpp +++ b/src/controller/loginController.hpp @@ -11,7 +11,7 @@ #include "oatpp/web/server/api/ApiController.hpp" #include "../dto/loginResultDto.hpp" -#include "token_manager.h" +#include "managers/token_manager.h" namespace fs = std::filesystem; diff --git a/src/controller/songController.hpp b/src/controller/songController.hpp index d7f7db2..ffc7ef0 100644 --- a/src/controller/songController.hpp +++ b/src/controller/songController.hpp @@ -14,8 +14,8 @@ #include "oatpp/web/server/api/ApiController.hpp" #include "managers/song_manager.h" -#include "models.h" -#include "token_manager.h" +#include "models/models.h" +#include "managers/token_manager.h" #include "types/scopes.h" class songController : public oatpp::web::server::api::ApiController @@ -38,13 +38,8 @@ public: auto auth = authHeader->std_str(); - //std::cout << "auth " << auth << std::endl; - token_manager tok; - if (!tok.is_token_valid(auth, Scope::upload)) { - // TODO: prevent user from moving forward - // token did not have the specified scope (permission) - } + OATPP_ASSERT_HTTP(tok.is_token_valid(auth, Scope::upload), Status::CODE_403, "Not allowed"); auto mp = std::make_shared(request->getHeaders()); diff --git a/src/loginHandler.cpp b/src/loginHandler.cpp deleted file mode 100644 index 4223142..0000000 --- a/src/loginHandler.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "loginHandler.h" - diff --git a/src/loginHandler.hpp b/src/loginHandler.hpp index a40a71b..e131660 100644 --- a/src/loginHandler.hpp +++ b/src/loginHandler.hpp @@ -8,7 +8,6 @@ #include "oatpp/web/server/HttpConnectionHandler.hpp" #include "dto/loginResultDto.hpp" -//#include "dto/loginResultDto.hpp" class loginHandler : public oatpp::web::server::HttpRequestHandler { diff --git a/src/main.cpp b/src/main.cpp index 8cdd48a..b999ed0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include #include -#include "models.h" #include #include "oatpp/network/server/Server.hpp" #include "oatpp/network/server/SimpleTCPConnectionProvider.hpp" @@ -14,6 +13,7 @@ #include "controller/loginController.hpp" #include "controller/songController.hpp" #include "database/base_repository.h" +#include "models/models.h" namespace fs = std::filesystem; diff --git a/src/directory_manager.cpp b/src/managers/directory_manager.cpp similarity index 73% rename from src/directory_manager.cpp rename to src/managers/directory_manager.cpp index 9f47566..e99904a 100644 --- a/src/directory_manager.cpp +++ b/src/managers/directory_manager.cpp @@ -1,14 +1,13 @@ #include #include #include -#include #include -#include "directory_manager.h" +#include "managers/directory_manager.h" namespace fs = std::filesystem; -std::string create_directory_process(Song song, const char *root_path) +std::string directory_manager::create_directory_process(Song song, const std::string& root_path) { auto curr_path = fs::path(root_path); @@ -19,7 +18,7 @@ std::string create_directory_process(Song song, const char *root_path) fs::create_directory(curr_path); } - auto art_path = fs::path(curr_path.string() + song.Artist); + auto art_path = fs::path(curr_path.string() + song.artist); if (fs::exists(art_path)) { std::cout<<"artist path exists"<SongPath); -} - -void copy_stock_to_root(const char *target, const std::string buff) +void directory_manager::copy_stock_to_root(const std::string& target, const std::string& buff) { std::cout<<"starting process"< #include #include -#include #include #include -#include #include -#include "token_manager.h" +#include "managers/token_manager.h" namespace fs = std::filesystem; @@ -60,62 +58,31 @@ loginResult token_manager::retrieve_token(std::string_view path) bool token_manager::is_token_valid(std::string& auth, Scope scope) { - std::istringstream iss(auth); - std::vector authHeader{std::istream_iterator(iss), - std::istream_iterator() - }; + auto authPair = fetch_auth_header(auth); - auto wordCount = 0; - /** - for (auto& word : authHeader) { - std::cout << "word " << wordCount++ << " " << word << std::endl; - } - */ + if (!std::get<0>(authPair)) { + std::cout << "no Bearer found" << std::endl; - if (!std::any_of(authHeader.begin(), authHeader.end(), [](std::string word) - { - std::cout << "comparing " << word << " to Bearer" << std::endl; - return (word.compare("Bearer") == 0); - })) { - std::cout << "Bearer not found" << std::endl; - return false; + return std::get<0>(authPair); } + auto authHeader = std::get<1>(authPair); + auto token = authHeader.at(authHeader.size()-1); - std::cout << "going to decode " << token << std::endl; - auto decoded = jwt::decode(token); - std::vector scopes; - for (auto d : decoded.get_payload_claims()) { - if (d.first.compare("scope") == 0) { - std::cout << "found scope" << std::endl; - std::string all_scopes(d.second.to_json().get()); - std::istringstream iss(all_scopes); - - scopes.assign(std::istream_iterator(iss), - std::istream_iterator()); - //std::cout << scopes << std::endl; - } - } - - std::cout << "printing all scopes" << std::endl; - - for (auto& scope_obj : scopes) { - std::cout << scope_obj << std::endl; - } - - - std::cout << "goodbye" << std::endl; - exit(1); + auto scopes = extract_scopes(jwt::decode(token)); switch (scope) { case Scope::upload: + return token_supports_scope(scopes, "upload:songs"); break; + case Scope::download: + return token_supports_scope(scopes, "download:songs"); default: break; } - return true; + return false; } auth_credentials token_manager::parse_auth_credentials(std::string_view path) @@ -140,3 +107,48 @@ auth_credentials token_manager::parse_auth_credentials(std::string_view path) return auth; } + +std::vector token_manager::extract_scopes(const jwt::decoded_jwt&& decoded) +{ + std::vector scopes; + + for (auto d : decoded.get_payload_claims()) { + if (d.first.compare("scope") == 0) { + std::cout << "found scope" << std::endl; + std::string all_scopes(d.second.to_json().get()); + std::istringstream iss(all_scopes); + + scopes.assign(std::istream_iterator(iss), + std::istream_iterator()); + } + } + + return scopes; +} + +std::pair> token_manager::fetch_auth_header(const std::string& auth) +{ + std::istringstream iss(auth); + std::vector authHeader{std::istream_iterator(iss), + std::istream_iterator() + }; + + bool foundBearer = false; + if (std::any_of(authHeader.begin(), authHeader.end(), + [](std::string word) { + return (word.compare("Bearer") == 0); + })) { + std::cout << "Bearer found" << std::endl; + foundBearer = true; + } + + return std::make_pair(foundBearer, authHeader); +} + +bool token_manager::token_supports_scope(const std::vector scopes, const std::string&& scope) +{ + return std::any_of(scopes.begin(), scopes.end(), + [&](std::string foundScope) { + return (foundScope.compare(scope) == 0); + }); +} diff --git a/src/metadata_retriever.cpp b/src/metadata_retriever.cpp deleted file mode 100644 index 1df9863..0000000 --- a/src/metadata_retriever.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include -#include -#include - -//#include -#include -//#include -#include -//#include -#include -//#include -#include - -#include "directory_manager.h" -#include "metadata_retriever.h" -#include "imageFile.h" - -extern "C" -{ - -void retrieve_metadata(Song*, char*); -void update_metadata(Song*, Song*); - -void retrieve_metadata(Song *sng, char* song_path) -{ - std::cout<<"extern C"<Title, file.tag()->title().toCString()); - strcpy(sng->Artist, file.tag()->artist().toCString()); - strcpy(sng->Album, file.tag()->album().toCString()); - strcpy(sng->Genre, file.tag()->genre().toCString()); - sng->Year = file.tag()->year(); - sng->Duration = file.audioProperties()->lengthInSeconds(); - strcpy(sng->SongPath, song_path); -} -void update_metadata(Song *sng_updated, Song *sng_old) -{ - std::cout<<"updating metadata"<SongPath); - - if (strlen(sng_updated->Title) > 0) { - file.tag()->setTitle(sng_updated->Title); - } - if (strlen(sng_updated->Artist) > 0) { - file.tag()->setArtist(sng_updated->Artist); - } - if (strlen(sng_updated->Album) > 0) { - file.tag()->setAlbum(sng_updated->Album); - } - if (strlen(sng_updated->Genre) > 0) { - file.tag()->setGenre(sng_updated->Genre); - } - if (sng_updated->Year > 0) { - file.tag()->setYear(sng_updated->Year); - } - - file.save(); -} -void update_cover_art(Cover *cov, Song *song, const char *root_path) -{ - TagLib::MPEG::File sngF(song->SongPath); - TagLib::ID3v2::Tag *tag = sngF.ID3v2Tag(); - auto frameList = tag->frameListMap()["APIC"]; - - if (frameList.isEmpty()) { - std::string stock_path{root_path}; - stock_path.append("CoverArt.png"); - strcpy(cov->ImagePath, stock_path.c_str()); - - imageFile stock_img(stock_path.c_str()); - - TagLib::ID3v2::AttachedPictureFrame *pic = - new TagLib::ID3v2::AttachedPictureFrame; - pic->setPicture(stock_img.data()); - pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); - - tag->addFrame(pic); - - sngF.save(); - std::cout<<"applied stock cover art"<( - frameList.front()); - auto img_path = create_directory_process(*song, root_path); - img_path.append(song->Title); - img_path.append(".png"); - strcpy(cov->ImagePath, img_path.c_str()); - std::cout<ImagePath<ImagePath, std::ios::out | - std::ios::binary); - img_save.write(frame->picture().data(), frame->picture().size()); - img_save.close(); - std::cout<<"saved to "<ImagePath< +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "managers/directory_manager.h" +#include "utilities/imageFile.h" +#include "utilities/metadata_retriever.h" + +Song metadata_retriever::retrieve_metadata(std::string& song_path) +{ + TagLib::FileRef file(song_path.c_str()); + Song song; + song.title = file.tag()->title().toCString(); + song.artist = file.tag()->artist().toCString(); + song.album = file.tag()->album().toCString(); + song.genre = file.tag()->genre().toCString(); + song.year = file.tag()->year(); + song.duration = file.audioProperties()->lengthInSeconds(); + song.songPath = song_path; + + /** + strcpy(sng->Title, file.tag()->title().toCString()); + strcpy(sng->Artist, file.tag()->artist().toCString()); + strcpy(sng->Album, file.tag()->album().toCString()); + strcpy(sng->Genre, file.tag()->genre().toCString()); + sng->Year = file.tag()->year(); + sng->Duration = file.audioProperties()->lengthInSeconds(); + strcpy(sng->SongPath, song_path); + */ + + return song; +} + +Cover metadata_retriever::update_cover_art(Cover cov, const Song song, const std::string& root_path) +{ + TagLib::MPEG::File sngF(song.songPath.c_str()); + TagLib::ID3v2::Tag *tag = sngF.ID3v2Tag(); + auto frameList = tag->frameListMap()["APIC"]; + + if (frameList.isEmpty()) { + std::string stock_path{root_path}; + stock_path.append("CoverArt.png"); + cov.imagePath = stock_path; + //strcpy(cov->ImagePath, stock_path.c_str()); + + imageFile stock_img(cov.imagePath.c_str()); + + TagLib::ID3v2::AttachedPictureFrame *pic = + new TagLib::ID3v2::AttachedPictureFrame; + pic->setPicture(stock_img.data()); + pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); + + tag->addFrame(pic); + + sngF.save(); + std::cout<<"applied stock cover art"<( + frameList.front()); + directory_manager dir; + auto img_path = dir.create_directory_process(song, root_path); + img_path.append(song.title); + img_path.append(".png"); + cov.imagePath = img_path; + //strcpy(cov->ImagePath, img_path.c_str()); + std::cout<picture().data(), frame->picture().size()); + img_save.close(); + std::cout<<"saved to "< 0) { + file.tag()->setTitle(sng_updated.title); + } + if (sng_updated.artist.size() > 0) { + file.tag()->setArtist(sng_updated.artist); + } + if (sng_updated.album.size() > 0) { + file.tag()->setAlbum(sng_updated.album); + } + if (sng_updated.genre.size() > 0) { + file.tag()->setGenre(sng_updated.genre); + } + if (sng_updated.year > 0) { + file.tag()->setYear(sng_updated.year); + } + + file.save(); +}