diff --git a/src/cpp/Crypto/KeyPair.h b/src/cpp/Crypto/KeyPair.h index 3c1068fdf..e300f4a38 100644 --- a/src/cpp/Crypto/KeyPair.h +++ b/src/cpp/Crypto/KeyPair.h @@ -7,8 +7,11 @@ #include "ed25519/ed25519.h" #include +class UserWriteKeysIntoDB; + class KeyPair { + friend UserWriteKeysIntoDB; public: KeyPair(); ~KeyPair(); @@ -17,7 +20,11 @@ public: std::string getPubkeyHex(); bool savePrivKey(int userId); + + inline const unsigned char* getPublicKey() const { return mSodiumPublic; } + protected: + const ObfusArray* getPrivateKey() const { return mSodiumSecret; } private: ObfusArray* mPrivateKey; diff --git a/src/cpp/Crypto/Obfus_array.h b/src/cpp/Crypto/Obfus_array.h index b8f447941..c9affd91a 100644 --- a/src/cpp/Crypto/Obfus_array.h +++ b/src/cpp/Crypto/Obfus_array.h @@ -9,12 +9,9 @@ public: ObfusArray(size_t size, const unsigned char * data); ~ObfusArray(); - operator const unsigned char*() { - return &m_Data[m_offsetSize]; - } - size_t size() { - return m_dataSize; - } + inline operator const unsigned char*() const {return &m_Data[m_offsetSize];} + + inline size_t size() const { return m_dataSize;} private: size_t m_arraySize; diff --git a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp index e78becc59..eb5aa20e5 100644 --- a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp +++ b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp @@ -140,37 +140,3 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi return new CheckEmailPage(session); } -Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handlePassphrase(Session* session, const Poco::Net::HTTPServerRequest& request) -{ - //couldn't use form here, because request is const - /* - Poco::Net::HTMLForm form(request); - if (!form.empty()) { - auto registerKeyChoice = form.get("passphrase", ""); - std::string oldPassphrase = ""; - if (registerKeyChoice == "no") { - auto oldPassphrase = form.get("passphrase-existing", ""); - - if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) { - // passphrase is valid - session->setPassphrase(oldPassphrase); - session->updateState(SESSION_STATE_PASSPHRASE_SHOWN); - // go one - return new SaveKeysPage(session); - } - else { - session->addError(new Error("Merkspruch", "Dieser Merkspruch ist ungültig, bitte überprüfen oder neu generieren (lassen).")); - } - } - else if (registerKeyChoice == "yes") { - session->generatePassphrase(); - } - } - return new PassphrasePage(session); - */ -} - -Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleSaveKeys(Session* session, const Poco::Net::HTTPServerRequest& request) -{ - -} \ No newline at end of file diff --git a/src/cpp/HTTPInterface/PageRequestHandlerFactory.h b/src/cpp/HTTPInterface/PageRequestHandlerFactory.h index d98c7d74b..bf172496d 100644 --- a/src/cpp/HTTPInterface/PageRequestHandlerFactory.h +++ b/src/cpp/HTTPInterface/PageRequestHandlerFactory.h @@ -3,6 +3,7 @@ #include "Poco/Net/HTTPRequestHandlerFactory.h" #include "Poco/RegularExpression.h" +#include "../model/Session.h" #define HTTP_PAGES_COUNT 1 @@ -14,8 +15,6 @@ public: protected: Poco::Net::HTTPRequestHandler* handleCheckEmail(Session* session, const std::string uri, const Poco::Net::HTTPServerRequest& request); - Poco::Net::HTTPRequestHandler* handlePassphrase(Session* session, const Poco::Net::HTTPServerRequest& request); - Poco::Net::HTTPRequestHandler* handleSaveKeys(Session* session, const Poco::Net::HTTPServerRequest& request); Poco::RegularExpression mRemoveGETParameters; }; diff --git a/src/cpp/HTTPInterface/PassphrasePage.cpp b/src/cpp/HTTPInterface/PassphrasePage.cpp new file mode 100644 index 000000000..661dd7058 --- /dev/null +++ b/src/cpp/HTTPInterface/PassphrasePage.cpp @@ -0,0 +1,154 @@ +#include "PassphrasePage.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/DeflatingStream.h" + + +#line 7 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + + +enum PageState +{ + PAGE_ASK_PASSPHRASE, + PAGE_SHOW_PASSPHRASE +}; + + +PassphrasePage::PassphrasePage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) +{ + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); + if (_compressResponse) response.set("Content-Encoding", "gzip"); + + Poco::Net::HTMLForm form(request, request.stream()); +#line 15 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + + PageState state = PAGE_ASK_PASSPHRASE; + bool hasErrors = mSession->errorCount() > 0; + + // save login cookie, because maybe we've get an new session + auto cookie_id = mSession->getHandle(); + auto user_host = request.clientAddress().host(); + mSession->setClientIp(user_host); + response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id))); + + if (!form.empty()) { + auto registerKeyChoice = form.get("passphrase", ""); + std::string oldPassphrase = ""; + if (registerKeyChoice == "no") { + auto oldPassphrase = form.get("passphrase-existing", ""); + + if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) { + // passphrase is valid + mSession->setPassphrase(oldPassphrase); + mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN); + state = PAGE_SHOW_PASSPHRASE; + } + else { + mSession->addError(new Error("Merkspruch", "Dieser Merkspruch ist ungültig, bitte überprüfen oder neu generieren (lassen).")); + } + } + else if (registerKeyChoice == "yes") { + mSession->generatePassphrase(); + } + } + + if(mSession->getSessionState() == SESSION_STATE_PASSPHRASE_GENERATED) { + state = PAGE_SHOW_PASSPHRASE; + mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN); + } + std::ostream& _responseStream = response.send(); + Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); + std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: Merkspruch\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t"; +#line 71 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + if(mSession && hasErrors) { responseStream << "\n"; + responseStream << "\t\t"; +#line 72 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + responseStream << ( mSession->getErrorsHtml() ); + responseStream << "\n"; + responseStream << "\t"; +#line 73 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +} responseStream << "\n"; + responseStream << "\t

Einen neuen Account anlegen

\n"; + responseStream << "\t"; +#line 75 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + if(state == PAGE_SHOW_PASSPHRASE) { responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\tSchreibe dir den Merkspruch auf und packe ihn gut weg. Du brauchst ihn um deine Adresse wiederherzustellen. Wenn du ihn verlierst, sind auch deine Gradidos verloren.\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t"; +#line 81 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + responseStream << ( mSession->getPassphrase() ); + responseStream << "\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\tWeiter\n"; + responseStream << "\t\t
\n"; + responseStream << "\t"; +#line 85 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + } else if(state == PAGE_ASK_PASSPHRASE) { responseStream << "\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\tNeue Gradido Adresse anlegen / wiederherstellen\n"; + responseStream << "\t\t\t

Hast du schonmal ein Gradido Konto besessen?

\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\n"; + responseStream << "\t\t\n"; + responseStream << "\t
\n"; + responseStream << "\t"; +#line 103 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\tUngültige Seite, wenn du das siehst stimmt hier etwas nicht. Bitte wende dich an den Server-Admin. \n"; + responseStream << "\t\t
\n"; + responseStream << "\t"; +#line 107 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" + } responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\n"; + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/src/cpp/HTTPInterface/PassphrasePage.h b/src/cpp/HTTPInterface/PassphrasePage.h new file mode 100644 index 000000000..248a9e821 --- /dev/null +++ b/src/cpp/HTTPInterface/PassphrasePage.h @@ -0,0 +1,20 @@ +#ifndef PassphrasePage_INCLUDED +#define PassphrasePage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class PassphrasePage: public SessionHTTPRequestHandler +{ +public: + PassphrasePage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // PassphrasePage_INCLUDED diff --git a/src/cpp/HTTPInterface/SaveKeysPage.cpp b/src/cpp/HTTPInterface/SaveKeysPage.cpp index 21a74ab9c..7df771344 100644 --- a/src/cpp/HTTPInterface/SaveKeysPage.cpp +++ b/src/cpp/HTTPInterface/SaveKeysPage.cpp @@ -7,8 +7,12 @@ #line 7 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" - -#include "../model/Session.h" +enum PageState +{ + PAGE_ASK, + PAGE_SHOW_PUBKEY, + PAGE_ERROR +}; @@ -26,13 +30,45 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 12 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 16 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" bool hasErrors = mSession->errorCount() > 0; bool hasPassword = mSession->getUser()->hasCryptoKey(); + PageState state = PAGE_ASK; if(!form.empty()) { + // privkey + auto savePrivkeyChoice = form.get("save-privkey"); + bool savePrivkey = false; + if(savePrivkeyChoice == "yes") { + if(!hasPassword) { + // check pwd + auto pwd = form.get("save-privkey-password", ""); + if(!mSession->getUser()->validatePwd(pwd)) { + mSession->addError(new Error("Passwort", "Das Passwort stimmt nicht. Bitte verwende dein Passwort von der Registrierung")); + hasErrors = true; + } else { + savePrivkey = true; + } + } else { + savePrivkey = true; + } + } + if(!hasErrors) { + auto savePassphraseChoice = form.get("save-passphrase"); + bool savePassphrase = false; + if(savePassphraseChoice == "yes") { + savePassphrase = true; + } + if(!mSession->generateKeys(savePrivkey, savePassphrase)) { + hasErrors = true; + } else if(mSession->getSessionState() >= SESSION_STATE_KEY_PAIR_GENERATED) { + state = PAGE_SHOW_PUBKEY; + } else { + state = PAGE_ERROR; + } + } } std::ostream& _responseStream = response.send(); Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); @@ -59,16 +95,19 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne responseStream << "\n"; responseStream << "
\n"; responseStream << "\t"; -#line 40 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 76 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" if(hasErrors) { responseStream << "\n"; responseStream << "\t\t"; -#line 41 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 77 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" responseStream << ( mSession->getErrorsHtml() ); responseStream << "\n"; responseStream << "\t"; -#line 42 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 78 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" } responseStream << "\n"; responseStream << "\t

Daten speichern

\n"; + responseStream << "\t"; +#line 80 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" + if(state == PAGE_ASK) { responseStream << "\n"; responseStream << "\t
\n"; responseStream << "\t\t
\n"; responseStream << "\t\t\tGradido Private Key speichern\n"; @@ -82,7 +121,7 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t

\n"; responseStream << "\t\t\t"; -#line 56 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 93 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" if(!hasPassword) { responseStream << "\n"; responseStream << "\t\t\t\t

Ich brauche nochmal dein Passwort wenn du dich für ja entscheidest.

\n"; responseStream << "\t\t\t\t

\n"; @@ -90,7 +129,7 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne responseStream << "\t\t\t\t\t\n"; responseStream << "\t\t\t\t

\n"; responseStream << "\t\t\t"; -#line 62 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" +#line 99 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" } responseStream << "\n"; responseStream << "\t\t\t

\n"; responseStream << "\t\t\t\t\n"; @@ -114,6 +153,29 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne responseStream << "\t\t

\n"; responseStream << "\t\t\n"; responseStream << "\t
\n"; + responseStream << "\t"; +#line 122 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" + } else if(state == PAGE_SHOW_PUBKEY) { responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Je nach Auswahl werden deine Daten nun verschlüsselt und gespeichert.

\n"; + responseStream << "\t\t\t

Deine Gradido Adresse (Hex):

\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\t\t"; +#line 127 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" + responseStream << ( mSession->getUser()->getPublicKeyHex() ); + responseStream << "\n"; + responseStream << "\t\t\t

\n"; + responseStream << "\t\t\tZurück zur Startseite\n"; + responseStream << "\t\t
\n"; + responseStream << "\t"; +#line 131 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" + } else if(state == PAGE_ERROR) { responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Ein Fehler trat auf, bitte versuche es erneut oder wende dich an den Server-Admin

\n"; + responseStream << "\t\t
\n"; + responseStream << "\t"; +#line 135 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp" + } responseStream << "\n"; responseStream << "
\n"; responseStream << "\n"; responseStream << "\n"; diff --git a/src/cpp/ServerConfig.cpp b/src/cpp/ServerConfig.cpp index 1a2389130..6e61d1e2b 100644 --- a/src/cpp/ServerConfig.cpp +++ b/src/cpp/ServerConfig.cpp @@ -19,6 +19,7 @@ using Poco::SharedPtr; namespace ServerConfig { Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; ObfusArray* g_ServerCryptoKey = nullptr; +// std::string g_ServerAdminPublic; UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr; Context::Ptr g_SSL_CLient_Context = nullptr; EmailAccount g_EmailAccount; @@ -63,6 +64,8 @@ namespace ServerConfig { return false; } g_ServerCryptoKey = new ObfusArray(realBinSize, key); + + //g_ServerAdminPublic = cfg.getString("crypto.server_admin_public"); return true; } diff --git a/src/cpp/ServerConfig.h b/src/cpp/ServerConfig.h index bb5c71b51..d7fc84b69 100644 --- a/src/cpp/ServerConfig.h +++ b/src/cpp/ServerConfig.h @@ -23,6 +23,7 @@ namespace ServerConfig { extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; extern ObfusArray* g_ServerCryptoKey; + //extern unsigned char g_ServerAdminPublic[]; extern UniLib::controller::CPUSheduler* g_CPUScheduler; extern Poco::Net::Context::Ptr g_SSL_CLient_Context; extern EmailAccount g_EmailAccount; diff --git a/src/cpp/SingletonManager/ErrorManager.cpp b/src/cpp/SingletonManager/ErrorManager.cpp index 1481107c1..2cbb742a1 100644 --- a/src/cpp/SingletonManager/ErrorManager.cpp +++ b/src/cpp/SingletonManager/ErrorManager.cpp @@ -27,7 +27,8 @@ int SendErrorMessage::run() mailClientSession->close(); } catch (Poco::Exception& exc) { - printf("[SendErrorMessage::%s] error sending error message to admin\n", __FUNCTION__); + printf("[SendErrorMessage::%s] error sending error message to admin: %s\n", + __FUNCTION__, exc.displayText().data()); return -1; } return 0; diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index d79d01cb0..5c9277cdf 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -18,6 +18,7 @@ using namespace Poco::Data::Keywords; int WriteEmailVerification::run() { + Profiler timeUsed; auto verificationCode = mSession->getEmailVerificationCode(); printf("{[WriteEmailVerification::run] E-Mail Verification Code: %llu\n", verificationCode); auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); @@ -29,12 +30,31 @@ int WriteEmailVerification::run() mSession->addError(new Error("WriteEmailVerification", "error inserting email verification code")); return -1; } - + printf("[WriteEmailVerification::run] timeUsed: %s\n", timeUsed.string().data()); return 0; } // --------------------------------------------------------------------------------------------------------------- +int WritePassphraseIntoDB::run() +{ + Profiler timeUsed; + + // TODO: encrypt passphrase, need server admin crypto box pubkey + //int crypto_box_seal(unsigned char *c, const unsigned char *m, + //unsigned long long mlen, const unsigned char *pk); + size_t mlen = mPassphrase.size(); + size_t crypto_size = crypto_box_SEALBYTES + mlen; + + + auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement insert(dbSession); + insert << "INSERT INTO user_backups (user_id, passphrase) VALUES(?,?)", + use(mUserId), use(mPassphrase); + + printf("[WritePassphraseIntoDB::run] timeUsed: %s\n", timeUsed.string().data()); + return 0; +} // -------------------------------------------------------------------------------------------------------------- @@ -232,6 +252,13 @@ bool Session::loadUser(const std::string& email, const std::string& password) return true; } +Poco::Net::HTTPCookie Session::getLoginCookie() +{ + auto keks = Poco::Net::HTTPCookie("user", std::to_string(mHandleId)); + // TODO: additional config, like js permit + return keks; +} + bool Session::loadFromEmailVerificationCode(unsigned long long emailVerificationCode) { Profiler usedTime; @@ -315,6 +342,7 @@ const char* Session::translateSessionStateToString(SessionStates state) case SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED: return "Verification Code checked"; case SESSION_STATE_PASSPHRASE_GENERATED: return "Passphrase generated"; case SESSION_STATE_PASSPHRASE_SHOWN: return "Passphrase shown"; + case SESSION_STATE_PASSPHRASE_WRITTEN: return "Passphrase written"; case SESSION_STATE_KEY_PAIR_GENERATED: return "Gradido Address created"; case SESSION_STATE_KEY_PAIR_WRITTEN: return "Gradido Address saved"; default: return "unknown"; @@ -356,11 +384,28 @@ bool Session::generatePassphrase() bool Session::generateKeys(bool savePrivkey, bool savePassphrase) { + bool validUser = true; if (mSessionUser) { - if (!mSessionUser->generateKeys(savePrivkey, mPassphrase)) { - + if (!mSessionUser->generateKeys(savePrivkey, mPassphrase, this)) { + validUser = false; + } + else { + if (savePassphrase) { + UniLib::controller::TaskPtr savePassphrase(new WritePassphraseIntoDB(mSessionUser->getDBId(), mPassphrase)); + savePassphrase->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this)); + savePassphrase->scheduleTask(savePassphrase); + } } } + else { + validUser = false; + } + if (!validUser) { + addError(new Error("Benutzer", "Kein gültiger Benutzer, bitte logge dich erneut ein.")); + return false; + } + // delete passphrase after all went well + mPassphrase.clear(); return true; } \ No newline at end of file diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index c24e2bd18..db81c9b8b 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -18,6 +18,7 @@ #include "Poco/Thread.h" #include "Poco/DateTime.h" #include "Poco/Net/IPAddress.h" +#include "Poco/Net/HTTPCookie.h" #define EMAIL_VERIFICATION_CODE_SIZE 8 @@ -31,6 +32,7 @@ enum SessionStates { SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED, SESSION_STATE_PASSPHRASE_GENERATED, SESSION_STATE_PASSPHRASE_SHOWN, + SESSION_STATE_PASSPHRASE_WRITTEN, SESSION_STATE_KEY_PAIR_GENERATED, SESSION_STATE_KEY_PAIR_WRITTEN, SESSION_STATE_COUNT @@ -55,6 +57,8 @@ public: bool updateEmailVerification(unsigned long long emailVerificationCode); + Poco::Net::HTTPCookie getLoginCookie(); + inline User* getUser() { return mSessionUser; } inline int getHandle() { return mHandleId; } @@ -110,6 +114,21 @@ private: }; +class WritePassphraseIntoDB : public UniLib::controller::CPUTask +{ +public: + WritePassphraseIntoDB(int userId, const std::string& passphrase) + : mUserId(userId), mPassphrase(passphrase) {} + + + virtual int run(); + virtual const char* getResourceType() const { return "WritePassphraseIntoDB"; }; + +protected: + int mUserId; + std::string mPassphrase; +}; + class SessionStateUpdateCommand : public UniLib::controller::Command { public: diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index 9515c5dca..b3785e4a4 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -1,56 +1,19 @@ #include "User.h" #include "Profiler.h" +#include "Session.h" #include #include "ed25519/ed25519.h" #include "Poco/Util/Application.h" #include "../ServerConfig.h" #include "../SingletonManager/ConnectionManager.h" +#include "../SingletonManager/ErrorManager.h" #include "Poco/Data/Binding.h" using namespace Poco::Data::Keywords; -NewUser::NewUser(User* user, const char* password, const char* passphrase) - : mUser(user), mPassword(password), mPassphrase(passphrase) -{ -} - - -NewUser::~NewUser() -{ - -} - -void NewUser::run() -{ - // create crypto key - if (!mUser->hasCryptoKey()) { - mUser->createCryptoKey(mPassword.data()); - } - - // generate -} - - -// ------------------------------------------------------------------------------------ - -LoginUser::LoginUser(User* user, const char* password) - : mUser(user), mPassword(password) -{ -// auto app = Poco::Util::Application::instance(); -} - -LoginUser::~LoginUser() -{ - -} - -void LoginUser::run() -{ - -} // ------------------------------------------------------------------------------------------------- @@ -71,6 +34,21 @@ int UserCreateCryptoKey::run() return 0; } +// ------------------------------------------------------------------------------------------------------------- + +int UserGenerateKeys::run() +{ + Profiler timeUsed; + // always return true, cannot fail (only if low on memory) + mKeys.generateFromPassphrase(mPassphrase.data(), &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); + + mUser->setPublicKeyHex(mKeys.getPubkeyHex()); + + printf("[UserGenerateKeys::run] time: %s\n", timeUsed.string().data()); + + return 0; +} + // ----------------------------------------------------------------------------------------------------- int UserWriteIntoDB::run() @@ -88,11 +66,73 @@ int UserWriteIntoDB::run() return 0; } +// -------------------------------------------------------------------------------------------------------- + +UserWriteKeysIntoDB::UserWriteKeysIntoDB(UniLib::controller::TaskPtr parent, User* user, bool savePrivKey) + : UniLib::controller::CPUTask(1), mUser(user), mSavePrivKey(savePrivKey) +{ + if (strcmp(parent->getResourceType(), "UserGenerateKeys") != 0) { + throw Poco::Exception("given TaskPtr isn't UserGenerateKeys"); + } + setParentTaskPtrInArray(parent, 0); +} + +int UserWriteKeysIntoDB::run() +{ + Profiler timeUsed; + auto cm = ConnectionManager::getInstance(); + auto em = ErrorManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + auto keyPairs = getParent(0).cast()->getKeyPairs(); + auto pubKey = keyPairs->getPublicKey(); + + Poco::Data::BLOB pubkey_blob(pubKey, crypto_sign_PUBLICKEYBYTES); + Poco::Data::Statement update(session); + Poco::Data::BLOB* pprivkey_blob = nullptr; + if (mSavePrivKey) { + // TODO: encrypt privkey + auto privKey = keyPairs->getPrivateKey(); + pprivkey_blob = mUser->encrypt(privKey); + //Poco::Data::BLOB privkey_blob(*privKey, privKey->size()); + + update << "UPDATE users SET pubkey=?, privkey=? where id=?", + use(pubkey_blob), use(*pprivkey_blob), bind(mUser->getDBId()); + } + else { + update << "UPDATE users SET pubkey=? where id=?", + use(pubkey_blob), bind(mUser->getDBId()); + } + + try { + if (update.execute() != 1) { + em->addError(new ParamError("UserWritePrivKeyIntoDB::run", "error writing keys into db for user", std::to_string(mUser->getDBId()))); + em->sendErrorsAsEmail(); + if (pprivkey_blob) { + delete pprivkey_blob; + } + return -1; + } + } + catch (Poco::Exception& ex) { + em->addError(new ParamError("UserWritePrivKeyIntoDB::run", "mysql error updating", ex.displayText().data())); + em->sendErrorsAsEmail(); + if (pprivkey_blob) { + delete pprivkey_blob; + } + return -1; + } + if (pprivkey_blob) { + delete pprivkey_blob; + } + printf("UserWritePrivKeyIntoDB time: %s\n", timeUsed.string().data()); + return 0; +} + // ******************************************************************************* -User::User(const char* email, const char* name) - : mDBId(0), mEmail(email), mFirstName(name), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr) +User::User(const char* email) + : mDBId(0), mEmail(email), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr) { //crypto_shorthash(mPasswordHashed, (const unsigned char*)password, strlen(password), *ServerConfig::g_ServerCryptoKey); //memset(mPasswordHashed, 0, crypto_shorthash_BYTES); @@ -102,15 +142,16 @@ User::User(const char* email, const char* name) Poco::Nullable pubkey; Poco::Data::Statement select(session); - select << "SELECT id, password, pubkey, email_checked from users where email = ?", - into(mDBId), into(mPasswordHashed), into(pubkey), into(mEmailChecked), use(mEmail); + select << "SELECT id, name, password, pubkey, email_checked from users where email = ?", + into(mDBId), into(mFirstName), into(mPasswordHashed), into(pubkey), into(mEmailChecked), use(mEmail); try { if (select.execute() == 1) { if (!pubkey.isNull()) { - size_t hexSize = pubkey.value.size() * 2 + 1; + auto pubkey_value = pubkey.value(); + size_t hexSize = pubkey_value.size() * 2 + 1; char* hexString = (char*)malloc(hexSize); memset(hexString, 0, hexSize); - sodium_bin2hex(hexString, hexSize, pubkey.value.content().data(), pubkey.value.size()); + sodium_bin2hex(hexString, hexSize, pubkey_value.content().data(), pubkey_value.size()); mPublicHex = hexString; free(hexString); } @@ -118,6 +159,11 @@ User::User(const char* email, const char* name) } catch(...) {} } +User* User::login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr) +{ + +} + User::~User() { @@ -198,14 +244,14 @@ ObfusArray* User::createCryptoKey(const std::string& password) { Profiler timeUsed; - // TODO: put it in secure location + // TODO: put it in secure location, or use value from server config static const unsigned char app_secret[] = { 0x21, 0xff, 0xbb, 0xc6, 0x16, 0xfe }; sha_context context_sha512; //unsigned char* hash512 = (unsigned char*)malloc(SHA_512_SIZE); if (SHA_512_SIZE < crypto_pwhash_SALTBYTES) { addError(new Error(__FUNCTION__, "sha512 is to small for libsodium pwhash saltbytes")); - return; + return nullptr; } @@ -221,7 +267,7 @@ ObfusArray* User::createCryptoKey(const std::string& password) addError(new ParamError(__FUNCTION__, " error creating pwd hash, maybe to much memory requestet? error:", strerror(errno))); //printf("[User::%s] error creating pwd hash, maybe to much memory requestet? error: %s\n", __FUNCTION__, strerror(errno)); //printf("pwd: %s\n", pwd); - return ; + return nullptr; } lock(); @@ -234,10 +280,60 @@ ObfusArray* User::createCryptoKey(const std::string& password) return cryptoKey; } -bool User::generateKeys(bool savePrivkey, const std::string& passphrase) +bool User::generateKeys(bool savePrivkey, const std::string& passphrase, Session* session) { - // TODO: call create key pair from passphrase from worker thread - // TODO: evt. save privkey from worker thread + Profiler timeUsed; + + UniLib::controller::TaskPtr generateKeysTask(new UserGenerateKeys(this, passphrase)); + generateKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_GENERATED, session)); + //generateKeysTask->scheduleTask(generateKeysTask); + // run directly because we like to show pubkey on interface, shouldn't last to long + generateKeysTask->run(); + + if (mDBId == 0) { + loadEntryDBId(ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); + if (mDBId == 0) { + auto em = ErrorManager::getInstance(); + em->addError(new ParamError("User::generateKeys", "user not found in db with email", mEmail.data())); + em->sendErrorsAsEmail(); + } + return false; + } + + UniLib::controller::TaskPtr saveKeysTask(new UserWriteKeysIntoDB(generateKeysTask, this, savePrivkey)); + saveKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_WRITTEN, session)); + saveKeysTask->scheduleTask(saveKeysTask); + + + printf("[User::generateKeys] call two tasks, time used: %s\n", timeUsed.string().data()); + return true; + +} + +Poco::Data::BLOB* User::encrypt(const ObfusArray* data) +{ + if (!hasCryptoKey()) { + addError(new Error("User::encrypt", "hasn't crypto key")); + return nullptr; + } + size_t message_len = data->size(); + size_t ciphertext_len = crypto_secretbox_MACBYTES + message_len; + + unsigned char nonce[crypto_secretbox_NONCEBYTES]; + // we use a hardcoded value for nonce + memset(nonce, 31, crypto_secretbox_NONCEBYTES); + + unsigned char* ciphertext = (unsigned char*)malloc(ciphertext_len); + memset(ciphertext, 0, ciphertext_len); + + if (0 != crypto_secretbox_easy(ciphertext, *data, message_len, nonce, *mCryptoKey)) { + //printf("[%s] error encrypting message \n", __FUNCTION__); + addError(new Error("User::encrypt", "encrypting message failed")); + free(ciphertext); + return nullptr; + } + free(ciphertext); + return new Poco::Data::BLOB(ciphertext, ciphertext_len); } Poco::Data::Statement User::insertIntoDB(Poco::Data::Session session) diff --git a/src/cpp/model/User.h b/src/cpp/model/User.h index f57149b48..51910abce 100644 --- a/src/cpp/model/User.h +++ b/src/cpp/model/User.h @@ -4,6 +4,7 @@ #include "../Crypto/KeyPair.h" #include #include "ErrorList.h" + #include "Poco/Thread.h" #include "Poco/Data/Session.h" #include "../tasks/CPUTask.h" @@ -11,6 +12,7 @@ class NewUser; class UserCreateCryptoKey; class UserWriteIntoDB; +class Session; class User : public ErrorList { @@ -21,14 +23,17 @@ public: // new user //User(const char* email, const char* name, const char* password); // existing user - User(const char* email, const char* name); + User(const char* email); + // login + //User(const std::string& email, const std::string& password); ~User(); static std::string generateNewPassphrase(Mnemonic* word_source); static bool validatePassphrase(const std::string& passphrase); + static User* login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr); - bool generateKeys(bool savePrivkey, const std::string& passphrase); + bool generateKeys(bool savePrivkey, const std::string& passphrase, Session* session); bool loadEntryDBId(Poco::Data::Session session); @@ -36,17 +41,22 @@ public: inline const char* getEmail() const { return mEmail.data(); } inline const char* getName() const { return mFirstName.data(); } - inline int getDBId() { return mDBId; } + inline int getDBId() const { return mDBId; } inline void setEmailChecked() { mEmailChecked = true; } - std::string getPublicKeyHex() { return mPublicHex; } + inline std::string getPublicKeyHex() { lock(); std::string pubkeyHex = mPublicHex; unlock(); return pubkeyHex; } + inline void setPublicKeyHex(const std::string& publicKeyHex) { lock(); mPublicHex = publicKeyHex; unlock(); } bool validatePwd(const std::string& pwd); + Poco::Data::BLOB* encrypt(const ObfusArray* data); protected: typedef unsigned long long passwordHashed; ObfusArray* createCryptoKey(const std::string& password); inline void setCryptoKey(ObfusArray* cryptoKey) { mCryptoKey = cryptoKey; } + + + Poco::Data::Statement insertIntoDB(Poco::Data::Session session); inline passwordHashed getPwdHashed() { lock(); auto ret = mPasswordHashed; unlock(); return ret; } inline void setPwdHashed(passwordHashed pwdHashed) { lock(); mPasswordHashed = pwdHashed; unlock(); } @@ -82,6 +92,25 @@ private: std::string mPassword; }; +class UserGenerateKeys : public UniLib::controller::CPUTask +{ +public: + UserGenerateKeys(User* user, const std::string& passphrase) + : mUser(user), mPassphrase(passphrase) {} + + ~UserGenerateKeys() { + + } + virtual int run(); + inline KeyPair* getKeyPairs() { return &mKeys; } + + virtual const char* getResourceType() const { return "UserGenerateKeys"; }; +protected: + User* mUser; + std::string mPassphrase; + KeyPair mKeys; +}; + class UserWriteIntoDB : public UniLib::controller::CPUTask { public: @@ -94,33 +123,17 @@ private: User* mUser; }; - -class NewUser : public Poco::Runnable +class UserWriteKeysIntoDB : public UniLib::controller::CPUTask { public: - NewUser(User* user, const char* password, const char* passphrase); - ~NewUser(); + UserWriteKeysIntoDB(UniLib::controller::TaskPtr parent, User* user, bool savePrivKey); + virtual int run(); - virtual void run(); + virtual const char* getResourceType() const { return "UserWriteKeysIntoDB"; }; protected: - User* mUser; - std::string mPassword; - std::string mPassphrase; - -}; - -class LoginUser : public Poco::Runnable -{ -public: - LoginUser(User* user, const char* password); - ~LoginUser(); - - virtual void run(); -protected: - User* mUser; - std::string mPassword; - + User* mUser; + bool mSavePrivKey; }; #endif //GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE \ No newline at end of file diff --git a/src/cpp/tasks/CPUTask.cpp b/src/cpp/tasks/CPUTask.cpp index 5db250faf..bdf75d935 100644 --- a/src/cpp/tasks/CPUTask.cpp +++ b/src/cpp/tasks/CPUTask.cpp @@ -1,5 +1,6 @@ #include "CPUTask.h" #include "CPUSheduler.h" +#include "../ServerConfig.h" namespace UniLib { namespace controller { @@ -15,6 +16,12 @@ namespace UniLib { assert(cpuScheduler); } + CPUTask::CPUTask(size_t taskDependenceCount/* = 0*/) + : Task(), mScheduler(ServerConfig::g_CPUScheduler) + { + assert(mScheduler); + } + CPUTask::~CPUTask() { diff --git a/src/cpp/tasks/CPUTask.h b/src/cpp/tasks/CPUTask.h index b643767e5..e1c1d5cc0 100644 --- a/src/cpp/tasks/CPUTask.h +++ b/src/cpp/tasks/CPUTask.h @@ -49,7 +49,8 @@ namespace UniLib { { public: CPUTask(CPUSheduler* cpuSheduler, size_t taskDependenceCount); - CPUTask(CPUSheduler* cpuScheduler); + CPUTask(CPUSheduler* cpuScheduler); + CPUTask(size_t taskDependenceCount = 0); virtual ~CPUTask(); virtual const char* getResourceType() const {return "CPUTask";}; diff --git a/src/cpsp/login.cpsp b/src/cpsp/login.cpsp index a769b778e..68435175d 100644 --- a/src/cpsp/login.cpsp +++ b/src/cpsp/login.cpsp @@ -2,6 +2,26 @@ <%@ page form="true" %> <%@ page compressed="true" %> <%! +#include "../SingletonManager/SessionManager.h" +#include "Poco/Net/HTTPCookie.h" + + +%> +<%% + auto session = SessionManager::getInstance()->getNewSession(); + + if(!form.empty()) { + auto email = form.get("login-email", ""); + auto password = form.get("login-password", ""); + if(session->loadUser(email, password)) { + auto user_host = request.clientAddress().host(); + session->setClientIp(user_host); + response.addCookie(session->getLoginCookie()); + auto uri_start = request.serverParams().getServerName(); + response.redirect(uri_start + "/"); + return; + } + } %> @@ -12,8 +32,18 @@ Gradido Login Server: Login + +<%= session->getErrorsHtml() %>

Login

diff --git a/src/cpsp/passphrase.cpsp b/src/cpsp/passphrase.cpsp index 34999b94f..e69c5dd85 100644 --- a/src/cpsp/passphrase.cpsp +++ b/src/cpsp/passphrase.cpsp @@ -30,16 +30,16 @@ enum PageState if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) { // passphrase is valid - session->setPassphrase(oldPassphrase); - session->updateState(SESSION_STATE_PASSPHRASE_SHOWN); + mSession->setPassphrase(oldPassphrase); + mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN); state = PAGE_SHOW_PASSPHRASE; } else { - session->addError(new Error("Merkspruch", "Dieser Merkspruch ist ungültig, bitte überprüfen oder neu generieren (lassen).")); + mSession->addError(new Error("Merkspruch", "Dieser Merkspruch ist ungültig, bitte überprüfen oder neu generieren (lassen).")); } } else if (registerKeyChoice == "yes") { - session->generatePassphrase(); + mSession->generatePassphrase(); } } diff --git a/src/cpsp/register.cpsp b/src/cpsp/register.cpsp index f1f351447..b6f7c06f0 100644 --- a/src/cpsp/register.cpsp +++ b/src/cpsp/register.cpsp @@ -20,12 +20,9 @@ ); } if(userReturned) { - auto cookie_id = session->getHandle(); - //auto user_host_string = request.clientAddress().toString(); auto user_host = request.clientAddress().host(); session->setClientIp(user_host); - //printf("cookie: %d, user_host: %s\n", cookie_id, user_host.data()); - response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id))); + response.addCookie(session->getLoginCookie()); } } %> diff --git a/src/cpsp/saveKeys.cpsp b/src/cpsp/saveKeys.cpsp index 0edbd3b98..326c66060 100644 --- a/src/cpsp/saveKeys.cpsp +++ b/src/cpsp/saveKeys.cpsp @@ -5,10 +5,13 @@ <%@ page form="true" %> <%@ page compressed="true" %> <%! - enum PageState { - PAGE_ASK, - PAGE_SHOW_PUBKEY - } +enum PageState +{ + PAGE_ASK, + PAGE_SHOW_PUBKEY, + PAGE_ERROR +}; + %> <%% @@ -40,6 +43,13 @@ if(savePassphraseChoice == "yes") { savePassphrase = true; } + if(!mSession->generateKeys(savePrivkey, savePassphrase)) { + hasErrors = true; + } else if(mSession->getSessionState() >= SESSION_STATE_KEY_PAIR_GENERATED) { + state = PAGE_SHOW_PUBKEY; + } else { + state = PAGE_ERROR; + } } } %> @@ -110,7 +120,18 @@ label:not(.grd_radio_label) { <% } else if(state == PAGE_SHOW_PUBKEY) { %> - +
+

Je nach Auswahl werden deine Daten nun verschlüsselt und gespeichert.

+

Deine Gradido Adresse (Hex):

+

+ <%= mSession->getUser()->getPublicKeyHex() %> +

+ Zurück zur Startseite +
+ <% } else if(state == PAGE_ERROR) { %> +
+

Ein Fehler trat auf, bitte versuche es erneut oder wende dich an den Server-Admin

+
<% } %>