save keys (encrypt privkey) done, work on login

This commit is contained in:
Dario 2019-10-02 11:55:03 +02:00
parent 9a60d49cb5
commit d6e9cc19ab
20 changed files with 584 additions and 145 deletions

View File

@ -7,8 +7,11 @@
#include "ed25519/ed25519.h"
#include <sodium.h>
class UserWriteKeysIntoDB;
class KeyPair
{
friend UserWriteKeysIntoDB;
public:
KeyPair();
~KeyPair();
@ -17,7 +20,11 @@ public:
std::string getPubkeyHex();
bool savePrivKey(int userId);
inline const unsigned char* getPublicKey() const { return mSodiumPublic; }
protected:
const ObfusArray* getPrivateKey() const { return mSodiumSecret; }
private:
ObfusArray* mPrivateKey;

View File

@ -9,12 +9,9 @@ public:
ObfusArray(size_t size, const unsigned char * data);
~ObfusArray();
operator const unsigned char*() {
return &m_Data[m_offsetSize];
}
size_t size() {
return m_dataSize;
}
inline operator const unsigned char*() const {return &m_Data[m_offsetSize];}
inline size_t size() const { return m_dataSize;}
private:
size_t m_arraySize;

View File

@ -140,37 +140,3 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi
return new CheckEmailPage(session);
}
Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handlePassphrase(Session* session, const Poco::Net::HTTPServerRequest& request)
{
//couldn't use form here, because request is const
/*
Poco::Net::HTMLForm form(request);
if (!form.empty()) {
auto registerKeyChoice = form.get("passphrase", "");
std::string oldPassphrase = "";
if (registerKeyChoice == "no") {
auto oldPassphrase = form.get("passphrase-existing", "");
if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) {
// passphrase is valid
session->setPassphrase(oldPassphrase);
session->updateState(SESSION_STATE_PASSPHRASE_SHOWN);
// go one
return new SaveKeysPage(session);
}
else {
session->addError(new Error("Merkspruch", "Dieser Merkspruch ist ung&uuml;ltig, bitte &uuml;berpr&uuml;fen oder neu generieren (lassen)."));
}
}
else if (registerKeyChoice == "yes") {
session->generatePassphrase();
}
}
return new PassphrasePage(session);
*/
}
Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleSaveKeys(Session* session, const Poco::Net::HTTPServerRequest& request)
{
}

View File

@ -3,6 +3,7 @@
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/RegularExpression.h"
#include "../model/Session.h"
#define HTTP_PAGES_COUNT 1
@ -14,8 +15,6 @@ public:
protected:
Poco::Net::HTTPRequestHandler* handleCheckEmail(Session* session, const std::string uri, const Poco::Net::HTTPServerRequest& request);
Poco::Net::HTTPRequestHandler* handlePassphrase(Session* session, const Poco::Net::HTTPServerRequest& request);
Poco::Net::HTTPRequestHandler* handleSaveKeys(Session* session, const Poco::Net::HTTPServerRequest& request);
Poco::RegularExpression mRemoveGETParameters;
};

View File

