Merge pull request #519 from gradido/change_password_require_password

Change password require old password
This commit is contained in:
einhornimmond 2021-06-15 12:23:26 +02:00 committed by GitHub
commit ffab831617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 684 additions and 89 deletions

View File

@ -230,7 +230,8 @@ with:
"User.description" : "Tischler",
"User.disabled": 0,
"User.language": "de",
"User.password": "1234"
"User.password": "1234",
"User.password_old": "4321"
}
}
```
@ -240,6 +241,7 @@ Notes:
- User will be disabled if he wants his account deleted, but has transactions. Until transactions are saved in real blockchain, we need this data because the public key is in db only saved in state_users so if we delete this entry, validating all transactions is no longer possible.
- Disabled Users can neither login nor receive transactions.
- It is not required to provide all fields of `update`, it can be a subset depending on what you intend to change.
- `User.password`: to change user password, needed current passwort in `User.password_old` (only if user was logged in with his password, not by reset password email code)
### Response
In case of success:
@ -252,7 +254,7 @@ In case of success:
}
```
- `valid_values`: should contain count of entries in update if no error occurred (User.password will not be counted)
- `valid_values`: should contain count of entries in update if no error occurred (User.password will now be counted also)
- `errors`: contain on error string for every entry in update, which type isn't like expected
- `password`:
- "new password is the same as old password": no change taking place

View File

@ -129,6 +129,7 @@ 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")
FILE(GLOB TEST_JSON_INTERFACE "src/cpp/test/JSONInterface/*.cpp" "src/cpp/test/JSONInterface/*.h")
SET(LOCAL_SRCS
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} ${COMPILED_PAGES}
@ -138,7 +139,7 @@ SET(LOCAL_SRCS
${PROTO_GRADIDO} ${PROTO_HEDERA}
)
SET(LOCAL_TEST_SRC
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} ${TEST_JSON_INTERFACE}
)
aux_source_directory("src/cpp" LOCAL_SRCS)

View File

@ -48,15 +48,15 @@ WORKDIR ${DOCKER_WORKDIR}
RUN if [ ! -d "./build_cov" ] ; then mkdir build_cov; fi
RUN cd build_cov && \
cmake -DCMAKE_BUILD_TYPE=Debug -DCOLLECT_COVERAGE_DATA=ON -DCOVERAGE_TOOL=fastcov ..
#make -j$(nproc) Gradido_LoginServer_Test
cmake -DCMAKE_BUILD_TYPE=Debug -DCOLLECT_COVERAGE_DATA=ON -DCOVERAGE_TOOL=fastcov .. && \
make -j$(nproc) Gradido_LoginServer_Test
#RUN chmod +x build_cov/bin/Gradido_LoginServer_Test
#CMD gdb -ex run ./build_cov/bin/Gradido_LoginServer_Test
#CMD ./build_cov/bin/Gradido_LoginServer_Test
#ENTRYPOINT make -C build_cov coverage
CMD cd build_cov && make -j$(nproc) Gradido_LoginServer_Test && make coverage && \
CMD cd build_cov && make coverage && \
if [ ! -d "./coverage" ] ; then mkdir coverage; fi && \
cp coverage.info ./coverage/

View File

@ -12,6 +12,7 @@
#include "CheckEmailPage.h"
#include "PassphrasePage.h"
#include "SaveKeysPage.h"
#include "TestUserGenerator.h"
#include "ElopageWebhook.h"
#include "ElopageWebhookLight.h"
#include "UserUpdatePasswordPage.h"
@ -229,6 +230,11 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c
return basicSetup(new LoginPage(nullptr), request, timeUsed);
}
}
if (ServerConfig::g_ServerSetupType != ServerConfig::SERVER_TYPE_PRODUCTION) {
if (url_first_part == "/testUserGenerator") {
return basicSetup(new TestUserGenerator, request, timeUsed);
}
}
return basicSetup(new LoginPage(nullptr), request, timeUsed);
//return new HandleFileRequest;
//return new PageRequestHandlerFactory;

View File

@ -100,7 +100,7 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
return new JsonGetUserInfos;
}
else if (url_first_part == "/updateUserInfos") {
return new JsonUpdateUserInfos;
return new JsonUpdateUserInfos(s);
}
else if (url_first_part == "/search") {
return new JsonSearch;

View File

@ -99,10 +99,10 @@ Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
return stateError("invalid session");
}
}
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
auto receiver_user = controller::User::create();
if (1 != receiver_user->load(email)) {
return stateError("invalid email");
return stateSuccess();
}
auto receiver_user_id = receiver_user->getModel()->getID();
std::string checkEmailUrl = receiver_user->getGroupBaseUrl() + ServerConfig::g_frontend_checkEmailPath;

View File

