Merge branch 'master' of ssh://**REDACTED**/~/_C++/gradido_login_server

This commit is contained in:
Dario via Pythagoras 2020-06-10 16:54:15 +02:00
commit 3d071f3517
33 changed files with 661 additions and 56 deletions

View File

@ -37,6 +37,9 @@ FILE(GLOB PROTO_HEDERA "src/cpp/proto/hedera/*.cc" "src/cpp/proto/hedera/*.h")
# used only for test project
FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h")
FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h")
FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h")
FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h")
FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h")
SET(LOCAL_SRCS
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface}
@ -44,6 +47,9 @@ SET(LOCAL_SRCS
${SINGLETON_MANAGER} ${LIB_SRC} ${MYSQL} ${TASKS}
${PROTO_GRADIDO} ${PROTO_HEDERA}
)
SET(LOCAL_TEST_SRC
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
)
aux_source_directory("src/cpp" LOCAL_SRCS)
if(MSVC)
@ -63,6 +69,9 @@ source_group("lib" FILES ${LIB_SRC})
source_group("HTTP-Interface" FILES ${HTTPInterface})
source_group("Json-Interface" FILES ${JSONInterface})
source_group("Test\\crypto" FILES ${TEST_CRYPTO})
source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE})
source_group("Test\\model" FILES ${TEST_MODEL})
source_group("Test\\controller" FILES ${TEST_CONTROLLER})
source_group("Test" FILES ${TEST})
endif(MSVC)
@ -152,7 +161,7 @@ enable_testing()
#_TEST_BUILD
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${TEST} ${TEST_CRYPTO})
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC})
target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} ${IROHA_ED25519})

View File