@ -0,0 +1,154 @@
#include "PassphrasePage.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/DeflatingStream.h"
#line 7 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
enum PageState
{
PAGE_ASK_PASSPHRASE,
PAGE_SHOW_PASSPHRASE
};
PassphrasePage::PassphrasePage(Session* arg):
SessionHTTPRequestHandler(arg)
{
}
void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
bool _compressResponse(request.hasToken("Accept-Encoding", "gzip"));
if (_compressResponse) response.set("Content-Encoding", "gzip");
Poco::Net::HTMLForm form(request, request.stream());
#line 15 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
PageState state = PAGE_ASK_PASSPHRASE;
bool hasErrors = mSession->errorCount() > 0;
// save login cookie, because maybe we've get an new session
auto cookie_id = mSession->getHandle();
auto user_host = request.clientAddress().host();
mSession->setClientIp(user_host);
response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id)));
if (!form.empty()) {
auto registerKeyChoice = form.get("passphrase", "");
std::string oldPassphrase = "";
if (registerKeyChoice == "no") {
auto oldPassphrase = form.get("passphrase-existing", "");
if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) {
// passphrase is valid
mSession->setPassphrase(oldPassphrase);
mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN);
state = PAGE_SHOW_PASSPHRASE;
}
else {
mSession->addError(new Error("Merkspruch", "Dieser Merkspruch ist ung&uuml;ltig, bitte &uuml;berpr&uuml;fen oder neu generieren (lassen)."));
}
}
else if (registerKeyChoice == "yes") {
mSession->generatePassphrase();
}
}
if(mSession->getSessionState() == SESSION_STATE_PASSPHRASE_GENERATED) {
state = PAGE_SHOW_PASSPHRASE;
mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN);
}
std::ostream& _responseStream = response.send();
Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;
responseStream << "\n";
responseStream << "<!DOCTYPE html>\n";
responseStream << "<html>\n";
responseStream << "<head>\n";
responseStream << "<meta charset=\"UTF-8\">\n";
responseStream << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
responseStream << "<title>Gradido Login Server: Merkspruch</title>\n";
responseStream << "<!--<link rel=\"stylesheet\" type=\"text/css\" href=\"css/styles.min.css\">-->\n";
responseStream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gradido2.dario-rekowski.de/css/styles.css\">\n";
responseStream << "<style type=\"text/css\" >\n";
responseStream << "input:not([type='radio']) {\n";
responseStream << "\twidth:200px;\n";
responseStream << "}\n";
responseStream << "label:not(.grd_radio_label) {\n";
responseStream << "\twidth:80px;\n";
responseStream << "\tdisplay:inline-block;\n";
responseStream << "}\n";
responseStream << "</style>\n";
responseStream << "</head>\n";
responseStream << "<body>\n";
responseStream << "<div class=\"grd_container\">\n";
responseStream << "\t";
#line 71 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
if(mSession && hasErrors) { responseStream << "\n";
responseStream << "\t\t";
#line 72 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
responseStream << ( mSession->getErrorsHtml() );
responseStream << "\n";
responseStream << "\t";
#line 73 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
} responseStream << "\n";
responseStream << "\t<h1>Einen neuen Account anlegen</h1>\n";
responseStream << "\t";
#line 75 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
if(state == PAGE_SHOW_PASSPHRASE) { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text-max-width\">\n";
responseStream << "\t\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\t\tSchreibe dir den Merkspruch auf und packe ihn gut weg. Du brauchst ihn um deine Adresse wiederherzustellen. Wenn du ihn verlierst, sind auch deine Gradidos verloren.\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t\t\t<div class=\"grd_textarea\">\n";
responseStream << "\t\t\t\t";
#line 81 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
responseStream << ( mSession->getPassphrase() );
responseStream << "\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t\t\t<a href=\"/saveKeys\">Weiter</a>\n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 85 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
} else if(state == PAGE_ASK_PASSPHRASE) { responseStream << "\n";
responseStream << "\t<form method=\"POST\">\n";
responseStream << "\t\t<fieldset class=\"grd_container_small\">\n";
responseStream << "\t\t\t<legend>Neue Gradido Adresse anlegen / wiederherstellen</legend>\n";
responseStream << "\t\t\t<p>Hast du schonmal ein Gradido Konto besessen?</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<input id=\"passphrase-new-yes\" type=\"radio\" name=\"passphrase\" value=\"yes\" checked/>\n";
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"passphrase-new-yes\">Nein, bitte ein neues erstellen!</label>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<input id=\"passphrase-new-no\" type=\"radio\" name=\"passphrase\" value=\"no\"/>\n";
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"passphrase-new-no\">Ja, bitte wiederherstellen!</label>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<textarea style=\"width:100%;height:100px\" name=\"passphrase-existing\">";
#line 98 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
responseStream << ( !form.empty() ? form.get("passphrase-existing", "") : "" );
responseStream << "</textarea>\n";
responseStream << "\t\t</fieldset>\n";
responseStream << "\t\t<input class=\"grd_bn_succeed\" type=\"submit\" name=\"submit\" value=\"Weiter\">\n";
responseStream << "\t\t\n";
responseStream << "\t</form>\n";
responseStream << "\t";
#line 103 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
} else { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\tUngültige Seite, wenn du das siehst stimmt hier etwas nicht. Bitte wende dich an den Server-Admin. \n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 107 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
} responseStream << "\n";
responseStream << "</div>\n";
responseStream << "</body>\n";
responseStream << "</html>\n";
if (_compressResponse) _gzipStream.close();
}

View File