@ -4,6 +4,13 @@
#include "../SingletonManager/LanguageManager.h"
#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h"
JsonUpdateUserInfos::JsonUpdateUserInfos(Session* session)
: JsonRequestHandler(session)
{
}
Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
{
/*
@ -28,7 +35,11 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
/// Throws InvalidAccessException if Var is empty.
try {
paramJsonObject->get("email").convert(email);
paramJsonObject->get("session_id").convert(session_id);
auto session_id_obj = paramJsonObject->get("session_id");
if (!session_id_obj.isEmpty()) {
session_id_obj.convert(session_id);
}
updates = paramJsonObject->getObject("update");
}
catch (Poco::Exception& ex) {
@ -39,18 +50,21 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
return stateError("parameter format unknown");
}
if (!session_id) {
if (!session_id && !mSession) {
return stateError("session_id invalid");
}
if (updates.isNull()) {
return stateError("update is zero or not an object");
}
auto session = sm->getSession(session_id);
if (!session) {
if (session_id) {
mSession = sm->getSession(session_id);
}
if (!mSession) {
return customStateError("not found", "session not found");
}
auto user = session->getNewUser();
auto user = mSession->getNewUser();
auto user_model = user->getModel();
if (user_model->getEmail() != email) {
return customStateError("not same", "email don't belong to logged in user");
@ -61,6 +75,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
Poco::JSON::Array jsonErrorsArray;
int extractet_values = 0;
bool password_changed = false;
//['User.first_name' => 'first_name', 'User.last_name' => 'last_name', 'User.disabled' => 0|1, 'User.language' => 'de']
for (auto it = updates->begin(); it != updates->end(); it++) {
std::string name = it->first;
@ -71,7 +86,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
if ( "User.first_name" == name) {
std::string str_val = validateString(value, "User.first_name", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0 && user_model->getFirstName() != str_val) {
user_model->setFirstName(str_val);
extractet_values++;
}
@ -79,7 +94,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
else if ("User.last_name" == name ) {
std::string str_val = validateString(value, "User.last_name", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0 && user_model->getLastName() != str_val) {
user_model->setLastName(str_val);
extractet_values++;
}
@ -88,14 +103,18 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
else if ("User.username" == name) {
std::string str_val = validateString(value, "User.username", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0 && user_model->getUsername() != str_val) {
if (user_model->getUsername() != "") {
jsonErrorsArray.add("change username currently not supported!");
}
else if (user_model->getUsername() != str_val) {
else
{
if (user->isUsernameAlreadyUsed(str_val)) {
jsonErrorsArray.add("username already used");
}
else if (!sm->isValid(str_val, VALIDATE_USERNAME)) {
jsonErrorsArray.add("username must start with [a-z] or [A-Z] and than can contain also [0-9], - and _");
}
else {
user_model->setUsername(str_val);
extractet_values++;
@ -106,33 +125,35 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
else if ("User.description" == name) {
std::string str_val = validateString(value, "User.description", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0 && str_val != user_model->getDescription()) {
user_model->setDescription(str_val);
extractet_values++;
}
}
else if ("User.disabled" == name) {
if (value.isBoolean()) {
bool disabled;
bool disabled;
if (value.isInteger()) {
int idisabled;
value.convert(idisabled);
disabled = static_cast<bool>(idisabled);
} else if (value.isBoolean()) {
value.convert(disabled);
user_model->setDisabled(disabled);
extractet_values++;
}
else if (value.isInteger()) {
int disabled;
value.convert(disabled);
user_model->setDisabled(static_cast<bool>(disabled));
extractet_values++;
}
else {
jsonErrorsArray.add("User.disabled isn't a boolean or integer");
}
if (user_model->isDisabled() != disabled) {
user_model->setDisabled(disabled);
extractet_values++;
}
}
else if ("User.language" == name && value.size() > 0) {
else if ("User.language" == name && value.size() > 0)
{
std::string str_val = validateString(value, "User.language", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0 && user_model->getLanguageKey() != str_val) {
auto lang = LanguageManager::languageFromString(str_val);
if (LANG_NULL == lang) {
jsonErrorsArray.add("User.language isn't a valid language");
@ -144,32 +165,44 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
}
}
else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS) {
else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS)
{
std::string str_val = validateString(value, "User.password", jsonErrorsArray);
if (str_val.size() > 0) {
if (str_val.size() > 0)
{
NotificationList errors;
if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
jsonErrorsArray.add("User.password isn't valid");
jsonErrorsArray.add(errors.getErrorsArray());
}
else {
auto result_new_password = user->setNewPassword(value.toString());
switch (result_new_password) {
// 0 = new and current passwords are the same
case 0: jsonErrorsArray.add("new password is the same as old password"); break;
// 1 = password changed, private key re-encrypted and saved into db
//case 1: extractet_values++; break;
// 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
case 2: jsonErrorsArray.add("password changed, couldn't load private key for re-encryption"); break;
// -1 = stored pubkey and private key didn't match
case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break;
if (!user->hasPassword() || isOldPasswordValid(updates, jsonErrorsArray))
{
NotificationList errors;
if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
jsonErrorsArray.add("User.password isn't valid");
jsonErrorsArray.add(errors.getErrorsArray());
}
else
{
auto result_new_password = user->setNewPassword(value.toString());
switch (result_new_password) {
// 0 = new and current passwords are the same
// 1 = password changed, private key re-encrypted and saved into db
case 1:
extractet_values++;
password_changed = true;
break;
// 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
case 2:
jsonErrorsArray.add("password changed, couldn't load private key for re-encryption");
extractet_values++;
password_changed = true;
break;
// -1 = stored pubkey and private key didn't match
case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break;
}
}
}
}
}
}
}
@ -179,7 +212,9 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
jsonErrorsArray.add(error_message);
}
}
if (extractet_values > 0) {
// if only password was changed, no need to call an additional db update
// password db entry will be updated inside of controller::User::setNewPassword method
if (extractet_values - (int)password_changed > 0) {
if (1 != user_model->updateFieldsFromCommunityServer()) {
user_model->addError(new Error("JsonUpdateUserInfos", "error by saving update to db"));
user_model->sendErrorsAsEmail();
@ -188,7 +223,12 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
}
result->set("errors", jsonErrorsArray);
result->set("valid_values", extractet_values);
if (!jsonErrorsArray.size()) {
result->set("state", "success");
}
else {
result->set("state", "error");
}
return result;
}
@ -206,8 +246,51 @@ std::string JsonUpdateUserInfos::validateString(Poco::Dynamic::Var value, const
if (string_value.size() == 0) {
errorMessage += " is empty";
errorArray.add(errorArray);
errorArray.add(errorMessage);
return "";
}
return string_value;
}
bool JsonUpdateUserInfos::isOldPasswordValid(Poco::JSON::Object::Ptr updates, Poco::JSON::Array& errors)
{
auto sm = SessionManager::getInstance();
auto user = mSession->getNewUser();
std::string old_password;
auto old_password_obj = updates->get("User.password_old");
if (old_password_obj.isEmpty()) {
errors.add("User.password_old not found");
}
else if (!old_password_obj.isString()) {
errors.add("User.password_old isn't a string");
}
else {
old_password_obj.convert(old_password);
}
NotificationList local_errors;
if (old_password.size())
{
if (!sm->checkPwdValidation(old_password, &local_errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
errors.add("User.password_old didn't match");
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
}
else
{
auto secret_key = user->createSecretKey(old_password);
if (secret_key->getKeyHashed() == user->getModel()->getPasswordHashed()) {
return true;
}
else if (secret_key.isNull()) {
errors.add("Password calculation for this user already running, please try again later");
}
else {
errors.add("User.password_old didn't match");
}
}
}
return false;
}

View File

@ -14,11 +14,13 @@
class JsonUpdateUserInfos : public JsonRequestHandler
{
public:
JsonUpdateUserInfos(Session* session);
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
std::string validateString(Poco::Dynamic::Var value, const char* fieldName, Poco::JSON::Array& errorArray);
bool isOldPasswordValid(Poco::JSON::Object::Ptr updates, Poco::JSON::Array& errors);
};

View File

@ -44,6 +44,7 @@ bool SessionManager::init()
switch (i) {
//case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("/^[a-zA-Z_ -]{3,}$/"); break;
case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[^<>&;]{3,}$"); break;
case VALIDATE_USERNAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z][a-zA-Z0-9_-]*$"); break;
case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break;
case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&+-_])[A-Za-z0-9@$!%*?&+-_]{8,}$"); break;
case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break;

View File

@ -24,6 +24,7 @@
enum SessionValidationTypes {
VALIDATE_NAME,
VALIDATE_USERNAME,
VALIDATE_EMAIL,
VALIDATE_PASSWORD,
VALIDATE_PASSPHRASE,

View File

@ -194,20 +194,14 @@ namespace controller {
return json;
}
int User::login(const std::string& password)
Poco::AutoPtr<SecretKeyCryptography> User::createSecretKey(const std::string& password)
{
if (!mPassword.isNull() && mPassword->hasKey()) {
return 2;
}
auto observer = SingletonTaskObserver::getInstance();
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
assert(mPassword.isNull());
auto model = getModel();
auto email_hash = observer->makeHash(model->getEmail());
if (observer->getTaskCount(email_hash, TASK_OBSERVER_PASSWORD_CREATION) > 0) {
return -3;
return nullptr;
}
observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION);
Poco::AutoPtr<SecretKeyCryptography> authenticated_encryption(new SecretKeyCryptography);
@ -215,7 +209,23 @@ namespace controller {
authenticated_encryption->createKey(model->getEmail(), password);
observer->removeTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION);
return authenticated_encryption;
}
int User::login(const std::string& password)
{
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
if (!mPassword.isNull() && mPassword->hasKey()) {
return 2;
}
assert(mPassword.isNull());
auto authenticated_encryption = createSecretKey(password);
if (authenticated_encryption.isNull()) {
return -3;
}
auto model = getModel();
if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed())
{
// printf("[User::login] password key hashed is the same as saved password hash\n");

View File

@ -96,6 +96,9 @@ namespace controller {
//! - create authenticated encryption key from password and email
//! - compare hash with in db saved hash
int login(const std::string& password);
//! \brief simply check if password is correct, independent if user is already logged in or not
Poco::AutoPtr<SecretKeyCryptography> createSecretKey(const std::string& password);
// ***********************************************************************************
// password related

View File

@ -68,7 +68,6 @@ TEST(TestJsonCheckUsername, UsernameWithoutGroup)
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "no group given");
delete result;
}
@ -89,6 +88,8 @@ TEST(TestJsonCheckUsername, ExistingUsername)
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "username already in use");
delete result;
}
TEST(TestJsonCheckUsername, NewUsername)
@ -103,6 +104,8 @@ TEST(TestJsonCheckUsername, NewUsername)
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
delete result;
}
TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
@ -118,6 +121,7 @@ TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
delete result;
}

View File

@ -0,0 +1,313 @@
#include "gtest/gtest.h"
#include "JSONInterface/JsonUpdateUserInfos.h"
#include "TestJsonUpdateUserInfos.h"
#include "lib/Profiler.h"
void TestJsonUpdateUserInfos::SetUp()
{
auto sm = SessionManager::getInstance();
//sm->init();
mUserSession = sm->getNewSession();
auto user = controller::User::create();
user->load("Jeet_bb@gmail.com");
mUserSession->setUser(user);
}
void TestJsonUpdateUserInfos::TearDown()
{
auto sm = SessionManager::getInstance();
if (!mUserSession) {
sm->releaseSession(mUserSession);
}
}
Poco::JSON::Object::Ptr TestJsonUpdateUserInfos::chooseAccount(const Poco::JSON::Object::Ptr update)
{
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("email", mUserSession->getNewUser()->getModel()->getEmail());
params->set("update", update);
return params;
}
TEST_F(TestJsonUpdateUserInfos, EmptyOldPassword)
{
JsonUpdateUserInfos jsonCall(mUserSession);
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "haLL1o_/%s");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_LE(timeUsed.millis(), 300);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
ASSERT_EQ(valid_values, 0);
//User.password_old not found
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
ASSERT_EQ(error_array.size(), 1);
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password_old not found");
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "error");
delete result;
}
TEST_F(TestJsonUpdateUserInfos, OnlyOldPassword)
{
JsonUpdateUserInfos jsonCall(mUserSession);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password_old", "TestP4ssword&H");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_LE(timeUsed.millis(), 200);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
ASSERT_EQ(valid_values, 0);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
ASSERT_EQ(error_array.size(), 0);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
delete result;
}
TEST_F(TestJsonUpdateUserInfos, WrongPassword)
{
JsonUpdateUserInfos jsonCall(mUserSession);
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "newPassword");
update->set("User.password_old", "TestP4sswordH");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
ASSERT_EQ(valid_values, 0);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
ASSERT_EQ(error_array.size(), 1);
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password_old didn't match");
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "error");
delete result;
}
TEST_F(TestJsonUpdateUserInfos, EmptyPassword)
{
JsonUpdateUserInfos jsonCall(mUserSession);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "");
update->set("User.password_old", "TestP4sswordH");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_LE(timeUsed.millis(), 200);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
ASSERT_EQ(valid_values, 0);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
ASSERT_EQ(error_array.size(), 1);
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password is empty");
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "error");
delete result;
}
TEST_F(TestJsonUpdateUserInfos, NewPasswordSameAsOldPassword)
{
JsonUpdateUserInfos jsonCall(mUserSession);
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "TestP4ssword&H");
update->set("User.password_old", "TestP4ssword&H");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
EXPECT_EQ(valid_values, 0);
ASSERT_EQ(error_array.size(), 0);
ASSERT_EQ(state.toString(), "success");
delete result;
}
TEST_F(TestJsonUpdateUserInfos, PasswordNotSecureEnough)
{
JsonUpdateUserInfos jsonCall(mUserSession);
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "newPassword");
update->set("User.password_old", "TestP4ssword&H");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) {
EXPECT_EQ(valid_values, 1);
ASSERT_EQ(error_array.size(), 0);
ASSERT_EQ(state.toString(), "success");
}
else {
EXPECT_EQ(valid_values, 0);
ASSERT_EQ(error_array.size(), 2);
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password isn't valid");
ASSERT_EQ(state.toString(), "error");
}
delete result;
}
/*
TEST_F(TestJsonUpdateUserInfos, PasswordCorrect)
{
JsonUpdateUserInfos jsonCall(mUserSession);
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.password", "uasjUs7ZS/as12");
update->set("User.password_old", "TestP4ssword&H");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
EXPECT_EQ(valid_values, 1);
ASSERT_EQ(error_array.size(), 0);
ASSERT_EQ(state.toString(), "success");
delete result;
}
*/
TEST_F(TestJsonUpdateUserInfos, NoChanges)
{
JsonUpdateUserInfos jsonCall(mUserSession);
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
update->set("User.first_name", "Darios");
update->set("User.last_name", "Bruder");
auto params = chooseAccount(update);
Profiler timeUsed;
auto result = jsonCall.handle(params);
auto errors = result->get("errors");
ASSERT_TRUE(errors.isArray());
auto valid_values_obj = result->get("valid_values");
ASSERT_TRUE(valid_values_obj.isInteger());
int valid_values = 0;
valid_values_obj.convert(valid_values);
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
EXPECT_EQ(valid_values, 0);
ASSERT_EQ(error_array.size(), 0);
ASSERT_EQ(state.toString(), "success");
delete result;
}

View File

@ -0,0 +1,23 @@
#ifndef __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H
#define __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H
#include "gtest/gtest.h"
#include "SingletonManager/SessionManager.h"
#include "Poco/JSON/Object.h"
class TestJsonUpdateUserInfos : public ::testing::Test
{
protected:
void SetUp() override;
void TearDown() override;
Poco::JSON::Object::Ptr chooseAccount(const Poco::JSON::Object::Ptr update);
Session* mUserSession;
std::string mEmail;
};
#endif //__GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H

View File

@ -13,9 +13,12 @@
#include "Poco/SplitterChannel.h"
#include "../SingletonManager/ConnectionManager.h"
#include "../SingletonManager/SessionManager.h"
#include "../lib/Profiler.h"
#include "Crypto/SecretKeyCryptography.h"
std::list<Test*> gTests;
@ -27,7 +30,7 @@ void fillTests()
// gTests.push_back(new LoginTest());
}
void runMysql(std::string sqlQuery)
int runMysql(std::string sqlQuery)
{
auto cm = ConnectionManager::getInstance();
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
@ -38,8 +41,10 @@ void runMysql(std::string sqlQuery)
mysqlStatement.execute(true);
}
catch (Poco::Exception& ex) {
printf("exception in runMysql: %s\n", ex.displayText().data());
std::clog << "exception in runMysql: " << ex.displayText() << std::endl;
return -1;
}
return 0;
}
int load(int argc, char* argv[]) {
@ -47,6 +52,9 @@ int load(int argc, char* argv[]) {
std::clog << "[load]" << std::endl;
Poco::AutoPtr<Poco::Util::LayeredConfiguration> test_config(new Poco::Util::LayeredConfiguration);
std::string config_file_name = Poco::Path::config() + "grd_login/grd_login_test.properties";
#ifdef WIN32
config_file_name = "Gradido_LoginServer_Test.properties";
#endif
if(argc > 1 && strlen(argv[1]) > 4) {
config_file_name = argv[1];
}
@ -66,11 +74,11 @@ int load(int argc, char* argv[]) {
if (!ServerConfig::initServerCrypto(*test_config)) {
//printf("[Gradido_LoginServer::%s] error init server crypto\n", __FUNCTION__);
printf("[load] error init server crypto");
std::clog << "[load] error init server crypto" << std::endl;
return -1;
}
if (!ServerConfig::loadMnemonicWordLists()) {
printf("[load] error in loadMnemonicWordLists");
std::clog << "[load] error in loadMnemonicWordLists" << std::endl;
return -2;
}
@ -79,6 +87,9 @@ int load(int argc, char* argv[]) {
ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker");
ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker");
ServerConfig::g_disableEmail = true;
SessionManager::getInstance()->init();
// load up connection configs
// register MySQL connector
@ -95,7 +106,7 @@ int load(int argc, char* argv[]) {
}
catch (Poco::Exception& ex) {
// maybe we in docker environment and db needs some time to start up
printf("Poco Exception by connecting to db: %s, let's try again\n", ex.displayText().data());
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", let's try again" << std::endl;
}
if(!connected) {
// let's wait 10 seconds
@ -110,7 +121,7 @@ int load(int argc, char* argv[]) {
connected = true;
}
} catch(Poco::Exception& ex) {
printf("Poco Exception by connecting to db: %s, let's wait another 10 seconds\n", ex.displayText().data());
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", let's wait another 10 seconds" << std::endl;
}
}
if(!connected) {
@ -118,10 +129,21 @@ int load(int argc, char* argv[]) {
try {
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_LOGIN_SERVER);
} catch(Poco::Exception& ex) {
printf("Poco Exception by connecting to db: %s, exit\n", ex.displayText().data());
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", exit" << std::endl;
return -4;
}
}
// password hash from user 2 in test user entry
Poco::UInt64 precalculated_password_hash = 10417562666175322069;
std::clog << "measure Time for secret key generation..." << std::endl;
Profiler timeForArgon2;
SecretKeyCryptography secret_cryptografie;
secret_cryptografie.createKey("Jeet_bb@gmail.com", "TestP4ssword&H");
ServerConfig::g_FakeLoginSleepTime = timeForArgon2.millis();
std::clog << "time for secret key generation: " << timeForArgon2.string() << std::endl;
std::string log_Path = "/var/log/grd_login/";
//#ifdef _WIN32
@ -144,6 +166,7 @@ int load(int argc, char* argv[]) {
log.error("Test Error");
//errorLog
//printf("try connect php server mysql \n");
@ -157,31 +180,47 @@ int load(int argc, char* argv[]) {
"users"
};
for (int i = 0; i < 2; i++) {
runMysql("TRUNCATE " + tables[i]);
runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1");
if (runMysql("TRUNCATE " + tables[i])) {
return -1;
}
if (runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1")) {
return -1;
}
}
std::stringstream ss;
// password = TestP4ssword&H
ss << "INSERT INTO `users` (`id`, `email`, `first_name`, `last_name`, `username`, `password`, `pubkey`, `privkey`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`, `group_id`) VALUES "
<< "(1, 'd_schultz32@gmx.de', 'DDD', 'Schultz', 'Diddel', 13134558453895551556, 0x146d3fb9e88abc0fca0b0091c1ab1b32b399be037436f340befa8bf004461889, 0x0dcc08960f45f631fe23bc7ddee0724cedc9ec0c861ce30f5091d20ffd96062d08ca215726fb9bd64860c754772e945eea4cc872ed0a36c7b640e8b0bf7a873ec6765fa510711622341347ce2307b5ce, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
<< "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', 12910944485867375321, 0x952e215a21d4376b4ac252c4bf41e156e1498e1b6b8ccf2a6826d96712f4f461, 0x4d40bf0860655f728312140dc3741e897bc2d13d00ea80a63e2961046a5a7bd8315397dfb488b89377087bc1a5f4f3af8ffdcf203329ae23ba04be7d38ad3852699d90ff1fc00e5b1ca92b64cc59c01f, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
<< "(3, 'Tiger_231@yahoo.com', 'Dieter', 'Schultz', 'Tiger', 13528673707291575501, 0xb539944bf6444a2bfc988244f0c0c9dc326452be9b8a2a43fcd90663719f4f6d, 0x5461fda60b719b65ba00bd6298e48410c4cbf0e89deb13cc784ba8978cf047454e8556ee3eddc8487ee835c33a83163bc8d8babbf2a5c431876bc0a0c114ff0a0d6b57baa12cf8f23c64fb642c862db5, '2020-02-20 16:05:45', 1, 0, 'de', 0, 1), "
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 15522411320147607375, 0x476b059744f08b0995522b484c90f8d2f47d9b59f4b3c96d9dc0ae6ab7b84979, 0x5277bf044cba4fec64e6f4d38da132755b029161231daefc9a7b4692ad37e05cdd88e0a2c2215baf854dd3a813578c214167af1113607e9f999ca848a7598ba5068e38f2a1afb097e4752a88024d79c8, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 7022671043835614958, 0xb1584e169d60a7e771d3a348235dfd7b5f9e8235fcc26090761a0264b0daa6ff, 0xb46fb7110bf91e28f367aa80f84d1bbd639b6f689f4b0aa28c0f71529232df9bf9ee0fb02fa4c1b9f5a6799c82d119e5646f7231d011517379faaacf6513d973ac3043d4c786490ba62d56d75b86164d, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 1548398919826089202, 0x4046ae49c1b620f2a321aba0c874fa2bc7ba844ab808bb0eeb18a908d468db14, 0x9522657ecd7456eedf86d065aa087ba7a94a8961a8e4950d044136155d38fe0840f2c0a2876ce055b3eaa6e9ab95c5feba89e535e0434fb2648d94d6e6ec68211aa2ea9e42d1ccd40b6b3c31e41f848e, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
<< "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 5822761891727948301, 0xb13ede3402abb8f29722b14fec0a2006ae7a3a51fb677cd6a2bbd797ac6905a5, 0x6aa39d7670c64a31639c7d89b874ad929b2eaeb2e5992dbad71b6cea700bf9e3c6cf866d0f0fdc22b44a0ebf51a860799e880ef86266199931dd0a301e5552db44b9b7fa99ed5945652bc7b31eff767c, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
runMysql(ss.str());
<< "(1, 'd_schultz32@gmx.de', 'DDD', 'Schultz', 'Diddel', 18242007140018938940, 0x69f2fefd6fa6947a370b9f8d3147f6617cf67416517ce25cb2d63901c666933c, 0x567f3e623a1899d1f8d69190c5799433c134ce0137c0c38cc0347874586d6234a19f2a0b484e6cc1863502e580ae6c17db1131f29a35eba45a46be29c7ee592940a3bd3ad519075fdeed6e368f0eb818, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
// if this isn't the same, some tests will fail, so we update the test data here.
if (secret_cryptografie.getKeyHashed() != precalculated_password_hash) {
ss << "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', " << secret_cryptografie.getKeyHashed() << ", 0, 0, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
}
else {
ss << "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', 10417562666175322069, 0x6afd24f46eb79a839281fe537a1888155b102d4fbe0613ea92d51845bd8036cb, 0xe7aed71cd4ae2d1aba9343ffb3822b759f972e41b63a6032b7f6c69f566217784c2e7bcdaeaa2f7dd16bf3b6f1540b22afa65fc054550a9296454c6ecdbd4131eac7f9c703318a867e666691e1808a6e, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
}
ss << "(3, 'Tiger_231@yahoo.com', 'Dieter', 'Schultz', 'Tiger', 13790258844849208764, 0x9a79a5daea92218608fa1e3a657d78961dc04c97ff996cc0ea17d6896b5368e6, 0x4993a156a120728f0fa93fc63ab01482ed85ecf433c729c8426c4bb93f0b7ce6142fda531b11f5d5e925acd1d2e55fdfef94fe07dbb78d43322f7df1234c7251aa58946c96ec6e551395f0fb5e87decf, '2020-02-20 16:05:45', 1, 0, 'de', 0, 1), "
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 1914014100253540772, 0x1c199421a66070afb28cb7c37de98865b28924bff26161bb65faaf5695050ee3, 0xe38ca460ca748954b29d79f0e943eed3ba85e7e13b18f69349666e31a8e3b06c9df105171796b37b4201895a2f3fe8ec8bf58a181700caaa5752a94a968c50e90ebb6280002a056126b2055ff75d69d1, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 8105871797752167168, 0x98d703f0ea1def3ef9e6265a76281d125a94c80665425bd7a844580ec1a2ce98, 0x63612a1d07d78a0c945d765a10a30d9de2be602e79e3f39268d731bc6f7fa945d7d04c638000bae089ac058263f52e7c1f2c3550b35b5727e41523f2f592781add65d12b8b8c0b3226f32174cfa1bcee, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 9005874071610817324, 0xb3ee1c82a9877f664d05364106e259621b2e203bfbb5323edb7b597051efecc2, 0xa039da7d59e2475dd1aaa635f803ec1aeffc2506e7a96a934bf8d7cf4ac2a96dc962d4e1bdf8e11c5ce7e18189edc36014b89e9e72628004ec5901be6c407a955efb5142a1ee9a2f3aed888125a44aa2, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
<< "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 7264393213873828644, 0x735a5c22ebe84ab1d6453991d50019b677b82b0663b023c30127ec906ee9b59a, 0xaec30051ad3ab2d2132a76e9dfe5a396d2dfbcc83a4eb27223b4da8803893959af9e29c6963f9e73eddc447cb3d3995527b94054e7fdecd7d5f8cb45c3954ff9bb2c9e0374f2124b3170301f990c5d7d, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
if (runMysql(ss.str())) {
return -1;
}
ss.str(std::string());
ss << "INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `description`) VALUES"
<< "(1, 'gdd1', 'Gradido1', 'gdd1.gradido.com', 'Der erste offizielle Gradido Server (zum Testen)'), "
<< "(2, 'gdd_test', 'Gradido Test', 'gdd1.gradido.com', 'Testgroup (zum Testen)'); ";
runMysql(ss.str());
if (runMysql(ss.str())) {
return -1;
}
ss.str(std::string());
printf("init db in : %s\n", timeUsed.string().data());
std::clog << "init db in : " << timeUsed.string() << std::endl;
fillTests();
@ -198,10 +237,10 @@ int run()
std::clog << "[Gradido_LoginServer_Test::run]" << std::endl;
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
{
//printf("running: %s\n", it->getName());
printf("running test: %s\n", (*it)->getName());
std::string name = (*it)->getName();
std::clog << "running test: " << name << std::endl;
try {
if (!(*it)->test()) printf("success\n");
if (!(*it)->test()) std::clog << "Success" << std::endl;
} catch(std::exception& ex) {
std::clog << "exception in running test: " << ex.what() << std::endl;
}
@ -209,7 +248,7 @@ int run()
return 0;
}
void ende()
void endegTests()
{
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
{
@ -219,6 +258,7 @@ void ende()
}
gTests.clear();
}
@ -226,20 +266,24 @@ int main(int argc, char** argv)
{
try {
if (load(argc, argv) < 0) {
printf("early exit\n");
std::clog << "early exit" << std::endl;
return -42;
}
} catch(std::exception& ex) {
printf("no catched exception while loading: %s\n", ex.what());
std::string exception_text = ex.what();
std::clog << "no catched exception while loading: " << exception_text << std::endl;
}
//printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max);
run();
ende();
::testing::InitGoogleTest(&argc, argv);
endegTests();
::testing::InitGoogleTest(&argc, argv);
auto result = RUN_ALL_TESTS();
SessionManager::getInstance()->deinitalize();
ServerConfig::unload();
return result;
}

View File

@ -0,0 +1,102 @@
<%@ page class="TestUserGenerator" %>
<%@ page form="true" %>
<%@ page baseClass="PageRequestMessagedHandler" %>
<%@ header include="HTTPInterface/PageRequestMessagedHandler.h" %>
<%!
#include "Crypto/SecretKeyCryptography.h"
#include "Crypto/KeyPairEd25519.h"
#include "ServerConfig.h"
#include "lib/DataTypeConverter.h"
#include "controller/User.h"
%>
<%%
const char* pageName = "Test User Generator";
// needed for header_large
auto user = controller::User::create();
std::string email;
std::string password_hashed;
std::string pubkey_hex;
std::string privkey_hex_encrypted;
std::string passphrase_str;
bool user_created = false;
// add
if(!form.empty()) {
email = form.get("email", "");
auto password = form.get("password", "");
if(email == "") {
addError(new Error("Create User", "E-Mail is empty!"));
}
else if(password == "") {
addError(new Error("Create User", "Password is empty!"));
}
else
{
auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
passphrase_str = passphrase->getString();
auto key_pair = KeyPairEd25519::create(passphrase);
Poco::AutoPtr<SecretKeyCryptography> secret_key = new SecretKeyCryptography;
secret_key->createKey(email, password);
password_hashed = std::to_string(secret_key->getKeyHashed());
auto privkey_encrypted = key_pair->getCryptedPrivKey(secret_key);
privkey_hex_encrypted = DataTypeConverter::binToHex(privkey_encrypted);
pubkey_hex = key_pair->getPublicKeyHex();
user_created = true;
delete key_pair;
}
}
// select all
auto groups = controller::Group::listAll();
//auto groups = controller::Group::load("gdd1");
//std::vector<Poco::SharedPtr<controller::Group>> groups;
%><%@ include file="include/header_large.cpsp" %>
<%= getErrorsHtml() %>
<div class="center-form-container">
<div class="center-form-title">
<h3>Einen neuen User anlegen</h3>
</div>
<div class="center-form-form">
<form method="POST">
<label class="form-label" for="email">Email</label>
<input class="form-control" id="email" type="text" name="email"/>
<label class="form-label" for="password">Password</label>
<input class="form-control" id="password" type="text" name="password"/>
<input class="center-form-submit form-button" type="submit" name="submit" value="Create User">
</form>
</div>
<% if(user_created) { %>
<div class="content-list">
<div class="content-list-title">
<h2>Generierte Daten</h2>
</div>
<div class="content-list-table">
<div class="row">
<div class="cell header-cell c4">E-Mail</div>
<div class="cell c4"><%= email %></div>
</div>
<div class="row">
<div class="cell header-cell c4">Password hash</div>
<div class="cell c3"><%= password_hashed %></div>
</div>
<div class="row">
<div class="cell header-cell c4">public key</div>
<div class="cell c5">0x<%= pubkey_hex %></div>
</div>
<div class="row">
<div class="cell header-cell c4">private key encrypted</div>
<div class="cell c6">0x<%= privkey_hex_encrypted %></div>
</div>
<div class="row">
<div class="cell header-cell c4">Passphrase</div>
<div class="cell c10"><%= passphrase_str %></div>
</div>
</div>
</div>
<pre>'<%= email %>', <%= password_hashed %>, 0x<%= pubkey_hex %>, 0x<%= privkey_hex_encrypted %></pre>
<% } %>
</div>
<%@ include file="include/footer.cpsp" %>