@ -68,7 +68,7 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::createKey(const std
return AUTH_ENCRYPT_OK;
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const MemoryBin* message, MemoryBin** encryptedMessage)
AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const
{
assert(message && encryptedMessage);
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
@ -100,7 +100,7 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const Memor
return AUTH_ENCRYPT_OK;
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const MemoryBin* encryptedMessage, MemoryBin** message)
AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const MemoryBin* encryptedMessage, MemoryBin** message) const
{
assert(message && encryptedMessage);
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
@ -128,6 +128,34 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const Memor
return AUTH_DECRYPT_OK;
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const std::vector<unsigned char>& encryptedMessage, MemoryBin** message) const
{
assert(message);
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
if (!mEncryptionKey) {
return AUTH_NO_KEY;
}
size_t decryptSize = encryptedMessage.size() - crypto_secretbox_MACBYTES;
//unsigned char* decryptBuffer = (unsigned char*)malloc(decryptSize);
auto mm = MemoryManager::getInstance();
//ObfusArray* decryptedData = new ObfusArray(decryptSize);
auto decryptedData = mm->getFreeMemory(decryptSize);
unsigned char nonce[crypto_secretbox_NONCEBYTES];
// we use a hardcoded value for nonce
// TODO: use a dynamic value, save it along with the other parameters
memset(nonce, 31, crypto_secretbox_NONCEBYTES);
if (crypto_secretbox_open_easy(*decryptedData, encryptedMessage.data(), encryptedMessage.size(), nonce, *mEncryptionKey)) {
mm->releaseMemory(decryptedData);
return AUTH_DECRYPT_MESSAGE_FAILED;
}
*message = decryptedData;
return AUTH_DECRYPT_OK;
}
const char* AuthenticatedEncryption::getErrorMessage(ResultType type)
{
switch (type) {

View File

@ -5,6 +5,7 @@
#include "../SingletonManager/MemoryManager.h"
#include <shared_mutex>
#include <vector>
/*!
*
@ -46,6 +47,9 @@ public:
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
return mEncryptionKeyHash == b.getKeyHashed();
}
inline bool operator == (const KeyHashed& hash) const {
return mEncryptionKeyHash == hash;
}
inline bool hasKey() const { std::shared_lock<std::shared_mutex> _lock(mWorkingMutex); return mEncryptionKey != nullptr; }
@ -56,11 +60,16 @@ public:
//! \return AUTH_CREATE_ENCRYPTION_KEY_FAILED call strerror(errno) for more details
ResultType createKey(const std::string& salt_parameter, const std::string& passwd);
ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage);
ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const;
ResultType decrypt(const MemoryBin* encryptedMessage, MemoryBin** message);
ResultType decrypt(const MemoryBin* encryptedMessage, MemoryBin** message) const;
//! \brief same as the other decrypt only in other format
//! \param encryptedMessage format from Poco Binary Data from DB, like returned from model/table/user for encrypted private key
//!
//! double code, I don't know how to prevent without unnecessary copy of encryptedMessage
ResultType decrypt(const std::vector<unsigned char>& encryptedMessage, MemoryBin** message) const;
const char* getErrorMessage(ResultType type);
static const char* getErrorMessage(ResultType type);
protected:
// algorithms parameter
@ -75,4 +84,6 @@ protected:
mutable std::shared_mutex mWorkingMutex;
};
#endif //__GRADIDO_LOGIN_SERVER_CRYPTO_AUTHENTICATED_ENCRYPTION_H

View File

@ -17,7 +17,7 @@ class IKeyPair
{
public:
//! \return caller take ownership of return value
virtual MemoryBin* sign(const MemoryBin* message) = 0;
virtual MemoryBin* sign(const MemoryBin* message) const = 0 ;
};

View File

@ -8,10 +8,13 @@
#include "Passphrase.h"
KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey)
KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey)
: mSodiumSecret(privateKey)
{
memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES);
//memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES);
// read pubkey from private key, so we are sure it is the correct pubkey for the private key
crypto_sign_ed25519_sk_to_pk(mSodiumPublic, *privateKey);
}
KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey)
@ -93,6 +96,7 @@ KeyPairEd25519* KeyPairEd25519::create(const Passphrase* passphrase)
}
crypto_sign_seed_keypair(key_pair->mSodiumPublic, *key_pair->mSodiumSecret, hash);
return key_pair;
// print hex for all keys for debugging
@ -105,7 +109,7 @@ KeyPairEd25519* KeyPairEd25519::create(const Passphrase* passphrase)
// using
}
MemoryBin* KeyPairEd25519::sign(const MemoryBin* message)
MemoryBin* KeyPairEd25519::sign(const MemoryBin* message) const
{
if (!message || !message->size()) return nullptr;
@ -146,4 +150,19 @@ MemoryBin* KeyPairEd25519::sign(const MemoryBin* message)
return signBinBuffer;
}
MemoryBin* KeyPairEd25519::getCryptedPrivKey(const AuthenticatedEncryption* password) const
{
if (!password) return nullptr;
if (!mSodiumSecret) return nullptr;
MemoryBin* encryptedKey = nullptr;
if (AuthenticatedEncryption::AUTH_ENCRYPT_OK == password->encrypt(mSodiumSecret, &encryptedKey)) {
return encryptedKey;
}
else {
return nullptr;
}
}

View File

@ -12,6 +12,7 @@
*/
#include "sodium.h"
#include "AuthenticatedEncryption.h"
class Passphrase;
@ -20,7 +21,7 @@ class KeyPairEd25519 : public IKeyPair
public:
//! \param privateKey: take ownership, release after object destruction
//! \param publicKey: copy
KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey);
KeyPairEd25519(MemoryBin* privateKey);
KeyPairEd25519(const unsigned char* publicKey);
~KeyPairEd25519();
@ -30,20 +31,30 @@ public:
static KeyPairEd25519* create(const Passphrase* passphrase);
//! \return caller take ownership of return value
MemoryBin* sign(const MemoryBin* message);
MemoryBin* sign(const MemoryBin* message) const;
inline const unsigned char* getPublicKey() const { return mSodiumPublic; }
inline bool isTheSame(const KeyPairEd25519& b) const {
return 0 == sodium_memcmp(mSodiumPublic, b.mSodiumPublic, crypto_sign_PUBLICKEYBYTES);
}
inline bool isTheSame(const unsigned char* pubkey) const {
return 0 == sodium_memcmp(mSodiumPublic, pubkey, crypto_sign_PUBLICKEYBYTES);
}
inline bool operator == (const KeyPairEd25519& b) const { return isTheSame(b); }
inline bool operator != (const KeyPairEd25519& b) const { return !isTheSame(b); }
inline bool operator == (const unsigned char* b) const { return isTheSame(b); }
inline bool operator != (const unsigned char* b) const { return !isTheSame(b); }
inline bool hasPrivateKey() const { return mSodiumSecret != nullptr; }
//! \brief only way to get a private key.. encrypted
MemoryBin* getCryptedPrivKey(const AuthenticatedEncryption* password) const;
protected:
KeyPairEd25519();

View File

@ -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> Passphrase::create(const Poco::UInt16 wordIndices[PHRA
clearPassphrase += word;
clearPassphrase += " ";
}
else {
return nullptr;
}
}
return new Passphrase(clearPassphrase, wordSource);
}
Poco::AutoPtr<Passphrase> 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()
{

View File

@ -16,6 +16,8 @@ public:
static Poco::AutoPtr<Passphrase> create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], const Mnemonic* wordSource);
static Poco::AutoPtr<Passphrase> create(const MemoryBin* wordIndices, const Mnemonic* wordSource);
//! \brief generate new passphrase with random
static Poco::AutoPtr<Passphrase> generate(const Mnemonic* wordSource);
static const Mnemonic* detectMnemonic(const std::string& passphrase, const KeyPairEd25519* keyPair = nullptr);
//! \brief transform passphrase into another language/mnemonic source