@ -0,0 +1,20 @@
#ifndef PassphrasePage_INCLUDED
#define PassphrasePage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "SessionHTTPRequestHandler.h"
class PassphrasePage: public SessionHTTPRequestHandler
{
public:
PassphrasePage(Session*);
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // PassphrasePage_INCLUDED

View File

@ -7,8 +7,12 @@
#line 7 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#include "../model/Session.h"
enum PageState
{
PAGE_ASK,
PAGE_SHOW_PUBKEY,
PAGE_ERROR
};
@ -26,13 +30,45 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne
if (_compressResponse) response.set("Content-Encoding", "gzip");
Poco::Net::HTMLForm form(request, request.stream());
#line 12 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 16 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
bool hasErrors = mSession->errorCount() > 0;
bool hasPassword = mSession->getUser()->hasCryptoKey();
PageState state = PAGE_ASK;
if(!form.empty()) {
// privkey
auto savePrivkeyChoice = form.get("save-privkey");
bool savePrivkey = false;
if(savePrivkeyChoice == "yes") {
if(!hasPassword) {
// check pwd
auto pwd = form.get("save-privkey-password", "");
if(!mSession->getUser()->validatePwd(pwd)) {
mSession->addError(new Error("Passwort", "Das Passwort stimmt nicht. Bitte verwende dein Passwort von der Registrierung"));
hasErrors = true;
} else {
savePrivkey = true;
}
} else {
savePrivkey = true;
}
}
if(!hasErrors) {
auto savePassphraseChoice = form.get("save-passphrase");
bool savePassphrase = false;
if(savePassphraseChoice == "yes") {
savePassphrase = true;
}
if(!mSession->generateKeys(savePrivkey, savePassphrase)) {
hasErrors = true;
} else if(mSession->getSessionState() >= SESSION_STATE_KEY_PAIR_GENERATED) {
state = PAGE_SHOW_PUBKEY;
} else {
state = PAGE_ERROR;
}
}
}
std::ostream& _responseStream = response.send();
Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
@ -59,16 +95,19 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne
responseStream << "<body>\n";
responseStream << "<div class=\"grd_container\">\n";
responseStream << "\t";
#line 40 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 76 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
if(hasErrors) { responseStream << "\n";
responseStream << "\t\t";
#line 41 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 77 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
responseStream << ( mSession->getErrorsHtml() );
responseStream << "\n";
responseStream << "\t";
#line 42 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 78 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
} responseStream << "\n";
responseStream << "\t<h1>Daten speichern</h1>\n";
responseStream << "\t";
#line 80 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
if(state == PAGE_ASK) { responseStream << "\n";
responseStream << "\t<form method=\"POST\">\n";
responseStream << "\t\t<fieldset>\n";
responseStream << "\t\t\t<legend>Gradido Private Key speichern</legend>\n";
@ -82,7 +121,7 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"save-privkey-yes\">Ja, bitte speichern!</label>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t";
#line 56 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 93 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
if(!hasPassword) { responseStream << "\n";
responseStream << "\t\t\t\t<p>Ich brauche nochmal dein Passwort wenn du dich für ja entscheidest.</p>\n";
responseStream << "\t\t\t\t<p class=\"grd_small\">\n";
@ -90,7 +129,7 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne
responseStream << "\t\t\t\t\t<input id=\"save-privkey-password\" type=\"password\" name=\"save-privkey-password\"/>\n";
responseStream << "\t\t\t\t</p>\n";
responseStream << "\t\t\t";
#line 62 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
#line 99 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
} responseStream << "\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<input id=\"save-privkey-no\" type=\"radio\" name=\"save-privkey\" value=\"no\"/>\n";
@ -114,6 +153,29 @@ void SaveKeysPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne
responseStream << "\t\t</fieldset>\n";
responseStream << "\t\t<input class=\"grd_bn_succeed\" type=\"submit\" value=\"Speichern\">\n";
responseStream << "\t</form>\n";
responseStream << "\t";
#line 122 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
} else if(state == PAGE_SHOW_PUBKEY) { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\t<p>Je nach Auswahl werden deine Daten nun verschl&uuml;sselt und gespeichert. </p>\n";
responseStream << "\t\t\t<p>Deine Gradido Adresse (Hex): </p>\n";
responseStream << "\t\t\t<p class=\"grd_textarea\">\n";
responseStream << "\t\t\t\t";
#line 127 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
responseStream << ( mSession->getUser()->getPublicKeyHex() );
responseStream << "\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<a class=\"grd_bn\" href=\"../\">Zur&uuml;ck zur Startseite</a>\n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 131 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
} else if(state == PAGE_ERROR) { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\t<p>Ein Fehler trat auf, bitte versuche es erneut oder wende dich an den Server-Admin</p>\n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 135 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\saveKeys.cpsp"
} responseStream << "\n";
responseStream << "</div>\n";
responseStream << "</body>\n";
responseStream << "</html>\n";

View File

@ -19,6 +19,7 @@ using Poco::SharedPtr;
namespace ServerConfig {
Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
ObfusArray* g_ServerCryptoKey = nullptr;
// std::string g_ServerAdminPublic;
UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr;
Context::Ptr g_SSL_CLient_Context = nullptr;
EmailAccount g_EmailAccount;
@ -63,6 +64,8 @@ namespace ServerConfig {
return false;
}
g_ServerCryptoKey = new ObfusArray(realBinSize, key);
//g_ServerAdminPublic = cfg.getString("crypto.server_admin_public");
return true;
}

View File

@ -23,6 +23,7 @@ namespace ServerConfig {
extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
extern ObfusArray* g_ServerCryptoKey;
//extern unsigned char g_ServerAdminPublic[];
extern UniLib::controller::CPUSheduler* g_CPUScheduler;
extern Poco::Net::Context::Ptr g_SSL_CLient_Context;
extern EmailAccount g_EmailAccount;

View File

@ -27,7 +27,8 @@ int SendErrorMessage::run()
mailClientSession->close();
}
catch (Poco::Exception& exc) {
printf("[SendErrorMessage::%s] error sending error message to admin\n", __FUNCTION__);
printf("[SendErrorMessage::%s] error sending error message to admin: %s\n",
__FUNCTION__, exc.displayText().data());
return -1;
}
return 0;

View File

@ -18,6 +18,7 @@ using namespace Poco::Data::Keywords;
int WriteEmailVerification::run()
{
Profiler timeUsed;
auto verificationCode = mSession->getEmailVerificationCode();
printf("{[WriteEmailVerification::run] E-Mail Verification Code: %llu\n", verificationCode);
auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
@ -29,12 +30,31 @@ int WriteEmailVerification::run()
mSession->addError(new Error("WriteEmailVerification", "error inserting email verification code"));
return -1;
}
printf("[WriteEmailVerification::run] 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 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);
printf("[WritePassphraseIntoDB::run] timeUsed: %s\n", timeUsed.string().data());
return 0;
}
// --------------------------------------------------------------------------------------------------------------
@ -232,6 +252,13 @@ bool Session::loadUser(const std::string& email, const std::string& password)
return true;
}
Poco::Net::HTTPCookie Session::getLoginCookie()
{
auto keks = Poco::Net::HTTPCookie("user", std::to_string(mHandleId));
// TODO: additional config, like js permit
return keks;
}
bool Session::loadFromEmailVerificationCode(unsigned long long emailVerificationCode)
{
Profiler usedTime;
@ -315,6 +342,7 @@ const char* Session::translateSessionStateToString(SessionStates state)
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";
@ -356,11 +384,28 @@ bool Session::generatePassphrase()
bool Session::generateKeys(bool savePrivkey, bool savePassphrase)
{
bool validUser = true;
if (mSessionUser) {
if (!mSessionUser->generateKeys(savePrivkey, mPassphrase)) {
if (!mSessionUser->generateKeys(savePrivkey, mPassphrase, this)) {
validUser = false;
}
else {
if (savePassphrase) {
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("Benutzer", "Kein g&uuml;ltiger Benutzer, bitte logge dich erneut ein."));
return false;
}
// delete passphrase after all went well
mPassphrase.clear();
return true;
}

View File

@ -18,6 +18,7 @@
#include "Poco/Thread.h"
#include "Poco/DateTime.h"
#include "Poco/Net/IPAddress.h"
#include "Poco/Net/HTTPCookie.h"
#define EMAIL_VERIFICATION_CODE_SIZE 8
@ -31,6 +32,7 @@ enum SessionStates {
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
@ -55,6 +57,8 @@ public:
bool updateEmailVerification(unsigned long long emailVerificationCode);
Poco::Net::HTTPCookie getLoginCookie();
inline User* getUser() { return mSessionUser; }
inline int getHandle() { return mHandleId; }
@ -110,6 +114,21 @@ private:
};
class WritePassphraseIntoDB : public UniLib::controller::CPUTask
{
public:
WritePassphraseIntoDB(int userId, const std::string& passphrase)
: mUserId(userId), mPassphrase(passphrase) {}
virtual int run();
virtual const char* getResourceType() const { return "WritePassphraseIntoDB"; };
protected:
int mUserId;
std::string mPassphrase;
};
class SessionStateUpdateCommand : public UniLib::controller::Command
{
public:

View File

@ -1,56 +1,19 @@
#include "User.h"
#include "Profiler.h"
#include "Session.h"
#include <sodium.h>
#include "ed25519/ed25519.h"
#include "Poco/Util/Application.h"
#include "../ServerConfig.h"
#include "../SingletonManager/ConnectionManager.h"
#include "../SingletonManager/ErrorManager.h"
#include "Poco/Data/Binding.h"
using namespace Poco::Data::Keywords;
NewUser::NewUser(User* user, const char* password, const char* passphrase)
: mUser(user), mPassword(password), mPassphrase(passphrase)
{
}
NewUser::~NewUser()
{
}
void NewUser::run()
{
// create crypto key
if (!mUser->hasCryptoKey()) {
mUser->createCryptoKey(mPassword.data());
}
// generate
}
// ------------------------------------------------------------------------------------
LoginUser::LoginUser(User* user, const char* password)
: mUser(user), mPassword(password)
{
// auto app = Poco::Util::Application::instance();
}
LoginUser::~LoginUser()
{
}
void LoginUser::run()
{
}
// -------------------------------------------------------------------------------------------------
@ -71,6 +34,21 @@ int UserCreateCryptoKey::run()
return 0;
}
// -------------------------------------------------------------------------------------------------------------
int UserGenerateKeys::run()
{
Profiler timeUsed;
// always return true, cannot fail (only if low on memory)
mKeys.generateFromPassphrase(mPassphrase.data(), &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
mUser->setPublicKeyHex(mKeys.getPubkeyHex());
printf("[UserGenerateKeys::run] time: %s\n", timeUsed.string().data());
return 0;
}
// -----------------------------------------------------------------------------------------------------
int UserWriteIntoDB::run()
@ -88,11 +66,73 @@ int UserWriteIntoDB::run()
return 0;
}
// --------------------------------------------------------------------------------------------------------
UserWriteKeysIntoDB::UserWriteKeysIntoDB(UniLib::controller::TaskPtr parent, User* user, bool savePrivKey)
: UniLib::controller::CPUTask(1), mUser(user), mSavePrivKey(savePrivKey)
{
if (strcmp(parent->getResourceType(), "UserGenerateKeys") != 0) {
throw Poco::Exception("given TaskPtr isn't UserGenerateKeys");
}
setParentTaskPtrInArray(parent, 0);
}
int UserWriteKeysIntoDB::run()
{
Profiler timeUsed;
auto cm = ConnectionManager::getInstance();
auto em = ErrorManager::getInstance();
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
auto keyPairs = getParent(0).cast<UserGenerateKeys>()->getKeyPairs();
auto pubKey = keyPairs->getPublicKey();
Poco::Data::BLOB pubkey_blob(pubKey, crypto_sign_PUBLICKEYBYTES);
Poco::Data::Statement update(session);
Poco::Data::BLOB* pprivkey_blob = nullptr;
if (mSavePrivKey) {
// TODO: encrypt privkey
auto privKey = keyPairs->getPrivateKey();
pprivkey_blob = mUser->encrypt(privKey);
//Poco::Data::BLOB privkey_blob(*privKey, privKey->size());
update << "UPDATE users SET pubkey=?, privkey=? where id=?",
use(pubkey_blob), use(*pprivkey_blob), bind(mUser->getDBId());
}
else {
update << "UPDATE users SET pubkey=? where id=?",
use(pubkey_blob), bind(mUser->getDBId());
}
try {
if (update.execute() != 1) {
em->addError(new ParamError("UserWritePrivKeyIntoDB::run", "error writing keys into db for user", std::to_string(mUser->getDBId())));
em->sendErrorsAsEmail();
if (pprivkey_blob) {
delete pprivkey_blob;
}
return -1;
}
}
catch (Poco::Exception& ex) {
em->addError(new ParamError("UserWritePrivKeyIntoDB::run", "mysql error updating", ex.displayText().data()));
em->sendErrorsAsEmail();
if (pprivkey_blob) {
delete pprivkey_blob;
}
return -1;
}
if (pprivkey_blob) {
delete pprivkey_blob;
}
printf("UserWritePrivKeyIntoDB time: %s\n", timeUsed.string().data());
return 0;
}
// *******************************************************************************
User::User(const char* email, const char* name)
: mDBId(0), mEmail(email), mFirstName(name), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr)
User::User(const char* email)
: mDBId(0), mEmail(email), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr)
{
//crypto_shorthash(mPasswordHashed, (const unsigned char*)password, strlen(password), *ServerConfig::g_ServerCryptoKey);
//memset(mPasswordHashed, 0, crypto_shorthash_BYTES);
@ -102,15 +142,16 @@ User::User(const char* email, const char* name)
Poco::Nullable<Poco::Data::BLOB> pubkey;
Poco::Data::Statement select(session);
select << "SELECT id, password, pubkey, email_checked from users where email = ?",
into(mDBId), into(mPasswordHashed), into(pubkey), into(mEmailChecked), use(mEmail);
select << "SELECT id, name, password, pubkey, email_checked from users where email = ?",
into(mDBId), into(mFirstName), into(mPasswordHashed), into(pubkey), into(mEmailChecked), use(mEmail);
try {
if (select.execute() == 1) {
if (!pubkey.isNull()) {
size_t hexSize = pubkey.value.size() * 2 + 1;
auto pubkey_value = pubkey.value();
size_t hexSize = pubkey_value.size() * 2 + 1;
char* hexString = (char*)malloc(hexSize);
memset(hexString, 0, hexSize);
sodium_bin2hex(hexString, hexSize, pubkey.value.content().data(), pubkey.value.size());
sodium_bin2hex(hexString, hexSize, pubkey_value.content().data(), pubkey_value.size());
mPublicHex = hexString;
free(hexString);
}
@ -118,6 +159,11 @@ User::User(const char* email, const char* name)
} catch(...) {}
}
User* User::login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr)
{
}
User::~User()
{
@ -198,14 +244,14 @@ ObfusArray* User::createCryptoKey(const std::string& password)
{
Profiler timeUsed;
// TODO: put it in secure location
// TODO: put it in secure location, or use value from server config
static const unsigned char app_secret[] = { 0x21, 0xff, 0xbb, 0xc6, 0x16, 0xfe };
sha_context context_sha512;
//unsigned char* hash512 = (unsigned char*)malloc(SHA_512_SIZE);
if (SHA_512_SIZE < crypto_pwhash_SALTBYTES) {
addError(new Error(__FUNCTION__, "sha512 is to small for libsodium pwhash saltbytes"));
return;
return nullptr;
}
@ -221,7 +267,7 @@ ObfusArray* User::createCryptoKey(const std::string& password)
addError(new ParamError(__FUNCTION__, " error creating pwd hash, maybe to much memory requestet? error:", strerror(errno)));
//printf("[User::%s] error creating pwd hash, maybe to much memory requestet? error: %s\n", __FUNCTION__, strerror(errno));
//printf("pwd: %s\n", pwd);
return ;
return nullptr;
}
lock();
@ -234,10 +280,60 @@ ObfusArray* User::createCryptoKey(const std::string& password)
return cryptoKey;
}
bool User::generateKeys(bool savePrivkey, const std::string& passphrase)
bool User::generateKeys(bool savePrivkey, const std::string& passphrase, Session* session)
{
// TODO: call create key pair from passphrase from worker thread
// TODO: evt. save privkey from worker thread
Profiler timeUsed;
UniLib::controller::TaskPtr generateKeysTask(new UserGenerateKeys(this, passphrase));
generateKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_GENERATED, session));
//generateKeysTask->scheduleTask(generateKeysTask);
// run directly because we like to show pubkey on interface, shouldn't last to long
generateKeysTask->run();
if (mDBId == 0) {
loadEntryDBId(ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER));
if (mDBId == 0) {
auto em = ErrorManager::getInstance();
em->addError(new ParamError("User::generateKeys", "user not found in db with email", mEmail.data()));
em->sendErrorsAsEmail();
}
return false;
}
UniLib::controller::TaskPtr saveKeysTask(new UserWriteKeysIntoDB(generateKeysTask, this, savePrivkey));
saveKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_WRITTEN, session));
saveKeysTask->scheduleTask(saveKeysTask);
printf("[User::generateKeys] call two tasks, time used: %s\n", timeUsed.string().data());
return true;
}
Poco::Data::BLOB* User::encrypt(const ObfusArray* data)
{
if (!hasCryptoKey()) {
addError(new Error("User::encrypt", "hasn't crypto key"));
return nullptr;
}
size_t message_len = data->size();
size_t ciphertext_len = crypto_secretbox_MACBYTES + message_len;
unsigned char nonce[crypto_secretbox_NONCEBYTES];
// we use a hardcoded value for nonce
memset(nonce, 31, crypto_secretbox_NONCEBYTES);
unsigned char* ciphertext = (unsigned char*)malloc(ciphertext_len);
memset(ciphertext, 0, ciphertext_len);
if (0 != crypto_secretbox_easy(ciphertext, *data, message_len, nonce, *mCryptoKey)) {
//printf("[%s] error encrypting message \n", __FUNCTION__);
addError(new Error("User::encrypt", "encrypting message failed"));
free(ciphertext);
return nullptr;
}
free(ciphertext);
return new Poco::Data::BLOB(ciphertext, ciphertext_len);
}
Poco::Data::Statement User::insertIntoDB(Poco::Data::Session session)

