diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 000000000..1936cc1d4 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +html diff --git a/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp b/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp index 940d084bc..c2ebcd232 100644 --- a/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp +++ b/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp @@ -10,7 +10,7 @@ #include "../Crypto/KeyPair.h" #include "../SingletonManager/ConnectionManager.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "Poco/Data/Binding.h" using namespace Poco::Data::Keywords; @@ -20,7 +20,7 @@ typedef Poco::Tuple, std::string> UserBack struct SListEntry { Poco::AutoPtr user; - std::vector> backups; + std::vector> backups; }; #line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp" @@ -94,7 +94,7 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, SListEntry entry; entry.user = controller::User::create(); entry.user->load(user_id); - entry.backups = controller::UserBackups::load(user_id); + entry.backups = controller::UserBackup::load(user_id); notMatchingEntrys.push_back(entry); diff --git a/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp b/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp index 42778fd45..71a2f1bb0 100644 --- a/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp +++ b/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp @@ -10,7 +10,7 @@ // includes #include "../controller/User.h" #include "../controller/EmailVerificationCode.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" enum PageState @@ -43,7 +43,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request PageState state = PAGE_ASK_EMAIL; Poco::AutoPtr user = controller::User::create(); Poco::AutoPtr code; - Poco::AutoPtr userBackup; + Poco::AutoPtr userBackup; bool validUser = false; std::string pageName = "Admin User Passwort Reset"; @@ -69,7 +69,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request } } - auto backups = controller::UserBackups::load(userId); + auto backups = controller::UserBackup::load(userId); auto userPubkey = user->getModel()->getPublicKey(); for(auto it = backups.begin(); it != backups.end(); it++) { auto keys = (*it)->getKeyPair(); @@ -235,7 +235,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "Bitte schreibe sie dir auf und packe sie gut weg.\n"; responseStream << "\n"; #line 105 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" - responseStream << ( controller::UserBackups::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) ); + responseStream << ( controller::UserBackup::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) ); responseStream << "\n"; responseStream << " \n"; responseStream << "\n"; diff --git a/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp b/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp index 3b8087c0c..77fd06514 100644 --- a/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp +++ b/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp @@ -13,7 +13,7 @@ #include "../Crypto/Passphrase.h" #include "../Crypto/KeyPairEd25519.h" #include "../lib/DataTypeConverter.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "../tasks/SigningTransaction.h" #include "../ServerConfig.h" @@ -85,7 +85,7 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request else { mSession->setPassphrase(passphrase); - auto newPassphraseModel = controller::UserBackups::create( + auto newPassphraseModel = controller::UserBackup::create( user_model->getID(), passphrase->getString(), ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES diff --git a/src/cpp/HTTPInterface/ResetPassword.cpp b/src/cpp/HTTPInterface/ResetPassword.cpp index 23d6b8331..7d1bbd28e 100644 --- a/src/cpp/HTTPInterface/ResetPassword.cpp +++ b/src/cpp/HTTPInterface/ResetPassword.cpp @@ -11,7 +11,7 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/EmailManager.h" #include "../controller/User.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" enum PageState { PAGE_EMAIL_ASK, diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index 32a3ab700..fc94661fb 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -1,5 +1,5 @@ #include "User.h" -#include "UserBackups.h" +#include "UserBackup.h" #include "sodium.h" @@ -299,7 +299,7 @@ namespace controller { auto user_model = getModel(); if (user_model->getID() <= 0) return -2; - auto backups = UserBackups::load(user_model->getID()); + auto backups = UserBackup::load(user_model->getID()); if (backups.size() == 0) return -1; for (auto it = backups.begin(); it != backups.end(); it++) { auto user_backup = *it; diff --git a/src/cpp/controller/UserBackups.cpp b/src/cpp/controller/UserBackup.cpp similarity index 70% rename from src/cpp/controller/UserBackups.cpp rename to src/cpp/controller/UserBackup.cpp index bf7096442..9a152592f 100644 --- a/src/cpp/controller/UserBackups.cpp +++ b/src/cpp/controller/UserBackup.cpp @@ -1,14 +1,14 @@ -#include "UserBackups.h" +#include "UserBackup.h" #include "../Crypto/Passphrase.h" namespace controller { - UserBackups::UserBackups(model::table::UserBackups* dbModel) + UserBackup::UserBackup(model::table::UserBackup* dbModel) { mDBModel = dbModel; } - UserBackups::~UserBackups() + UserBackup::~UserBackup() { } @@ -17,20 +17,20 @@ namespace controller { // --------------- static members ----------------------------- - Poco::AutoPtr UserBackups::create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) + Poco::AutoPtr UserBackup::create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) { - auto db = new model::table::UserBackups(user_id, passphrase, type); - return Poco::AutoPtr(new UserBackups(db)); + auto db = new model::table::UserBackup(user_id, passphrase, type); + return Poco::AutoPtr(new UserBackup(db)); } - std::vector> UserBackups::load(int user_id) + std::vector> UserBackup::load(int user_id) { - auto db = new model::table::UserBackups(); + auto db = new model::table::UserBackup(); auto results = db->loadFromDB("user_id", user_id, 1); - std::vector> resultObjects; + std::vector> resultObjects; if (db->errorCount()) { db->sendErrorsAsEmail(); db->release(); @@ -41,14 +41,14 @@ namespace controller { return resultObjects; } for (auto it = results.begin(); it != results.end(); it++) { - resultObjects.push_back(new UserBackups(new model::table::UserBackups(*it))); + resultObjects.push_back(new UserBackup(new model::table::UserBackup(*it))); } return resultObjects; } - Poco::SharedPtr UserBackups::getKeyPair() + Poco::SharedPtr UserBackup::getKeyPair() { if (!mKeyPair.isNull()) { return mKeyPair; @@ -61,7 +61,7 @@ namespace controller { return mKeyPair; } - KeyPairEd25519* UserBackups::createGradidoKeyPair() + KeyPairEd25519* UserBackup::createGradidoKeyPair() { auto model = getModel(); auto mnemonicType = model->getMnemonicType(); @@ -71,7 +71,7 @@ namespace controller { return KeyPairEd25519::create(passphrase); } - std::string UserBackups::getPassphrase(ServerConfig::Mnemonic_Types type) + std::string UserBackup::getPassphrase(ServerConfig::Mnemonic_Types type) { if ((int)type < 0 || (int)type >= ServerConfig::Mnemonic_Types::MNEMONIC_MAX) { return ""; @@ -96,7 +96,7 @@ namespace controller { } - std::string UserBackups::formatPassphrase(std::string passphrase, int targetLinesCount/* = 5*/) + std::string UserBackup::formatPassphrase(std::string passphrase, int targetLinesCount/* = 5*/) { int count = passphrase.size(); int charPerLine = count / (targetLinesCount); diff --git a/src/cpp/controller/UserBackups.h b/src/cpp/controller/UserBackup.h similarity index 68% rename from src/cpp/controller/UserBackups.h rename to src/cpp/controller/UserBackup.h index c1cb08047..a21d1c3ab 100644 --- a/src/cpp/controller/UserBackups.h +++ b/src/cpp/controller/UserBackup.h @@ -1,7 +1,7 @@ #ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_USER_BACKUPS_INCLUDE #define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_BACKUPS_INCLUDE -#include "../model/table/UserBackups.h" +#include "../model/table/UserBackup.h" #include "../Crypto/KeyPair.h" #include "../Crypto/KeyPairEd25519.h" @@ -10,19 +10,19 @@ #include "TableControllerBase.h" namespace controller { - class UserBackups : public TableControllerBase + class UserBackup : public TableControllerBase { public: - ~UserBackups(); + ~UserBackup(); - static Poco::AutoPtr create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); + static Poco::AutoPtr create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); - static std::vector> load(int user_id); + static std::vector> load(int user_id); inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } - inline Poco::AutoPtr getModel() { return _getModel(); } + inline Poco::AutoPtr getModel() { return _getModel(); } //! depracted //! \return create keyPair from passphrase if not exist, else return existing pointer @@ -37,7 +37,7 @@ namespace controller { std::string getPassphrase(ServerConfig::Mnemonic_Types type); protected: - UserBackups(model::table::UserBackups* dbModel); + UserBackup(model::table::UserBackup* dbModel); Poco::SharedPtr mKeyPair; }; diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 86fad389c..783fdc2e8 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -1,1323 +1,1323 @@ -#include "Session.h" -#include "../lib/Profiler.h" -#include "../ServerConfig.h" - -#include "Poco/RegularExpression.h" -#include "Poco/Net/StringPartSource.h" -#include "Poco/Net/MediaType.h" - -#include "../SingletonManager/SessionManager.h" -#include "../SingletonManager/ConnectionManager.h" -#include "../SingletonManager/ErrorManager.h" -#include "../SingletonManager/EmailManager.h" -#include "../SingletonManager/SingletonTaskObserver.h" - -#include "../tasks/PrepareEmailTask.h" -#include "../tasks/SendEmailTask.h" -#include "../tasks/SigningTransaction.h" -#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" -#include "../tasks/VerificationEmailResendTask.h" - -#include "../lib/JsonRequest.h" - -#include "../Crypto/Passphrase.h" - - -#include "../controller/User.h" -#include "../controller/UserBackups.h" -#include "../controller/EmailVerificationCode.h" - -#include "table/ModelBase.h" - - -#include "sodium.h" - -using namespace Poco::Data::Keywords; - -int WriteEmailVerification::run() -{ - auto em = ErrorManager::getInstance(); - - mEmailVerificationCode->getModel()->setUserId(mUser->getDBId()); - auto emailVerificationModel = mEmailVerificationCode->getModel(); - emailVerificationModel->setUserId(mUser->getDBId()); - if (!emailVerificationModel->insertIntoDB(true) || emailVerificationModel->errorCount() > 0) { - emailVerificationModel->sendErrorsAsEmail(); - return -1; - } - - 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 em = ErrorManager::getInstance(); - - 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); - try { - if (insert.execute() != 1) { - em->addError(new ParamError("WritePassphraseIntoDB::run", "inserting passphrase for user failed", std::to_string(mUserId))); - em->sendErrorsAsEmail(); - } - } - catch (Poco::Exception& ex) { - em->addError(new ParamError("WritePassphraseIntoDB::run", "insert passphrase mysql error", ex.displayText().data())); - em->sendErrorsAsEmail(); - } - - //printf("[WritePassphraseIntoDB] timeUsed: %s\n", timeUsed.string().data()); - return 0; -} - - -// -------------------------------------------------------------------------------------------------------------- - -Session::Session(int handle) - : mHandleId(handle), mSessionUser(nullptr), mState(SESSION_STATE_EMPTY), mActive(false) -{ - -} - -Session::~Session() -{ - //printf("[Session::~Session] \n"); - if (tryLock()) { - unlock(); - reset(); - } - - - //printf("[Session::~Session] finished \n"); -} - - -void Session::reset() -{ - //printf("[Session::reset]\n"); - lock("Session::reset"); - std::unique_lock _lock(mSharedMutex); - mSessionUser.assign(nullptr); - mNewUser.assign(nullptr); - mEmailVerificationCodeObject.assign(nullptr); - - // watch out - //updateTimeout(); - mLastActivity = Poco::DateTime(); - - mState = SESSION_STATE_EMPTY; - - mPassphrase = ""; - mLastExternReferer = ""; - mClientLoginIP = Poco::Net::IPAddress(); - unlock(); - - // reset transactions - mCurrentActiveProcessingTransaction = nullptr; - mProcessingTransactions.clear(); - - //printf("[Session::reset] finished\n"); -} - -int Session::isActive() -{ - int ret = 0; - try { - mWorkMutex.tryLock(100); - } - catch (Poco::TimeoutException &ex) { - return -1; - } - ret = (int)mActive; - unlock(); - return ret; - -} - -bool Session::isDeadLocked() -{ - try { - mWorkMutex.tryLock(200); - unlock(); - return false; - } - catch (Poco::Exception& ex) { - - } - return true; -} - -bool Session::setActive(bool active) -{ - try { - mWorkMutex.tryLock(100); - } - catch (Poco::TimeoutException &ex) { - return false; - } - mActive = active; - unlock(); - return true; -} - -void Session::updateTimeout() -{ - lock("Session::updateTimeout"); - mLastActivity = Poco::DateTime(); - unlock(); -} - -Poco::AutoPtr Session::getEmailVerificationCodeObject() -{ - lock("Session::getEmailVerificationCodeObject"); - std::shared_lock _lock(mSharedMutex); - auto ret = mEmailVerificationCodeObject; - unlock(); - return ret; -} - -bool Session::adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email) -{ - Profiler usedTime; - - if (mNewUser->getModel()->getRole() != model::table::ROLE_ADMIN) { - addError(new Error(gettext("Benutzer"), gettext("Eingeloggter Benutzer ist kein Admin")), false); - return false; - } - - auto sm = SessionManager::getInstance(); - if (!sm->isValid(first_name, VALIDATE_NAME)) { - addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - return false; - } - - - // check if user with that email already exist - if (mNewUser->getModel()->isExistInDB("email", email)) { - addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); - return false; - } - - auto newUser = controller::User::create(email, first_name, last_name); - updateTimeout(); - - - auto newUserModel = newUser->getModel(); - if (!newUserModel->insertIntoDB(true)) { - addError(new Error(gettext("Benutzer"), gettext("Fehler beim speichern!"))); - return false; - } - - auto email_verification_code = controller::EmailVerificationCode::create(newUserModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); - if (!email_verification_code->getModel()->insertIntoDB(false)) { - addError(new Error(gettext("Email Verification Code"), gettext("Fehler beim speichern!"))); - return false; - } - - EmailManager::getInstance()->addEmail(new model::Email(email_verification_code, newUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE)); - - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = email_verification_code; - - - return true; -} -// -bool Session::createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) -{ - Profiler usedTime; - auto sm = SessionManager::getInstance(); - if (!sm->isValid(first_name, VALIDATE_NAME)) { - addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - return false; - } - if (!sm->checkPwdValidation(password, this)) { - return false; - } - /*if (passphrase.size() > 0 && !sm->isValid(passphrase, VALIDATE_PASSPHRASE)) { - addError(new Error("Merkspruch", "Der Merkspruch ist nicht gültig, er besteht aus 24 Wörtern, mit Komma getrennt.")); - return false; - } - if (passphrase.size() == 0) { - //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); - } - else { - //mPassphrase = passphrase; - }*/ - - // check if user with that email already exist - - auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement select(dbConnection); - select << "SELECT email from users where email = ?;", useRef(email); - try { - if (select.execute() > 0) { - addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); - return false; - } - } - catch (Poco::Exception& exc) { - printf("mysql exception: %s\n", exc.displayText().data()); - } - - mSessionUser = new User(email.data(), first_name.data(), last_name.data()); - mNewUser = controller::User::create(email, first_name, last_name); - updateTimeout(); - - // Prepare E-Mail - //UniLib::controller::TaskPtr prepareEmail(new PrepareEmailTask(ServerConfig::g_CPUScheduler)); - //prepareEmail->scheduleTask(prepareEmail); - - // create user crypto key - UniLib::controller::TaskPtr cryptoKeyTask(new UserCreateCryptoKey(mSessionUser, mNewUser, password, ServerConfig::g_CryptoCPUScheduler)); - cryptoKeyTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_CRYPTO_KEY_GENERATED, this)); - cryptoKeyTask->scheduleTask(cryptoKeyTask); - - // depends on crypto key, write user record into db - UniLib::controller::TaskPtr writeUserIntoDB(new UserWriteIntoDB(mSessionUser, ServerConfig::g_CPUScheduler, 1)); - writeUserIntoDB->setParentTaskPtrInArray(cryptoKeyTask, 0); - writeUserIntoDB->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_USER_WRITTEN, this)); - writeUserIntoDB->scheduleTask(writeUserIntoDB); - - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = controller::EmailVerificationCode::create(model::table::EMAIL_OPT_IN_REGISTER); - UniLib::controller::TaskPtr writeEmailVerification(new WriteEmailVerification(mSessionUser, mEmailVerificationCodeObject, ServerConfig::g_CPUScheduler, 1)); - - writeEmailVerification->setParentTaskPtrInArray(writeUserIntoDB, 0); - writeEmailVerification->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN, this)); - writeEmailVerification->scheduleTask(writeEmailVerification); - - - /*printf("LastName: %s\n", last_name.data()); - for (int i = 0; i < last_name.size(); i++) { - char c = last_name.data()[i]; - //printf("%d ", c); - } - //printf("\n\n"); - */ - - // depends on writeUser because need user_id, write email verification into db - /*auto message = new Poco::Net::MailMessage; - Poco::Net::MediaType mt("text", "plain"); - mt.setParameter("charset", "utf-8"); - message->setContentType(mt); - - message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, email)); - message->setSubject(gettext("Gradido: E-Mail Verification")); - std::stringstream ss; - ss << "Hallo " << first_name << " " << last_name << "," << std::endl << std::endl; - ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Gradido registriert. " << std::endl; - ss << "Wenn du es warst, klicke bitte auf den Link: " << ServerConfig::g_serverPath << "/checkEmail/" << mEmailVerificationCode << std::endl; - //ss << "oder kopiere den Code: " << mEmailVerificationCode << " selbst dort hinein." << std::endl; - ss << "oder kopiere den obigen Link in Dein Browserfenster." << std::endl; - ss << std::endl; - ss << "Mit freundlichen " << u8"Grüßen" << std::endl; - ss << "Dario, Gradido Server Admin" << std::endl; - - - message->addContent(new Poco::Net::StringPartSource(ss.str())); - */ - //UniLib::controller::TaskPtr sendEmail(new SendEmailTask(message, ServerConfig::g_CPUScheduler, 1)); - //Email(AutoPtr emailVerification, AutoPtr user, EmailType type); - UniLib::controller::TaskPtr sendEmail(new SendEmailTask(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_VERIFICATION_CODE), ServerConfig::g_CPUScheduler, 1)); - //sendEmail->setParentTaskPtrInArray(prepareEmail, 0); - sendEmail->setParentTaskPtrInArray(writeEmailVerification, 0); - sendEmail->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_SEND, this)); - sendEmail->scheduleTask(sendEmail); - - // write user into db - // generate and write email verification into db - // send email - - //printf("[Session::createUser] time: %s\n", usedTime.string().data()); - - return true; -} - -bool Session::createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) -{ - std::unique_lock _lock(mSharedMutex); - static const char* function_name = "Session::createUserDirect"; - auto sm = SessionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto email_manager = EmailManager::getInstance(); - - if (!sm->isValid(first_name, VALIDATE_NAME)) { - addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - return false; - } - if (!sm->checkPwdValidation(password, this)) { - return false; - } - - // check if email already exist - auto user = controller::User::create(); - if (user->load(email) >= 1) { - addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits ein Konto")), false); - return false; - } - - // user - mNewUser = controller::User::create(email, first_name, last_name); - auto user_model = mNewUser->getModel(); - user_model->insertIntoDB(true); - auto user_id = user_model->getID(); - - - // one retry in case of connection error - if (!user_id) { - user_model->insertIntoDB(true); - auto user_id = user_model->getID(); - if (!user_id) { - em->addError(new ParamError(function_name, "error saving new user in db, after one retry with email", email)); - em->sendErrorsAsEmail(); - addError(new Error(gettext("Server"), gettext("Fehler beim speichen des Kontos bitte versuche es später noch einmal")), false); - return false; - } - } - - generateKeys(true, true); - - // calculate encryption key, could need some time, will save encrypted privkey to db - UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(mNewUser, password); - create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); - - // email verification code - auto email_verification = controller::EmailVerificationCode::create(user_id, model::table::EMAIL_OPT_IN_REGISTER_DIRECT); - email_verification->getModel()->insertIntoDB(false); - mEmailVerificationCodeObject = email_verification; - - auto _7days_later = Poco::DateTime() + Poco::Timespan(7, 0, 0, 0, 0); - ServerConfig::g_CronJobsTimer.schedule(new VerificationEmailResendTimerTask(user_id), Poco::Timestamp(_7days_later.timestamp())); - - email_manager->addEmail(new model::Email(email_verification, mNewUser, model::EMAIL_USER_VERIFICATION_CODE)); - - return true; -} - -bool Session::ifUserExist(const std::string& email) -{ - auto em = ErrorManager::getInstance(); - const char* funcName = "Session::ifUserExist"; - auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement select(dbConnection); - bool emailChecked = false; - int userId = 0; - select << "SELECT email_checked, id from users where email = ? and email_checked = 1", - into(emailChecked), into(userId), useRef(email); - - try { - if(select.execute() == 1) return true; - } - catch (Poco::Exception& ex) { - em->addError(new ParamError(funcName, "select user from email verification code mysql error ", ex.displayText().data())); - em->sendErrorsAsEmail(); - } - return false; -} - -int Session::updateEmailVerification(Poco::UInt64 emailVerificationCode) -{ - const static char* funcName = "Session::updateEmailVerification"; - Poco::ScopedLock _lock(mWorkMutex); - // new mutex, will replace the Poco Mutex complete in the future - std::unique_lock _lock_shared(mSharedMutex); - Profiler usedTime; - - auto em = ErrorManager::getInstance(); - if (mEmailVerificationCodeObject.isNull()) { - em->addError(new Error(funcName, "email verification object is zero")); - em->sendErrorsAsEmail(); - - return -2; - } - auto email_verification_code_model = mEmailVerificationCodeObject->getModel(); - assert(email_verification_code_model); - if(email_verification_code_model->getCode() == emailVerificationCode) { - if (mSessionUser && mSessionUser->getDBId() == 0) { - //addError(new Error("E-Mail Verification", "Benutzer wurde nicht richtig gespeichert, bitte wende dich an den Server-Admin")); - em->addError(new Error(funcName, "user exist with 0 as id")); - em->sendErrorsAsEmail(); - - //return false; - return -2; - } - - // load correct user from db - if (mNewUser.isNull() || !mNewUser->getModel() || mNewUser->getModel()->getID() != email_verification_code_model->getUserId()) { - mNewUser = controller::User::create(); - if (1 != mNewUser->load(email_verification_code_model->getUserId())) { - em->addError(new ParamError(funcName, "user load didn't return 1 with user_id ", email_verification_code_model->getUserId())); - em->sendErrorsAsEmail(); - - return -2; - } - } - - auto user_model = mNewUser->getModel(); - assert(user_model); - bool first_email_activation = false; - auto verification_type = email_verification_code_model->getType(); - if (model::table::EMAIL_OPT_IN_REGISTER == verification_type || - model::table::EMAIL_OPT_IN_EMPTY == verification_type || - model::table::EMAIL_OPT_IN_REGISTER_DIRECT == verification_type) { - first_email_activation = true; - } - if (first_email_activation && user_model->isEmailChecked()) { - mSessionUser = new User(mNewUser); - addError(new Error(gettext("E-Mail Verification"), gettext("Du hast dein Konto bereits aktiviert!")), false); - - return 1; - } - if (first_email_activation) { - user_model->setEmailChecked(true); - - user_model->updateIntoDB("email_checked", 1); - if (user_model->errorCount() > 0) { - user_model->sendErrorsAsEmail(); - } - - // no find all active sessions - - updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); - return 0; - } - - if (email_verification_code_model->getType() == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - - if (mEmailVerificationCodeObject->deleteFromDB()) { - mEmailVerificationCodeObject.assign(nullptr); - } - else { - em->getErrors(mEmailVerificationCodeObject->getModel()); - em->addError(new Error(funcName, "error deleting email verification code")); - em->sendErrorsAsEmail(); - return -2; - } - updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - return 0; - } - - em->addError(new Error(funcName, "invalid code path")); - em->sendErrorsAsEmail(); - - return -2; - - /*if (updated_rows == 1) { - Poco::Data::Statement delete_row(dbConnection); - delete_row << "DELETE FROM email_opt_in where verification_code = ?", use(emailVerificationCode); - if (delete_row.execute() != 1) { - em->addError(new Error(funcName, "delete from email_opt_in entry didn't work as expected, please check db")); - em->sendErrorsAsEmail(); - } - if (mSessionUser) { - mSessionUser->setEmailChecked(); - mSessionUser->setLanguage(getLanguage()); - } - updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); - //printf("[%s] time: %s\n", funcName, usedTime.string().data()); - unlock(); - return true; - } - else { - em->addError(new ParamError(funcName, "update user work not like expected, updated row count", updated_rows)); - em->sendErrorsAsEmail(); - }*/ - - - } - else { - addError(new Error(gettext("E-Mail Verification"), gettext("Falscher Code für aktiven Login"))); - //printf("[%s] time: %s\n", funcName, usedTime.string().data()); - - return -1; - } - //printf("[%s] time: %s\n", funcName, usedTime.string().data()); - - return 0; -} - - -int Session::sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized) -{ - mNewUser = user; - mSessionUser = new User(user); - auto em = EmailManager::getInstance(); - - std::unique_lock _lock(mSharedMutex); - - // creating email verification code also for user without passphrase - // first check if already exist - // check if email was already send shortly before - bool frequent_resend = false; - bool email_already_send = false; - - mEmailVerificationCodeObject = controller::EmailVerificationCode::load(user->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); - if (mEmailVerificationCodeObject.isNull()) { - mEmailVerificationCodeObject = controller::EmailVerificationCode::create(mNewUser->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); - mEmailVerificationCodeObject->getModel()->insertIntoDB(false); - } - else { - email_already_send = true; - } - auto email_verification_model = mEmailVerificationCodeObject->getModel(); - if (email_already_send) { - auto time_elapsed = Poco::DateTime() - email_verification_model->getUpdated(); - if (time_elapsed.totalHours() < 1) { - frequent_resend = true; - } - } - - if (!frequent_resend) { - if (passphraseMemorized) { - em->addEmail(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_RESET_PASSWORD)); - } - else { - em->addEmail(new model::Email(user, model::EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE)); - } - } - - if (frequent_resend) return 2; - if (email_already_send) return 1; - - return 0; -} - -int Session::comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource) -{ - KeyPair keys; - static const char* functionName = "Session::comparePassphraseWithSavedKeys"; - if (!wordSource) { - addError(new Error(functionName, "wordSource is empty")); - sendErrorsAsEmail(); - return -2; - } - if (!keys.generateFromPassphrase(inputPassphrase.data(), wordSource)) { - addError(new ParamError(functionName, "invalid passphrase", inputPassphrase)); - if (!mNewUser.isNull() && mNewUser->getModel()) { - addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); - } - sendErrorsAsEmail(); - addError(new Error(gettext("Passphrase"), gettext("Deine Passphrase ist ungütig")), false); - return 0; - } - auto userModel = mNewUser->getModel(); - auto existingPublic = userModel->getPublicKey(); - if (!existingPublic) { - userModel->loadFromDB("email", userModel->getEmail()); - existingPublic = userModel->getPublicKey(); - if (!existingPublic) { - addError(new Error(functionName, "cannot load existing public key from db")); - addError(new ParamError(functionName, "user email", userModel->getEmail())); - sendErrorsAsEmail(); - addError(new Error(gettext("Passphrase"), gettext("Ein Fehler trat auf, bitte versuche es erneut")), false); - return -1; - } - } - if (0 == memcmp(userModel->getPublicKey(), keys.getPublicKey(), crypto_sign_PUBLICKEYBYTES)) { - mPassphrase = inputPassphrase; - return 1; - } - addError(new Error(gettext("Passphrase"), gettext("Das ist nicht die richtige Passphrase.")), false); - return 0; -} - -bool Session::startProcessingTransaction(const std::string& proto_message_base64, bool autoSign/* = false*/) -{ - static const char* funcName = "Session::startProcessingTransaction"; - lock(funcName); - HASH hs = ProcessingTransaction::calculateHash(proto_message_base64); - // check if it is already running or waiting - for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { - if (it->isNull()) { - it = mProcessingTransactions.erase(it); - } - if (hs == (*it)->getHash()) { - addError(new Error(funcName, "transaction already in list")); - unlock(); - return false; - } - } - if (mSessionUser.isNull() || !mSessionUser->getEmail()) { - addError(new Error(funcName, "user is zero")); - unlock(); - return false; - } - - Poco::AutoPtr processorTask( - new ProcessingTransaction( - proto_message_base64, - DRMakeStringHash(mSessionUser->getEmail()), - mSessionUser->getLanguage()) - ); - if (autoSign && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) == ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) { - if (processorTask->run() != 0) { - getErrors(processorTask); - unlock(); - return false; - } - Poco::AutoPtr signingTransaction(new SigningTransaction(processorTask, mNewUser)); - //signingTransaction->scheduleTask(signingTransaction); - if (signingTransaction->run() != 0) { - getErrors(signingTransaction); - unlock(); - return false; - } - - } - else { - processorTask->scheduleTask(processorTask); - mProcessingTransactions.push_back(processorTask); - } - unlock(); - return true; - -} - -Poco::AutoPtr Session::getNextReadyTransaction(size_t* working/* = nullptr*/) -{ - lock("Session::getNextReadyTransaction"); - if (working) { - *working = 0; - } - else if (!mCurrentActiveProcessingTransaction.isNull()) - { - unlock(); - return mCurrentActiveProcessingTransaction; - } - for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { - if (working && !(*it)->isTaskFinished()) { - (*working)++; - } - if (mCurrentActiveProcessingTransaction.isNull() && (*it)->isTaskFinished()) { - if (!working) { - mCurrentActiveProcessingTransaction = *it; - unlock(); - return mCurrentActiveProcessingTransaction; - } - // no early exit - else { - mCurrentActiveProcessingTransaction = *it; - } - - } - } - unlock(); - return mCurrentActiveProcessingTransaction; -} - -bool Session::finalizeTransaction(bool sign, bool reject) -{ - int result = -1; - lock("Session::finalizeTransaction"); - if (mCurrentActiveProcessingTransaction.isNull()) { - unlock(); - return false; - } - mProcessingTransactions.remove(mCurrentActiveProcessingTransaction); - - if (!reject) { - if (sign) { - Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mNewUser)); - //signingTransaction->scheduleTask(signingTransaction); - result = signingTransaction->run(); - } - } - mCurrentActiveProcessingTransaction.assign(nullptr); - unlock(); - return result == 0; -} - -size_t Session::getProcessingTransactionCount() -{ - size_t count = 0; - lock("Session::getProcessingTransactionCount"); - - for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { - - (*it)->lock(); - if ((*it)->errorCount() > 0) { - (*it)->sendErrorsAsEmail(); - (*it)->unlock(); - it = mProcessingTransactions.erase(it); - if (it == mProcessingTransactions.end()) break; - } - else { - (*it)->unlock(); - } - - } - count = mProcessingTransactions.size(); - unlock(); - return count; -} - -bool Session::isPwdValid(const std::string& pwd) -{ - if (mSessionUser) { - return mSessionUser->validatePwd(pwd, this); - } - return false; -} - -UserStates Session::loadUser(const std::string& email, const std::string& password) -{ - static const char* functionName = "Session::loadUser"; - auto observer = SingletonTaskObserver::getInstance(); - if (email != "") { - if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) { - return USER_PASSWORD_ENCRYPTION_IN_PROCESS; - } - } - //Profiler usedTime; - //printf("before lock\n"); - lock(functionName); - //printf("locked \n"); - if (!mSessionUser.isNull() && mSessionUser->getEmail() != email) { - mSessionUser.assign(nullptr); - mNewUser.assign(nullptr); - //printf("user nullptr assigned\n"); - } - //printf("after checking if session user is null\n"); - //if (!mSessionUser) { - if (mNewUser.isNull()) { - //printf("new user is null\n"); - mNewUser = controller::User::create(); - //printf("new user created\n"); - // load user for email only once from db - mNewUser->load(email); - //printf("load new user from db with email: %s\n", email.data()); - mSessionUser = new User(mNewUser); - //mSessionUser = new User(email.data()); - - //printf("user loaded from email\n"); - } - //printf("before get model\n"); - auto user_model = mNewUser->getModel(); - if (user_model && user_model->isDisabled()) { - return USER_DISABLED; - } - //printf("before if login\n"); - if (!mSessionUser.isNull() && mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { - //printf("before login\n"); - int loginResult = 0; - int exitCount = 0; - do { - loginResult = mNewUser->login(password); - Poco::Thread::sleep(100); - exitCount++; - } while (-3 == loginResult && exitCount < 15); - if (exitCount > 1) { - addError(new ParamError(functionName, "login succeed, retrys: ", exitCount)); - addError(new ParamError(functionName, "email: ", email)); - sendErrorsAsEmail(); - } - - if (exitCount >= 15) - { - auto running_password_creations = observer->getTasksCount(TASK_OBSERVER_PASSWORD_CREATION); - - addError(new ParamError(functionName, "login failed after 15 retrys and 100 ms sleep between, currently running passwort creation tasks: ", running_password_creations)); - addError(new ParamError(functionName, "email: ", email)); - sendErrorsAsEmail(); - return USER_PASSWORD_ENCRYPTION_IN_PROCESS; - } - - //printf("new user login with result: %d\n", loginResult); - - if (-1 == loginResult) { - addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key")); - addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); - sendErrorsAsEmail(); - //unlock(); - //return USER_KEYS_DONT_MATCH; - } - if (0 == loginResult) { - unlock(); - return USER_PASSWORD_INCORRECT; - } - // error decrypting private key - if (-2 == loginResult) { - // check if we have access to the passphrase, if so we can reencrypt the private key - printf("try reencrypting key\n"); - auto user_model = mNewUser->getModel(); - auto user_backups = controller::UserBackups::load(user_model->getID()); - for (auto it = user_backups.begin(); it != user_backups.end(); it++) { - auto key = std::unique_ptr((*it)->createGradidoKeyPair()); - if (key->isTheSame(user_model->getPublicKey())) - { - - // set valid key pair - if (1 == mNewUser->setGradidoKeyPair(key.release())) { - // save new encrypted private key - user_model->updatePrivkey(); - } - else { - auto em = ErrorManager::getInstance(); - em->addError(new Error(functionName, "error reencrypt private key")); - em->addError(new ParamError(functionName, "for user with email", user_model->getEmail())); - em->sendErrorsAsEmail(); - } - break; - } - } - } - // can be removed if session user isn't used any more - // don't calculate password two times anymore - mSessionUser->login(mNewUser); - //printf("after old user login\n"); - /*if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { - unlock(); - return USER_PASSWORD_INCORRECT; - }*/ - } - else { - //printf("before sleep\n"); - User::fakeCreateCryptoKey(); - } - - /*if (!mSessionUser->validatePwd(password, this)) { - addError(new Error("Login", "E-Mail oder Passwort nicht korrekt, bitte versuche es erneut!")); - unlock(); - return false; - } - if (!mSessionUser->isEmailChecked()) { - addError(new Error("Account", "E-Mail Adresse wurde noch nicht bestätigt, hast du schon eine E-Mail erhalten?")); - unlock(); - return false; - }*/ - //printf("before detect session state\n"); - detectSessionState(); - unlock(); - //printf("before return user state\n"); - return mSessionUser->getUserState(); -} - -bool Session::deleteUser() -{ - lock("Session::deleteUser"); - bool bResult = false; - if(mSessionUser) { - JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, 443); - Poco::Net::NameValueCollection payload; - payload.add("user", std::string(mSessionUser->getPublicKeyHex())); - //auto ret = phpServerRequest.request("userDelete", payload); - JsonRequestReturn ret = JSON_REQUEST_RETURN_OK; - if (ret == JSON_REQUEST_RETURN_ERROR) { - addError(new Error("Session::deleteUser", "php server error")); - getErrors(&phpServerRequest); - sendErrorsAsEmail(); - } - else if (ret == JSON_REQUEST_RETURN_OK) { - bResult = mSessionUser->deleteFromDB(); - } - else { - addError(new Error(gettext("Benutzer"), gettext("Konnte Community Server nicht erreichen. E-Mail an den Admin ist raus."))); - unlock(); - return false; - } - } - if(!bResult) { - addError(new Error(gettext("Benutzer"), gettext("Fehler beim Löschen des Accounts. Bitte logge dich erneut ein und versuche es nochmal."))); - } - unlock(); - return bResult; -} - -void Session::setLanguage(Languages lang) -{ - //printf("[Session::setLanguage] new language: %d\n", lang); - lock("Session::setLanguage"); - if (mLanguageCatalog.isNull() || mLanguageCatalog->getLanguage() != lang) { - auto lm = LanguageManager::getInstance(); - mLanguageCatalog = lm->getFreeCatalog(lang); - } - unlock(); -} - -Languages Session::getLanguage() -{ - Languages lang = LANG_NULL; - lock("Session::getLanguage"); - if (!mLanguageCatalog.isNull()) { - lang = mLanguageCatalog->getLanguage(); - } - unlock(); - return lang; -} - - -/* -SESSION_STATE_CRYPTO_KEY_GENERATED, -SESSION_STATE_USER_WRITTEN, -SESSION_STATE_EMAIL_VERIFICATION_WRITTEN, -SESSION_STATE_EMAIL_VERIFICATION_SEND, -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 -*/ -void Session::detectSessionState() -{ - if (mSessionUser.isNull() || !mSessionUser->hasCryptoKey()) { - return; - } - UserStates userState = mSessionUser->getUserState(); - - int checkEmail = -1, resetPasswd = -1; - try { - auto emailVerificationCodeObjects = controller::EmailVerificationCode::load(mSessionUser->getDBId()); - - for (int i = 0; i < emailVerificationCodeObjects.size(); i++) { - auto type = emailVerificationCodeObjects[i]->getModel()->getType(); - if (type == model::table::EMAIL_OPT_IN_EMPTY || type == model::table::EMAIL_OPT_IN_REGISTER) { - checkEmail = i; - } - else if (type == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - resetPasswd = i; - } - } - std::unique_lock _lock_shared(mSharedMutex); - if (resetPasswd != -1) { - mEmailVerificationCodeObject = emailVerificationCodeObjects[resetPasswd]; - } - else if (checkEmail != -1) { - mEmailVerificationCodeObject = emailVerificationCodeObjects[checkEmail]; - } - - } - catch (Poco::Exception& ex) { - printf("[Session::detectSessionState] exception: %s\n", ex.displayText().data()); - //return; - } - - if (userState <= USER_EMAIL_NOT_ACTIVATED) { - - if (checkEmail != -1) { - updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); - return; - } - - updateState(SESSION_STATE_USER_WRITTEN); - return; - } - - if (USER_NO_KEYS == userState) { - - auto user_id = mSessionUser->getDBId(); - auto userBackups = controller::UserBackups::load(user_id); - - // check passphrase, only possible while passphrase isn't crypted in db - bool correctPassphraseFound = false; - // always trigger SESSION_STATE_PASSPHRASE_WRITTEN, else lost of data possible - bool cryptedPassphrase = userBackups.size() > 0; - for (auto it = userBackups.begin(); it != userBackups.end(); it++) { - KeyPair keys; - auto passphrase = (*it)->getModel()->getPassphrase(); - Mnemonic* wordSource = nullptr; - if (User::validatePassphrase(passphrase, &wordSource)) { - if (keys.generateFromPassphrase((*it)->getModel()->getPassphrase().data(), wordSource)) { - if (sodium_memcmp(mSessionUser->getPublicKey(), keys.getPublicKey(), ed25519_pubkey_SIZE) == 0) { - correctPassphraseFound = true; - break; - } - } - } - else { - cryptedPassphrase = true; - } - } - /* - auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement select(dbConnection); - Poco::Nullable passphrase; - - select << "SELECT passphrase from user_backups where user_id = ?;", - into(passphrase), use(user_id); - try { - if (select.execute() == 1 && !passphrase.isNull()) { - //KeyPair keys;keys.generateFromPassphrase(passphrase.value().rawContent()) - updateState(SESSION_STATE_PASSPHRASE_WRITTEN); - return; - } - } - catch (Poco::Exception& exc) { - printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data()); - }*/ - if (correctPassphraseFound || cryptedPassphrase) { - updateState(SESSION_STATE_PASSPHRASE_WRITTEN); - return; - } - if (mPassphrase != "") { - updateState(SESSION_STATE_PASSPHRASE_GENERATED); - return; - } - updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); - return; - } - - updateState(SESSION_STATE_KEY_PAIR_WRITTEN); - - if (resetPasswd != -1) { - // don't go to reset password screen after login, only throw checkEmail - //updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - return; - } - -} - -Poco::Net::HTTPCookie Session::getLoginCookie() -{ - auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId)); - // prevent reading or changing cookie with js -// keks.setHttpOnly(); - - keks.setPath("/"); - // send cookie only via https, on linux, except in test builds -#ifndef WIN32 - if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || - ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { - keks.setSecure(true); - } -#endif - - return keks; -} - -bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode) -{ - Profiler usedTime; - auto em = ErrorManager::getInstance(); - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = controller::EmailVerificationCode::load(emailVerificationCode); - if (mEmailVerificationCodeObject.isNull()) { - addError(new Error(gettext("E-Mail Verification"), gettext("Konnte kein passendes Konto finden."))); - return false; - } - - mNewUser = controller::User::create(); - assert(mEmailVerificationCodeObject->getModel() && mEmailVerificationCodeObject->getModel()->getUserId()); - mNewUser->load(mEmailVerificationCodeObject->getModel()->getUserId()); - if (mNewUser->getModel()->errorCount() > 0) { - mNewUser->getModel()->sendErrorsAsEmail(); - addError(new Error(gettext("E-Mail Verification"), gettext("Fehler beim laden des Benutzers."))); - return false; - } - mSessionUser = new User(mNewUser); - mSessionUser->setLanguage(getLanguage()); - - auto verificationType = mEmailVerificationCodeObject->getModel()->getType(); - if (verificationType == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - } - else { - updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); - } - - return true; -} - -void Session::updateState(SessionStates newState) -{ - lock("Session::updateState"); - if (!mActive) { - unlock(); - return; - } - updateTimeout(); - //printf("[%s] newState: %s\n", __FUNCTION__, translateSessionStateToString(newState)); - if (newState > mState) { - mState = newState; - } - - unlock(); -} - -const char* Session::getSessionStateString() -{ - SessionStates state; - lock("Session::getSessionStateString"); - state = mState; - unlock(); - return translateSessionStateToString(state); -} - - -const char* Session::translateSessionStateToString(SessionStates state) -{ - switch (state) { - case SESSION_STATE_EMPTY: return "uninitalized"; - case SESSION_STATE_CRYPTO_KEY_GENERATED: return "crpyto key generated"; - case SESSION_STATE_USER_WRITTEN: return "User saved"; - case SESSION_STATE_EMAIL_VERIFICATION_WRITTEN: return "E-Mail verification code saved"; - case SESSION_STATE_EMAIL_VERIFICATION_SEND: return "Verification E-Mail sended"; - 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"; - case SESSION_STATE_RESET_PASSWORD_REQUEST: return "Passwort reset requested"; - case SESSION_STATE_RESET_PASSWORD_SUCCEED: return "Passwort reset succeeded"; - default: return "unknown"; - } - - return "error"; -} - - -/* -bool Session::useOrGeneratePassphrase(const std::string& passphase) -{ - if (passphase != "" && User::validatePassphrase(passphase)) { - // passphrase is valid - setPassphrase(passphase); - updateState(SESSION_STATE_PASSPHRASE_SHOWN); - return true; - } - else { - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); - updateState(SESSION_STATE_PASSPHRASE_GENERATED); - return true; - } -} -*/ -bool Session::generatePassphrase() -{ - if (mNewUser.isNull()) return false; - - auto lang = getLanguage(); - if (lang == LANG_EN) { - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); - } - else { - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); - } - //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); - updateState(SESSION_STATE_PASSPHRASE_GENERATED); - return true; -} - -bool Session::generateKeys(bool savePrivkey, bool savePassphrase) -{ - if (mNewUser.isNull()) { - addError(new Error(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); - return false; - } - static const char* function_name = "Session::generateKeys"; - auto lang = getLanguage(); - auto user_model = mNewUser->getModel(); - auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; - /*if (LANG_DE == lang) { - mnemonic_type = ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES; - }*/ - - auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); - if (!passphrase) { - addError(new ParamError(function_name, "Error generating passphrase with mnemonic: ", mnemonic_type)); - addError(new ParamError(function_name, "user email: ", mNewUser->getModel()->getEmail())); - sendErrorsAsEmail(); - addError(new Error(gettext("Benutzer"), gettext("Fehler beim generieren der Passphrase, der Admin bekommt eine E-Mail. "))); - return false; - } - - if (savePassphrase) { - auto user_backup = controller::UserBackups::create(user_model->getID(), passphrase->getString(), mnemonic_type); - // sync version - //user_backup->getModel()->insertIntoDB(false); - - // async version - UniLib::controller::TaskPtr save_user_backup_task = new model::table::ModelInsertTask(user_backup->getModel(), false, true); - save_user_backup_task->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this)); - save_user_backup_task->scheduleTask(save_user_backup_task); - } - - // keys - auto gradido_key_pair = KeyPairEd25519::create(passphrase); - auto set_key_result = mNewUser->setGradidoKeyPair(gradido_key_pair); - size_t result_save_key = 0; - if (1 == set_key_result && savePrivkey) { - // save public key and private key in db - result_save_key = user_model->updatePubkeyAndPrivkey(); - } - else { - // save public key in db - result_save_key = user_model->updatePublickey(); - } - if (!result_save_key) { - user_model->addError(new Error(function_name, "Error saving new generated pubkey")); - user_model->addError(new ParamError(function_name, "e-mail: ", user_model->getEmail())); - user_model->sendErrorsAsEmail(); - //addError(new Error(gettext("Benutzer"), gettext("Fehler beim Speichern der Keys, der Admin bekommt eine E-Mail. Evt. nochmal versuchen oder abwarten!"))); - return false; - } - return true; - /* - - bool validUser = true; - if (mSessionUser) { - if (!mSessionUser->generateKeys(savePrivkey, mPassphrase, this)) { - validUser = false; - } - else { - if (savePassphrase) { - //printf("[Session::generateKeys] create save passphrase task\n"); - 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(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); - return false; - } - // delete passphrase after all went well - mPassphrase.clear(); - - return true; - */ -} +#include "Session.h" +#include "../lib/Profiler.h" +#include "../ServerConfig.h" + +#include "Poco/RegularExpression.h" +#include "Poco/Net/StringPartSource.h" +#include "Poco/Net/MediaType.h" + +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/ConnectionManager.h" +#include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/EmailManager.h" +#include "../SingletonManager/SingletonTaskObserver.h" + +#include "../tasks/PrepareEmailTask.h" +#include "../tasks/SendEmailTask.h" +#include "../tasks/SigningTransaction.h" +#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" +#include "../tasks/VerificationEmailResendTask.h" + +#include "../lib/JsonRequest.h" + +#include "../Crypto/Passphrase.h" + + +#include "../controller/User.h" +#include "../controller/UserBackup.h" +#include "../controller/EmailVerificationCode.h" + +#include "table/ModelBase.h" + + +#include "sodium.h" + +using namespace Poco::Data::Keywords; + +int WriteEmailVerification::run() +{ + auto em = ErrorManager::getInstance(); + + mEmailVerificationCode->getModel()->setUserId(mUser->getDBId()); + auto emailVerificationModel = mEmailVerificationCode->getModel(); + emailVerificationModel->setUserId(mUser->getDBId()); + if (!emailVerificationModel->insertIntoDB(true) || emailVerificationModel->errorCount() > 0) { + emailVerificationModel->sendErrorsAsEmail(); + return -1; + } + + 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 em = ErrorManager::getInstance(); + + 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); + try { + if (insert.execute() != 1) { + em->addError(new ParamError("WritePassphraseIntoDB::run", "inserting passphrase for user failed", std::to_string(mUserId))); + em->sendErrorsAsEmail(); + } + } + catch (Poco::Exception& ex) { + em->addError(new ParamError("WritePassphraseIntoDB::run", "insert passphrase mysql error", ex.displayText().data())); + em->sendErrorsAsEmail(); + } + + //printf("[WritePassphraseIntoDB] timeUsed: %s\n", timeUsed.string().data()); + return 0; +} + + +// -------------------------------------------------------------------------------------------------------------- + +Session::Session(int handle) + : mHandleId(handle), mSessionUser(nullptr), mState(SESSION_STATE_EMPTY), mActive(false) +{ + +} + +Session::~Session() +{ + //printf("[Session::~Session] \n"); + if (tryLock()) { + unlock(); + reset(); + } + + + //printf("[Session::~Session] finished \n"); +} + + +void Session::reset() +{ + //printf("[Session::reset]\n"); + lock("Session::reset"); + std::unique_lock _lock(mSharedMutex); + mSessionUser.assign(nullptr); + mNewUser.assign(nullptr); + mEmailVerificationCodeObject.assign(nullptr); + + // watch out + //updateTimeout(); + mLastActivity = Poco::DateTime(); + + mState = SESSION_STATE_EMPTY; + + mPassphrase = ""; + mLastExternReferer = ""; + mClientLoginIP = Poco::Net::IPAddress(); + unlock(); + + // reset transactions + mCurrentActiveProcessingTransaction = nullptr; + mProcessingTransactions.clear(); + + //printf("[Session::reset] finished\n"); +} + +int Session::isActive() +{ + int ret = 0; + try { + mWorkMutex.tryLock(100); + } + catch (Poco::TimeoutException &ex) { + return -1; + } + ret = (int)mActive; + unlock(); + return ret; + +} + +bool Session::isDeadLocked() +{ + try { + mWorkMutex.tryLock(200); + unlock(); + return false; + } + catch (Poco::Exception& ex) { + + } + return true; +} + +bool Session::setActive(bool active) +{ + try { + mWorkMutex.tryLock(100); + } + catch (Poco::TimeoutException &ex) { + return false; + } + mActive = active; + unlock(); + return true; +} + +void Session::updateTimeout() +{ + lock("Session::updateTimeout"); + mLastActivity = Poco::DateTime(); + unlock(); +} + +Poco::AutoPtr Session::getEmailVerificationCodeObject() +{ + lock("Session::getEmailVerificationCodeObject"); + std::shared_lock _lock(mSharedMutex); + auto ret = mEmailVerificationCodeObject; + unlock(); + return ret; +} + +bool Session::adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email) +{ + Profiler usedTime; + + if (mNewUser->getModel()->getRole() != model::table::ROLE_ADMIN) { + addError(new Error(gettext("Benutzer"), gettext("Eingeloggter Benutzer ist kein Admin")), false); + return false; + } + + auto sm = SessionManager::getInstance(); + if (!sm->isValid(first_name, VALIDATE_NAME)) { + addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + return false; + } + + + // check if user with that email already exist + if (mNewUser->getModel()->isExistInDB("email", email)) { + addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); + return false; + } + + auto newUser = controller::User::create(email, first_name, last_name); + updateTimeout(); + + + auto newUserModel = newUser->getModel(); + if (!newUserModel->insertIntoDB(true)) { + addError(new Error(gettext("Benutzer"), gettext("Fehler beim speichern!"))); + return false; + } + + auto email_verification_code = controller::EmailVerificationCode::create(newUserModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); + if (!email_verification_code->getModel()->insertIntoDB(false)) { + addError(new Error(gettext("Email Verification Code"), gettext("Fehler beim speichern!"))); + return false; + } + + EmailManager::getInstance()->addEmail(new model::Email(email_verification_code, newUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE)); + + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = email_verification_code; + + + return true; +} +// +bool Session::createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) +{ + Profiler usedTime; + auto sm = SessionManager::getInstance(); + if (!sm->isValid(first_name, VALIDATE_NAME)) { + addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + return false; + } + if (!sm->checkPwdValidation(password, this)) { + return false; + } + /*if (passphrase.size() > 0 && !sm->isValid(passphrase, VALIDATE_PASSPHRASE)) { + addError(new Error("Merkspruch", "Der Merkspruch ist nicht gültig, er besteht aus 24 Wörtern, mit Komma getrennt.")); + return false; + } + if (passphrase.size() == 0) { + //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); + } + else { + //mPassphrase = passphrase; + }*/ + + // check if user with that email already exist + + auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(dbConnection); + select << "SELECT email from users where email = ?;", useRef(email); + try { + if (select.execute() > 0) { + addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); + return false; + } + } + catch (Poco::Exception& exc) { + printf("mysql exception: %s\n", exc.displayText().data()); + } + + mSessionUser = new User(email.data(), first_name.data(), last_name.data()); + mNewUser = controller::User::create(email, first_name, last_name); + updateTimeout(); + + // Prepare E-Mail + //UniLib::controller::TaskPtr prepareEmail(new PrepareEmailTask(ServerConfig::g_CPUScheduler)); + //prepareEmail->scheduleTask(prepareEmail); + + // create user crypto key + UniLib::controller::TaskPtr cryptoKeyTask(new UserCreateCryptoKey(mSessionUser, mNewUser, password, ServerConfig::g_CryptoCPUScheduler)); + cryptoKeyTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_CRYPTO_KEY_GENERATED, this)); + cryptoKeyTask->scheduleTask(cryptoKeyTask); + + // depends on crypto key, write user record into db + UniLib::controller::TaskPtr writeUserIntoDB(new UserWriteIntoDB(mSessionUser, ServerConfig::g_CPUScheduler, 1)); + writeUserIntoDB->setParentTaskPtrInArray(cryptoKeyTask, 0); + writeUserIntoDB->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_USER_WRITTEN, this)); + writeUserIntoDB->scheduleTask(writeUserIntoDB); + + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = controller::EmailVerificationCode::create(model::table::EMAIL_OPT_IN_REGISTER); + UniLib::controller::TaskPtr writeEmailVerification(new WriteEmailVerification(mSessionUser, mEmailVerificationCodeObject, ServerConfig::g_CPUScheduler, 1)); + + writeEmailVerification->setParentTaskPtrInArray(writeUserIntoDB, 0); + writeEmailVerification->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN, this)); + writeEmailVerification->scheduleTask(writeEmailVerification); + + + /*printf("LastName: %s\n", last_name.data()); + for (int i = 0; i < last_name.size(); i++) { + char c = last_name.data()[i]; + //printf("%d ", c); + } + //printf("\n\n"); + */ + + // depends on writeUser because need user_id, write email verification into db + /*auto message = new Poco::Net::MailMessage; + Poco::Net::MediaType mt("text", "plain"); + mt.setParameter("charset", "utf-8"); + message->setContentType(mt); + + message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, email)); + message->setSubject(gettext("Gradido: E-Mail Verification")); + std::stringstream ss; + ss << "Hallo " << first_name << " " << last_name << "," << std::endl << std::endl; + ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Gradido registriert. " << std::endl; + ss << "Wenn du es warst, klicke bitte auf den Link: " << ServerConfig::g_serverPath << "/checkEmail/" << mEmailVerificationCode << std::endl; + //ss << "oder kopiere den Code: " << mEmailVerificationCode << " selbst dort hinein." << std::endl; + ss << "oder kopiere den obigen Link in Dein Browserfenster." << std::endl; + ss << std::endl; + ss << "Mit freundlichen " << u8"Grüßen" << std::endl; + ss << "Dario, Gradido Server Admin" << std::endl; + + + message->addContent(new Poco::Net::StringPartSource(ss.str())); + */ + //UniLib::controller::TaskPtr sendEmail(new SendEmailTask(message, ServerConfig::g_CPUScheduler, 1)); + //Email(AutoPtr emailVerification, AutoPtr user, EmailType type); + UniLib::controller::TaskPtr sendEmail(new SendEmailTask(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_VERIFICATION_CODE), ServerConfig::g_CPUScheduler, 1)); + //sendEmail->setParentTaskPtrInArray(prepareEmail, 0); + sendEmail->setParentTaskPtrInArray(writeEmailVerification, 0); + sendEmail->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_SEND, this)); + sendEmail->scheduleTask(sendEmail); + + // write user into db + // generate and write email verification into db + // send email + + //printf("[Session::createUser] time: %s\n", usedTime.string().data()); + + return true; +} + +bool Session::createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) +{ + std::unique_lock _lock(mSharedMutex); + static const char* function_name = "Session::createUserDirect"; + auto sm = SessionManager::getInstance(); + auto em = ErrorManager::getInstance(); + auto email_manager = EmailManager::getInstance(); + + if (!sm->isValid(first_name, VALIDATE_NAME)) { + addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + return false; + } + if (!sm->checkPwdValidation(password, this)) { + return false; + } + + // check if email already exist + auto user = controller::User::create(); + if (user->load(email) >= 1) { + addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits ein Konto")), false); + return false; + } + + // user + mNewUser = controller::User::create(email, first_name, last_name); + auto user_model = mNewUser->getModel(); + user_model->insertIntoDB(true); + auto user_id = user_model->getID(); + + + // one retry in case of connection error + if (!user_id) { + user_model->insertIntoDB(true); + auto user_id = user_model->getID(); + if (!user_id) { + em->addError(new ParamError(function_name, "error saving new user in db, after one retry with email", email)); + em->sendErrorsAsEmail(); + addError(new Error(gettext("Server"), gettext("Fehler beim speichen des Kontos bitte versuche es später noch einmal")), false); + return false; + } + } + + generateKeys(true, true); + + // calculate encryption key, could need some time, will save encrypted privkey to db + UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(mNewUser, password); + create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); + + // email verification code + auto email_verification = controller::EmailVerificationCode::create(user_id, model::table::EMAIL_OPT_IN_REGISTER_DIRECT); + email_verification->getModel()->insertIntoDB(false); + mEmailVerificationCodeObject = email_verification; + + auto _7days_later = Poco::DateTime() + Poco::Timespan(7, 0, 0, 0, 0); + ServerConfig::g_CronJobsTimer.schedule(new VerificationEmailResendTimerTask(user_id), Poco::Timestamp(_7days_later.timestamp())); + + email_manager->addEmail(new model::Email(email_verification, mNewUser, model::EMAIL_USER_VERIFICATION_CODE)); + + return true; +} + +bool Session::ifUserExist(const std::string& email) +{ + auto em = ErrorManager::getInstance(); + const char* funcName = "Session::ifUserExist"; + auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(dbConnection); + bool emailChecked = false; + int userId = 0; + select << "SELECT email_checked, id from users where email = ? and email_checked = 1", + into(emailChecked), into(userId), useRef(email); + + try { + if(select.execute() == 1) return true; + } + catch (Poco::Exception& ex) { + em->addError(new ParamError(funcName, "select user from email verification code mysql error ", ex.displayText().data())); + em->sendErrorsAsEmail(); + } + return false; +} + +int Session::updateEmailVerification(Poco::UInt64 emailVerificationCode) +{ + const static char* funcName = "Session::updateEmailVerification"; + Poco::ScopedLock _lock(mWorkMutex); + // new mutex, will replace the Poco Mutex complete in the future + std::unique_lock _lock_shared(mSharedMutex); + Profiler usedTime; + + auto em = ErrorManager::getInstance(); + if (mEmailVerificationCodeObject.isNull()) { + em->addError(new Error(funcName, "email verification object is zero")); + em->sendErrorsAsEmail(); + + return -2; + } + auto email_verification_code_model = mEmailVerificationCodeObject->getModel(); + assert(email_verification_code_model); + if(email_verification_code_model->getCode() == emailVerificationCode) { + if (mSessionUser && mSessionUser->getDBId() == 0) { + //addError(new Error("E-Mail Verification", "Benutzer wurde nicht richtig gespeichert, bitte wende dich an den Server-Admin")); + em->addError(new Error(funcName, "user exist with 0 as id")); + em->sendErrorsAsEmail(); + + //return false; + return -2; + } + + // load correct user from db + if (mNewUser.isNull() || !mNewUser->getModel() || mNewUser->getModel()->getID() != email_verification_code_model->getUserId()) { + mNewUser = controller::User::create(); + if (1 != mNewUser->load(email_verification_code_model->getUserId())) { + em->addError(new ParamError(funcName, "user load didn't return 1 with user_id ", email_verification_code_model->getUserId())); + em->sendErrorsAsEmail(); + + return -2; + } + } + + auto user_model = mNewUser->getModel(); + assert(user_model); + bool first_email_activation = false; + auto verification_type = email_verification_code_model->getType(); + if (model::table::EMAIL_OPT_IN_REGISTER == verification_type || + model::table::EMAIL_OPT_IN_EMPTY == verification_type || + model::table::EMAIL_OPT_IN_REGISTER_DIRECT == verification_type) { + first_email_activation = true; + } + if (first_email_activation && user_model->isEmailChecked()) { + mSessionUser = new User(mNewUser); + addError(new Error(gettext("E-Mail Verification"), gettext("Du hast dein Konto bereits aktiviert!")), false); + + return 1; + } + if (first_email_activation) { + user_model->setEmailChecked(true); + + user_model->updateIntoDB("email_checked", 1); + if (user_model->errorCount() > 0) { + user_model->sendErrorsAsEmail(); + } + + // no find all active sessions + + updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); + return 0; + } + + if (email_verification_code_model->getType() == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + + if (mEmailVerificationCodeObject->deleteFromDB()) { + mEmailVerificationCodeObject.assign(nullptr); + } + else { + em->getErrors(mEmailVerificationCodeObject->getModel()); + em->addError(new Error(funcName, "error deleting email verification code")); + em->sendErrorsAsEmail(); + return -2; + } + updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + return 0; + } + + em->addError(new Error(funcName, "invalid code path")); + em->sendErrorsAsEmail(); + + return -2; + + /*if (updated_rows == 1) { + Poco::Data::Statement delete_row(dbConnection); + delete_row << "DELETE FROM email_opt_in where verification_code = ?", use(emailVerificationCode); + if (delete_row.execute() != 1) { + em->addError(new Error(funcName, "delete from email_opt_in entry didn't work as expected, please check db")); + em->sendErrorsAsEmail(); + } + if (mSessionUser) { + mSessionUser->setEmailChecked(); + mSessionUser->setLanguage(getLanguage()); + } + updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); + //printf("[%s] time: %s\n", funcName, usedTime.string().data()); + unlock(); + return true; + } + else { + em->addError(new ParamError(funcName, "update user work not like expected, updated row count", updated_rows)); + em->sendErrorsAsEmail(); + }*/ + + + } + else { + addError(new Error(gettext("E-Mail Verification"), gettext("Falscher Code für aktiven Login"))); + //printf("[%s] time: %s\n", funcName, usedTime.string().data()); + + return -1; + } + //printf("[%s] time: %s\n", funcName, usedTime.string().data()); + + return 0; +} + + +int Session::sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized) +{ + mNewUser = user; + mSessionUser = new User(user); + auto em = EmailManager::getInstance(); + + std::unique_lock _lock(mSharedMutex); + + // creating email verification code also for user without passphrase + // first check if already exist + // check if email was already send shortly before + bool frequent_resend = false; + bool email_already_send = false; + + mEmailVerificationCodeObject = controller::EmailVerificationCode::load(user->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); + if (mEmailVerificationCodeObject.isNull()) { + mEmailVerificationCodeObject = controller::EmailVerificationCode::create(mNewUser->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); + mEmailVerificationCodeObject->getModel()->insertIntoDB(false); + } + else { + email_already_send = true; + } + auto email_verification_model = mEmailVerificationCodeObject->getModel(); + if (email_already_send) { + auto time_elapsed = Poco::DateTime() - email_verification_model->getUpdated(); + if (time_elapsed.totalHours() < 1) { + frequent_resend = true; + } + } + + if (!frequent_resend) { + if (passphraseMemorized) { + em->addEmail(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_RESET_PASSWORD)); + } + else { + em->addEmail(new model::Email(user, model::EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE)); + } + } + + if (frequent_resend) return 2; + if (email_already_send) return 1; + + return 0; +} + +int Session::comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource) +{ + KeyPair keys; + static const char* functionName = "Session::comparePassphraseWithSavedKeys"; + if (!wordSource) { + addError(new Error(functionName, "wordSource is empty")); + sendErrorsAsEmail(); + return -2; + } + if (!keys.generateFromPassphrase(inputPassphrase.data(), wordSource)) { + addError(new ParamError(functionName, "invalid passphrase", inputPassphrase)); + if (!mNewUser.isNull() && mNewUser->getModel()) { + addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); + } + sendErrorsAsEmail(); + addError(new Error(gettext("Passphrase"), gettext("Deine Passphrase ist ungütig")), false); + return 0; + } + auto userModel = mNewUser->getModel(); + auto existingPublic = userModel->getPublicKey(); + if (!existingPublic) { + userModel->loadFromDB("email", userModel->getEmail()); + existingPublic = userModel->getPublicKey(); + if (!existingPublic) { + addError(new Error(functionName, "cannot load existing public key from db")); + addError(new ParamError(functionName, "user email", userModel->getEmail())); + sendErrorsAsEmail(); + addError(new Error(gettext("Passphrase"), gettext("Ein Fehler trat auf, bitte versuche es erneut")), false); + return -1; + } + } + if (0 == memcmp(userModel->getPublicKey(), keys.getPublicKey(), crypto_sign_PUBLICKEYBYTES)) { + mPassphrase = inputPassphrase; + return 1; + } + addError(new Error(gettext("Passphrase"), gettext("Das ist nicht die richtige Passphrase.")), false); + return 0; +} + +bool Session::startProcessingTransaction(const std::string& proto_message_base64, bool autoSign/* = false*/) +{ + static const char* funcName = "Session::startProcessingTransaction"; + lock(funcName); + HASH hs = ProcessingTransaction::calculateHash(proto_message_base64); + // check if it is already running or waiting + for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { + if (it->isNull()) { + it = mProcessingTransactions.erase(it); + } + if (hs == (*it)->getHash()) { + addError(new Error(funcName, "transaction already in list")); + unlock(); + return false; + } + } + if (mSessionUser.isNull() || !mSessionUser->getEmail()) { + addError(new Error(funcName, "user is zero")); + unlock(); + return false; + } + + Poco::AutoPtr processorTask( + new ProcessingTransaction( + proto_message_base64, + DRMakeStringHash(mSessionUser->getEmail()), + mSessionUser->getLanguage()) + ); + if (autoSign && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) == ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) { + if (processorTask->run() != 0) { + getErrors(processorTask); + unlock(); + return false; + } + Poco::AutoPtr signingTransaction(new SigningTransaction(processorTask, mNewUser)); + //signingTransaction->scheduleTask(signingTransaction); + if (signingTransaction->run() != 0) { + getErrors(signingTransaction); + unlock(); + return false; + } + + } + else { + processorTask->scheduleTask(processorTask); + mProcessingTransactions.push_back(processorTask); + } + unlock(); + return true; + +} + +Poco::AutoPtr Session::getNextReadyTransaction(size_t* working/* = nullptr*/) +{ + lock("Session::getNextReadyTransaction"); + if (working) { + *working = 0; + } + else if (!mCurrentActiveProcessingTransaction.isNull()) + { + unlock(); + return mCurrentActiveProcessingTransaction; + } + for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { + if (working && !(*it)->isTaskFinished()) { + (*working)++; + } + if (mCurrentActiveProcessingTransaction.isNull() && (*it)->isTaskFinished()) { + if (!working) { + mCurrentActiveProcessingTransaction = *it; + unlock(); + return mCurrentActiveProcessingTransaction; + } + // no early exit + else { + mCurrentActiveProcessingTransaction = *it; + } + + } + } + unlock(); + return mCurrentActiveProcessingTransaction; +} + +bool Session::finalizeTransaction(bool sign, bool reject) +{ + int result = -1; + lock("Session::finalizeTransaction"); + if (mCurrentActiveProcessingTransaction.isNull()) { + unlock(); + return false; + } + mProcessingTransactions.remove(mCurrentActiveProcessingTransaction); + + if (!reject) { + if (sign) { + Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mNewUser)); + //signingTransaction->scheduleTask(signingTransaction); + result = signingTransaction->run(); + } + } + mCurrentActiveProcessingTransaction.assign(nullptr); + unlock(); + return result == 0; +} + +size_t Session::getProcessingTransactionCount() +{ + size_t count = 0; + lock("Session::getProcessingTransactionCount"); + + for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { + + (*it)->lock(); + if ((*it)->errorCount() > 0) { + (*it)->sendErrorsAsEmail(); + (*it)->unlock(); + it = mProcessingTransactions.erase(it); + if (it == mProcessingTransactions.end()) break; + } + else { + (*it)->unlock(); + } + + } + count = mProcessingTransactions.size(); + unlock(); + return count; +} + +bool Session::isPwdValid(const std::string& pwd) +{ + if (mSessionUser) { + return mSessionUser->validatePwd(pwd, this); + } + return false; +} + +UserStates Session::loadUser(const std::string& email, const std::string& password) +{ + static const char* functionName = "Session::loadUser"; + auto observer = SingletonTaskObserver::getInstance(); + if (email != "") { + if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) { + return USER_PASSWORD_ENCRYPTION_IN_PROCESS; + } + } + //Profiler usedTime; + //printf("before lock\n"); + lock(functionName); + //printf("locked \n"); + if (!mSessionUser.isNull() && mSessionUser->getEmail() != email) { + mSessionUser.assign(nullptr); + mNewUser.assign(nullptr); + //printf("user nullptr assigned\n"); + } + //printf("after checking if session user is null\n"); + //if (!mSessionUser) { + if (mNewUser.isNull()) { + //printf("new user is null\n"); + mNewUser = controller::User::create(); + //printf("new user created\n"); + // load user for email only once from db + mNewUser->load(email); + //printf("load new user from db with email: %s\n", email.data()); + mSessionUser = new User(mNewUser); + //mSessionUser = new User(email.data()); + + //printf("user loaded from email\n"); + } + //printf("before get model\n"); + auto user_model = mNewUser->getModel(); + if (user_model && user_model->isDisabled()) { + return USER_DISABLED; + } + //printf("before if login\n"); + if (!mSessionUser.isNull() && mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { + //printf("before login\n"); + int loginResult = 0; + int exitCount = 0; + do { + loginResult = mNewUser->login(password); + Poco::Thread::sleep(100); + exitCount++; + } while (-3 == loginResult && exitCount < 15); + if (exitCount > 1) { + addError(new ParamError(functionName, "login succeed, retrys: ", exitCount)); + addError(new ParamError(functionName, "email: ", email)); + sendErrorsAsEmail(); + } + + if (exitCount >= 15) + { + auto running_password_creations = observer->getTasksCount(TASK_OBSERVER_PASSWORD_CREATION); + + addError(new ParamError(functionName, "login failed after 15 retrys and 100 ms sleep between, currently running passwort creation tasks: ", running_password_creations)); + addError(new ParamError(functionName, "email: ", email)); + sendErrorsAsEmail(); + return USER_PASSWORD_ENCRYPTION_IN_PROCESS; + } + + //printf("new user login with result: %d\n", loginResult); + + if (-1 == loginResult) { + addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key")); + addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); + sendErrorsAsEmail(); + //unlock(); + //return USER_KEYS_DONT_MATCH; + } + if (0 == loginResult) { + unlock(); + return USER_PASSWORD_INCORRECT; + } + // error decrypting private key + if (-2 == loginResult) { + // check if we have access to the passphrase, if so we can reencrypt the private key + printf("try reencrypting key\n"); + auto user_model = mNewUser->getModel(); + auto user_backups = controller::UserBackup::load(user_model->getID()); + for (auto it = user_backups.begin(); it != user_backups.end(); it++) { + auto key = std::unique_ptr((*it)->createGradidoKeyPair()); + if (key->isTheSame(user_model->getPublicKey())) + { + + // set valid key pair + if (1 == mNewUser->setGradidoKeyPair(key.release())) { + // save new encrypted private key + user_model->updatePrivkey(); + } + else { + auto em = ErrorManager::getInstance(); + em->addError(new Error(functionName, "error reencrypt private key")); + em->addError(new ParamError(functionName, "for user with email", user_model->getEmail())); + em->sendErrorsAsEmail(); + } + break; + } + } + } + // can be removed if session user isn't used any more + // don't calculate password two times anymore + mSessionUser->login(mNewUser); + //printf("after old user login\n"); + /*if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { + unlock(); + return USER_PASSWORD_INCORRECT; + }*/ + } + else { + //printf("before sleep\n"); + User::fakeCreateCryptoKey(); + } + + /*if (!mSessionUser->validatePwd(password, this)) { + addError(new Error("Login", "E-Mail oder Passwort nicht korrekt, bitte versuche es erneut!")); + unlock(); + return false; + } + if (!mSessionUser->isEmailChecked()) { + addError(new Error("Account", "E-Mail Adresse wurde noch nicht bestätigt, hast du schon eine E-Mail erhalten?")); + unlock(); + return false; + }*/ + //printf("before detect session state\n"); + detectSessionState(); + unlock(); + //printf("before return user state\n"); + return mSessionUser->getUserState(); +} + +bool Session::deleteUser() +{ + lock("Session::deleteUser"); + bool bResult = false; + if(mSessionUser) { + JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, 443); + Poco::Net::NameValueCollection payload; + payload.add("user", std::string(mSessionUser->getPublicKeyHex())); + //auto ret = phpServerRequest.request("userDelete", payload); + JsonRequestReturn ret = JSON_REQUEST_RETURN_OK; + if (ret == JSON_REQUEST_RETURN_ERROR) { + addError(new Error("Session::deleteUser", "php server error")); + getErrors(&phpServerRequest); + sendErrorsAsEmail(); + } + else if (ret == JSON_REQUEST_RETURN_OK) { + bResult = mSessionUser->deleteFromDB(); + } + else { + addError(new Error(gettext("Benutzer"), gettext("Konnte Community Server nicht erreichen. E-Mail an den Admin ist raus."))); + unlock(); + return false; + } + } + if(!bResult) { + addError(new Error(gettext("Benutzer"), gettext("Fehler beim Löschen des Accounts. Bitte logge dich erneut ein und versuche es nochmal."))); + } + unlock(); + return bResult; +} + +void Session::setLanguage(Languages lang) +{ + //printf("[Session::setLanguage] new language: %d\n", lang); + lock("Session::setLanguage"); + if (mLanguageCatalog.isNull() || mLanguageCatalog->getLanguage() != lang) { + auto lm = LanguageManager::getInstance(); + mLanguageCatalog = lm->getFreeCatalog(lang); + } + unlock(); +} + +Languages Session::getLanguage() +{ + Languages lang = LANG_NULL; + lock("Session::getLanguage"); + if (!mLanguageCatalog.isNull()) { + lang = mLanguageCatalog->getLanguage(); + } + unlock(); + return lang; +} + + +/* +SESSION_STATE_CRYPTO_KEY_GENERATED, +SESSION_STATE_USER_WRITTEN, +SESSION_STATE_EMAIL_VERIFICATION_WRITTEN, +SESSION_STATE_EMAIL_VERIFICATION_SEND, +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 +*/ +void Session::detectSessionState() +{ + if (mSessionUser.isNull() || !mSessionUser->hasCryptoKey()) { + return; + } + UserStates userState = mSessionUser->getUserState(); + + int checkEmail = -1, resetPasswd = -1; + try { + auto emailVerificationCodeObjects = controller::EmailVerificationCode::load(mSessionUser->getDBId()); + + for (int i = 0; i < emailVerificationCodeObjects.size(); i++) { + auto type = emailVerificationCodeObjects[i]->getModel()->getType(); + if (type == model::table::EMAIL_OPT_IN_EMPTY || type == model::table::EMAIL_OPT_IN_REGISTER) { + checkEmail = i; + } + else if (type == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + resetPasswd = i; + } + } + std::unique_lock _lock_shared(mSharedMutex); + if (resetPasswd != -1) { + mEmailVerificationCodeObject = emailVerificationCodeObjects[resetPasswd]; + } + else if (checkEmail != -1) { + mEmailVerificationCodeObject = emailVerificationCodeObjects[checkEmail]; + } + + } + catch (Poco::Exception& ex) { + printf("[Session::detectSessionState] exception: %s\n", ex.displayText().data()); + //return; + } + + if (userState <= USER_EMAIL_NOT_ACTIVATED) { + + if (checkEmail != -1) { + updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); + return; + } + + updateState(SESSION_STATE_USER_WRITTEN); + return; + } + + if (USER_NO_KEYS == userState) { + + auto user_id = mSessionUser->getDBId(); + auto userBackups = controller::UserBackup::load(user_id); + + // check passphrase, only possible while passphrase isn't crypted in db + bool correctPassphraseFound = false; + // always trigger SESSION_STATE_PASSPHRASE_WRITTEN, else lost of data possible + bool cryptedPassphrase = userBackups.size() > 0; + for (auto it = userBackups.begin(); it != userBackups.end(); it++) { + KeyPair keys; + auto passphrase = (*it)->getModel()->getPassphrase(); + Mnemonic* wordSource = nullptr; + if (User::validatePassphrase(passphrase, &wordSource)) { + if (keys.generateFromPassphrase((*it)->getModel()->getPassphrase().data(), wordSource)) { + if (sodium_memcmp(mSessionUser->getPublicKey(), keys.getPublicKey(), ed25519_pubkey_SIZE) == 0) { + correctPassphraseFound = true; + break; + } + } + } + else { + cryptedPassphrase = true; + } + } + /* + auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(dbConnection); + Poco::Nullable passphrase; + + select << "SELECT passphrase from user_backups where user_id = ?;", + into(passphrase), use(user_id); + try { + if (select.execute() == 1 && !passphrase.isNull()) { + //KeyPair keys;keys.generateFromPassphrase(passphrase.value().rawContent()) + updateState(SESSION_STATE_PASSPHRASE_WRITTEN); + return; + } + } + catch (Poco::Exception& exc) { + printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data()); + }*/ + if (correctPassphraseFound || cryptedPassphrase) { + updateState(SESSION_STATE_PASSPHRASE_WRITTEN); + return; + } + if (mPassphrase != "") { + updateState(SESSION_STATE_PASSPHRASE_GENERATED); + return; + } + updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); + return; + } + + updateState(SESSION_STATE_KEY_PAIR_WRITTEN); + + if (resetPasswd != -1) { + // don't go to reset password screen after login, only throw checkEmail + //updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + return; + } + +} + +Poco::Net::HTTPCookie Session::getLoginCookie() +{ + auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId)); + // prevent reading or changing cookie with js +// keks.setHttpOnly(); + + keks.setPath("/"); + // send cookie only via https, on linux, except in test builds +#ifndef WIN32 + if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || + ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { + keks.setSecure(true); + } +#endif + + return keks; +} + +bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode) +{ + Profiler usedTime; + auto em = ErrorManager::getInstance(); + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = controller::EmailVerificationCode::load(emailVerificationCode); + if (mEmailVerificationCodeObject.isNull()) { + addError(new Error(gettext("E-Mail Verification"), gettext("Konnte kein passendes Konto finden."))); + return false; + } + + mNewUser = controller::User::create(); + assert(mEmailVerificationCodeObject->getModel() && mEmailVerificationCodeObject->getModel()->getUserId()); + mNewUser->load(mEmailVerificationCodeObject->getModel()->getUserId()); + if (mNewUser->getModel()->errorCount() > 0) { + mNewUser->getModel()->sendErrorsAsEmail(); + addError(new Error(gettext("E-Mail Verification"), gettext("Fehler beim laden des Benutzers."))); + return false; + } + mSessionUser = new User(mNewUser); + mSessionUser->setLanguage(getLanguage()); + + auto verificationType = mEmailVerificationCodeObject->getModel()->getType(); + if (verificationType == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + } + else { + updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); + } + + return true; +} + +void Session::updateState(SessionStates newState) +{ + lock("Session::updateState"); + if (!mActive) { + unlock(); + return; + } + updateTimeout(); + //printf("[%s] newState: %s\n", __FUNCTION__, translateSessionStateToString(newState)); + if (newState > mState) { + mState = newState; + } + + unlock(); +} + +const char* Session::getSessionStateString() +{ + SessionStates state; + lock("Session::getSessionStateString"); + state = mState; + unlock(); + return translateSessionStateToString(state); +} + + +const char* Session::translateSessionStateToString(SessionStates state) +{ + switch (state) { + case SESSION_STATE_EMPTY: return "uninitalized"; + case SESSION_STATE_CRYPTO_KEY_GENERATED: return "crpyto key generated"; + case SESSION_STATE_USER_WRITTEN: return "User saved"; + case SESSION_STATE_EMAIL_VERIFICATION_WRITTEN: return "E-Mail verification code saved"; + case SESSION_STATE_EMAIL_VERIFICATION_SEND: return "Verification E-Mail sended"; + 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"; + case SESSION_STATE_RESET_PASSWORD_REQUEST: return "Passwort reset requested"; + case SESSION_STATE_RESET_PASSWORD_SUCCEED: return "Passwort reset succeeded"; + default: return "unknown"; + } + + return "error"; +} + + +/* +bool Session::useOrGeneratePassphrase(const std::string& passphase) +{ + if (passphase != "" && User::validatePassphrase(passphase)) { + // passphrase is valid + setPassphrase(passphase); + updateState(SESSION_STATE_PASSPHRASE_SHOWN); + return true; + } + else { + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); + updateState(SESSION_STATE_PASSPHRASE_GENERATED); + return true; + } +} +*/ +bool Session::generatePassphrase() +{ + if (mNewUser.isNull()) return false; + + auto lang = getLanguage(); + if (lang == LANG_EN) { + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); + } + else { + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); + } + //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); + updateState(SESSION_STATE_PASSPHRASE_GENERATED); + return true; +} + +bool Session::generateKeys(bool savePrivkey, bool savePassphrase) +{ + if (mNewUser.isNull()) { + addError(new Error(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); + return false; + } + static const char* function_name = "Session::generateKeys"; + auto lang = getLanguage(); + auto user_model = mNewUser->getModel(); + auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; + /*if (LANG_DE == lang) { + mnemonic_type = ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES; + }*/ + + auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + if (!passphrase) { + addError(new ParamError(function_name, "Error generating passphrase with mnemonic: ", mnemonic_type)); + addError(new ParamError(function_name, "user email: ", mNewUser->getModel()->getEmail())); + sendErrorsAsEmail(); + addError(new Error(gettext("Benutzer"), gettext("Fehler beim generieren der Passphrase, der Admin bekommt eine E-Mail. "))); + return false; + } + + if (savePassphrase) { + auto user_backup = controller::UserBackup::create(user_model->getID(), passphrase->getString(), mnemonic_type); + // sync version + //user_backup->getModel()->insertIntoDB(false); + + // async version + UniLib::controller::TaskPtr save_user_backup_task = new model::table::ModelInsertTask(user_backup->getModel(), false, true); + save_user_backup_task->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this)); + save_user_backup_task->scheduleTask(save_user_backup_task); + } + + // keys + auto gradido_key_pair = KeyPairEd25519::create(passphrase); + auto set_key_result = mNewUser->setGradidoKeyPair(gradido_key_pair); + size_t result_save_key = 0; + if (1 == set_key_result && savePrivkey) { + // save public key and private key in db + result_save_key = user_model->updatePubkeyAndPrivkey(); + } + else { + // save public key in db + result_save_key = user_model->updatePublickey(); + } + if (!result_save_key) { + user_model->addError(new Error(function_name, "Error saving new generated pubkey")); + user_model->addError(new ParamError(function_name, "e-mail: ", user_model->getEmail())); + user_model->sendErrorsAsEmail(); + //addError(new Error(gettext("Benutzer"), gettext("Fehler beim Speichern der Keys, der Admin bekommt eine E-Mail. Evt. nochmal versuchen oder abwarten!"))); + return false; + } + return true; + /* + + bool validUser = true; + if (mSessionUser) { + if (!mSessionUser->generateKeys(savePrivkey, mPassphrase, this)) { + validUser = false; + } + else { + if (savePassphrase) { + //printf("[Session::generateKeys] create save passphrase task\n"); + 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(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); + return false; + } + // delete passphrase after all went well + mPassphrase.clear(); + + return true; + */ +} diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index 27539ecf1..80763d337 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -12,7 +12,7 @@ #include "../SingletonManager/LanguageManager.h" #include "../SingletonManager/SingletonTaskObserver.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "Poco/Data/Binding.h" @@ -1090,7 +1090,7 @@ MemoryBin* User::sign(const unsigned char* message, size_t messageSize) //addError(new Error("User::sign", "decrypt privkey failed")); - auto userBackups = controller::UserBackups::load(mDBId); + auto userBackups = controller::UserBackup::load(mDBId); // get privkey, only possible while passphrase isn't crypted in db bool correctPassphraseFound = false; diff --git a/src/cpp/model/table/CryptoKeys.cpp b/src/cpp/model/table/CryptoKey.cpp similarity index 75% rename from src/cpp/model/table/CryptoKeys.cpp rename to src/cpp/model/table/CryptoKey.cpp index e159f51cc..201047a5b 100644 --- a/src/cpp/model/table/CryptoKeys.cpp +++ b/src/cpp/model/table/CryptoKey.cpp @@ -1,20 +1,20 @@ -#include "CryptoKeys.h" +#include "CryptoKey.h" #include "../../lib/DataTypeConverter.h" using namespace Poco::Data::Keywords; namespace model { namespace table { - CryptoKeys::CryptoKeys() + CryptoKey::CryptoKey() { } - CryptoKeys::~CryptoKeys() + CryptoKey::~CryptoKey() { } - std::string CryptoKeys::toString() + std::string CryptoKey::toString() { assert(mKeyType < KEY_TYPE_COUNT && mKeyType >= 0); std::stringstream ss; @@ -24,7 +24,7 @@ namespace model { } - const char* CryptoKeys::typeToString(KeyType type) + const char* CryptoKey::typeToString(KeyType type) { switch (type) { case KEY_TYPE_ED25519_REF10: return "ed25519 ref10"; @@ -33,7 +33,7 @@ namespace model { return ""; } - Poco::Data::Statement CryptoKeys::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement CryptoKey::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -44,7 +44,7 @@ namespace model { return select; } - Poco::Data::Statement CryptoKeys::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement CryptoKey::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); lock(); @@ -56,7 +56,7 @@ namespace model { } - Poco::Data::Statement CryptoKeys::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement CryptoKey::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); lock(); diff --git a/src/cpp/model/table/CryptoKeys.h b/src/cpp/model/table/CryptoKey.h similarity index 92% rename from src/cpp/model/table/CryptoKeys.h rename to src/cpp/model/table/CryptoKey.h index 15991c70b..1a04dd387 100644 --- a/src/cpp/model/table/CryptoKeys.h +++ b/src/cpp/model/table/CryptoKey.h @@ -13,11 +13,11 @@ namespace model { KEY_TYPE_COUNT }; - class CryptoKeys : public ModelBase + class CryptoKey : public ModelBase { public: - CryptoKeys(); - ~CryptoKeys(); + CryptoKey(); + ~CryptoKey(); // generic db operations const char* getTableName() const { return "crypto_keys"; } diff --git a/src/cpp/model/table/Groups.cpp b/src/cpp/model/table/Group.cpp similarity index 73% rename from src/cpp/model/table/Groups.cpp rename to src/cpp/model/table/Group.cpp index e99780783..458f8f0dd 100644 --- a/src/cpp/model/table/Groups.cpp +++ b/src/cpp/model/table/Group.cpp @@ -1,19 +1,19 @@ -#include "Groups.h" +#include "Group.h" using namespace Poco::Data::Keywords; namespace model { namespace table { - Groups::Groups() + Group::Group() { } - Groups::~Groups() + Group::~Group() { } - std::string Groups::toString() + std::string Group::toString() { std::stringstream ss; ss << "Alias: " << mAlias << std::endl; @@ -22,7 +22,7 @@ namespace model { return ss.str(); } - Poco::Data::Statement Groups::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement Group::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -32,7 +32,7 @@ namespace model { return select; } - Poco::Data::Statement Groups::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement Group::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); lock(); @@ -43,7 +43,7 @@ namespace model { return select; } - Poco::Data::Statement Groups::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement Group::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); lock(); diff --git a/src/cpp/model/table/Groups.h b/src/cpp/model/table/Group.h similarity index 91% rename from src/cpp/model/table/Groups.h rename to src/cpp/model/table/Group.h index adc5789c0..bde1b0d68 100644 --- a/src/cpp/model/table/Groups.h +++ b/src/cpp/model/table/Group.h @@ -6,11 +6,11 @@ namespace model { namespace table { - class Groups : public ModelBase + class Group : public ModelBase { public: - Groups(); - ~Groups(); + Group(); + ~Group(); // generic db operations const char* getTableName() const { return "groups"; } diff --git a/src/cpp/model/table/HederaAccounts.cpp b/src/cpp/model/table/HederaAccount.cpp similarity index 66% rename from src/cpp/model/table/HederaAccounts.cpp rename to src/cpp/model/table/HederaAccount.cpp index 3c019374d..4018c653a 100644 --- a/src/cpp/model/table/HederaAccounts.cpp +++ b/src/cpp/model/table/HederaAccount.cpp @@ -1,21 +1,21 @@ -#include "HederaAccounts.h" +#include "HederaAccount.h" using namespace Poco::Data::Keywords; namespace model { namespace table { - HederaAccounts::HederaAccounts() + HederaAccount::HederaAccount() { } - HederaAccounts::~HederaAccounts() + HederaAccount::~HederaAccount() { } - std::string HederaAccounts::toString() + std::string HederaAccount::toString() { std::stringstream ss; ss << "user id: " << std::to_string(mUserId) << std::endl; @@ -28,7 +28,7 @@ namespace model { return ss.str(); } - Poco::Data::Statement HederaAccounts::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement HederaAccount::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -39,7 +39,16 @@ namespace model { return select; } - Poco::Data::Statement HederaAccounts::_loadIdFromDB(Poco::Data::Session session) + + Poco::Data::Statement HederaAccount::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + select << "SELECT id, user_id, account_hedera_id, account_key_id, balance, updated FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; + + return select; + } + Poco::Data::Statement HederaAccount::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); lock(); @@ -49,7 +58,7 @@ namespace model { unlock(); return select; } - Poco::Data::Statement HederaAccounts::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement HederaAccount::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); lock(); @@ -59,5 +68,7 @@ namespace model { unlock(); return insert; } + + } } \ No newline at end of file diff --git a/src/cpp/model/table/HederaAccounts.h b/src/cpp/model/table/HederaAccount.h similarity index 72% rename from src/cpp/model/table/HederaAccounts.h rename to src/cpp/model/table/HederaAccount.h index 74b2063d4..c9c85b554 100644 --- a/src/cpp/model/table/HederaAccounts.h +++ b/src/cpp/model/table/HederaAccount.h @@ -2,15 +2,18 @@ #define GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_ACCOUNTS_INCLUDE #include "ModelBase.h" +#include "Poco/Tuple.h" namespace model { namespace table { - class HederaAccounts : public ModelBase + typedef Poco::Tuple HederaAccountsTuple; + + class HederaAccount : public ModelBase { public: - HederaAccounts(); - ~HederaAccounts(); + HederaAccount(); + ~HederaAccount(); // generic db operations const char* getTableName() const { return "hedera_accounts"; } @@ -19,6 +22,7 @@ namespace model { protected: Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); diff --git a/src/cpp/model/table/HederaIds.cpp b/src/cpp/model/table/HederaId.cpp similarity index 74% rename from src/cpp/model/table/HederaIds.cpp rename to src/cpp/model/table/HederaId.cpp index 8eeed0e55..b048a0d71 100644 --- a/src/cpp/model/table/HederaIds.cpp +++ b/src/cpp/model/table/HederaId.cpp @@ -1,20 +1,20 @@ -#include "HederaIds.h" +#include "HederaId.h" using namespace Poco::Data::Keywords; namespace model { namespace table { - HederaIds::HederaIds() + HederaId::HederaId() { } - HederaIds::~HederaIds() + HederaId::~HederaId() { } - std::string HederaIds::toString() + std::string HederaId::toString() { std::stringstream ss; ss << "Shard Num: " << std::to_string(mShardNum) << std::endl; @@ -23,7 +23,7 @@ namespace model { return ss.str(); } - Poco::Data::Statement HederaIds::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement HederaId::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -34,7 +34,7 @@ namespace model { return select; } - Poco::Data::Statement HederaIds::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement HederaId::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); lock(); @@ -44,7 +44,7 @@ namespace model { unlock(); return select; } - Poco::Data::Statement HederaIds::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement HederaId::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); lock(); diff --git a/src/cpp/model/table/HederaIds.h b/src/cpp/model/table/HederaId.h similarity index 91% rename from src/cpp/model/table/HederaIds.h rename to src/cpp/model/table/HederaId.h index eaa6612b8..ef35b2e70 100644 --- a/src/cpp/model/table/HederaIds.h +++ b/src/cpp/model/table/HederaId.h @@ -7,11 +7,11 @@ namespace model { namespace table { - class HederaIds : public ModelBase + class HederaId : public ModelBase { public: - HederaIds(); - ~HederaIds(); + HederaId(); + ~HederaId(); // generic db operations const char* getTableName() const { return "hedera_ids"; } diff --git a/src/cpp/model/table/HederaTopics.cpp b/src/cpp/model/table/HederaTopic.cpp similarity index 84% rename from src/cpp/model/table/HederaTopics.cpp rename to src/cpp/model/table/HederaTopic.cpp index aeed1ea05..ef80ea071 100644 --- a/src/cpp/model/table/HederaTopics.cpp +++ b/src/cpp/model/table/HederaTopic.cpp @@ -1,20 +1,20 @@ -#include "HederaTopics.h" +#include "HederaTopic.h" using namespace Poco::Data::Keywords; namespace model { namespace table { - HederaTopics::HederaTopics() + HederaTopic::HederaTopic() { } - HederaTopics::~HederaTopics() + HederaTopic::~HederaTopic() { } - std::string HederaTopics::toString() + std::string HederaTopic::toString() { std::stringstream ss; ss << "Topic Hedera id: " << std::to_string(mTopicHederaId) << std::endl; @@ -29,7 +29,7 @@ namespace model { return ss.str(); } - Poco::Data::Statement HederaTopics::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement HederaTopic::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -42,7 +42,7 @@ namespace model { return select; } - Poco::Data::Statement HederaTopics::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement HederaTopic::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); lock(); @@ -52,7 +52,7 @@ namespace model { unlock(); return select; } - Poco::Data::Statement HederaTopics::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement HederaTopic::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); lock(); diff --git a/src/cpp/model/table/HederaTopics.h b/src/cpp/model/table/HederaTopic.h similarity index 92% rename from src/cpp/model/table/HederaTopics.h rename to src/cpp/model/table/HederaTopic.h index 4584026ab..fe5cc342b 100644 --- a/src/cpp/model/table/HederaTopics.h +++ b/src/cpp/model/table/HederaTopic.h @@ -6,11 +6,11 @@ namespace model { namespace table { - class HederaTopics : public ModelBase + class HederaTopic : public ModelBase { public: - HederaTopics(); - ~HederaTopics(); + HederaTopic(); + ~HederaTopic(); // generic db operations const char* getTableName() const { return "hedera_topics"; } diff --git a/src/cpp/model/table/User.cpp b/src/cpp/model/table/User.cpp index e6f694c71..745982a25 100644 --- a/src/cpp/model/table/User.cpp +++ b/src/cpp/model/table/User.cpp @@ -315,7 +315,7 @@ namespace model { ss << "created: " << Poco::DateTimeFormatter::format(mCreated, "%f.%m.%Y %H:%M:%S") << "
"; ss << "email checked: " << mEmailChecked << "
"; ss << "language key: " << mLanguageKey << "
"; - ss << "role: " << UserRoles::typeToString(getRole()) << "
"; + ss << "role: " << UserRole::typeToString(getRole()) << "
"; ss << "disabled: " << mDisabled << "
"; mm->releaseMemory(pubkeyHex); @@ -357,7 +357,7 @@ namespace model { userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); userObj.set("disabled", mDisabled); try { - userObj.set("role", UserRoles::typeToString(getRole())); + userObj.set("role", UserRole::typeToString(getRole())); } catch (Poco::Exception ex) { addError(new ParamError("User::getJson", "exception by getting role", ex.displayText().data())); diff --git a/src/cpp/model/table/User.h b/src/cpp/model/table/User.h index 50908b049..3a6164232 100644 --- a/src/cpp/model/table/User.h +++ b/src/cpp/model/table/User.h @@ -11,7 +11,7 @@ #include -#include "UserRoles.h" +#include "UserRole.h" namespace model { namespace table { diff --git a/src/cpp/model/table/UserBackups.cpp b/src/cpp/model/table/UserBackup.cpp similarity index 78% rename from src/cpp/model/table/UserBackups.cpp rename to src/cpp/model/table/UserBackup.cpp index 0dbf0adfa..e45a78066 100644 --- a/src/cpp/model/table/UserBackups.cpp +++ b/src/cpp/model/table/UserBackup.cpp @@ -1,4 +1,4 @@ -#include "UserBackups.h" +#include "UserBackup.h" #include "../../controller/User.h" using namespace Poco::Data::Keywords; @@ -6,31 +6,31 @@ using namespace Poco::Data::Keywords; namespace model { namespace table { - UserBackups::UserBackups() + UserBackup::UserBackup() : mUserId(0), mMnemonicType(0) { detectMnemonic(); } - UserBackups::UserBackups(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) + UserBackup::UserBackup(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) : mUserId(user_id), mPassphrase(passphrase), mMnemonicType(type) { detectMnemonic(); } - UserBackups::UserBackups(const UserBackupsTuple& tuple) + UserBackup::UserBackup(const UserBackupsTuple& tuple) : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mPassphrase(tuple.get<2>()), mMnemonicType(tuple.get<3>()) { detectMnemonic(); } - UserBackups::~UserBackups() + UserBackup::~UserBackup() { } - Poco::Data::Statement UserBackups::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement UserBackup::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); @@ -43,7 +43,7 @@ namespace model { } - Poco::Data::Statement UserBackups::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserBackup::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -55,7 +55,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement UserBackup::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); @@ -66,7 +66,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserBackup::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -77,7 +77,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + Poco::Data::Statement UserBackup::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { Poco::Data::Statement select(session); if (fieldNames.size() <= 1) { @@ -107,7 +107,7 @@ namespace model { } // generic db operations - std::string UserBackups::toString() + std::string UserBackup::toString() { std::stringstream ss; ss << "user_id: " << mUserId << std::endl; @@ -116,7 +116,7 @@ namespace model { return ss.str(); } - void UserBackups::detectMnemonic() + void UserBackup::detectMnemonic() { if (mMnemonicType == -1) { const static char* function_name = "UserBackups::detectMnemonic"; diff --git a/src/cpp/model/table/UserBackups.h b/src/cpp/model/table/UserBackup.h similarity index 88% rename from src/cpp/model/table/UserBackups.h rename to src/cpp/model/table/UserBackup.h index d307f8f5d..c5084b0f7 100644 --- a/src/cpp/model/table/UserBackups.h +++ b/src/cpp/model/table/UserBackup.h @@ -9,13 +9,13 @@ namespace model { typedef Poco::Tuple UserBackupsTuple; - class UserBackups : public ModelBase + class UserBackup : public ModelBase { public: - UserBackups(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); - UserBackups(const UserBackupsTuple& tuple); - UserBackups(); - ~UserBackups(); + UserBackup(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); + UserBackup(const UserBackupsTuple& tuple); + UserBackup(); + ~UserBackup(); // generic db operations const char* getTableName() const { return "user_backups"; } diff --git a/src/cpp/model/table/UserRoles.cpp b/src/cpp/model/table/UserRole.cpp similarity index 73% rename from src/cpp/model/table/UserRoles.cpp rename to src/cpp/model/table/UserRole.cpp index 0d1f673e9..28e314606 100644 --- a/src/cpp/model/table/UserRoles.cpp +++ b/src/cpp/model/table/UserRole.cpp @@ -1,4 +1,4 @@ -#include "UserRoles.h" +#include "UserRole.h" using namespace Poco::Data::Keywords; @@ -6,28 +6,28 @@ namespace model { namespace table { - UserRoles::UserRoles(int user_id, RoleType type) + UserRole::UserRole(int user_id, RoleType type) : mUserId(user_id), mType(type) { } - UserRoles::UserRoles(const UserRolesTuple& tuple) + UserRole::UserRole(const UserRolesTuple& tuple) : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mType(tuple.get<2>()) { } - UserRoles::UserRoles() + UserRole::UserRole() { } - UserRoles::~UserRoles() + UserRole::~UserRole() { } - Poco::Data::Statement UserRoles::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement UserRole::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); @@ -40,7 +40,7 @@ namespace model { } - Poco::Data::Statement UserRoles::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserRole::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -52,7 +52,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement UserRole::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); @@ -63,7 +63,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserRole::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -74,7 +74,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + Poco::Data::Statement UserRole::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { Poco::Data::Statement select(session); if (fieldNames.size() <= 1) { @@ -104,7 +104,7 @@ namespace model { } // generic db operations - std::string UserRoles::toString() + std::string UserRole::toString() { std::stringstream ss; ss << "user_id: " << mUserId << std::endl; @@ -112,7 +112,7 @@ namespace model { return ss.str(); } - const char* UserRoles::typeToString(RoleType type) + const char* UserRole::typeToString(RoleType type) { switch (type) { case ROLE_NOT_LOADED: return "not loaded"; diff --git a/src/cpp/model/table/UserRoles.h b/src/cpp/model/table/UserRole.h similarity index 90% rename from src/cpp/model/table/UserRoles.h rename to src/cpp/model/table/UserRole.h index 7b3fad790..7683bff94 100644 --- a/src/cpp/model/table/UserRoles.h +++ b/src/cpp/model/table/UserRole.h @@ -17,13 +17,13 @@ namespace model { typedef Poco::Tuple UserRolesTuple; - class UserRoles : public ModelBase + class UserRole : public ModelBase { public: - UserRoles(int user_id, RoleType type); - UserRoles(const UserRolesTuple& tuple); - UserRoles(); - ~UserRoles(); + UserRole(int user_id, RoleType type); + UserRole(const UserRolesTuple& tuple); + UserRole(); + ~UserRole(); // generic db operations const char* getTableName() const { return "user_roles"; } diff --git a/src/cpsp/adminCheckUserBackup.cpsp b/src/cpsp/adminCheckUserBackup.cpsp index bca35b05a..35ac38ad4 100644 --- a/src/cpsp/adminCheckUserBackup.cpsp +++ b/src/cpsp/adminCheckUserBackup.cpsp @@ -18,7 +18,7 @@ typedef Poco::Tuple, std::string> UserBack struct SListEntry { Poco::AutoPtr user; - std::vector> backups; + std::vector> backups; }; %> @@ -73,7 +73,7 @@ struct SListEntry SListEntry entry; entry.user = controller::User::create(); entry.user->load(user_id); - entry.backups = controller::UserBackups::load(user_id); + entry.backups = controller::UserBackup::load(user_id); notMatchingEntrys.push_back(entry); diff --git a/src/cpsp/adminUserPasswordReset.cpsp b/src/cpsp/adminUserPasswordReset.cpsp index 648a18f61..f534b8c4d 100644 --- a/src/cpsp/adminUserPasswordReset.cpsp +++ b/src/cpsp/adminUserPasswordReset.cpsp @@ -21,7 +21,7 @@ enum PageState PageState state = PAGE_ASK_EMAIL; Poco::AutoPtr user = controller::User::create(); Poco::AutoPtr code; - Poco::AutoPtr userBackup; + Poco::AutoPtr userBackup; bool validUser = false; std::string pageName = "Admin User Passwort Reset"; diff --git a/src/cpsp/repairDefectPassphrase.cpsp b/src/cpsp/repairDefectPassphrase.cpsp index fc9eba7fd..0e8c82e64 100644 --- a/src/cpsp/repairDefectPassphrase.cpsp +++ b/src/cpsp/repairDefectPassphrase.cpsp @@ -64,7 +64,7 @@ enum PageState else { mSession->setPassphrase(passphrase); - auto newPassphraseModel = controller::UserBackups::create( + auto newPassphraseModel = controller::UserBackup::create( user_model->getID(), passphrase->getString(), ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES