mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
814 lines
26 KiB
C++
814 lines
26 KiB
C++
#include "Session.h"
|
||
#include "../lib/Profiler.h"
|
||
#include "../ServerConfig.h"
|
||
|
||
#include "Poco/RegularExpression.h"
|
||
#include "Poco/Net/StringPartSource.h"
|
||
#include "Poco/Net/MediaType.h"
|
||
|
||
#include "../SingletonManager/SessionManager.h"
|
||
#include "../SingletonManager/ConnectionManager.h"
|
||
#include "../SingletonManager/ErrorManager.h"
|
||
|
||
#include "../tasks/PrepareEmailTask.h"
|
||
#include "../tasks/SendEmailTask.h"
|
||
#include "../tasks/SigningTransaction.h"
|
||
|
||
#include "../lib/JsonRequest.h"
|
||
|
||
|
||
#include "sodium.h"
|
||
|
||
using namespace Poco::Data::Keywords;
|
||
|
||
int WriteEmailVerification::run()
|
||
{
|
||
Profiler timeUsed;
|
||
auto em = ErrorManager::getInstance();
|
||
|
||
//printf("[WriteEmailVerification::run] E-Mail Verification Code: %llu\n", verificationCode);
|
||
auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
//int user_id = mUser->getDBId();
|
||
Poco::Data::Statement insert(dbSession);
|
||
insert << "INSERT INTO email_opt_in (user_id, verification_code) VALUES(?,?);",
|
||
bind(mUser->getDBId()), use(mEmailVerificationCode);
|
||
try {
|
||
if (1 != insert.execute()) {
|
||
em->addError(new Error("[WriteEmailVerification]", "error inserting email verification code"));
|
||
em->sendErrorsAsEmail();
|
||
return -1;
|
||
}
|
||
} catch (Poco::Exception& ex) {
|
||
em->addError(new ParamError("[WriteEmailVerification]", "error inserting email verification code", ex.displayText().data()));
|
||
em->sendErrorsAsEmail();
|
||
return -2;
|
||
}
|
||
//printf("[WriteEmailVerification] timeUsed: %s\n", timeUsed.string().data());
|
||
return 0;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------------------------------------------
|
||
|
||
int WritePassphraseIntoDB::run()
|
||
{
|
||
Profiler timeUsed;
|
||
|
||
// TODO: encrypt passphrase, need server admin crypto box pubkey
|
||
//int crypto_box_seal(unsigned char *c, const unsigned char *m,
|
||
//unsigned long long mlen, const unsigned char *pk);
|
||
size_t mlen = mPassphrase.size();
|
||
size_t crypto_size = crypto_box_SEALBYTES + mlen;
|
||
|
||
auto em = ErrorManager::getInstance();
|
||
|
||
auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement insert(dbSession);
|
||
insert << "INSERT INTO user_backups (user_id, passphrase) VALUES(?,?)",
|
||
use(mUserId), use(mPassphrase);
|
||
try {
|
||
if (insert.execute() != 1) {
|
||
em->addError(new ParamError("WritePassphraseIntoDB::run", "inserting passphrase for user failed", std::to_string(mUserId)));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
}
|
||
catch (Poco::Exception& ex) {
|
||
em->addError(new ParamError("WritePassphraseIntoDB::run", "insert passphrase mysql error", ex.displayText().data()));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
|
||
//printf("[WritePassphraseIntoDB] timeUsed: %s\n", timeUsed.string().data());
|
||
return 0;
|
||
}
|
||
|
||
|
||
// --------------------------------------------------------------------------------------------------------------
|
||
|
||
Session::Session(int handle)
|
||
: mHandleId(handle), mSessionUser(nullptr), mEmailVerificationCode(0), mEmailVerificationCodeObject(nullptr), mState(SESSION_STATE_EMPTY), mActive(false)
|
||
{
|
||
|
||
}
|
||
|
||
Session::~Session()
|
||
{
|
||
//printf("[Session::~Session] \n");
|
||
if (tryLock()) {
|
||
unlock();
|
||
reset();
|
||
}
|
||
//printf("[Session::~Session] finished \n");
|
||
}
|
||
|
||
|
||
void Session::reset()
|
||
{
|
||
//printf("[Session::reset]\n");
|
||
lock("Session::reset");
|
||
|
||
mSessionUser = nullptr;
|
||
if (mEmailVerificationCodeObject) {
|
||
delete mEmailVerificationCodeObject;
|
||
mEmailVerificationCodeObject = nullptr;
|
||
}
|
||
|
||
// watch out
|
||
//updateTimeout();
|
||
mLastActivity = Poco::DateTime();
|
||
|
||
mState = SESSION_STATE_EMPTY;
|
||
|
||
mPassphrase = "";
|
||
mClientLoginIP = Poco::Net::IPAddress();
|
||
mEmailVerificationCode = 0;
|
||
unlock();
|
||
//printf("[Session::reset] finished\n");
|
||
}
|
||
|
||
void Session::updateTimeout()
|
||
{
|
||
lock("Session::updateTimeout");
|
||
mLastActivity = Poco::DateTime();
|
||
unlock();
|
||
}
|
||
|
||
controller::EmailVerificationCode* Session::getEmailVerificationCodeObject()
|
||
{
|
||
lock("Session::getEmailVerificationCodeObject");
|
||
auto ret = mEmailVerificationCodeObject;
|
||
unlock();
|
||
return ret;
|
||
}
|
||
|
||
bool Session::createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password)
|
||
{
|
||
Profiler usedTime;
|
||
auto sm = SessionManager::getInstance();
|
||
if (!sm->isValid(first_name, VALIDATE_NAME)) {
|
||
addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")));
|
||
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 <>&;")));
|
||
return false;
|
||
}
|
||
if (!sm->isValid(email, VALIDATE_EMAIL)) {
|
||
addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")));
|
||
return false;
|
||
}
|
||
if (!sm->checkPwdValidation(password, this)) {
|
||
return false;
|
||
}
|
||
/*if (passphrase.size() > 0 && !sm->isValid(passphrase, VALIDATE_PASSPHRASE)) {
|
||
addError(new Error("Merkspruch", "Der Merkspruch ist nicht gültig, er besteht aus 24 Wörtern, mit Komma getrennt."));
|
||
return false;
|
||
}
|
||
if (passphrase.size() == 0) {
|
||
//mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
|
||
mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]);
|
||
}
|
||
else {
|
||
//mPassphrase = passphrase;
|
||
}*/
|
||
|
||
// check if user with that email already exist
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement select(dbConnection);
|
||
select << "SELECT email from users where email = ?;", useRef(email);
|
||
try {
|
||
if (select.execute() > 0) {
|
||
addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")));
|
||
return false;
|
||
}
|
||
}
|
||
catch (Poco::Exception& exc) {
|
||
printf("mysql exception: %s\n", exc.displayText().data());
|
||
}
|
||
|
||
mSessionUser = new User(email.data(), first_name.data(), last_name.data());
|
||
updateTimeout();
|
||
|
||
// Prepare E-Mail
|
||
UniLib::controller::TaskPtr prepareEmail(new PrepareEmailTask(ServerConfig::g_CPUScheduler));
|
||
prepareEmail->scheduleTask(prepareEmail);
|
||
|
||
// create user crypto key
|
||
UniLib::controller::TaskPtr cryptoKeyTask(new UserCreateCryptoKey(mSessionUser, password, ServerConfig::g_CryptoCPUScheduler));
|
||
cryptoKeyTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_CRYPTO_KEY_GENERATED, this));
|
||
cryptoKeyTask->scheduleTask(cryptoKeyTask);
|
||
|
||
// depends on crypto key, write user record into db
|
||
UniLib::controller::TaskPtr writeUserIntoDB(new UserWriteIntoDB(mSessionUser, ServerConfig::g_CPUScheduler, 1));
|
||
writeUserIntoDB->setParentTaskPtrInArray(cryptoKeyTask, 0);
|
||
writeUserIntoDB->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_USER_WRITTEN, this));
|
||
writeUserIntoDB->scheduleTask(writeUserIntoDB);
|
||
|
||
createEmailVerificationCode();
|
||
|
||
UniLib::controller::TaskPtr writeEmailVerification(new WriteEmailVerification(mSessionUser, mEmailVerificationCode, ServerConfig::g_CPUScheduler, 1));
|
||
writeEmailVerification->setParentTaskPtrInArray(writeUserIntoDB, 0);
|
||
writeEmailVerification->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN, this));
|
||
writeEmailVerification->scheduleTask(writeEmailVerification);
|
||
|
||
/*printf("LastName: %s\n", last_name.data());
|
||
for (int i = 0; i < last_name.size(); i++) {
|
||
char c = last_name.data()[i];
|
||
//printf("%d ", c);
|
||
}
|
||
//printf("\n\n");
|
||
*/
|
||
|
||
// depends on writeUser because need user_id, write email verification into db
|
||
auto message = new Poco::Net::MailMessage;
|
||
Poco::Net::MediaType mt("text", "plain");
|
||
mt.setParameter("charset", "utf-8");
|
||
message->setContentType(mt);
|
||
|
||
message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, email));
|
||
message->setSubject(gettext("Gradido: E-Mail Verification"));
|
||
std::stringstream ss;
|
||
ss << "Hallo " << first_name << " " << last_name << "," << std::endl << std::endl;
|
||
ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Gradido registriert. " << std::endl;
|
||
ss << "Wenn du es warst, klicke bitte auf den Link: " << ServerConfig::g_serverPath << "/checkEmail/" << mEmailVerificationCode << std::endl;
|
||
//ss << "oder kopiere den Code: " << mEmailVerificationCode << " selbst dort hinein." << std::endl;
|
||
ss << "oder kopiere den obigen Link in Dein Browserfenster." << std::endl;
|
||
ss << std::endl;
|
||
ss << "Mit freundlichen " << u8"Gr<EFBFBD><EFBFBD>en" << std::endl;
|
||
ss << "Dario, Gradido Server Admin" << std::endl;
|
||
|
||
|
||
message->addContent(new Poco::Net::StringPartSource(ss.str()));
|
||
|
||
UniLib::controller::TaskPtr sendEmail(new SendEmailTask(message, ServerConfig::g_CPUScheduler, 1));
|
||
sendEmail->setParentTaskPtrInArray(prepareEmail, 0);
|
||
sendEmail->setParentTaskPtrInArray(writeEmailVerification, 1);
|
||
sendEmail->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_EMAIL_VERIFICATION_SEND, this));
|
||
sendEmail->scheduleTask(sendEmail);
|
||
|
||
|
||
// write user into db
|
||
// generate and write email verification into db
|
||
// send email
|
||
|
||
//printf("[Session::createUser] time: %s\n", usedTime.string().data());
|
||
|
||
return true;
|
||
}
|
||
|
||
bool Session::ifUserExist(const std::string& email)
|
||
{
|
||
auto em = ErrorManager::getInstance();
|
||
const char* funcName = "Session::ifUserExist";
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement select(dbConnection);
|
||
bool emailChecked = false;
|
||
int userId = 0;
|
||
select << "SELECT email_checked, id from users where email = ? and email_checked = 1",
|
||
into(emailChecked), into(userId), useRef(email);
|
||
|
||
try {
|
||
if(select.execute() == 1) return true;
|
||
}
|
||
catch (Poco::Exception& ex) {
|
||
em->addError(new ParamError(funcName, "select user from email verification code mysql error ", ex.displayText().data()));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
int Session::updateEmailVerification(Poco::UInt64 emailVerificationCode)
|
||
{
|
||
const static char* funcName = "Session::updateEmailVerification";
|
||
lock(funcName);
|
||
Profiler usedTime;
|
||
|
||
auto em = ErrorManager::getInstance();
|
||
if(mEmailVerificationCode == emailVerificationCode) {
|
||
if (mSessionUser && mSessionUser->getDBId() == 0) {
|
||
//addError(new Error("E-Mail Verification", "Benutzer wurde nicht richtig gespeichert, bitte wende dich an den Server-Admin"));
|
||
em->addError(new Error(funcName, "user exist with 0 as id"));
|
||
em->sendErrorsAsEmail();
|
||
//return false;
|
||
}
|
||
|
||
// load correct user from db
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement select(dbConnection);
|
||
bool emailChecked = false;
|
||
int userId = 0;
|
||
select << "SELECT email_checked, id from users where id = (SELECT user_id FROM email_opt_in where verification_code=?)",
|
||
into(emailChecked), into(userId), use(emailVerificationCode);
|
||
|
||
try {
|
||
select.execute();
|
||
}
|
||
catch (Poco::Exception& ex) {
|
||
em->addError(new ParamError(funcName, "select user from email verification code mysql error ", ex.displayText().data()));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
if (userId != 0 && emailChecked) {
|
||
mSessionUser = new User(userId);
|
||
addError(new Error(gettext("E-Mail Verification"), gettext("Du hast dein Konto bereits aktiviert!")));
|
||
unlock();
|
||
return 1;
|
||
}
|
||
if (userId == 0) {
|
||
addError(new Error(gettext("E-Mail Verification"), gettext("Der Code stimmt nicht, bitte überprüfe ihn nochmal oder registriere dich erneut oder wende dich an den Server-Admin")));
|
||
//printf("[%s] time: %s\n", funcName, usedTime.string().data());
|
||
unlock();
|
||
return -1;
|
||
}
|
||
|
||
Poco::Data::Statement update(dbConnection);
|
||
update << "UPDATE users SET email_checked=1 where id = ?", use(userId);
|
||
|
||
try {
|
||
auto updated_rows = update.execute();
|
||
if (!updated_rows) {
|
||
//addError(new Error(gettext("E-Mail Verification"), gettext("Der Code stimmt nicht, bitte überprüfe ihn nochmal oder registriere dich erneut oder wende dich an den Server-Admin")));
|
||
//printf("[%s] time: %s\n", funcName, usedTime.string().data());
|
||
em->addError(new Error(funcName, "impossible error, update users failed with shortly before acquired user id "));
|
||
em->sendErrorsAsEmail();
|
||
|
||
unlock();
|
||
return -2;
|
||
}
|
||
updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED);
|
||
}
|
||
catch (Poco::Exception& ex) {
|
||
em->addError(new ParamError(funcName, "update user from email verification code mysql error ", ex.displayText().data()));
|
||
em->sendErrorsAsEmail();
|
||
unlock();
|
||
return -2;
|
||
}
|
||
/*if (updated_rows == 1) {
|
||
Poco::Data::Statement delete_row(dbConnection);
|
||
delete_row << "DELETE FROM email_opt_in where verification_code = ?", use(emailVerificationCode);
|
||
if (delete_row.execute() != 1) {
|
||
em->addError(new Error(funcName, "delete from email_opt_in entry didn't work as expected, please check db"));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
if (mSessionUser) {
|
||
mSessionUser->setEmailChecked();
|
||
mSessionUser->setLanguage(getLanguage());
|
||
}
|
||
updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED);
|
||
//printf("[%s] time: %s\n", funcName, usedTime.string().data());
|
||
unlock();
|
||
return true;
|
||
}
|
||
else {
|
||
em->addError(new ParamError(funcName, "update user work not like expected, updated row count", updated_rows));
|
||
em->sendErrorsAsEmail();
|
||
}*/
|
||
|
||
|
||
}
|
||
else {
|
||
addError(new Error(gettext("E-Mail Verification"), gettext("Falscher Code für aktiven Login")));
|
||
//printf("[%s] time: %s\n", funcName, usedTime.string().data());
|
||
unlock();
|
||
return -1;
|
||
}
|
||
//printf("[%s] time: %s\n", funcName, usedTime.string().data());
|
||
unlock();
|
||
return 0;
|
||
}
|
||
|
||
bool Session::createNewEmailVerificationCode()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool Session::startProcessingTransaction(const std::string& proto_message_base64)
|
||
{
|
||
lock("Session::startProcessingTransaction");
|
||
HASH hs = ProcessingTransaction::calculateHash(proto_message_base64);
|
||
// check if it is already running or waiting
|
||
for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) {
|
||
if (it->isNull()) {
|
||
it = mProcessingTransactions.erase(it);
|
||
}
|
||
if (hs == (*it)->getHash()) {
|
||
addError(new Error("Session::startProcessingTransaction", "transaction already in list"));
|
||
unlock();
|
||
return false;
|
||
}
|
||
}
|
||
Poco::AutoPtr<ProcessingTransaction> processorTask(new ProcessingTransaction(proto_message_base64));
|
||
processorTask->scheduleTask(processorTask);
|
||
mProcessingTransactions.push_back(processorTask);
|
||
unlock();
|
||
return true;
|
||
|
||
}
|
||
|
||
Poco::AutoPtr<ProcessingTransaction> Session::getNextReadyTransaction(size_t* working/* = nullptr*/)
|
||
{
|
||
lock("Session::getNextReadyTransaction");
|
||
if (working) {
|
||
*working = 0;
|
||
}
|
||
else if (!mCurrentActiveProcessingTransaction.isNull())
|
||
{
|
||
unlock();
|
||
return mCurrentActiveProcessingTransaction;
|
||
}
|
||
for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) {
|
||
if (working && !(*it)->isTaskFinished()) {
|
||
*working++;
|
||
}
|
||
if (mCurrentActiveProcessingTransaction.isNull() && (*it)->isTaskFinished()) {
|
||
if (!working) {
|
||
mCurrentActiveProcessingTransaction = *it;
|
||
unlock();
|
||
return mCurrentActiveProcessingTransaction;
|
||
}
|
||
// no early exit
|
||
else {
|
||
mCurrentActiveProcessingTransaction = *it;
|
||
}
|
||
|
||
}
|
||
}
|
||
unlock();
|
||
return mCurrentActiveProcessingTransaction;
|
||
}
|
||
|
||
void Session::finalizeTransaction(bool sign, bool reject)
|
||
{
|
||
lock("Session::finalizeTransaction");
|
||
if (mCurrentActiveProcessingTransaction.isNull()) {
|
||
unlock();
|
||
return;
|
||
}
|
||
mProcessingTransactions.remove(mCurrentActiveProcessingTransaction);
|
||
|
||
if (!reject) {
|
||
if (sign) {
|
||
Poco::AutoPtr<SigningTransaction> signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mSessionUser));
|
||
signingTransaction->scheduleTask(signingTransaction);
|
||
}
|
||
}
|
||
mCurrentActiveProcessingTransaction = nullptr;
|
||
unlock();
|
||
}
|
||
|
||
size_t Session::getProcessingTransactionCount()
|
||
{
|
||
size_t count = 0;
|
||
lock("Session::getProcessingTransactionCount");
|
||
|
||
for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) {
|
||
|
||
(*it)->lock();
|
||
if ((*it)->errorCount() > 0) {
|
||
(*it)->sendErrorsAsEmail();
|
||
(*it)->unlock();
|
||
it = mProcessingTransactions.erase(it);
|
||
if (it == mProcessingTransactions.end()) break;
|
||
}
|
||
else {
|
||
(*it)->unlock();
|
||
}
|
||
|
||
}
|
||
count = mProcessingTransactions.size();
|
||
unlock();
|
||
return count;
|
||
}
|
||
|
||
bool Session::isPwdValid(const std::string& pwd)
|
||
{
|
||
if (mSessionUser) {
|
||
return mSessionUser->validatePwd(pwd, this);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
UserStates Session::loadUser(const std::string& email, const std::string& password)
|
||
{
|
||
//Profiler usedTime;
|
||
lock("Session::loadUser");
|
||
if (mSessionUser && mSessionUser->getEmail() != email) {
|
||
mSessionUser = nullptr;
|
||
}
|
||
if (!mSessionUser) {
|
||
// load user for email only once from db
|
||
mSessionUser = new User(email.data());
|
||
}
|
||
if (mSessionUser->getUserState() >= USER_LOADED_FROM_DB) {
|
||
if (!mSessionUser->validatePwd(password, this)) {
|
||
unlock();
|
||
return USER_PASSWORD_INCORRECT;
|
||
}
|
||
}
|
||
else {
|
||
User::fakeCreateCryptoKey();
|
||
}
|
||
|
||
/*if (!mSessionUser->validatePwd(password, this)) {
|
||
addError(new Error("Login", "E-Mail oder Passwort nicht korrekt, bitte versuche es erneut!"));
|
||
unlock();
|
||
return false;
|
||
}
|
||
if (!mSessionUser->isEmailChecked()) {
|
||
addError(new Error("Account", "E-Mail Adresse wurde noch nicht bestätigt, hast du schon eine E-Mail erhalten?"));
|
||
unlock();
|
||
return false;
|
||
}*/
|
||
detectSessionState();
|
||
unlock();
|
||
|
||
return mSessionUser->getUserState();
|
||
}
|
||
|
||
bool Session::deleteUser()
|
||
{
|
||
lock("Session::deleteUser");
|
||
bool bResult = false;
|
||
if(mSessionUser) {
|
||
JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, 443);
|
||
Poco::Net::NameValueCollection payload;
|
||
payload.add("user", std::string(mSessionUser->getPublicKeyHex()));
|
||
//auto ret = phpServerRequest.request("userDelete", payload);
|
||
JsonRequestReturn ret = JSON_REQUEST_RETURN_OK;
|
||
if (ret == JSON_REQUEST_RETURN_ERROR) {
|
||
addError(new Error("Session::deleteUser", "php server error"));
|
||
getErrors(&phpServerRequest);
|
||
sendErrorsAsEmail();
|
||
}
|
||
else if (ret == JSON_REQUEST_RETURN_OK) {
|
||
bResult = mSessionUser->deleteFromDB();
|
||
}
|
||
else {
|
||
addError(new Error(gettext("Benutzer"), gettext("Konnte Community Server nicht erreichen. E-Mail an den Admin ist raus.")));
|
||
unlock();
|
||
return false;
|
||
}
|
||
}
|
||
if(!bResult) {
|
||
addError(new Error(gettext("Benutzer"), gettext("Fehler beim Löschen des Accounts. Bitte logge dich erneut ein und versuche es nochmal.")));
|
||
}
|
||
unlock();
|
||
return bResult;
|
||
}
|
||
|
||
void Session::setLanguage(Languages lang)
|
||
{
|
||
lock("Session::setLanguage");
|
||
if (mLanguageCatalog.isNull() || mLanguageCatalog->getLanguage() != lang) {
|
||
auto lm = LanguageManager::getInstance();
|
||
mLanguageCatalog = lm->getFreeCatalog(lang);
|
||
}
|
||
unlock();
|
||
}
|
||
|
||
Languages Session::getLanguage()
|
||
{
|
||
Languages lang = LANG_NULL;
|
||
lock("Session::getLanguage");
|
||
if (!mLanguageCatalog.isNull()) {
|
||
lang = mLanguageCatalog->getLanguage();
|
||
}
|
||
unlock();
|
||
return lang;
|
||
}
|
||
|
||
|
||
/*
|
||
SESSION_STATE_CRYPTO_KEY_GENERATED,
|
||
SESSION_STATE_USER_WRITTEN,
|
||
SESSION_STATE_EMAIL_VERIFICATION_WRITTEN,
|
||
SESSION_STATE_EMAIL_VERIFICATION_SEND,
|
||
SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED,
|
||
SESSION_STATE_PASSPHRASE_GENERATED,
|
||
SESSION_STATE_PASSPHRASE_SHOWN,
|
||
SESSION_STATE_PASSPHRASE_WRITTEN,
|
||
SESSION_STATE_KEY_PAIR_GENERATED,
|
||
SESSION_STATE_KEY_PAIR_WRITTEN,
|
||
SESSION_STATE_COUNT
|
||
*/
|
||
void Session::detectSessionState()
|
||
{
|
||
if (!mSessionUser || !mSessionUser->hasCryptoKey()) {
|
||
return;
|
||
}
|
||
UserStates userState = mSessionUser->getUserState();
|
||
|
||
/*
|
||
if (mSessionUser->getDBId() == 0) {
|
||
updateState(SESSION_STATE_CRYPTO_KEY_GENERATED);
|
||
return;
|
||
}*/
|
||
if (userState <= USER_EMAIL_NOT_ACTIVATED) {
|
||
|
||
if (mEmailVerificationCode == 0) {
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement select(dbConnection);
|
||
auto user_id = mSessionUser->getDBId();
|
||
select << "SELECT verification_code from email_opt_in where user_id = ?",
|
||
into(mEmailVerificationCode), use(user_id);
|
||
try {
|
||
if (select.execute() == 1) {
|
||
updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN);
|
||
return;
|
||
}
|
||
}
|
||
catch (Poco::Exception& ex) {
|
||
printf("[Session::detectSessionState] mysql exception: %s\n", ex.displayText().data());
|
||
}
|
||
}
|
||
|
||
updateState(SESSION_STATE_USER_WRITTEN);
|
||
return;
|
||
}
|
||
|
||
if (USER_NO_KEYS == userState) {
|
||
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
Poco::Data::Statement select(dbConnection);
|
||
Poco::Nullable<Poco::Data::BLOB> passphrase;
|
||
auto user_id = mSessionUser->getDBId();
|
||
select << "SELECT passphrase from user_backups where user_id = ?;",
|
||
into(passphrase), use(user_id);
|
||
try {
|
||
if (select.execute() == 1 && !passphrase.isNull()) {
|
||
updateState(SESSION_STATE_PASSPHRASE_WRITTEN);
|
||
return;
|
||
}
|
||
}
|
||
catch (Poco::Exception& exc) {
|
||
printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data());
|
||
}
|
||
if (mPassphrase != "") {
|
||
updateState(SESSION_STATE_PASSPHRASE_GENERATED);
|
||
return;
|
||
}
|
||
updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED);
|
||
return;
|
||
}
|
||
|
||
updateState(SESSION_STATE_KEY_PAIR_WRITTEN);
|
||
|
||
}
|
||
|
||
Poco::Net::HTTPCookie Session::getLoginCookie()
|
||
{
|
||
auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId));
|
||
// prevent reading or changing cookie with js
|
||
keks.setHttpOnly();
|
||
keks.setPath("/");
|
||
// send cookie only via https
|
||
#ifndef WIN32
|
||
keks.setSecure(true);
|
||
#endif
|
||
|
||
return keks;
|
||
}
|
||
|
||
bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode)
|
||
{
|
||
Profiler usedTime;
|
||
const static char* funcName = "Session::loadFromEmailVerificationCode";
|
||
auto em = ErrorManager::getInstance();
|
||
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||
|
||
Poco::Data::Statement select(dbConnection);
|
||
std::string email, first_name, last_name;
|
||
int user_id = 0;
|
||
select.reset(dbConnection);
|
||
select << "SELECT user_id FROM email_opt_in WHERE verification_code=?",
|
||
into(user_id), use(emailVerificationCode);
|
||
try {
|
||
size_t rowCount = select.execute();
|
||
if (rowCount != 1) {
|
||
em->addError(new ParamError(funcName, "select user by email verification code work not like expected, selected row count", rowCount));
|
||
em->addError(new ParamError(funcName, "emailVerficiation Code: ", std::to_string(emailVerificationCode)));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
if (rowCount < 1) {
|
||
addError(new Error(gettext("E-Mail Verification"), gettext("Konnte keinen passenden Account finden.")));
|
||
return false;
|
||
}
|
||
|
||
mSessionUser = new User(user_id);
|
||
mSessionUser->setLanguage(getLanguage());
|
||
|
||
mEmailVerificationCode = emailVerificationCode;
|
||
updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN);
|
||
//printf("[Session::loadFromEmailVerificationCode] time: %s\n", usedTime.string().data());
|
||
return true;
|
||
}
|
||
catch (const Poco::Exception& ex) {
|
||
em->addError(new ParamError(funcName, "exception selecting user from verification code", ex.displayText().data()));
|
||
em->addError(new ParamError(funcName, "emailVerficiation Code: ", std::to_string(emailVerificationCode)));
|
||
em->sendErrorsAsEmail();
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void Session::updateState(SessionStates newState)
|
||
{
|
||
lock("Session::updateState");
|
||
if (!mActive) return;
|
||
updateTimeout();
|
||
//printf("[%s] newState: %s\n", __FUNCTION__, translateSessionStateToString(newState));
|
||
if (newState > mState) {
|
||
mState = newState;
|
||
}
|
||
|
||
unlock();
|
||
}
|
||
|
||
const char* Session::getSessionStateString()
|
||
{
|
||
SessionStates state;
|
||
lock("Session::getSessionStateString");
|
||
state = mState;
|
||
unlock();
|
||
return translateSessionStateToString(state);
|
||
}
|
||
|
||
|
||
const char* Session::translateSessionStateToString(SessionStates state)
|
||
{
|
||
switch (state) {
|
||
case SESSION_STATE_EMPTY: return "uninitalized";
|
||
case SESSION_STATE_CRYPTO_KEY_GENERATED: return "crpyto key generated";
|
||
case SESSION_STATE_USER_WRITTEN: return "User saved";
|
||
case SESSION_STATE_EMAIL_VERIFICATION_WRITTEN: return "E-Mail verification code saved";
|
||
case SESSION_STATE_EMAIL_VERIFICATION_SEND: return "Verification E-Mail sended";
|
||
case SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED: return "Verification Code checked";
|
||
case SESSION_STATE_PASSPHRASE_GENERATED: return "Passphrase generated";
|
||
case SESSION_STATE_PASSPHRASE_SHOWN: return "Passphrase shown";
|
||
case SESSION_STATE_PASSPHRASE_WRITTEN: return "Passphrase written";
|
||
case SESSION_STATE_KEY_PAIR_GENERATED: return "Gradido Address created";
|
||
case SESSION_STATE_KEY_PAIR_WRITTEN: return "Gradido Address saved";
|
||
default: return "unknown";
|
||
}
|
||
|
||
return "error";
|
||
}
|
||
|
||
void Session::createEmailVerificationCode()
|
||
{
|
||
uint32_t* code_p = (uint32_t*)&mEmailVerificationCode;
|
||
for (int i = 0; i < sizeof(mEmailVerificationCode) / 4; i++) {
|
||
code_p[i] = randombytes_random();
|
||
}
|
||
|
||
}
|
||
/*
|
||
bool Session::useOrGeneratePassphrase(const std::string& passphase)
|
||
{
|
||
if (passphase != "" && User::validatePassphrase(passphase)) {
|
||
// passphrase is valid
|
||
setPassphrase(passphase);
|
||
updateState(SESSION_STATE_PASSPHRASE_SHOWN);
|
||
return true;
|
||
}
|
||
else {
|
||
mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
|
||
updateState(SESSION_STATE_PASSPHRASE_GENERATED);
|
||
return true;
|
||
}
|
||
}
|
||
*/
|
||
bool Session::generatePassphrase()
|
||
{
|
||
mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
|
||
|
||
updateState(SESSION_STATE_PASSPHRASE_GENERATED);
|
||
return true;
|
||
}
|
||
|
||
bool Session::generateKeys(bool savePrivkey, bool savePassphrase)
|
||
{
|
||
bool validUser = true;
|
||
if (mSessionUser) {
|
||
if (!mSessionUser->generateKeys(savePrivkey, mPassphrase, this)) {
|
||
validUser = false;
|
||
}
|
||
else {
|
||
if (savePassphrase) {
|
||
//printf("[Session::generateKeys] create save passphrase task\n");
|
||
UniLib::controller::TaskPtr savePassphrase(new WritePassphraseIntoDB(mSessionUser->getDBId(), mPassphrase));
|
||
savePassphrase->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this));
|
||
savePassphrase->scheduleTask(savePassphrase);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
validUser = false;
|
||
}
|
||
if (!validUser) {
|
||
addError(new Error(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein.")));
|
||
return false;
|
||
}
|
||
// delete passphrase after all went well
|
||
mPassphrase.clear();
|
||
|
||
return true;
|
||
}
|