diff --git a/CMakeLists.txt b/CMakeLists.txt index b99c71fff..e110a1e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,13 +19,14 @@ include_directories( FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h") FILE(GLOB HTTPInterface "src/cpp/HTTPInterface/*.h" "src/cpp/HTTPInterface/*.cpp") +FILE(GLOB JSONInterface "src/cpp/JSONInterface/*.h" "src/cpp/JSONInterface/*.cpp") FILE(GLOB TASKS "src/cpp/tasks/*.cpp" "src/cpp/tasks/*.h") FILE(GLOB SINGLETON_MANAGER "src/cpp/SingletonManager/*.h" "src/cpp/SingletonManager/*.cpp") FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp") FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp") FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h") FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h") -SET(LOCAL_SRCS ${TINF} ${MAIN} ${HTTPInterface} ${CRYPTO} ${MODEL} ${SINGLETON_MANAGER} ${MYSQL} ${TASKS}) +SET(LOCAL_SRCS ${TINF} ${MAIN} ${HTTPInterface} ${JSONInterface} ${CRYPTO} ${MODEL} ${SINGLETON_MANAGER} ${MYSQL} ${TASKS}) aux_source_directory("src/cpp" LOCAL_SRCS) if(MSVC) @@ -37,6 +38,7 @@ source_group("model" FILES ${MODEL}) source_group("mysql" FILES ${MYSQL}) source_group("SingletonManager" FILES ${SINGLETON_MANAGER}) source_group("HTTP-Interface" FILES ${HTTPInterface}) +source_group("Json-Interface" FILES ${JSONInterface}) endif(MSVC) diff --git a/src/cpp/Gradido_LoginServer.cpp b/src/cpp/Gradido_LoginServer.cpp index d1049686a..e6d96d964 100644 --- a/src/cpp/Gradido_LoginServer.cpp +++ b/src/cpp/Gradido_LoginServer.cpp @@ -1,6 +1,7 @@ #include "Gradido_LoginServer.h" #include "ServerConfig.h" #include "HTTPInterface/PageRequestHandlerFactory.h" +#include "JSONInterface/JsonRequestHandlerFactory.h" #include "model/Profiler.h" @@ -81,6 +82,7 @@ int Gradido_LoginServer::main(const std::vector& args) else { unsigned short port = (unsigned short)config().getInt("HTTPServer.port", 9980); + unsigned short json_port = (unsigned short)config().getInt("JSONServer.port", 1201); // load word lists if (!ServerConfig::loadMnemonicWordLists()) { @@ -155,27 +157,33 @@ int Gradido_LoginServer::main(const std::vector& args) requestLog.setChannel(requestLogAsyncChannel); requestLog.setLevel("information"); + // HTTP Interface Server // set-up a server socket Poco::Net::ServerSocket svs(port); // set-up a HTTPServer instance Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool(); Poco::Net::HTTPServer srv(new PageRequestHandlerFactory, svs, new Poco::Net::HTTPServerParams); ServerConfig::g_ServerKeySeed->put(7, 918276611); - Poco::Int64 key[6]; - const unsigned char* seed = *ServerConfig::g_ServerKeySeed; - // skip first two values - seed += 16; - memcpy(key, seed, 6 * 8); - printf("key: 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n", - key[0], key[1], key[2], key[3], key[4], key[5]); + // start the HTTPServer srv.start(); + + // JSON Interface Server + Poco::Net::ServerSocket json_svs(json_port); + Poco::Net::HTTPServer json_srv(new JsonRequestHandlerFactory, json_svs, new Poco::Net::HTTPServerParams); + + // start the json server + json_srv.start(); + printf("[Gradido_LoginServer::main] started in %s\n", usedTime.string().data()); // wait for CTRL-C or kill waitForTerminationRequest(); // Stop the HTTPServer srv.stop(); + // Stop the json server + json_srv.stop(); + ServerConfig::unload(); Poco::Net::uninitializeSSL(); } diff --git a/src/cpp/JSONInterface/JsonGetLogin.cpp b/src/cpp/JSONInterface/JsonGetLogin.cpp new file mode 100644 index 000000000..c9d973cc7 --- /dev/null +++ b/src/cpp/JSONInterface/JsonGetLogin.cpp @@ -0,0 +1,81 @@ +#include "JsonGetLogin.h" +#include "Poco/URI.h" + +#include "../SingletonManager/SessionManager.h" + +Poco::JSON::Object JsonGetLogin::handle(Poco::Dynamic::Var params) +{ + + int session_id = 0; + Poco::JSON::Object result; + if (params.isStruct()) { + session_id = params["session_id"]; + //std::string miau = params["miau"]; + } + else if (params.isVector()) { + try { + const Poco::URI::QueryParameters queryParams = params.extract(); + for (auto it = queryParams.begin(); it != queryParams.end(); it++) { + if (it->first == "session_id") { + session_id = stoi(it->second); + break; + } + } + //auto var = params[0]; + } + catch (const std::invalid_argument& ia) { + result.set("state", "error"); + result.set("msg", "error parsing query params, invalid argument: "); + result.set("details", ia.what()); + return result; + } + catch (const std::out_of_range& oor) { + result.set("state", "error"); + result.set("msg", "error parsing query params, Out of Range error: "); + result.set("details", oor.what()); + return result; + } + catch (const std::logic_error & ler) { + result.set("state", "error"); + result.set("msg", "error parsing query params, Logical error: "); + result.set("details", ler.what()); + return result; + } + catch (Poco::Exception& ex) { + //printf("[JsonGetLogin::handle] exception: %s\n", ex.displayText().data()); + result.set("state", "error"); + result.set("msg", "error parsing query params, Poco Error"); + result.set("details", ex.displayText()); + return result; + } + } + + if (session_id) { + auto sm = SessionManager::getInstance(); + auto session = sm->getSession(session_id); + if (session) { + auto user = session->getUser(); + if (!user) { + result.set("state", "not found"); + result.set("msg", "Session didn't contain user"); + return result; + } + result.set("state", "success"); + result.set("clientIP", session->getClientIp()); + result.set("user", user->getJson()); + return result; + } + else { + result.set("state", "not found"); + result.set("msg", "Session not found"); + return result; + } + + } + else { + result.set("state", "error"); + result.set("msg", "empty session id"); + } + + return result; +} \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonGetLogin.h b/src/cpp/JSONInterface/JsonGetLogin.h new file mode 100644 index 000000000..e80435e25 --- /dev/null +++ b/src/cpp/JSONInterface/JsonGetLogin.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_GET_LOGIN_ +#define __JSON_INTERFACE_JSON_GET_LOGIN_ + +#include "JsonRequestHandler.h" + +class JsonGetLogin : public JsonRequestHandler +{ +public: + Poco::JSON::Object handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_GET_LOGIN_ \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonRequestHandler.cpp b/src/cpp/JSONInterface/JsonRequestHandler.cpp new file mode 100644 index 000000000..6d4058e42 --- /dev/null +++ b/src/cpp/JSONInterface/JsonRequestHandler.cpp @@ -0,0 +1,48 @@ +#include "JsonRequestHandler.h" + +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" + +#include "Poco/URI.h" +#include "Poco/DeflatingStream.h" + +#include "Poco/JSON/Parser.h" + + + +void JsonRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) +{ + + response.setChunkedTransferEncoding(true); + response.setContentType("application/json"); + bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); + if (_compressResponse) response.set("Content-Encoding", "gzip"); + + std::ostream& _responseStream = response.send(); + Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); + std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; + + auto method = request.getMethod(); + std::istream& request_stream = request.stream(); + Poco::JSON::Object json_result; + if (method == "POST") { + // extract parameter from request + Poco::JSON::Parser jsonParser; + try { + auto params = jsonParser.parse(request_stream); + // call logic + json_result = handle(params); + } + catch (Poco::Exception& ex) { + printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data()); + } + } + else if(method == "GET") { + Poco::URI uri(request.getURI()); + auto queryParameters = uri.getQueryParameters(); + json_result = handle(queryParameters); + } + json_result.stringify(responseStream); + + if (_compressResponse) _gzipStream.close(); +} diff --git a/src/cpp/JSONInterface/JsonRequestHandler.h b/src/cpp/JSONInterface/JsonRequestHandler.h new file mode 100644 index 000000000..57068b7fa --- /dev/null +++ b/src/cpp/JSONInterface/JsonRequestHandler.h @@ -0,0 +1,19 @@ +#ifndef __JSON_INTERFACE_JSON_REQUEST_HANDLER_ +#define __JSON_INTERFACE_JSON_REQUEST_HANDLER_ + +#include "Poco/Net/HTTPRequestHandler.h" +#include "Poco/JSON/Object.h" + +class JsonRequestHandler : public Poco::Net::HTTPRequestHandler +{ +public: + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); + + virtual Poco::JSON::Object handle(Poco::Dynamic::Var params) = 0; + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_REQUEST_HANDLER_ \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp new file mode 100644 index 000000000..31bb61775 --- /dev/null +++ b/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -0,0 +1,26 @@ +#include "JsonRequestHandlerFactory.h" + +#include "Poco/Net/HTTPServerRequest.h" + +#include "../SingletonManager/SessionManager.h" + +#include "JsonGetLogin.h" +#include "JsonUnknown.h" + +JsonRequestHandlerFactory::JsonRequestHandlerFactory() + : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)") +{ +} + +Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) +{ + std::string uri = request.getURI(); + std::string url_first_part; + mRemoveGETParameters.extract(uri, url_first_part); + + if (url_first_part == "/login") { + return new JsonGetLogin; + } + + return new JsonUnknown; +} diff --git a/src/cpp/JSONInterface/JsonRequestHandlerFactory.h b/src/cpp/JSONInterface/JsonRequestHandlerFactory.h new file mode 100644 index 000000000..26fe5c023 --- /dev/null +++ b/src/cpp/JSONInterface/JsonRequestHandlerFactory.h @@ -0,0 +1,19 @@ +#ifndef __DR_JSON_REQUEST_HANDLER_FACTORY_H +#define __DR_JSON_REQUEST_HANDLER_FACTORY_H + +#include "Poco/Net/HTTPRequestHandlerFactory.h" +#include "Poco/RegularExpression.h" + +#define HTTP_PAGES_COUNT 1 + +class JsonRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory +{ +public: + JsonRequestHandlerFactory(); + Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request); + +protected: + Poco::RegularExpression mRemoveGETParameters; +}; + +#endif // __DR_JSON_REQUEST_HANDLER_FACTORY_H \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonUnknown.cpp b/src/cpp/JSONInterface/JsonUnknown.cpp new file mode 100644 index 000000000..07612c2ec --- /dev/null +++ b/src/cpp/JSONInterface/JsonUnknown.cpp @@ -0,0 +1,11 @@ +#include "JsonUnknown.h" + +Poco::JSON::Object JsonUnknown::handle(Poco::Dynamic::Var params) +{ + Poco::JSON::Object result; + + result.set("state", "error"); + result.set("msg", "unknown call"); + + return result; +} \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonUnknown.h b/src/cpp/JSONInterface/JsonUnknown.h new file mode 100644 index 000000000..62c8eb34c --- /dev/null +++ b/src/cpp/JSONInterface/JsonUnknown.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_UNKNOWN_ +#define __JSON_INTERFACE_JSON_UNKNOWN_ + +#include "JsonRequestHandler.h" + +class JsonUnknown : public JsonRequestHandler +{ +public: + Poco::JSON::Object handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_UNKNOWN_ \ No newline at end of file diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index db563a9cf..e32588e3d 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -78,7 +78,7 @@ public: bool generateKeys(bool savePrivkey, bool savePassphrase); inline void setClientIp(Poco::Net::IPAddress ip) { mClientLoginIP = ip; } - + inline Poco::Net::IPAddress getClientIp() { return mClientLoginIP; } inline bool isIPValid(Poco::Net::IPAddress ip) { return mClientLoginIP == ip; } bool isPwdValid(const std::string& pwd); diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index 8b2614084..ad5066e4f 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -361,6 +361,19 @@ UserStates User::getUserState() return state; } +Poco::JSON::Object User::getJson() +{ + lock(); + Poco::JSON::Object userObj; + userObj.set("first_name", mFirstName); + userObj.set("last_name", mLastName); + userObj.set("email", mEmail); + userObj.set("public_hex", mPublicHex); + userObj.set("state", userStateToString(mState)); + unlock(); + return userObj; +} + // TODO: if a password and privkey already exist, load current private key and re encrypt with new crypto key bool User::setNewPassword(const std::string& newPassword) { @@ -692,4 +705,18 @@ bool User::loadEntryDBId(Poco::Data::Session session) } return true; +} + +const char* User::userStateToString(UserStates state) +{ + switch (state) { + case USER_EMPTY: return "empty"; + case USER_LOADED_FROM_DB: return "loaded from db"; + case USER_PASSWORD_INCORRECT: return "password incorrect"; + case USER_EMAIL_NOT_ACTIVATED: return "email not activated"; + case USER_NO_KEYS: return "no keys"; + case USER_NO_PRIVATE_KEY: return "no private key"; + case USER_COMPLETE: return "complete"; + } + return "- unknown -"; } \ No newline at end of file diff --git a/src/cpp/model/User.h b/src/cpp/model/User.h index f277cba6b..75599f872 100644 --- a/src/cpp/model/User.h +++ b/src/cpp/model/User.h @@ -8,6 +8,7 @@ #include "Poco/Thread.h" #include "Poco/Types.h" #include "Poco/Data/Session.h" +#include "Poco/JSON/Object.h" #include "../tasks/CPUTask.h" class NewUser; @@ -57,6 +58,7 @@ public: static std::string generateNewPassphrase(Mnemonic* word_source); static bool validatePassphrase(const std::string& passphrase); + static const char* userStateToString(UserStates state); //static User* login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr); bool generateKeys(bool savePrivkey, const std::string& passphrase, Session* session); @@ -83,7 +85,7 @@ public: Poco::Data::BLOB* encrypt(const ObfusArray* data); - + Poco::JSON::Object getJson(); // for poco auto ptr void duplicate();