diff --git a/src/cpp/Crypto/Passphrase.cpp b/src/cpp/Crypto/Passphrase.cpp index 743747bbc..421cca11b 100644 --- a/src/cpp/Crypto/Passphrase.cpp +++ b/src/cpp/Crypto/Passphrase.cpp @@ -3,6 +3,7 @@ #include "Poco/Types.h" #include "Poco/Tuple.h" + #include "../SingletonManager/ErrorManager.h" #include "KeyPairEd25519.h" @@ -163,10 +164,88 @@ Poco::AutoPtr Passphrase::create(const Poco::UInt16 wordIndices[PHRA clearPassphrase += word; clearPassphrase += " "; } + else { + return nullptr; + } } return new Passphrase(clearPassphrase, wordSource); } +Poco::AutoPtr Passphrase::generate(const Mnemonic* wordSource) +{ + auto em = ErrorManager::getInstance(); + auto mm = MemoryManager::getInstance(); + auto word_indices = mm->getFreeMemory(PHRASE_WORD_COUNT * sizeof(Poco::UInt16)); + Poco::UInt16* word_indices_p = (Poco::UInt16*)word_indices->data(); + + for (int i = 0; i < PHRASE_WORD_COUNT; i++) { + word_indices_p[i] = randombytes_random() % 2048; + } + auto result_passphrase = create(word_indices_p, wordSource); + mm->releaseMemory(word_indices); + + return result_passphrase; + /* + + unsigned int random_indices[PHRASE_WORD_COUNT]; + + unsigned int str_sizes[PHRASE_WORD_COUNT]; + unsigned int phrase_buffer_size = 0; + static const char* function_name = "Passphrase::generate"; + bool error_reloading_mnemonic_word_list = false; + int loop_trys = 0; + Poco::RegularExpression check_valid_word("^[a-zA-ZÄÖÜäöüß&;]*$"); + + // TODO: make sure words didn't double + for (int i = 0; i < PHRASE_WORD_COUNT; i++) { + random_indices[i] = randombytes_random() % 2048; + auto word = wordSource->getWord(random_indices[i]); + if (loop_trys > 10 || error_reloading_mnemonic_word_list) { + return nullptr; + } + if (!word) { + em->addError(new ParamError(function_name, "empty word get for index", random_indices[i])); + em->sendErrorsAsEmail(); + + random_indices[i] = randombytes_random() % 2048; + word = wordSource->getWord(random_indices[i]); + if (!word) return nullptr; + + } + else { + if (!check_valid_word.match(word, 0, Poco::RegularExpression::RE_NOTEMPTY)) { + em->addError(new ParamError(function_name, "invalid word", word)); + em->addError(new Error(function_name, "try to reload mnemonic word list, but this error is maybe evidence for a serious memory problem!!!")); + if (!ServerConfig::loadMnemonicWordLists()) { + em->addError(new Error(function_name, "error reloading mnemonic word lists")); + error_reloading_mnemonic_word_list = true; + } + else { + i = 0; + loop_trys++; + } + em->sendErrorsAsEmail(); + } + } + str_sizes[i] = strlen(word); + phrase_buffer_size += str_sizes[i]; + } + phrase_buffer_size += PHRASE_WORD_COUNT + 1; + + std::string phrase_buffer(phrase_buffer_size, '\0'); + int phrase_buffer_cursor = 0; + + for (int i = 0; i < PHRASE_WORD_COUNT; i++) { + memcpy(&phrase_buffer[phrase_buffer_cursor], wordSource->getWord(random_indices[i]), str_sizes[i]); + + phrase_buffer_cursor += str_sizes[i]; + phrase_buffer[phrase_buffer_cursor++] = ' '; + } + + + return create(; + */ +} bool Passphrase::createWordIndices() { diff --git a/src/cpp/Crypto/Passphrase.h b/src/cpp/Crypto/Passphrase.h index 6d9a31965..e559e9471 100644 --- a/src/cpp/Crypto/Passphrase.h +++ b/src/cpp/Crypto/Passphrase.h @@ -16,6 +16,8 @@ public: static Poco::AutoPtr create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], const Mnemonic* wordSource); static Poco::AutoPtr create(const MemoryBin* wordIndices, const Mnemonic* wordSource); + //! \brief generate new passphrase with random + static Poco::AutoPtr generate(const Mnemonic* wordSource); static const Mnemonic* detectMnemonic(const std::string& passphrase, const KeyPairEd25519* keyPair = nullptr); //! \brief transform passphrase into another language/mnemonic source diff --git a/src/cpp/Crypto/mnemonic.cpp b/src/cpp/Crypto/mnemonic.cpp index bf8d2fd7d..53fa3d781 100644 --- a/src/cpp/Crypto/mnemonic.cpp +++ b/src/cpp/Crypto/mnemonic.cpp @@ -9,6 +9,13 @@ #include "DRRandom.h" +#include "../SingletonManager/ErrorManager.h" +#include "../ServerConfig.h" + +#include "Poco/RegularExpression.h" + +static Poco::RegularExpression g_checkValidWord("^[a-zA-ZÄÖÜäöüß&;]*$"); + Mnemonic::Mnemonic() { memset(mWords, 0, 2048); @@ -180,6 +187,49 @@ bool Mnemonic::isWordExist(const std::string& word) const } */ +const char* Mnemonic::getWord(short index) const { + //std::shared_lock _lock(mWorkingMutex); + + if (index < 2048 && index >= 0) { + std::string word; + { + std::shared_lock _lock(mWorkingMutex); + word = mWords[index]; + } + + if (!g_checkValidWord.match(word, 0, Poco::RegularExpression::RE_NOTEMPTY)) { + auto em = ErrorManager::getInstance(); + const char* function_name = "Mnemonic::getWord"; + em->addError(new ParamError(function_name, "invalid word", word)); + em->addError(new Error(function_name, "try to reload mnemonic word list, but this error is maybe evidence for a serious memory problem!!!")); + + if (!ServerConfig::loadMnemonicWordLists()) { + em->addError(new Error(function_name, "error reloading mnemonic word lists")); + em->sendErrorsAsEmail(); + return nullptr; + } + + { + std::shared_lock _lock(mWorkingMutex); + word = mWords[index]; + } + if (!g_checkValidWord.match(word, 0, Poco::RegularExpression::RE_NOTEMPTY)) { + em->addError(new Error(function_name, "word invalid after reload mnemonic word lists")); + em->sendErrorsAsEmail(); + return nullptr; + } + em->sendErrorsAsEmail(); + + } + + { + std::shared_lock _lock(mWorkingMutex); + return mWords[index]; + } + } + return nullptr; +} + void Mnemonic::clear() { //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); diff --git a/src/cpp/Crypto/mnemonic.h b/src/cpp/Crypto/mnemonic.h index 7d9a848b7..ccdb85a73 100644 --- a/src/cpp/Crypto/mnemonic.h +++ b/src/cpp/Crypto/mnemonic.h @@ -30,11 +30,7 @@ public: int init(void(*fill_words_func)(unsigned char*), unsigned int original_size, unsigned int compressed_size); - inline const char* getWord(short index) const { - std::shared_lock _lock(mWorkingMutex); - if (index < 2048 && index >= 0) return mWords[index]; - return nullptr; - } + const char* getWord(short index) const; short getWordIndex(const char* word) const; inline bool isWordExist(const std::string& word) const { std::shared_lock _lock(mWorkingMutex); diff --git a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp index 8b303971a..9a5eb43c3 100644 --- a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp +++ b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp @@ -26,7 +26,7 @@ #include "TranslatePassphrase.h" #include "PassphrasedTransaction.h" #include "AdminUserPasswordReset.h" - +#include "RegisterDirectPage.h" #include "DecodeTransactionPage.h" #include "RepairDefectPassphrase.h" @@ -119,6 +119,11 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c pageRequestHandler->setProfiler(timeUsed); return pageRequestHandler; } + if (url_first_part == "/registerDirect") { + auto pageRequestHandler = new RegisterDirectPage; + pageRequestHandler->setProfiler(timeUsed); + return pageRequestHandler; + } if (url_first_part == "/resetPassword") { auto resetPassword = new ResetPassword; resetPassword->setProfiler(timeUsed); diff --git a/src/cpp/SingletonManager/MemoryManager.cpp b/src/cpp/SingletonManager/MemoryManager.cpp index 132ec94de..2c6e98ca7 100644 --- a/src/cpp/SingletonManager/MemoryManager.cpp +++ b/src/cpp/SingletonManager/MemoryManager.cpp @@ -118,6 +118,7 @@ MemoryManager::MemoryManager() mMemoryPageStacks[2] = new MemoryPageStack(65); // pubkey hex mMemoryPageStacks[3] = new MemoryPageStack(96); // privkey encrypted mMemoryPageStacks[4] = new MemoryPageStack(161); // privkey hex + mMemoryPageStacks[5] = new MemoryPageStack(48); // word indices } MemoryManager::~MemoryManager() @@ -135,6 +136,7 @@ Poco::Int8 MemoryManager::getMemoryStackIndex(Poco::UInt16 size) case 65: return 2; case 96: return 3; case 161: return 4; + case 48: return 5; default: return -1; } return -1; diff --git a/src/cpp/SingletonManager/MemoryManager.h b/src/cpp/SingletonManager/MemoryManager.h index b010fa362..7cb9233f7 100644 --- a/src/cpp/SingletonManager/MemoryManager.h +++ b/src/cpp/SingletonManager/MemoryManager.h @@ -85,7 +85,7 @@ protected: Poco::Int8 getMemoryStackIndex(Poco::UInt16 size); MemoryManager(); - MemoryPageStack* mMemoryPageStacks[5]; + MemoryPageStack* mMemoryPageStacks[6]; }; diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index 719f13382..78a6ed6c3 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -158,6 +158,15 @@ namespace controller { return 0; } + void User::setGradidoKeyPair(KeyPairEd25519* gradidoKeyPair) + { + assert(gradidoKeyPair); + std::unique_lock _lock(mSharedMutex); + if (mGradidoKeyPair) delete mGradidoKeyPair; + mGradidoKeyPair = gradidoKeyPair; + getModel()->setPublicKey(mGradidoKeyPair->getPublicKey()); + } + int User::setPassword(AuthenticatedEncryption* passwd) { std::unique_lock _lock(mSharedMutex); diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 424f8d5a8..01d24c3ff 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -64,6 +64,10 @@ namespace controller { std::shared_lock _lock(mSharedMutex); return mPassword; } + //! \brief set key pair, public in model, private with next setPassword call into model + //! \param gradidoKeyPair take owner ship + void setGradidoKeyPair(KeyPairEd25519* gradidoKeyPair); + inline const KeyPairEd25519* getGradidoKeyPair() { std::shared_lock _lock(mSharedMutex); return mGradidoKeyPair; diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 33784c7fc..e5be916c4 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -15,9 +15,13 @@ #include "../tasks/PrepareEmailTask.h" #include "../tasks/SendEmailTask.h" #include "../tasks/SigningTransaction.h" +#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" #include "../lib/JsonRequest.h" +#include "../Crypto/Passphrase.h" + + #include "../controller/User.h" #include "../controller/UserBackups.h" #include "../controller/EmailVerificationCode.h" @@ -313,6 +317,65 @@ bool Session::createUser(const std::string& first_name, const std::string& last_ return true; } +bool Session::createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) +{ + static const char* function_name = "Session::createUserDirect"; + auto sm = SessionManager::getInstance(); + auto em = ErrorManager::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; + } + + 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; + } + } + auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES]); + if (passphrase.isNull()) { + em->addError(new ParamError(function_name, "error generating passphrase for", email)); + em->sendErrorsAsEmail(); + } + auto gradido_key_pair = KeyPairEd25519::create(passphrase); + mNewUser->setGradidoKeyPair(gradido_key_pair); + UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(mNewUser, password); + create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); + + return true; +} + bool Session::ifUserExist(const std::string& email) { auto em = ErrorManager::getInstance(); diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index 34cedfae5..6aec94671 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -77,6 +77,9 @@ public: // create User send e-mail activation link bool createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); + //! \brief new register function, without showing user pubkeys, using controller/user + bool createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); + // adminRegister without passwort bool adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email); diff --git a/src/cpsp/registerDirect.cpsp b/src/cpsp/registerDirect.cpsp index 31d06d9fb..ac8ddab35 100644 --- a/src/cpsp/registerDirect.cpsp +++ b/src/cpsp/registerDirect.cpsp @@ -25,7 +25,7 @@ response.addCookie(session->getLoginCookie()); } - userReturned = session->createUser( + userReturned = session->createUserDirect( form.get("register-first-name", ""), form.get("register-last-name", ""), form.get("register-email", ""),