Added remove endpoint

This commit is contained in:
zvon 2021-07-09 18:28:16 +02:00
parent 0b84f16316
commit 06fd045fc1
3 changed files with 127 additions and 36 deletions

View File

@ -27,6 +27,7 @@ namespace FSLib {
bool exists( const string &path ); bool exists( const string &path );
bool isDirectory( const string &path ); bool isDirectory( const string &path );
bool rename( const string &file_a, const string &file_b ); bool rename( const string &file_a, const string &file_b );
bool deleteFile( const string &file );
string canonical( const string &path ); string canonical( const string &path );
bool createDirectoryFull( const string &path ); bool createDirectoryFull( const string &path );
string getContainingDirectory( const string &path ); string getContainingDirectory( const string &path );

View File

@ -1,6 +1,7 @@
#include "../filesystem.hpp" #include "../filesystem.hpp"
#include <cstring> #include <cstring>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/syslimits.h> #include <sys/syslimits.h>
#endif #endif
@ -71,6 +72,34 @@ bool FSLib::rename( const string &file_a, const string &file_b ) {
return ::rename( file_a.c_str(), file_b.c_str() ) == 0; return ::rename( file_a.c_str(), file_b.c_str() ) == 0;
} }
// TODO do windows version
bool deleteRecursive(const string &dir) {
for(const auto &file : FSLib::Directory(dir)) {
auto path = dir + "/" + file;
if(FSLib::isDirectory(path)) {
if(!deleteRecursive(path)) {
return false;
}
} else if(unlink(path.c_str()) != 0) {
return false;
}
}
return rmdir(dir.c_str()) == 0;
}
bool FSLib::deleteFile( const string &file ) {
// TODO log
auto canon = canonical( file );
if(canon.empty()) {
return false;
}
if(isDirectory(canon)) {
return deleteRecursive(canon);
}
return unlink(canon.c_str()) == 0;
}
bool FSLib::createDirectoryFull( const string &path ) { bool FSLib::createDirectoryFull( const string &path ) {
uint64_t pos{}; uint64_t pos{};
// go through all directories leading to the last one // go through all directories leading to the last one

133
main.cpp
View File

@ -20,16 +20,16 @@
std::vector<RenameLibrary> libraries{}; std::vector<RenameLibrary> libraries{};
Configuration cfg; Configuration cfg;
void sendResponse(const std::string &response, int status_code, const std::shared_ptr< restbed::Session > session) { void sendResponse(const std::string &response, int status_code, const std::shared_ptr< restbed::Session > &session) {
session->close(status_code, response, { { "Content-Length", std::to_string(response.length()) }, { "Access-Control-Allow-Origin", "*" } }); session->close(status_code, response, { { "Content-Length", std::to_string(response.length()) }, { "Access-Control-Allow-Origin", "*" } });
} }
void performPostFunc(const std::shared_ptr<restbed::Session> session, std::function<void(const std::shared_ptr<restbed::Session>, rapidjson::GenericDocument<rapidjson::UTF8<>>&)> callback) { void performPostFunc(const std::shared_ptr<restbed::Session> &session, const std::function<void(const std::shared_ptr<restbed::Session>, rapidjson::GenericDocument<rapidjson::UTF8<>>&)>& callback) {
const auto request = session->get_request( ); const auto request = session->get_request( );
int content_length = request->get_header( "Content-Length", 0 ); int content_length = request->get_header( "Content-Length", 0 );
session->fetch( content_length, [callback]( const std::shared_ptr< restbed::Session > session, const restbed::Bytes & body ) session->fetch( content_length, [callback]( const std::shared_ptr< restbed::Session > &session, const restbed::Bytes & body )
{ {
rapidjson::Document doc; rapidjson::Document doc;
std::cout << std::string(reinterpret_cast<const char*>(body.data()), body.size()) << std::endl; std::cout << std::string(reinterpret_cast<const char*>(body.data()), body.size()) << std::endl;
@ -49,7 +49,7 @@ bool verifyLogin( const std::shared_ptr< restbed::Session > &session, rapidjson:
return false; return false;
} }
std::cout << "AAAA" << std::endl; std::cout << "AAAA" << std::endl;
auto token = doc["token"].GetString(); const auto *token = doc["token"].GetString();
auto res = verifyJWT(token); auto res = verifyJWT(token);
if(!res) { if(!res) {
sendResponse("ERROR: Invalid token!", 401, session); sendResponse("ERROR: Invalid token!", 401, session);
@ -69,8 +69,8 @@ std::string getTypesJson() {
auto types = getTypes(); auto types = getTypes();
std::ostringstream result; std::ostringstream result;
result << "[\n"; result << "[\n";
if(types.size() > 0) { if(!types.empty()) {
for(auto type : types) { for(const auto &type : types) {
result << " {\n \"id\": " << type.second << "\n"; result << " {\n \"id\": " << type.second << "\n";
result << " \"name\": \"" << type.first << "\"\n },\n"; result << " \"name\": \"" << type.first << "\"\n },\n";
} }
@ -81,7 +81,7 @@ std::string getTypesJson() {
return result.str(); return result.str();
} }
void getTypesRest( const std::shared_ptr< restbed::Session > session ) { void getTypesRest( const std::shared_ptr< restbed::Session > &session ) {
sendResponse(getTypesJson(), restbed::OK, session); sendResponse(getTypesJson(), restbed::OK, session);
} }
@ -100,7 +100,7 @@ std::string getOptionsJson(const RenameObject &search, size_t type) {
std::ostringstream res; std::ostringstream res;
res << "[\n"; res << "[\n";
auto options = getOptions(search, type); auto options = getOptions(search, type);
if(options.size() > 0) { if(!options.empty()) {
for(auto &option : options) { for(auto &option : options) {
res << option.toJson(); res << option.toJson();
res << ",\n"; res << ",\n";
@ -112,7 +112,7 @@ std::string getOptionsJson(const RenameObject &search, size_t type) {
return res.str(); return res.str();
} }
void getOptionsRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void getOptionsRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(doc.HasParseError()) { if(doc.HasParseError()) {
sendResponse("ERROR: Invalid body!", 401, session); sendResponse("ERROR: Invalid body!", 401, session);
@ -155,7 +155,7 @@ std::string getCustomKeysJson(size_t type) {
std::ostringstream res; std::ostringstream res;
res << "[\n"; res << "[\n";
auto custom_keys = getCustomKeys(type); auto custom_keys = getCustomKeys(type);
if(custom_keys.size() > 0) { if(!custom_keys.empty()) {
for(auto &key : custom_keys) { for(auto &key : custom_keys) {
res << "\"" << key << "\",\n"; res << "\"" << key << "\",\n";
} }
@ -166,7 +166,7 @@ std::string getCustomKeysJson(size_t type) {
return res.str(); return res.str();
} }
void getCustomKeysRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void getCustomKeysRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(doc.FindMember("type") == doc.MemberEnd() || !doc["type"].IsUint64()) { if(doc.FindMember("type") == doc.MemberEnd() || !doc["type"].IsUint64()) {
sendResponse("ERROR: Invalid type!", 401, session); sendResponse("ERROR: Invalid type!", 401, session);
@ -182,9 +182,11 @@ std::pair<bool, std::string> renamePath(std::string path, const RenameObject &re
} }
if(path[0] == '/' && path.substr(0, cfg.getSourcePath().length()) != cfg.getSourcePath()) { if(path[0] == '/' && path.substr(0, cfg.getSourcePath().length()) != cfg.getSourcePath()) {
return {false, "Invalid path"}; return {false, "Invalid path"};
} else if(path.find("..") != std::string::npos) { }
if(path.find("..") != std::string::npos) {
return {false, "Path cannot contain '..'"}; return {false, "Path cannot contain '..'"};
} else if(path[0] != '/') { }
if(path[0] != '/') {
path = cfg.getSourcePath() + "/" + path; path = cfg.getSourcePath() + "/" + path;
} }
if(!FSLib::exists(path)) { if(!FSLib::exists(path)) {
@ -210,7 +212,7 @@ std::string renamePathJson(const std::string &path, const RenameObject &renamer)
return res.str(); return res.str();
} }
void renamePathRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) { void renamePathRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) {
if(!verifyLogin(session, doc)) { if(!verifyLogin(session, doc)) {
return; return;
} }
@ -237,7 +239,7 @@ std::string getFilesJson() {
std::ostringstream res; std::ostringstream res;
res << "[\n"; res << "[\n";
auto files = getFilesInSource(cfg.getSourcePath()); auto files = getFilesInSource(cfg.getSourcePath());
if(files.size() > 0) { if(!files.empty()) {
for(const auto &file : files) { for(const auto &file : files) {
res << "\"" << file << "\",\n"; res << "\"" << file << "\",\n";
} }
@ -247,7 +249,7 @@ std::string getFilesJson() {
return res.str(); return res.str();
} }
void getFilesRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void getFilesRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(!verifyLogin(session, doc)) { if(!verifyLogin(session, doc)) {
return; return;
@ -268,7 +270,7 @@ std::string getTargetsJson() {
std::ostringstream res; std::ostringstream res;
res << "[\n"; res << "[\n";
auto targets = getTargets(); auto targets = getTargets();
if(targets.size() > 0) { if(!targets.empty()) {
for(const auto &target : targets) { for(const auto &target : targets) {
res << " {\n" << " \"id\": " << target.first << "\n"; res << " {\n" << " \"id\": " << target.first << "\n";
res << " \"name\": \"" << target.second << "\"\n },\n"; res << " \"name\": \"" << target.second << "\"\n },\n";
@ -279,7 +281,7 @@ std::string getTargetsJson() {
return res.str(); return res.str();
} }
void getTargetsRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void getTargetsRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(!verifyLogin(session, doc)) { if(!verifyLogin(session, doc)) {
return; return;
@ -294,7 +296,7 @@ std::string getTargetDirectoriesJson(uint64_t id) {
std::ostringstream res; std::ostringstream res;
res << "[\n"; res << "[\n";
auto dirs = getTargetDirectories(cfg.getTargetPaths()[id].first); auto dirs = getTargetDirectories(cfg.getTargetPaths()[id].first);
if(dirs.size() > 0) { if(!dirs.empty()) {
for(const auto &dir : dirs) { for(const auto &dir : dirs) {
res << " \"" << dir << "\",\n"; res << " \"" << dir << "\",\n";
} }
@ -304,7 +306,7 @@ std::string getTargetDirectoriesJson(uint64_t id) {
return res.str(); return res.str();
} }
void getTargetDirectoriesRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void getTargetDirectoriesRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(!verifyLogin(session, doc)) { if(!verifyLogin(session, doc)) {
return; return;
@ -320,9 +322,11 @@ void getTargetDirectoriesRest( const std::shared_ptr< restbed::Session > session
std::pair<bool, std::string> move(std::string path, uint64_t target_id, const std::string &containing_dir) { std::pair<bool, std::string> move(std::string path, uint64_t target_id, const std::string &containing_dir) {
if(path[0] == '/' && path.substr(0, cfg.getSourcePath().length()) != cfg.getSourcePath()) { if(path[0] == '/' && path.substr(0, cfg.getSourcePath().length()) != cfg.getSourcePath()) {
return {false, "Invalid path"}; return {false, "Invalid path"};
} else if(path.find("..") != std::string::npos) { }
if(path.find("..") != std::string::npos) {
return {false, "Path cannot contain '..'"}; return {false, "Path cannot contain '..'"};
} else if(path[0] != '/') { }
if(path[0] != '/') {
path = cfg.getSourcePath() + "/" + path; path = cfg.getSourcePath() + "/" + path;
} }
if(target_id >= cfg.getTargetPaths().size()) { if(target_id >= cfg.getTargetPaths().size()) {
@ -355,12 +359,12 @@ std::string moveJson(const std::string &path, uint64_t target_id, const std::str
return res.str(); return res.str();
} }
void moveRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) void moveRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{ {
if(!verifyLogin(session, doc)) { if(!verifyLogin(session, doc)) {
return; return;
} }
std::string containing_dir = ""; std::string containing_dir;
if(doc.FindMember("path") == doc.MemberEnd() || !doc["path"].IsString()) { if(doc.FindMember("path") == doc.MemberEnd() || !doc["path"].IsString()) {
// TODO validate path, also validate against config // TODO validate path, also validate against config
sendResponse("ERROR: Invalid path!", 401, session); sendResponse("ERROR: Invalid path!", 401, session);
@ -379,7 +383,55 @@ void moveRest( const std::shared_ptr< restbed::Session > session, rapidjson::Gen
sendResponse(moveJson(path, id, containing_dir), 200, session); sendResponse(moveJson(path, id, containing_dir), 200, session);
} }
void loginRest( const std::shared_ptr< restbed::Session > session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) { std::pair<bool, std::string> remove(std::string path) {
if(path[0] == '/' && path.substr(0, cfg.getSourcePath().length()) != cfg.getSourcePath()) {
return {false, "Invalid path"};
}
if(path.find("..") != std::string::npos) {
return {false, "Path cannot contain '..'"};
}
if(path[0] != '/') {
path = cfg.getSourcePath() + "/" + path;
}
if(!FSLib::exists(path)) {
return {false, "Source doesn't exist"};
}
return {FSLib::deleteFile(path), "Library error"};
}
std::string removeJson(const std::string &path) {
std::ostringstream res;
res << "{\n \"success\": ";
auto remove_result = remove(path);
if(remove_result.first) {
res << "true";
} else {
res << "false";
}
res << "\"\n";
if(!remove_result.first) {
res << " \"error\": \"" << remove_result.second << "\"\n";
}
res << "}";
return res.str();
}
void removeRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc )
{
if(!verifyLogin(session, doc)) {
return;
}
if(doc.FindMember("path") == doc.MemberEnd() || !doc["path"].IsString()) {
// TODO validate path, also validate against config
sendResponse("ERROR: Invalid path!", 401, session);
return;
}
std::string path = doc["path"].GetString();
// TODO correct response code
sendResponse(removeJson(path), 200, session);
}
void loginRest( const std::shared_ptr< restbed::Session > &session, rapidjson::GenericDocument<rapidjson::UTF8<>> &doc ) {
if(doc.FindMember("user") == doc.MemberEnd() || !doc["user"].IsString()) { if(doc.FindMember("user") == doc.MemberEnd() || !doc["user"].IsString()) {
sendResponse("ERROR: Invalid user!", 401, session); sendResponse("ERROR: Invalid user!", 401, session);
return; return;
@ -388,10 +440,10 @@ void loginRest( const std::shared_ptr< restbed::Session > session, rapidjson::Ge
sendResponse("ERROR: Invalid password!", 401, session); sendResponse("ERROR: Invalid password!", 401, session);
return; return;
} }
auto user = doc["user"].GetString(); const auto *user = doc["user"].GetString();
auto password = doc["password"].GetString(); const auto *password = doc["password"].GetString();
bool valid = false; bool valid = false;
for(auto &user_cfg : cfg.getUsers()) { for(const auto &user_cfg : cfg.getUsers()) {
if(user_cfg.first == user) { if(user_cfg.first == user) {
valid = user_cfg.second == password; valid = user_cfg.second == password;
break; break;
@ -404,35 +456,39 @@ void loginRest( const std::shared_ptr< restbed::Session > session, rapidjson::Ge
} }
} }
void getOptionsCall(const std::shared_ptr<restbed::Session> session) { void getOptionsCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, getOptionsRest); performPostFunc(session, getOptionsRest);
} }
void getCustomKeysCall(const std::shared_ptr<restbed::Session> session) { void getCustomKeysCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, getCustomKeysRest); performPostFunc(session, getCustomKeysRest);
} }
void renameCall(const std::shared_ptr<restbed::Session> session) { void renameCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, renamePathRest); performPostFunc(session, renamePathRest);
} }
void getFilesCall(const std::shared_ptr<restbed::Session> session) { void getFilesCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, getFilesRest); performPostFunc(session, getFilesRest);
} }
void getTargetsCall(const std::shared_ptr<restbed::Session> session) { void getTargetsCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, getTargetsRest); performPostFunc(session, getTargetsRest);
} }
void getTargetDirectoriesCall(const std::shared_ptr<restbed::Session> session) { void getTargetDirectoriesCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, getTargetDirectoriesRest); performPostFunc(session, getTargetDirectoriesRest);
} }
void moveCall(const std::shared_ptr<restbed::Session> session) { void moveCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, moveRest); performPostFunc(session, moveRest);
} }
void loginCall(const std::shared_ptr<restbed::Session> session) { void removeCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, removeRest);
}
void loginCall(const std::shared_ptr<restbed::Session> &session) {
performPostFunc(session, loginRest); performPostFunc(session, loginRest);
} }
@ -486,6 +542,11 @@ int main(int argc, char **argv) {
move->set_method_handler( "POST", moveCall ); move->set_method_handler( "POST", moveCall );
service.publish(move); service.publish(move);
auto remove = std::make_shared< restbed::Resource >();
remove->set_path("/remove");
remove->set_method_handler( "POST", removeCall );
service.publish(remove);
auto login = std::make_shared< restbed::Resource >(); auto login = std::make_shared< restbed::Resource >();
login->set_path("/login"); login->set_path("/login");
login->set_method_handler( "POST", loginCall ); login->set_method_handler( "POST", loginCall );