View File

@ -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<std::shared_mutex> _lock(mWorkingMutex);
if (index < 2048 && index >= 0) {
std::string word;
{
std::shared_lock<std::shared_mutex> _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<std::shared_mutex> _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<std::shared_mutex> _lock(mWorkingMutex);
return mWords[index];
}
}
return nullptr;
}
void Mnemonic::clear()
{
//Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500);

View File

@ -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<std::shared_mutex> _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<std::shared_mutex> _lock(mWorkingMutex);

View File

@ -207,7 +207,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request
responseStream << "</li>\n";
responseStream << "\t\t\t<li>Private Key verschlüsselt: ";
#line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp"
responseStream << ( std::to_string(userModel->existPrivateKeyCrypted()) );
responseStream << ( std::to_string(userModel->hasPrivateKeyEncrypted()) );
responseStream << "</li>\n";
responseStream << "\t\t\t<li>Passwort gesetzt: ";
#line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp"

View File

@ -121,6 +121,9 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
}
response.redirect(ServerConfig::g_serverPath + "/passphrase");
return;
case USER_KEYS_DONT_MATCH:
addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it.")));
break;
case USER_NO_PRIVATE_KEY:
case USER_COMPLETE:
auto referer = request.find("Referer");
@ -222,20 +225,20 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
responseStream << " <div class=\"row\">\n";
responseStream << " <div class=\"col-12 logo-section\">\n";
responseStream << " <a href=\"";
#line 152 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "\" class=\"logo\">\n";
responseStream << "\t\t\t<picture>\n";
responseStream << "\t\t\t\t<source srcset=\"";
#line 154 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.webp\" type=\"image/webp\">\n";
responseStream << "\t\t\t\t<source srcset=\"";
#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 158 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" type=\"image/png\"> \n";
responseStream << "\t\t\t\t<img src=\"";
#line 156 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 159 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" alt=\"logo\" />\n";
responseStream << "\t\t\t</picture>\n";
@ -247,14 +250,14 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
responseStream << " <div class=\"grid\">\n";
responseStream << "\t\t\t<div class=\"center-ul-container\">\n";
responseStream << "\t\t\t\t";
#line 165 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 168 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( getErrorsHtml() );
responseStream << "\t \n";
responseStream << "\t\t\t</div>\n";
responseStream << " <div class=\"grid-body\">\n";
responseStream << " \n";
responseStream << "\t\t\t <!--<input type=\"hidden\" name=\"lang\" value=\"";
#line 169 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 172 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( LanguageManager::keyForLanguage(lang) );
responseStream << "\">-->\n";
responseStream << "\t\t\t ";
@ -294,46 +297,46 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
// end include flags.cpsp
responseStream << "\n";
responseStream << "\t\t\t <form action=\"";
#line 171 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 174 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_serverPath );
responseStream << "/\" method=\"POST\">\n";
responseStream << " <div class=\"row display-block\">\n";
responseStream << " <div class=\"col-lg-7 col-md-8 col-sm-9 col-12 mx-auto form-wrapper\">\n";
responseStream << " <div class=\"form-group input-rounded\">\n";
responseStream << " <input type=\"text\" class=\"form-control\" name=\"login-email\" placeholder=\"";
#line 175 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("E-Mail") );
responseStream << "\" value=\"";
#line 175 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( presetEmail );
responseStream << "\"/>\n";
responseStream << " </div>\n";
responseStream << " <div class=\"form-group input-rounded\">\n";
responseStream << " <input type=\"password\" class=\"form-control\" name=\"login-password\" placeholder=\"";
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 181 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Password") );
responseStream << "\" />\n";
responseStream << " </div>\n";
responseStream << " <button type=\"submit\" name=\"submit\" class=\"btn btn-primary btn-block\">";
#line 180 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 183 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext(" Login ") );
responseStream << "</button>\n";
responseStream << " <div class=\"signup-link\">\n";
responseStream << " <p>";
#line 182 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 185 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("You haven't any account yet? Please follow the link to create one.") );
responseStream << "</p>\n";
responseStream << " <a href=\"https://gradido.com\">";
#line 183 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Create New Account") );
responseStream << "</a>\n";
responseStream << " </div>\n";
responseStream << "\t\t\t\t\t<div class=\"reset-pwd-link\">\n";
responseStream << "\t\t\t\t\t\t<a href=\"";
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 189 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_serverPath );
responseStream << "/resetPassword\">";
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 189 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Passwort vergessen") );
responseStream << "</a>\n";
responseStream << "\t\t\t\t\t</div>\n";

View File

@ -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);

View File

@ -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;

View File

@ -85,7 +85,7 @@ protected:
Poco::Int8 getMemoryStackIndex(Poco::UInt16 size);
MemoryManager();
MemoryPageStack* mMemoryPageStacks[5];
MemoryPageStack* mMemoryPageStacks[6];
};

View File

@ -3,15 +3,26 @@
#include "sodium.h"
#include "../SingletonManager/SessionManager.h"
#include "../lib/DataTypeConverter.h"
namespace controller {
User::User(model::table::User* dbModel)
: mPassword(nullptr), mGradidoKeyPair(nullptr)
{
mDBModel = dbModel;
}
User::~User()
{
if (mPassword) {
delete mPassword;
mPassword = nullptr;
}
if (mGradidoKeyPair) {
delete mGradidoKeyPair;
mGradidoKeyPair = nullptr;
}
}
@ -111,4 +122,106 @@ namespace controller {
return json;
}
int User::login(const std::string& password)
{
if (mPassword && mPassword->hasKey()) {
return 2;
}
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
auto authenticated_encryption = new AuthenticatedEncryption();
auto model = getModel();
assert(authenticated_encryption && model);
authenticated_encryption->createKey(model->getEmail(), password);
if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed()) {
MemoryBin* clear_private_key = nullptr;
auto priv_key_encrypted = model->getPrivateKeyEncrypted();
auto priv_key_bin = MemoryManager::getInstance()->getFreeMemory(priv_key_encrypted.size());
memcpy(*priv_key_bin, priv_key_encrypted.data(), priv_key_encrypted.size());
if (AuthenticatedEncryption::AUTH_DECRYPT_OK == authenticated_encryption->decrypt(priv_key_bin, &clear_private_key)) {
auto gradido_key_pair = new KeyPairEd25519(clear_private_key);
if (*gradido_key_pair != model->getPublicKey()) {
delete authenticated_encryption;
delete gradido_key_pair;
return -1;
}
if (mGradidoKeyPair) delete mGradidoKeyPair;
mGradidoKeyPair = gradido_key_pair;
if (mPassword) delete mPassword;
mPassword = authenticated_encryption;
return 1;
}
}
delete authenticated_encryption;
// password didn't match
return 0;
}
void User::setGradidoKeyPair(KeyPairEd25519* gradidoKeyPair)
{
assert(gradidoKeyPair);
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
if (mGradidoKeyPair) delete mGradidoKeyPair;
mGradidoKeyPair = gradidoKeyPair;
getModel()->setPublicKey(mGradidoKeyPair->getPublicKey());
}
int User::setPassword(AuthenticatedEncryption* passwd)
{
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
auto model = getModel();
const static char* function_name = "controller::User::setPassword";
if (mPassword)
{
// if keys matched
if (*mPassword == *passwd) {
// but separate objects
if (mPassword != passwd) {
delete passwd;
}
return 0;
}
// if password exist but gradido key pair not, try to load key pair
if ((!mGradidoKeyPair || !mGradidoKeyPair->hasPrivateKey()) && model->hasPrivateKeyEncrypted()) {
//if (!mGradidoKeyPair) mGradidoKeyPair = new KeyPairEd25519;
MemoryBin* clear_private_key = nullptr;
if (AuthenticatedEncryption::AUTH_DECRYPT_OK == mPassword->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) {
if (mGradidoKeyPair) delete mGradidoKeyPair;
mGradidoKeyPair = new KeyPairEd25519(clear_private_key);
// check if saved pubkey and from private key extracted pubkey match
if (*mGradidoKeyPair != model->getPublicKey()) {
delete mGradidoKeyPair;
mGradidoKeyPair = nullptr;
delete passwd;
return -1;
}
}
}
}
// replace old password with new
if (mPassword && mPassword != passwd) {
delete mPassword;
}
mPassword = passwd;
// set new encrypted password and hash
model->setPasswordHashed(mPassword->getKeyHashed());
int result = 2;
if (mGradidoKeyPair && mGradidoKeyPair->hasPrivateKey()) {
auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword);
model->setPrivateKey(encryptedPrivateKey);
MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey);
result = model->updatePrivkeyAndPasswordHash();
}
else {
model->updateIntoDB("password", mPassword->getKeyHashed());
}
// save changes to db
return result;
}
}

View File

@ -2,7 +2,10 @@
#define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_INCLUDE
#include "../model/table/User.h"
//#include "../Crypto/AuthenticatedEncryption.h"
#include "../Crypto/KeyPairEd25519.h"
#include <shared_mutex>
#include "TableControllerBase.h"
@ -34,17 +37,52 @@ namespace controller {
inline Poco::AutoPtr<model::table::User> getModel() { return _getModel<model::table::User>(); }
inline const model::table::User* getModel() const { return _getModel<model::table::User>(); }
std::string getEmailWithNames();
const std::string& getPublicHex();
//! \brief check if password match saved password, long duration
//! \return 1 logged in
//! \return 2 already logged in
//! \return 0 password didn't match
//! \return -1 error saved public key didn't match with private key
//! - create authenticated encryption key from password and email
//! - compare hash with in db saved hash
int login(const std::string& password);
// ***********************************************************************************
// password related
//! \brief set authenticated encryption and save hash in db, also re encrypt private key if exist
//! \param passwd take owner ship
//! \return 0 = new and current passwords are the same
//! \return 1 = password changed, private key re-encrypted and saved into db
//! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
//! \return -1 = stored pubkey and private key didn't match
int setPassword(AuthenticatedEncryption* passwd);
inline const AuthenticatedEncryption* getPassword() {
std::shared_lock<std::shared_mutex> _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<std::shared_mutex> _lock(mSharedMutex);
return mGradidoKeyPair;
}
protected:
User(model::table::User* dbModel);
std::string mPublicHex;
AuthenticatedEncryption* mPassword;
KeyPairEd25519* mGradidoKeyPair;
mutable std::shared_mutex mSharedMutex;
};
}