View File

@ -4,6 +4,7 @@
#include "../Crypto/KeyPair.h"
#include <string>
#include "ErrorList.h"
#include "Poco/Thread.h"
#include "Poco/Data/Session.h"
#include "../tasks/CPUTask.h"
@ -11,6 +12,7 @@
class NewUser;
class UserCreateCryptoKey;
class UserWriteIntoDB;
class Session;
class User : public ErrorList
{
@ -21,14 +23,17 @@ public:
// new user
//User(const char* email, const char* name, const char* password);
// existing user
User(const char* email, const char* name);
User(const char* email);
// login
//User(const std::string& email, const std::string& password);
~User();
static std::string generateNewPassphrase(Mnemonic* word_source);
static bool validatePassphrase(const std::string& passphrase);
static User* login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr);
bool generateKeys(bool savePrivkey, const std::string& passphrase);
bool generateKeys(bool savePrivkey, const std::string& passphrase, Session* session);
bool loadEntryDBId(Poco::Data::Session session);
@ -36,17 +41,22 @@ public:
inline const char* getEmail() const { return mEmail.data(); }
inline const char* getName() const { return mFirstName.data(); }
inline int getDBId() { return mDBId; }
inline int getDBId() const { return mDBId; }
inline void setEmailChecked() { mEmailChecked = true; }
std::string getPublicKeyHex() { return mPublicHex; }
inline std::string getPublicKeyHex() { lock(); std::string pubkeyHex = mPublicHex; unlock(); return pubkeyHex; }
inline void setPublicKeyHex(const std::string& publicKeyHex) { lock(); mPublicHex = publicKeyHex; unlock(); }
bool validatePwd(const std::string& pwd);
Poco::Data::BLOB* encrypt(const ObfusArray* data);
protected:
typedef unsigned long long passwordHashed;
ObfusArray* createCryptoKey(const std::string& password);
inline void setCryptoKey(ObfusArray* cryptoKey) { mCryptoKey = cryptoKey; }
Poco::Data::Statement insertIntoDB(Poco::Data::Session session);
inline passwordHashed getPwdHashed() { lock(); auto ret = mPasswordHashed; unlock(); return ret; }
inline void setPwdHashed(passwordHashed pwdHashed) { lock(); mPasswordHashed = pwdHashed; unlock(); }
@ -82,6 +92,25 @@ private:
std::string mPassword;
};
class UserGenerateKeys : public UniLib::controller::CPUTask
{
public:
UserGenerateKeys(User* user, const std::string& passphrase)
: mUser(user), mPassphrase(passphrase) {}
~UserGenerateKeys() {
}
virtual int run();
inline KeyPair* getKeyPairs() { return &mKeys; }
virtual const char* getResourceType() const { return "UserGenerateKeys"; };
protected:
User* mUser;
std::string mPassphrase;
KeyPair mKeys;
};
class UserWriteIntoDB : public UniLib::controller::CPUTask
{
public:
@ -94,33 +123,17 @@ private:
User* mUser;
};
class NewUser : public Poco::Runnable
class UserWriteKeysIntoDB : public UniLib::controller::CPUTask
{
public:
NewUser(User* user, const char* password, const char* passphrase);
~NewUser();
UserWriteKeysIntoDB(UniLib::controller::TaskPtr parent, User* user, bool savePrivKey);
virtual int run();
virtual void run();
virtual const char* getResourceType() const { return "UserWriteKeysIntoDB"; };
protected:
User* mUser;
std::string mPassword;
std::string mPassphrase;
};
class LoginUser : public Poco::Runnable
{
public:
LoginUser(User* user, const char* password);
~LoginUser();
virtual void run();
protected:
User* mUser;
std::string mPassword;
User* mUser;
bool mSavePrivKey;
};
#endif //GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE

View File

@ -1,5 +1,6 @@
#include "CPUTask.h"
#include "CPUSheduler.h"
#include "../ServerConfig.h"
namespace UniLib {
namespace controller {
@ -15,6 +16,12 @@ namespace UniLib {
assert(cpuScheduler);
}
CPUTask::CPUTask(size_t taskDependenceCount/* = 0*/)
: Task(), mScheduler(ServerConfig::g_CPUScheduler)
{
assert(mScheduler);
}
CPUTask::~CPUTask()
{

View File

@ -49,7 +49,8 @@ namespace UniLib {
{
public:
CPUTask(CPUSheduler* cpuSheduler, size_t taskDependenceCount);
CPUTask(CPUSheduler* cpuScheduler);
CPUTask(CPUSheduler* cpuScheduler);
CPUTask(size_t taskDependenceCount = 0);
virtual ~CPUTask();
virtual const char* getResourceType() const {return "CPUTask";};

View File

@ -2,6 +2,26 @@
<%@ page form="true" %>
<%@ page compressed="true" %>
<%!
#include "../SingletonManager/SessionManager.h"
#include "Poco/Net/HTTPCookie.h"
%>
<%%
auto session = SessionManager::getInstance()->getNewSession();
if(!form.empty()) {
auto email = form.get("login-email", "");
auto password = form.get("login-password", "");
if(session->loadUser(email, password)) {
auto user_host = request.clientAddress().host();
session->setClientIp(user_host);
response.addCookie(session->getLoginCookie());
auto uri_start = request.serverParams().getServerName();
response.redirect(uri_start + "/");
return;
}
}
%>
<!DOCTYPE html>
@ -12,8 +32,18 @@
<title>Gradido Login Server: Login</title>
<!--<link rel="stylesheet" type="text/css" href="css/styles.min.css">-->
<link rel="stylesheet" type="text/css" href="https://gradido2.dario-rekowski.de/css/styles.css">
<style type="text/css" >
input:not([type='radio']) {
width:200px;
}
label:not(.grd_radio_label) {
width:80px;
display:inline-block;
}
</style>
</head>
<body>
<%= session->getErrorsHtml() %>
<h1>Login</h1>
<form method="POST">
<div class="grd_container">

View File

@ -30,16 +30,16 @@ enum PageState
if (oldPassphrase != "" && User::validatePassphrase(oldPassphrase)) {
// passphrase is valid
session->setPassphrase(oldPassphrase);
session->updateState(SESSION_STATE_PASSPHRASE_SHOWN);
mSession->setPassphrase(oldPassphrase);
mSession->updateState(SESSION_STATE_PASSPHRASE_SHOWN);
state = PAGE_SHOW_PASSPHRASE;
}
else {
session->addError(new Error("Merkspruch", "Dieser Merkspruch ist ung&uuml;ltig, bitte &uuml;berpr&uuml;fen oder neu generieren (lassen)."));
mSession->addError(new Error("Merkspruch", "Dieser Merkspruch ist ung&uuml;ltig, bitte &uuml;berpr&uuml;fen oder neu generieren (lassen)."));
}
}
else if (registerKeyChoice == "yes") {
session->generatePassphrase();
mSession->generatePassphrase();
}
}

View File

@ -20,12 +20,9 @@
);
}
if(userReturned) {
auto cookie_id = session->getHandle();
//auto user_host_string = request.clientAddress().toString();
auto user_host = request.clientAddress().host();
session->setClientIp(user_host);
//printf("cookie: %d, user_host: %s\n", cookie_id, user_host.data());
response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id)));
response.addCookie(session->getLoginCookie());
}
}
%>