View File

@ -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&uuml;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&uuml;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();
@ -631,6 +694,7 @@ bool Session::isPwdValid(const std::string& pwd)
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) {
@ -638,7 +702,7 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo
}
}
//Profiler usedTime;
lock("Session::loadUser");
lock(functionName);
if (mSessionUser && mSessionUser->getEmail() != email) {
mSessionUser.assign(nullptr);
mNewUser.assign(nullptr);
@ -653,6 +717,20 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo
//mSessionUser = new User(email.data());
}
if (mSessionUser->getUserState() >= USER_LOADED_FROM_DB) {
int loginResult = mNewUser->login(password);
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;
}
// can be removed if session user isn't used any more
if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) {
unlock();
return USER_PASSWORD_INCORRECT;

View File

@ -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);

View File

@ -426,8 +426,8 @@ User::User(Poco::AutoPtr<controller::User> ctrl_user)
mPublicHex = std::string((char*)(*hexStringTemp));
mm->releaseMemory(hexStringTemp);
}
if (model->existPrivateKeyCrypted()) {
auto privKeyVetor = model->getPrivateKeyCrypted();
if (model->hasPrivateKeyEncrypted()) {
auto privKeyVetor = model->getPrivateKeyEncrypted();
mPrivateKey = mm->getFreeMemory(privKeyVetor.size());
memcpy(*mPrivateKey, privKeyVetor.data(), privKeyVetor.size());
}

View File

@ -35,6 +35,7 @@ enum UserStates
USER_EMAIL_NOT_ACTIVATED,
USER_NO_KEYS,
USER_NO_PRIVATE_KEY,
USER_KEYS_DONT_MATCH,
USER_COMPLETE
};

View File

@ -143,7 +143,10 @@ namespace model {
size_t User::updatePrivkey()
{
lock();
if (mPrivateKey.isNull()) return 0;
if (mPrivateKey.isNull()) {
unlock();
return 0;
}
auto result = updateIntoDB("privkey", mPrivateKey.value());
unlock();
return result;
@ -151,12 +154,45 @@ namespace model {
size_t User::updatePublickey()
{
lock();
if (mPublicKey.isNull()) return 0;
if (mPublicKey.isNull()) {
unlock();
return 0;
}
auto result = updateIntoDB("pubkey", mPublicKey.value());
unlock();
return result;
}
size_t User::updatePrivkeyAndPasswordHash()
{
lock();
if (mPrivateKey.isNull() || !mPasswordHashed || !mID) {
unlock();
return 0;
}
auto cm = ConnectionManager::getInstance();
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement update(session);
update << "UPDATE users SET password = ?, privkey = ? where id = ?;",
bind(mPasswordHashed), use(mPrivateKey), use(mID);
size_t resultCount = 0;
try {
return update.execute();
}
catch (Poco::Exception& ex) {
lock("User::updatePrivkeyAndPasswordHash");
addError(new ParamError(getTableName(), "mysql error by insert", ex.displayText().data()));
addError(new ParamError(getTableName(), "data set: ", toString().data()));
unlock();
}
//printf("data valid: %s\n", toString().data());
return 0;
}
/*
std::string mEmail;

View File

@ -45,7 +45,7 @@ namespace model {
// specific db operation
size_t updatePrivkey();
size_t updatePublickey();
size_t updatePrivkeyAndPasswordHash();
// default getter unlocked
inline const std::string& getEmail() const { return mEmail; }
@ -56,8 +56,8 @@ namespace model {
inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); }
std::string getPublicKeyHex() const;
inline bool existPrivateKeyCrypted() const { return !mPrivateKey.isNull(); }
inline const std::vector<unsigned char>& getPrivateKeyCrypted() const { return mPrivateKey.value().content(); }
inline bool hasPrivateKeyEncrypted() const { return !mPrivateKey.isNull(); }
inline const std::vector<unsigned char>& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); }
inline bool isEmailChecked() const { return mEmailChecked; }
inline const std::string& getLanguageKey() const { return mLanguageKey; }
@ -67,7 +67,8 @@ namespace model {
inline void setLastName(const std::string& last_name) { mLastName = last_name; }
inline void setPasswordHashed(const Poco::UInt64& passwordHashed) { mPasswordHashed = passwordHashed; }
void setPublicKey(const unsigned char* publicKey);
// copy data, didn't move memory bin
//! \brief set encrypted private key
//! \param privateKey copy data, didn't move memory bin
void setPrivateKey(const MemoryBin* privateKey);
inline void setEmailChecked(bool emailChecked) { mEmailChecked = emailChecked; }
inline void setLanguageKey(const std::string& languageKey) { mLanguageKey = languageKey; }

View File

@ -0,0 +1,39 @@
#include "AuthenticatedEncryptionCreateKeyTask.h"
#include "../ServerConfig.h"
#include "../SingletonManager/SingletonTaskObserver.h"
#include "../SingletonManager/ErrorManager.h"
#include "../lib/Profiler.h"
AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr<controller::User> user, const std::string& passwd)
: UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd)
{
SingletonTaskObserver::getInstance()->addTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION);
}
AuthenticatedEncryptionCreateKeyTask::~AuthenticatedEncryptionCreateKeyTask()
{
SingletonTaskObserver::getInstance()->removeTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION);
}
int AuthenticatedEncryptionCreateKeyTask::run()
{
auto em = ErrorManager::getInstance();
const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run";
auto authenticated_encryption = new AuthenticatedEncryption;
Profiler timeUsed;
if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) {
em->addError(new Error(function_name, "error creating key"));
em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail()));
em->addError(new ParamError(function_name, "strerror: ", strerror(errno)));
em->sendErrorsAsEmail();
return -1;
}
printf("create password time: %s\n", timeUsed.string().data());
timeUsed.reset();
mUser->setPassword(authenticated_encryption);
printf("set password time: %s\n", timeUsed.string().data());
return 0;
}

View File

@ -0,0 +1,20 @@
#ifndef __GRADIDO_LOGIN_SERVER_TASKS_AUTHENTICATED_ENCRYPTION_CREATE_KEY_TASK_H
#define __GRADIDO_LOGIN_SERVER_TASKS_AUTHENTICATED_ENCRYPTION_CREATE_KEY_TASK_H
#include "CPUTask.h"
#include "../controller/User.h"
class AuthenticatedEncryptionCreateKeyTask : public UniLib::controller::CPUTask
{
public:
AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr<controller::User> user, const std::string& passwd);
virtual ~AuthenticatedEncryptionCreateKeyTask();
int run();
const char* getResourceType() const { return "AuthenticatedEncryptionCreateKeyTask"; };
protected:
Poco::AutoPtr<controller::User> mUser;
std::string mPassword;
};
#endif //__GRADIDO_LOGIN_SERVER_TASKS_AUTHENTICATED_ENCRYPTION_CREATE_KEY_TASK_H

View File

@ -0,0 +1,10 @@
#include "TestUser.h"
namespace controller {
void TestUser::SetUp()
{
}
//TEST_F(TestUser, )
}

View File

@ -0,0 +1,16 @@
#ifndef __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H
#define __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H
#include "gtest/gtest.h"
namespace controller {
class TestUser : public ::testing::Test {
protected:
void SetUp() override;
};
}
#endif //__GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H

View File

@ -9,13 +9,6 @@
void TestAuthenticatedEncryption::SetUp()
{
if (!ServerConfig::g_CryptoAppSecret) {
ServerConfig::g_CryptoAppSecret = DataTypeConverter::hexToBin("21ffbbc616fe");
}
if (!ServerConfig::g_ServerCryptoKey) {
auto serverKey = DataTypeConverter::hexToBin("a51ef8ac7ef1abf162fb7a65261acd7a");
ServerConfig::g_ServerCryptoKey = new ObfusArray(serverKey->size(), *serverKey);
}
}
TEST_F(TestAuthenticatedEncryption, encryptDecryptTest) {

View File

@ -84,7 +84,7 @@ void PassphraseTest::SetUp()
wordIndices3
));
ServerConfig::loadMnemonicWordLists();
}
TEST_F(PassphraseTest, detectMnemonic) {

View File

@ -3,6 +3,12 @@
#include <list>
#include "gtest/gtest.h"
#include "Poco/Util/PropertyFileConfiguration.h"
#include "Poco/Environment.h"
#include "../SingletonManager/ConnectionManager.h"
std::list<Test*> gTests;
void fillTests()
@ -16,6 +22,39 @@ void fillTests()
int load() {
// init server config, init seed array
Poco::AutoPtr<Poco::Util::LayeredConfiguration> test_config(new Poco::Util::LayeredConfiguration);
auto cfg = new Poco::Util::PropertyFileConfiguration("Gradido_LoginServer_Test.properties");
test_config->add(cfg);
if (!ServerConfig::initServerCrypto(*test_config)) {
//printf("[Gradido_LoginServer::%s] error init server crypto\n", __FUNCTION__);
printf("[load] error init server crypto");
return -1;
}
if (!ServerConfig::loadMnemonicWordLists()) {
printf("[load] error in loadMnemonicWordLists");
return -2;
}
// start cpu scheduler
uint8_t worker_count = Poco::Environment::processorCount();
ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker");
ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker");
// load up connection configs
// register MySQL connector
Poco::Data::MySQL::Connector::registerConnector();
//Poco::Data::MySQL::Connector::KEY;
auto conn = ConnectionManager::getInstance();
//conn->setConnection()
//printf("try connect login server mysql db\n");
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_LOGIN_SERVER);
//printf("try connect php server mysql \n");
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_PHP_SERVER);
fillTests();
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
{

View File

@ -89,7 +89,7 @@ enum PageState
<li><%= userModel->getEmail() %></li>
<li>Public Key: <%= userModel->getPublicKeyHex() %></li>
<li>E-Mail überprüft: <%= std::to_string(userModel->isEmailChecked()) %></li>
<li>Private Key verschlüsselt: <%= std::to_string(userModel->existPrivateKeyCrypted()) %></li>
<li>Private Key verschlüsselt: <%= std::to_string(userModel->hasPrivateKeyEncrypted()) %></li>
<li>Passwort gesetzt: <%= std::to_string(userModel->getPasswordHashed() != 0) %></li>
</ul>
<% } %>

View File

@ -100,6 +100,9 @@
}
response.redirect(ServerConfig::g_serverPath + "/passphrase");
return;
case USER_KEYS_DONT_MATCH:
addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it.")));
break;
case USER_NO_PRIVATE_KEY:
case USER_COMPLETE:
auto referer = request.find("Referer");

View File

@ -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", ""),