View File

@ -5,10 +5,13 @@
<%@ page form="true" %>
<%@ page compressed="true" %>
<%!
enum PageState {
PAGE_ASK,
PAGE_SHOW_PUBKEY
}
enum PageState
{
PAGE_ASK,
PAGE_SHOW_PUBKEY,
PAGE_ERROR
};
%>
<%%
@ -40,6 +43,13 @@
if(savePassphraseChoice == "yes") {
savePassphrase = true;
}
if(!mSession->generateKeys(savePrivkey, savePassphrase)) {
hasErrors = true;
} else if(mSession->getSessionState() >= SESSION_STATE_KEY_PAIR_GENERATED) {
state = PAGE_SHOW_PUBKEY;
} else {
state = PAGE_ERROR;
}
}
}
%>
@ -110,7 +120,18 @@ label:not(.grd_radio_label) {
<input class="grd_bn_succeed" type="submit" value="Speichern">
</form>
<% } else if(state == PAGE_SHOW_PUBKEY) { %>
<div class="grd_text">
<p>Je nach Auswahl werden deine Daten nun verschl&uuml;sselt und gespeichert. </p>
<p>Deine Gradido Adresse (Hex): </p>
<p class="grd_textarea">
<%= mSession->getUser()->getPublicKeyHex() %>
</p>
<a class="grd_bn" href="../">Zur&uuml;ck zur Startseite</a>
</div>
<% } else if(state == PAGE_ERROR) { %>
<div class="grd_text">
<p>Ein Fehler trat auf, bitte versuche es erneut oder wende dich an den Server-Admin</p>
</div>
<% } %>
</div>
</body>