mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
adding many new files, mostly from old projects, register handling with validation, loading and connect to mysql
This commit is contained in:
parent
e7ca744da0
commit
f7744ee2c1
@ -8,19 +8,28 @@ include_directories(
|
||||
"dependencies"
|
||||
"dependencies/tinf/src/"
|
||||
"dependencies/iroha-ed25519/include"
|
||||
#"dependencies/mariadb-connector-c/build/include"
|
||||
#"dependencies/mariadb-connector-c/include"
|
||||
"import/mariadb/include"
|
||||
)
|
||||
|
||||
FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h")
|
||||
FILE(GLOB HTTPInterface "src/cpp/HTTPInterface/*.h" "src/cpp/HTTPInterface/*.cpp")
|
||||
FILE(GLOB SINGLETON_MANAGER "src/cpp/SingletonManager/*.h" "src/cpp/SingletonManager/*.cpp")
|
||||
FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp")
|
||||
FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp")
|
||||
FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h")
|
||||
SET(LOCAL_SRCS ${TINF} ${MAIN} ${HTTPInterface} ${CRYPTO})
|
||||
FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/Poco/*.h")
|
||||
SET(LOCAL_SRCS ${TINF} ${MAIN} ${HTTPInterface} ${CRYPTO} ${MODEL} ${SINGLETON_MANAGER} ${MYSQL})
|
||||
aux_source_directory("src/cpp" LOCAL_SRCS)
|
||||
|
||||
if(MSVC)
|
||||
# src
|
||||
source_group("tinf" FILES ${TINF})
|
||||
source_group("crypto" FILES ${CRYPTO})
|
||||
source_group("model" FILES ${MODEL})
|
||||
source_group("mysql" FILES ${MYSQL})
|
||||
source_group("SingletonManager" FILES ${SINGLETON_MANAGER})
|
||||
source_group("HTTP-Interface" FILES ${HTTPInterface})
|
||||
|
||||
endif(MSVC)
|
||||
@ -28,16 +37,28 @@ endif(MSVC)
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
#add_subdirectory("dependencies/curl")
|
||||
#add_subdirectory("dependencies/mariadb-connector-c")
|
||||
|
||||
|
||||
add_executable(Gradido_LoginServer ${LOCAL_SRCS})
|
||||
|
||||
if(WIN32)
|
||||
|
||||
find_library(MYSQL_LIBRARIES mariadbclient.lib PATHS "import/mariadb/lib/release")
|
||||
#find_library(MYSQL_LIBRARIES_DEBUG mariadbclient.lib PATHS "import/mariadb/lib/debug")
|
||||
find_library(MARIADB_CLIENT_DEBUG mariadbclient PATHS "dependencies/mariadb-connector-c/build/libmariadb/Debug" REQUIRED)
|
||||
find_library(IROHA_ED25519 ed25519 PATHS "dependencies/iroha-ed25519/build/Debug" REQUIRED)
|
||||
set(MYSQL_INCLUDE_DIR "import/mariadb/include")
|
||||
|
||||
else(WIN32)
|
||||
|
||||
endif(WIN32)
|
||||
|
||||
target_link_libraries(Gradido_LoginServer ${CONAN_LIBS} ${IROHA_ED25519})
|
||||
|
||||
target_link_libraries(Gradido_LoginServer ${CONAN_LIBS} ${IROHA_ED25519} ${MARIADB_CLIENT})
|
||||
if(WIN32)
|
||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi)
|
||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${MARIADB_CLIENT_DEBUG} Shlwapi)
|
||||
else(WIN32)
|
||||
endif(WIN32)
|
||||
@ -6,3 +6,5 @@ protobuf/3.9.1@bincrafters/stable
|
||||
|
||||
[generators]
|
||||
cmake
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
#include "KeyPair.h"
|
||||
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define STR_BUFFER_SIZE 25
|
||||
|
||||
KeyPair::KeyPair()
|
||||
: mPrivateKey(nullptr), mSodiumSecret(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KeyPair::~KeyPair()
|
||||
{
|
||||
if (mPrivateKey) {
|
||||
delete mPrivateKey;
|
||||
}
|
||||
if (mSodiumSecret) {
|
||||
delete mSodiumSecret;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyPair::generateFromPassphrase(const char* passphrase, Mnemonic* word_source)
|
||||
{
|
||||
|
||||
// libsodium doc: https://libsodium.gitbook.io/doc/advanced/hmac-sha2
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
|
||||
//crypto_auth_hmacsha512_keygen
|
||||
unsigned long word_indices[PHRASE_WORD_COUNT];
|
||||
|
||||
//DHASH key = DRMakeStringHash(passphrase);
|
||||
size_t pass_phrase_size = strlen(passphrase);
|
||||
char acBuffer[STR_BUFFER_SIZE]; memset(acBuffer, 0, STR_BUFFER_SIZE);
|
||||
size_t buffer_cursor = 0;
|
||||
// get word indices for hmac key
|
||||
unsigned char word_cursor = 0;
|
||||
for (size_t i = 0; i < pass_phrase_size; i++) {
|
||||
if (passphrase[i] == ' ') {
|
||||
word_indices[word_cursor] = word_source->getWordIndex(acBuffer);
|
||||
|
||||
word_cursor++;
|
||||
memset(acBuffer, 0, STR_BUFFER_SIZE);
|
||||
buffer_cursor = 0;
|
||||
}
|
||||
else {
|
||||
acBuffer[buffer_cursor++] = passphrase[i];
|
||||
}
|
||||
|
||||
}
|
||||
sha_context state;
|
||||
|
||||
unsigned char hash[SHA_512_SIZE];
|
||||
//crypto_auth_hmacsha512_state state;
|
||||
size_t word_index_size = sizeof(word_indices);
|
||||
//crypto_auth_hmacsha512_init(&state, (unsigned char*)word_indices, sizeof(word_indices));
|
||||
sha512_init(&state);
|
||||
sha512_update(&state, (unsigned char*)word_indices, sizeof(word_indices));
|
||||
sha512_update(&state, (unsigned char*)passphrase, pass_phrase_size);
|
||||
//crypto_auth_hmacsha512_update(&state, (unsigned char*)passphrase, pass_phrase_size);
|
||||
sha512_final(&state, hash);
|
||||
//crypto_auth_hmacsha512_final(&state, hash);
|
||||
|
||||
|
||||
//ed25519_create_keypair(public_key, private_key, hash);
|
||||
private_key_t prv_key_t;
|
||||
memcpy(prv_key_t.data, hash, 32);
|
||||
public_key_t pbl_key_t;
|
||||
ed25519_derive_public_key(&prv_key_t, &pbl_key_t);
|
||||
|
||||
|
||||
//memcpy(private_key, prv_key_t.data, 32);
|
||||
if (mPrivateKey) {
|
||||
delete mPrivateKey;
|
||||
}
|
||||
mPrivateKey = new ObfusArray(ed25519_privkey_SIZE, prv_key_t.data);
|
||||
memcpy(mPublicKey, pbl_key_t.data, ed25519_pubkey_SIZE);
|
||||
|
||||
unsigned char sodium_secret[crypto_sign_SECRETKEYBYTES];
|
||||
|
||||
crypto_sign_seed_keypair(mSodiumPublic, sodium_secret, *mPrivateKey);
|
||||
|
||||
if(mSodiumSecret) {
|
||||
delete mSodiumSecret;
|
||||
}
|
||||
mSodiumSecret = new ObfusArray(crypto_sign_SECRETKEYBYTES, sodium_secret);
|
||||
|
||||
// using
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
#ifndef GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR
|
||||
#define GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR
|
||||
|
||||
#include "Obfus_array.h"
|
||||
#include "mnemonic.h"
|
||||
|
||||
#include "ed25519/ed25519.h"
|
||||
#include <sodium.h>
|
||||
|
||||
class KeyPair
|
||||
{
|
||||
public:
|
||||
KeyPair();
|
||||
~KeyPair();
|
||||
|
||||
bool generateFromPassphrase(const char* passphrase, Mnemonic* word_source);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
ObfusArray* mPrivateKey;
|
||||
ObfusArray* mSodiumSecret;
|
||||
unsigned char mPublicKey[ed25519_pubkey_SIZE];
|
||||
unsigned char mSodiumPublic[crypto_sign_PUBLICKEYBYTES];
|
||||
};
|
||||
|
||||
#endif //GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR
|
||||
@ -0,0 +1,28 @@
|
||||
#include "Obfus_array.h"
|
||||
#include <sodium.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
|
||||
ObfusArray::ObfusArray(size_t size, const unsigned char * data)
|
||||
: m_arraySize(0), m_offsetSize(0), m_dataSize(size), m_Data(nullptr)
|
||||
{
|
||||
m_arraySize = randombytes_random() % (int)roundf(size + size*0.25f);
|
||||
m_Data = (unsigned char*)malloc(m_arraySize);
|
||||
m_offsetSize = randombytes_random() % (int)roundf((m_arraySize - m_dataSize) * 0.8f);
|
||||
|
||||
for (size_t i = 0; i < (size_t)floorf(m_arraySize / 4.0f); i++) {
|
||||
uint32_t* d = (uint32_t*)m_Data[i];
|
||||
*d = randombytes_random();
|
||||
}
|
||||
uint32_t* d = (uint32_t*)(m_Data + (m_arraySize - 4));
|
||||
*d = randombytes_random();
|
||||
|
||||
memcpy(&m_Data[m_offsetSize], data, size);
|
||||
}
|
||||
|
||||
ObfusArray::~ObfusArray()
|
||||
{
|
||||
if (m_Data) {
|
||||
free(m_Data);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
#ifndef GRADIDO_LOGIN_SERVER_CRYPTO_OBFUS_ARRAY
|
||||
#define GRADIDO_LOGIN_SERVER_CRYPTO_OBFUS_ARRAY
|
||||
|
||||
|
||||
|
||||
class ObfusArray
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_arraySize;
|
||||
size_t m_offsetSize;
|
||||
size_t m_dataSize;
|
||||
unsigned char* m_Data;
|
||||
};
|
||||
|
||||
#endif //GRADIDO_LOGIN_SERVER_CRYPTO_OBFUS_ARRAY
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "DRHashList.h"
|
||||
|
||||
#define PHRASE_WORD_COUNT 24
|
||||
|
||||
|
||||
class Mnemonic
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
#include "Gradido_LoginServer.h"
|
||||
#include "ServerConfig.h"
|
||||
#include "HTTPInterface/PageRequestHandlerFactory.h"
|
||||
|
||||
|
||||
#include "SingletonManager/ConnectionManager.h"
|
||||
#include "SingletonManager/SessionManager.h"
|
||||
|
||||
#include "Poco/Util/HelpFormatter.h"
|
||||
#include "Poco/Net/ServerSocket.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "MySQL/Poco/Connector.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
@ -65,6 +71,22 @@ int Gradido_LoginServer::main(const std::vector<std::string>& args)
|
||||
{
|
||||
unsigned short port = (unsigned short)config().getInt("HTTPServer.port", 9980);
|
||||
|
||||
// load word lists
|
||||
ServerConfig::loadMnemonicWordLists();
|
||||
|
||||
// load up connection configs
|
||||
// register MySQL connector
|
||||
Poco::Data::MySQL::Connector::registerConnector();
|
||||
//Poco::Data::MySQL::Connector::KEY;
|
||||
auto conn = ConnectionManager::getInstance();
|
||||
//conn->setConnection()
|
||||
conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_LOGIN_SERVER);
|
||||
conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_PHP_SERVER);
|
||||
|
||||
SessionManager::getInstance()->init();
|
||||
// put urandom on linux servers
|
||||
//srand();
|
||||
|
||||
// set-up a server socket
|
||||
Poco::Net::ServerSocket svs(port);
|
||||
// set-up a HTTPServer instance
|
||||
|
||||
@ -27,7 +27,14 @@ void HandleFileRequest::handleRequest(Poco::Net::HTTPServerRequest& request, Poc
|
||||
}
|
||||
std::string path = "data" + uri;
|
||||
printf("file path: %s\n", path.data());
|
||||
response.sendFile(path, mediaType);
|
||||
try {
|
||||
response.sendFile(path, mediaType);
|
||||
}
|
||||
catch (...) {
|
||||
std::ostream& _responseStream = response.send();
|
||||
_responseStream << "Error, file not found";
|
||||
|
||||
}
|
||||
/*
|
||||
bool _compressResponse(request.hasToken("Accept-Encoding", "gzip"));
|
||||
if (_compressResponse) response.set("Content-Encoding", "gzip");
|
||||
|
||||
@ -1 +1,31 @@
|
||||
#include "ServerConfig.h"
|
||||
#include "ServerConfig.h"
|
||||
#include "Crypto/mnemonic_german.h"
|
||||
#include "Crypto/mnemonic_bip0039.h"
|
||||
|
||||
namespace ServerConfig {
|
||||
Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
|
||||
|
||||
void loadMnemonicWordLists()
|
||||
{
|
||||
for (int i = 0; i < MNEMONIC_MAX; i++) {
|
||||
int iResult = 0;
|
||||
switch (i) {
|
||||
case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER:
|
||||
iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german, g_mnemonic_german_original_size, g_mnemonic_german_compressed_size);
|
||||
if (iResult) {
|
||||
printf("[%s] error init german mnemonic set, error nr: %d\n", __FUNCTION__, iResult);
|
||||
//return -1;
|
||||
}
|
||||
break;
|
||||
case MNEMONIC_BIP0039_SORTED_ORDER:
|
||||
iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_bip0039, g_mnemonic_bip0039_original_size, g_mnemonic_bip0039_compressed_size);
|
||||
if (iResult) {
|
||||
printf("[%s] error init bip0039 mnemonic set, error nr: %d\n", __FUNCTION__, iResult);
|
||||
|
||||
}
|
||||
break;
|
||||
default: printf("[%s] unknown MnemonicType\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
#include "Crypto/mnemonic.h"
|
||||
|
||||
namespace ServerConfig {
|
||||
|
||||
enum Mnemonic_Types {
|
||||
MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER,
|
||||
MNEMONIC_BIP0039_SORTED_ORDER,
|
||||
MNEMONIC_MAX
|
||||
};
|
||||
|
||||
extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX];
|
||||
|
||||
void loadMnemonicWordLists();
|
||||
}
|
||||
@ -1,405 +1,65 @@
|
||||
#include "ConnectionManager.h"
|
||||
#include "../Connections/MysqlConnection.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
ConnectThread::ConnectThread(ConnectionManager* parent)
|
||||
: Thread(true), initMysqlThread(false), mParent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConnectThread::~ConnectThread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ConnectThread::ThreadFunction()
|
||||
{
|
||||
if (!initMysqlThread) {
|
||||
if(mysql_thread_init()) {
|
||||
printf("error by calling mysql thread init\n");
|
||||
}
|
||||
initMysqlThread = true;
|
||||
}
|
||||
mDataMutex.lock();
|
||||
|
||||
// clean up not longer used connections
|
||||
while (mConnectionWaitingOnDestroy.size() > 0) {
|
||||
auto con = mConnectionWaitingOnDestroy.front();
|
||||
mConnectionWaitingOnDestroy.pop();
|
||||
mDataMutex.unlock();
|
||||
delete con;
|
||||
mDataMutex.lock();
|
||||
}
|
||||
|
||||
// creating new connections
|
||||
while(mConnectionsWaitingOnConnectCall.size() > 0) {
|
||||
auto con = mConnectionsWaitingOnConnectCall.front();
|
||||
mConnectionsWaitingOnConnectCall.pop();
|
||||
mDataMutex.unlock();
|
||||
if(!con->connect()) {
|
||||
//printf("[ConnectThread::ThreadFunction] error connecting with type: %s\n",
|
||||
//Connection::getConnectionTypeName(con->getType()));
|
||||
};
|
||||
mParent->markAsAvailable(con);
|
||||
mParent->condSignal();
|
||||
mDataMutex.lock();
|
||||
}
|
||||
mDataMutex.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConnectThread::cleanUpInThread()
|
||||
{
|
||||
if (initMysqlThread) {
|
||||
mysql_thread_end();
|
||||
initMysqlThread = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectThread::addConnectionConnect(Connection* connection)
|
||||
{
|
||||
mDataMutex.lock();
|
||||
mConnectionsWaitingOnConnectCall.push(connection);
|
||||
mDataMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void ConnectThread::addConnectionDestroy(Connection* connection)
|
||||
{
|
||||
mDataMutex.lock();
|
||||
mConnectionWaitingOnDestroy.push(connection);
|
||||
mDataMutex.unlock();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// ConnectionManager
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
ConnectionManager* ConnectionManager::getInstance()
|
||||
{
|
||||
static ConnectionManager only;
|
||||
return &only;
|
||||
}
|
||||
|
||||
|
||||
ConnectionManager::ConnectionManager()
|
||||
: mConnectionEstablishThread(this), mInitalized(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConnectionManager::~ConnectionManager()
|
||||
{
|
||||
if (mInitalized) {
|
||||
deinitalize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionManager::deinitalize()
|
||||
bool ConnectionManager::setConnectionsFromConfig(const Poco::Util::LayeredConfiguration& config, ConnectionType type)
|
||||
{
|
||||
lock();
|
||||
mInitalized = false;
|
||||
unlock();
|
||||
|
||||
mConnectionEstablishThread.exitThread();
|
||||
|
||||
for (auto it = mConnections.begin(); it != mConnections.end(); it++)
|
||||
{
|
||||
auto freeConnections = it->second->mFreeConnections;
|
||||
while (freeConnections.size() > 0) {
|
||||
delete freeConnections.top();
|
||||
freeConnections.pop();
|
||||
}
|
||||
auto cfg_ptr = it->second->cfg_ptr;
|
||||
cfg_ptr->removeRef();
|
||||
if (cfg_ptr->getRef() <= 0) {
|
||||
delete cfg_ptr;
|
||||
}
|
||||
}
|
||||
mConnections.clear();
|
||||
mInitalized = false;
|
||||
|
||||
}
|
||||
|
||||
bool ConnectionManager::addConnectionPool(DRSimpleResourcePtr<Config>* cfg_ptr)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
printf("[ConnectionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
if ((*cfg_ptr)->name == std::string("")) {
|
||||
// getConnectionTypeName
|
||||
ConnectionConfig* cfg = static_cast<ConnectionConfig*>((Config*)(*cfg_ptr));
|
||||
(*cfg_ptr)->name = "Connect_";
|
||||
(*cfg_ptr)->name += Connection::getConnectionTypeName(cfg->type);
|
||||
if (cfg->type == CONN_MYSQL) {
|
||||
DBConnectionConfig* db_cfg = static_cast<DBConnectionConfig*>((Config*)(*cfg_ptr));
|
||||
(*cfg_ptr)->name += "_";
|
||||
(*cfg_ptr)->name += db_cfg->db;
|
||||
}
|
||||
}
|
||||
|
||||
DHASH id = (*cfg_ptr)->getHash();
|
||||
|
||||
// check if collision
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
printf("[ConnectionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = mConnections.find(id);
|
||||
if (it != mConnections.end()) {
|
||||
unlock();
|
||||
if ((*it->second->cfg_ptr)->name == (*cfg_ptr)->name) {
|
||||
printf("connection %s already in there: %s\n", (*cfg_ptr)->name.data(), __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
printf("Hash Collision detected with %s and %s in %s\n",
|
||||
(*cfg_ptr)->name.data(), (*it->second->cfg_ptr)->name.data(), __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
// try to create connection object
|
||||
|
||||
auto con = createConnection(cfg_ptr);
|
||||
if (!con) {
|
||||
printf("couldn't create connection with cfg: %s\n", (*cfg_ptr)->name.data());
|
||||
return false;
|
||||
}
|
||||
// create pool
|
||||
auto pool = new ConnectionPool;
|
||||
//pool->cfg = cfg;
|
||||
pool->cfg_ptr = cfg_ptr;
|
||||
pool->cfg_ptr->addRef();
|
||||
printf("create new connection pool for connection: %s\n", (*cfg_ptr)->name.data());
|
||||
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
printf("[ConnectionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
mConnections.insert(std::pair<int, ConnectionPool*>(id, pool));
|
||||
|
||||
unlock();
|
||||
|
||||
// start connection
|
||||
if(con) {
|
||||
mConnectionEstablishThread.addConnectionConnect(con);
|
||||
mConnectionEstablishThread.condSignal();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConnectionManager::markAsAvailable(Connection* con)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return false;
|
||||
}
|
||||
|
||||
DHASH id = con->getHash();
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = mConnections.find(id);
|
||||
if (it == mConnections.end()) {
|
||||
addError(new ParamError(__FUNCTION__, "couldn't find connection pool for id:", id));
|
||||
delete con;
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
else if (!con->isOpen()) {
|
||||
if (con->errorCount() > 0) {
|
||||
it->second->mErrorConnectingAttempts++;
|
||||
addError(new ParamError(__FUNCTION__, "connection wasn't open and has errors, failed connecting attempt: ", it->second->mErrorConnectingAttempts));
|
||||
getErrors(con);
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
it->second->mFreeConnections.push(con);
|
||||
checkTime(it->second);
|
||||
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConnectionManager::checkTime(ConnectionPool* pool)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto currentSize = pool->mFreeConnections.size();
|
||||
// (re)start timer if at least three unused connections reached
|
||||
if (pool->mFreeConnectionsCount < 3 && currentSize >= 3) {
|
||||
pool->mConnectionFreeTimeout.reset();
|
||||
}
|
||||
if (currentSize >= 3 && pool->mConnectionFreeTimeout.seconds() > UNUSED_CONNECTION_TIMEOUT_SECONDS) {
|
||||
// clean one connection and reset timer
|
||||
auto con = pool->mFreeConnections.top();
|
||||
pool->mFreeConnections.pop();
|
||||
currentSize = pool->mFreeConnections.size();
|
||||
|
||||
mConnectionEstablishThread.addConnectionDestroy(con);
|
||||
mConnectionEstablishThread.condSignal();
|
||||
pool->mConnectionFreeTimeout.reset();
|
||||
|
||||
}
|
||||
pool->mFreeConnectionsCount = currentSize;
|
||||
}
|
||||
|
||||
Connection* ConnectionManager::createConnection(DRSimpleResourcePtr<Config>* cfg_ptr)
|
||||
{
|
||||
|
||||
auto con_cfg = static_cast<ConnectionConfig*>((Config*)(*cfg_ptr));
|
||||
switch (con_cfg->type) {
|
||||
case CONN_DEFAULT: return new Connection(cfg_ptr);
|
||||
case CONN_MYSQL: return new MysqlConnection(cfg_ptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ConnectionManager::isConnectionPool(DHASH id)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return false;
|
||||
}
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return false;
|
||||
}
|
||||
auto it = mConnections.find(id);
|
||||
if (it == mConnections.end()) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
Connection* ConnectionManager::getConnection(DHASH id)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return nullptr;
|
||||
}
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
unlock();
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return nullptr;
|
||||
}
|
||||
auto it = mConnections.find(id);
|
||||
if (it == mConnections.end()) {
|
||||
addError(new ParamError(__FUNCTION__, "couldn't find connection pool for id:", id));
|
||||
unlock();
|
||||
return nullptr;
|
||||
}
|
||||
Connection* result = nullptr;
|
||||
auto pool = it->second;
|
||||
if (pool->mFreeConnections.size() > 0) {
|
||||
result = pool->mFreeConnections.top();
|
||||
pool->mFreeConnections.pop();
|
||||
checkTime(pool);
|
||||
}
|
||||
unlock();
|
||||
// if pool is empty, create new connection
|
||||
if (pool->mFreeConnections.size() == 0) {
|
||||
auto con = createConnection(pool->cfg_ptr);
|
||||
if (!con) {
|
||||
addError(new ParamError(__FUNCTION__, "couldn't create connection with cfg:", (*pool->cfg_ptr)->name));
|
||||
return nullptr;
|
||||
}
|
||||
mConnectionEstablishThread.addConnectionConnect(con);
|
||||
mConnectionEstablishThread.condSignal();
|
||||
}
|
||||
|
||||
// we have get a connection, return
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
// we haven't get a connection, so we wait
|
||||
std::unique_lock<std::mutex> lk(mConnectCondMutex);
|
||||
mConnectCond.wait(lk, [] {return 1; });
|
||||
lock();
|
||||
if (!mInitalized) {
|
||||
unlock();
|
||||
addError(new Error(__FUNCTION__, "not initialized any more"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pool->mFreeConnections.size() == 0) {
|
||||
addError(new Error(__FUNCTION__, "no free connection after wait :/"));
|
||||
unlock();
|
||||
return nullptr;
|
||||
}
|
||||
result = pool->mFreeConnections.top();
|
||||
pool->mFreeConnections.pop();
|
||||
checkTime(pool);
|
||||
unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
// int ConnectionManager::connectMysql(
|
||||
// const char* db,
|
||||
// const char* username /* = "root"*/,
|
||||
// const char* pwd /* = nullptr*/,
|
||||
// const char* url /* = "127.0.0.1" */,
|
||||
// int port /*= 3306*/ )
|
||||
// {
|
||||
//mysqlx://mike:s3cr3t!@localhost:13009
|
||||
/*std::stringstream urlStream;
|
||||
urlStream << username;
|
||||
if (pwd) {
|
||||
urlStream << ":" << pwd;
|
||||
}
|
||||
urlStream << "@" << url;
|
||||
urlStream << ":" << port;
|
||||
*/
|
||||
/*
|
||||
mysqlx::Session* mysqlSession = nullptr;
|
||||
try {
|
||||
mysqlSession = new mysqlx::Session(url, port, username, pwd, db);
|
||||
}
|
||||
catch (const char* e) {
|
||||
printf("[ConnectionManager::connectMysql] catch e: %s\n", e);
|
||||
return -1;
|
||||
}
|
||||
phpServer.url = 127.0.0.1:80/gradido_php
|
||||
phpServer.db.host = localhost
|
||||
phpServer.db.name = cake_gradido_node
|
||||
phpServer.db.user = root
|
||||
phpServer.db.password =
|
||||
phpServer.db.port = 3306
|
||||
|
||||
mWorkingMutex.lock();
|
||||
loginServer.url =
|
||||
loginServer.db.host = localhost
|
||||
loginServer.db.name = gradido_login
|
||||
loginServer.db.user = gradido_login
|
||||
loginServer.db.password = hj2-sk28sKsj8(u_ske
|
||||
loginServer.db.port = 3306
|
||||
*/
|
||||
|
||||
int handle = mMysqlConnections.size();
|
||||
mMysqlConnections.insert(std::pair<int, mysqlx::Session*>(handle, mysqlSession));
|
||||
|
||||
return handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
mysqlx::Session* ConnectionManager::getMysqlConnection(int handle)
|
||||
{
|
||||
mysqlx::Session* session = nullptr;
|
||||
mWorkingMutex.lock();
|
||||
auto it = mMysqlConnections.find(handle);
|
||||
if (it != mMysqlConnections.end()) {
|
||||
session = it->second;
|
||||
/*
|
||||
connectionString example: host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true
|
||||
*/
|
||||
std::string firstKeyPart;
|
||||
switch (type) {
|
||||
case CONNECTION_MYSQL_LOGIN_SERVER: firstKeyPart = "loginServer"; break;
|
||||
case CONNECTION_MYSQL_PHP_SERVER: firstKeyPart = "phpServer"; break;
|
||||
default: addError(new Error(__FUNCTION__, "type invalid")); return false;
|
||||
}
|
||||
mWorkingMutex.unlock();
|
||||
return session;
|
||||
}
|
||||
*/
|
||||
std::stringstream dbConfig;
|
||||
dbConfig << "host=" << config.getString(firstKeyPart + ".db.host", "localhost") << ";";
|
||||
dbConfig << "port=" << config.getInt(firstKeyPart + ".db.port", 3306) << ";";
|
||||
std::string dbName = config.getString(firstKeyPart + ".db.name", "");
|
||||
if (dbName == "") {
|
||||
addError(new Error(__FUNCTION__, "no db name given"));
|
||||
return false;
|
||||
}
|
||||
dbConfig << "db=" << dbName << ";";
|
||||
dbConfig << "user=" << config.getString(firstKeyPart + ".db.user", "root") << ";";
|
||||
dbConfig << "password=" << config.getString(firstKeyPart + ".db.password", "") << ";";
|
||||
dbConfig << "auto-reconnect=true";
|
||||
|
||||
setConnection(dbConfig.str(), type);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -1,104 +1,57 @@
|
||||
/*!
|
||||
*
|
||||
* \author: einhornimmond
|
||||
*
|
||||
* \date: 28.02.19
|
||||
*
|
||||
* \brief: manage Connections like mysql or socket connections to another server
|
||||
*/
|
||||
#ifndef GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CONNECTION_MANAGER_INCLUDE
|
||||
#define GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CONNECTION_MANAGER_INCLUDE
|
||||
|
||||
#ifndef DR_LUA_WEB_MODULE_CONNECTION_MANAGER_H
|
||||
#define DR_LUA_WEB_MODULE_CONNECTION_MANAGER_H
|
||||
#include "../Crypto/DRHashList.h"
|
||||
#include <string>
|
||||
|
||||
#include "../LuaWebModule.h"
|
||||
#include "../Connections/Connection.h"
|
||||
#include "../CoreLib/Profiler.h"
|
||||
#include "../CoreLib/Thread.h"
|
||||
#include "../CoreLib/DRResourcePtr.h"
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include "Poco/Util/LayeredConfiguration.h"
|
||||
#include "Poco/Data/SessionPoolContainer.h"
|
||||
#include "Poco/Data/MySQL/Connector.h"
|
||||
|
||||
#define UNUSED_CONNECTION_TIMEOUT_SECONDS 2
|
||||
#include "../Model/ErrorList.h"
|
||||
|
||||
class ConnectionManager;
|
||||
|
||||
class ConnectThread : public Thread
|
||||
{
|
||||
public:
|
||||
ConnectThread(ConnectionManager* parent);
|
||||
virtual ~ConnectThread();
|
||||
|
||||
void addConnectionConnect(Connection* connection);
|
||||
void addConnectionDestroy(Connection* connection);
|
||||
|
||||
protected:
|
||||
std::mutex mDataMutex;
|
||||
std::queue<Connection*> mConnectionsWaitingOnConnectCall;
|
||||
std::queue<Connection*> mConnectionWaitingOnDestroy;
|
||||
|
||||
virtual int ThreadFunction();
|
||||
virtual void cleanUpInThread();
|
||||
|
||||
bool initMysqlThread;
|
||||
ConnectionManager* mParent;
|
||||
enum ConnectionType {
|
||||
CONNECTION_MYSQL_LOGIN_SERVER,
|
||||
CONNECTION_MYSQL_PHP_SERVER,
|
||||
CONNECTION_MAX
|
||||
};
|
||||
|
||||
|
||||
class ConnectionManager : public ErrorList
|
||||
{
|
||||
friend ConnectThread;
|
||||
|
||||
public:
|
||||
public:
|
||||
~ConnectionManager();
|
||||
|
||||
static ConnectionManager* getInstance();
|
||||
|
||||
bool addConnectionPool(DRSimpleResourcePtr<Config>* cfg);
|
||||
bool markAsAvailable(Connection* con);
|
||||
bool setConnectionsFromConfig(const Poco::Util::LayeredConfiguration& config, ConnectionType type);
|
||||
|
||||
bool isConnectionPool(DHASH id);
|
||||
|
||||
static Connection* createConnection(DRSimpleResourcePtr<Config>* cfg);
|
||||
inline Connection* getConnection(const char* name) { return getConnection(DRMakeStringHash(name)); }
|
||||
//! \param connectionString example: host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true
|
||||
inline void setConnection(std::string connectionString, ConnectionType type) {
|
||||
if (type == CONNECTION_MYSQL_LOGIN_SERVER || CONNECTION_MYSQL_PHP_SERVER) {
|
||||
mSessionPoolNames[type] = Poco::Data::Session::uri(Poco::Data::MySQL::Connector::KEY, connectionString);
|
||||
mSessionPools.add(Poco::Data::MySQL::Connector::KEY, connectionString);
|
||||
//mConnectionData[type] = connectionString;
|
||||
}
|
||||
}
|
||||
|
||||
Connection* getConnection(DHASH id);
|
||||
|
||||
inline void lock() { mWorkingMutex.lock(); }
|
||||
inline void unlock() { mWorkingMutex.unlock(); }
|
||||
|
||||
void deinitalize();
|
||||
inline Poco::Data::Session getConnection(ConnectionType type) {
|
||||
switch (type)
|
||||
{
|
||||
case CONNECTION_MYSQL_LOGIN_SERVER:
|
||||
break;
|
||||
case CONNECTION_MYSQL_PHP_SERVER:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ConnectionManager();
|
||||
|
||||
struct ConnectionPool {
|
||||
ConnectionPool(): mFreeConnectionsCount(0), mErrorConnectingAttempts(0){}
|
||||
DRSimpleResourcePtr<Config>* cfg_ptr;
|
||||
std::stack<Connection*> mFreeConnections;
|
||||
// used to measure how long at least two connections not used
|
||||
Profiler mConnectionFreeTimeout;
|
||||
// only for calculating connection timeout
|
||||
int mFreeConnectionsCount;
|
||||
|
||||
int mErrorConnectingAttempts;
|
||||
};
|
||||
|
||||
void checkTime(ConnectionPool* pool);
|
||||
|
||||
// connection Pool
|
||||
std::map<int, ConnectionPool*> mConnections;
|
||||
|
||||
// access mutex
|
||||
std::mutex mWorkingMutex;
|
||||
|
||||
inline void condSignal() { mConnectCond.notify_one(); }
|
||||
|
||||
// creating and destroying connections thread
|
||||
ConnectThread mConnectionEstablishThread;
|
||||
std::condition_variable mConnectCond;
|
||||
std::mutex mConnectCondMutex;
|
||||
|
||||
bool mInitalized;
|
||||
private:
|
||||
std::string mSessionPoolNames[CONNECTION_MAX];
|
||||
Poco::Data::SessionPoolContainer mSessionPools;
|
||||
};
|
||||
|
||||
#endif //DR_LUA_WEB_MODULE_CONNECTION_MANAGER_H
|
||||
#endif //GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CONNECTION_MANAGER_INCLUDE
|
||||
@ -15,8 +15,8 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include "../Error/Error.h"
|
||||
#include "../CoreLib/DRHash.hpp"
|
||||
#include "../Model/Error.h"
|
||||
#include "../Crypto/DRHash.h"
|
||||
|
||||
class ErrorManager : public IErrorCollection
|
||||
{
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#include "SessionManager.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
|
||||
SessionManager* SessionManager::getInstance()
|
||||
{
|
||||
static SessionManager only;
|
||||
@ -7,7 +10,7 @@ SessionManager* SessionManager::getInstance()
|
||||
}
|
||||
|
||||
SessionManager::SessionManager()
|
||||
: mInitalized(true)
|
||||
: mInitalized(false)
|
||||
{
|
||||
|
||||
}
|
||||
@ -19,6 +22,26 @@ SessionManager::~SessionManager()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SessionManager::init()
|
||||
{
|
||||
mWorkingMutex.lock();
|
||||
for (int i = 0; i < VALIDATE_MAX; i++) {
|
||||
switch (i) {
|
||||
//case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("/^[a-zA-Z_ -]{3,}$/"); break;
|
||||
case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z]{3,}$"); 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;
|
||||
default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
mInitalized = true;
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionManager::deinitalize()
|
||||
{
|
||||
|
||||
@ -32,13 +55,26 @@ void SessionManager::deinitalize()
|
||||
delete it->second;
|
||||
}
|
||||
mRequestSessionMap.clear();
|
||||
|
||||
for (int i = 0; i < VALIDATE_MAX; i++) {
|
||||
delete mValidations[i];
|
||||
}
|
||||
|
||||
|
||||
mInitalized = false;
|
||||
mWorkingMutex.unlock();
|
||||
}
|
||||
|
||||
bool SessionManager::isValid(const std::string& subject, SessionValidationTypes validationType)
|
||||
{
|
||||
if (validationType >= VALIDATE_MAX) {
|
||||
return false;
|
||||
}
|
||||
return *mValidations[validationType] == subject;
|
||||
}
|
||||
|
||||
MysqlSession* SessionManager::getNewMysqlSession(int* handle)
|
||||
|
||||
Session* SessionManager::getNewSession(int* handle)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
@ -53,7 +89,7 @@ MysqlSession* SessionManager::getNewMysqlSession(int* handle)
|
||||
mEmptyRequestStack.pop();
|
||||
auto resultIt = mRequestSessionMap.find(local_handle);
|
||||
if (resultIt != mRequestSessionMap.end()) {
|
||||
MysqlSession* result = resultIt->second;
|
||||
Session* result = resultIt->second;
|
||||
mWorkingMutex.unlock();
|
||||
|
||||
if (handle) {
|
||||
@ -64,9 +100,23 @@ MysqlSession* SessionManager::getNewMysqlSession(int* handle)
|
||||
}
|
||||
else {
|
||||
// else create new RequestSession Object
|
||||
int newHandle = mRequestSessionMap.size();
|
||||
auto requestSession = new MysqlSession(newHandle);
|
||||
mRequestSessionMap.insert(std::pair<int, MysqlSession*>(newHandle, requestSession));
|
||||
// calculate random handle
|
||||
// check if already exist, if get new
|
||||
int newHandle = 0;
|
||||
int maxTrys = 0;
|
||||
do {
|
||||
newHandle = randombytes_random();
|
||||
maxTrys++;
|
||||
} while (mRequestSessionMap.find(newHandle) != mRequestSessionMap.end() && maxTrys < 100);
|
||||
|
||||
if (maxTrys >= 100 || 0 == newHandle) {
|
||||
printf("[SessionManager::%s] can't find new handle, have already: %d",
|
||||
__FUNCTION__, mRequestSessionMap.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto requestSession = new Session(newHandle);
|
||||
mRequestSessionMap.insert(std::pair<int, Session*>(newHandle, requestSession));
|
||||
mWorkingMutex.unlock();
|
||||
|
||||
if (handle) {
|
||||
@ -79,7 +129,7 @@ MysqlSession* SessionManager::getNewMysqlSession(int* handle)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SessionManager::releseMysqlSession(int requestHandleSession)
|
||||
bool SessionManager::releseSession(int requestHandleSession)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
@ -115,13 +165,13 @@ bool SessionManager::isExist(int requestHandleSession)
|
||||
return result;
|
||||
}
|
||||
|
||||
MysqlSession* SessionManager::getMysqlSession(int handle)
|
||||
Session* SessionManager::getSession(int handle)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
return nullptr;
|
||||
}
|
||||
MysqlSession* result = nullptr;
|
||||
Session* result = nullptr;
|
||||
mWorkingMutex.lock();
|
||||
auto it = mRequestSessionMap.find(handle);
|
||||
if (it != mRequestSessionMap.end()) {
|
||||
|
||||
@ -11,12 +11,22 @@
|
||||
#define DR_LUA_WEB_MODULE_SESSION_MANAGER_H
|
||||
|
||||
|
||||
#include "../Session/MysqlSession.h"
|
||||
#include "../Model/Session.h"
|
||||
|
||||
#include "Poco/RegularExpression.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
enum SessionValidationTypes {
|
||||
VALIDATE_NAME,
|
||||
VALIDATE_EMAIL,
|
||||
VALIDATE_PASSWORD,
|
||||
VALIDATE_PASSPHRASE,
|
||||
VALIDATE_MAX
|
||||
};
|
||||
|
||||
class SessionManager
|
||||
{
|
||||
public:
|
||||
@ -24,15 +34,19 @@ public:
|
||||
|
||||
static SessionManager* getInstance();
|
||||
|
||||
MysqlSession* getNewMysqlSession(int* handle = nullptr);
|
||||
inline bool releseMysqlSession(MysqlSession* requestSession) {
|
||||
return releseMysqlSession(requestSession->getHandle());
|
||||
Session* getNewSession(int* handle = nullptr);
|
||||
inline bool releseSession(Session* requestSession) {
|
||||
return releseSession(requestSession->getHandle());
|
||||
}
|
||||
bool releseMysqlSession(int requestHandleSession);
|
||||
bool releseSession(int requestHandleSession);
|
||||
bool isExist(int requestHandleSession);
|
||||
MysqlSession* getMysqlSession(int handle);
|
||||
Session* getSession(int handle);
|
||||
|
||||
bool init();
|
||||
void deinitalize();
|
||||
|
||||
bool isValid(const std::string& subject, SessionValidationTypes validationType);
|
||||
|
||||
protected:
|
||||
SessionManager();
|
||||
|
||||
@ -41,10 +55,13 @@ protected:
|
||||
std::mutex mWorkingMutex;
|
||||
|
||||
// sessions storage
|
||||
std::map<int, MysqlSession*> mRequestSessionMap;
|
||||
std::stack<int> mEmptyRequestStack;
|
||||
std::map<int, Session*> mRequestSessionMap;
|
||||
std::stack<int> mEmptyRequestStack;
|
||||
|
||||
bool mInitalized;
|
||||
|
||||
// validations
|
||||
Poco::RegularExpression* mValidations[VALIDATE_MAX];
|
||||
};
|
||||
|
||||
#endif //DR_LUA_WEB_MODULE_SESSION_MANAGER_H
|
||||
@ -19,11 +19,25 @@ std::string Error::getString()
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
std::string Error::getHtmlString()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << mFunctionName << ": " << mMessage << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ParamError::getString()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << mFunctionName << ": " << mMessage << " " << mParam << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
std::string ParamError::getHtmlString()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << mFunctionName << ": " << mMessage << " " << mParam << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@ -22,6 +22,7 @@ public:
|
||||
const char* getFunctionName() { return mFunctionName.data(); }
|
||||
const char* getMessage() { return mMessage.data(); }
|
||||
virtual std::string getString();
|
||||
virtual std::string getHtmlString();
|
||||
|
||||
protected:
|
||||
std::string mFunctionName;
|
||||
@ -44,6 +45,7 @@ public:
|
||||
}
|
||||
|
||||
virtual std::string getString();
|
||||
virtual std::string getHtmlString();
|
||||
protected:
|
||||
std::string mParam;
|
||||
};
|
||||
|
||||
@ -63,4 +63,20 @@ void ErrorList::printErrors()
|
||||
printf(error->getString().data());
|
||||
delete error;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ErrorList::getErrorsHtml()
|
||||
{
|
||||
std::string res;
|
||||
res = "<ul class='grd-no-style'>";
|
||||
while (mErrorStack.size() > 0) {
|
||||
auto error = mErrorStack.top();
|
||||
mErrorStack.pop();
|
||||
res += "<li class='grd-error'>";
|
||||
res += error->getHtmlString();
|
||||
res += "</li>";
|
||||
delete error;
|
||||
}
|
||||
res += "</ul>";
|
||||
return res;
|
||||
}
|
||||
@ -36,6 +36,7 @@ public:
|
||||
int getErrors(ErrorList* send);
|
||||
|
||||
void printErrors();
|
||||
std::string getErrorsHtml();
|
||||
|
||||
protected:
|
||||
std::stack<Error*> mErrorStack;
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#include "Session.h"
|
||||
#include "Poco/RegularExpression.h"
|
||||
#include "../SingletonManager/SessionManager.h"
|
||||
|
||||
Session::Session(int handle)
|
||||
: mHandleId(handle)
|
||||
@ -11,3 +13,37 @@ Session::~Session()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Session::reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Session::createUser(const std::string& name, const std::string& email, const std::string& password, const std::string& passphrase)
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
if (!sm->isValid(name, VALIDATE_NAME)) {
|
||||
addError(new Error("Vorname", "Bitte gebe einen Namen an. Mindestens 3 Zeichen, keine Sonderzeichen oder Zahlen."));
|
||||
return false;
|
||||
}
|
||||
if (!sm->isValid(email, VALIDATE_EMAIL)) {
|
||||
addError(new Error("E-Mail", "Bitte gebe eine gültige E-Mail Adresse an."));
|
||||
return false;
|
||||
}
|
||||
if (!sm->isValid(password, VALIDATE_PASSWORD)) {
|
||||
addError(new Error("Password", "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen"));
|
||||
return false;
|
||||
}
|
||||
if (passphrase.size() > 0 && !sm->isValid(passphrase, VALIDATE_PASSPHRASE)) {
|
||||
addError(new Error("Merksatz", "Der Merksatz ist nicht gültig, er besteht aus 24 Wörtern, mit Komma getrennt."));
|
||||
return false;
|
||||
}
|
||||
mSessionUser = new User(email.data(), name.data(), password.data(), passphrase.size() ? passphrase.data() : nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::loadUser(const std::string& email, const std::string& password)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -10,7 +10,8 @@
|
||||
#ifndef DR_LUA_WEB_MODULE_SESSION_SESSION_H
|
||||
#define DR_LUA_WEB_MODULE_SESSION_SESSION_H
|
||||
|
||||
#include "../Error/ErrorList.h"
|
||||
#include "ErrorList.h"
|
||||
#include "User.h"
|
||||
|
||||
class Session : public ErrorList
|
||||
{
|
||||
@ -18,11 +19,15 @@ public:
|
||||
Session(int handle);
|
||||
~Session();
|
||||
|
||||
bool createUser(const std::string& name, const std::string& email, const std::string& password, const std::string& passphrase);
|
||||
bool loadUser(const std::string& email, const std::string& password);
|
||||
|
||||
inline int getHandle() { return mHandleId; }
|
||||
virtual void reset() = 0;
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
int mHandleId;
|
||||
User* mSessionUser;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
#include "User.h"
|
||||
#include <sodium.h>
|
||||
#include "ed25519/ed25519.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
|
||||
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(mUser->getEmail(), 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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// *******************************************************************************
|
||||
|
||||
User::User(const char* email, const char* name, const char* password, const char* passphrase)
|
||||
: mEmail(email), mFirstName(name), mCryptoKey(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
User::User(const char* email, const char* password)
|
||||
: mEmail(email)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
User::~User()
|
||||
{
|
||||
if (mCryptoKey) {
|
||||
delete mCryptoKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string User::generateNewPassphrase(Mnemonic* word_source)
|
||||
{
|
||||
unsigned int random_indices[PHRASE_WORD_COUNT];
|
||||
unsigned int str_sizes[PHRASE_WORD_COUNT];
|
||||
unsigned int phrase_buffer_size = 0;
|
||||
|
||||
for (int i = 0; i < PHRASE_WORD_COUNT; i++) {
|
||||
random_indices[i] = randombytes_random() % 2048;
|
||||
str_sizes[i] = strlen(word_source->getWord(random_indices[i]));
|
||||
phrase_buffer_size += str_sizes[i];
|
||||
}
|
||||
phrase_buffer_size += PHRASE_WORD_COUNT + 1;
|
||||
|
||||
std::string phrase_buffer(phrase_buffer_size, '\0');
|
||||
int phrase_buffer_cursor = 0;
|
||||
|
||||
for (int i = 0; i < PHRASE_WORD_COUNT; i++) {
|
||||
memcpy(&phrase_buffer[phrase_buffer_cursor], word_source->getWord(random_indices[i]), str_sizes[i]);
|
||||
|
||||
phrase_buffer_cursor += str_sizes[i];
|
||||
phrase_buffer[phrase_buffer_cursor++] = ' ';
|
||||
}
|
||||
|
||||
|
||||
return phrase_buffer;
|
||||
}
|
||||
|
||||
void User::createCryptoKey(const char* username, const char* password)
|
||||
{
|
||||
|
||||
// TODO: put it in secure location
|
||||
static const unsigned char app_secret[] = { 0x21, 0xff, 0xbb, 0xc6, 0x16, 0xfe };
|
||||
|
||||
size_t username_size = strlen(username);
|
||||
size_t password_size = strlen(password);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char hash512_salt[SHA_512_SIZE]; // need at least crypto_pwhash_SALTBYTES 16U
|
||||
sha512_init(&context_sha512);
|
||||
sha512_update(&context_sha512, (const unsigned char*)username, username_size);
|
||||
sha512_update(&context_sha512, app_secret, 6);
|
||||
sha512_final(&context_sha512, hash512_salt);
|
||||
|
||||
unsigned char* key = (unsigned char *)malloc(crypto_box_SEEDBYTES); // 32U
|
||||
|
||||
if (crypto_pwhash(key, crypto_box_SEEDBYTES, password, password_size, hash512_salt, 2U, 8388608, 2) != 0) {
|
||||
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 ;
|
||||
}
|
||||
lock();
|
||||
mCryptoKey = new ObfusArray(crypto_box_SEEDBYTES, key);
|
||||
unlock();
|
||||
free(key);
|
||||
|
||||
// mCryptoKey
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
#ifndef GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE
|
||||
#define GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE
|
||||
|
||||
#include "../Crypto/KeyPair.h"
|
||||
#include <string>
|
||||
#include "ErrorList.h"
|
||||
#include "Poco/Thread.h"
|
||||
|
||||
class NewUser;
|
||||
|
||||
class User : public ErrorList
|
||||
{
|
||||
friend NewUser;
|
||||
public:
|
||||
// new user
|
||||
User(const char* email, const char* name, const char* password, const char* passphrase);
|
||||
// existing user
|
||||
User(const char* email, const char* password);
|
||||
|
||||
~User();
|
||||
|
||||
static std::string generateNewPassphrase(Mnemonic* word_source);
|
||||
|
||||
inline bool hasCryptoKey() { lock(); bool bRet = mCryptoKey != nullptr; unlock(); return bRet; }
|
||||
inline const char* getEmail() { return mEmail.data(); }
|
||||
|
||||
|
||||
protected:
|
||||
void createCryptoKey(const char* email, const char* password);
|
||||
|
||||
inline void lock() { mWorkingMutex->lock(); }
|
||||
inline void unlock() { mWorkingMutex->unlock(); }
|
||||
|
||||
private:
|
||||
std::string mEmail;
|
||||
std::string mFirstName;
|
||||
// crypto key as obfus array
|
||||
ObfusArray* mCryptoKey;
|
||||
|
||||
Poco::Mutex* mWorkingMutex;
|
||||
|
||||
};
|
||||
|
||||
class NewUser : public Poco::Runnable
|
||||
{
|
||||
public:
|
||||
NewUser(User* user, const char* password, const char* passphrase);
|
||||
~NewUser();
|
||||
|
||||
|
||||
virtual void run();
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
#endif //GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE
|
||||
@ -21,8 +21,8 @@
|
||||
<legend>Login</legend>
|
||||
<p>Bitte gebe deine Zugangsdaten ein um dich einzuloggen.</p>
|
||||
<p class="grd_small">
|
||||
<label for="login-username">Benutzernamen</label>
|
||||
<input id="login-username" type="text" name="login-username"/>
|
||||
<label for="login-email">E-Mail</label>
|
||||
<input id="login-email" type="text" name="login-email"/>
|
||||
</p>
|
||||
<p class="grd_small">
|
||||
<label for="login-password">Passwort</label>
|
||||
|
||||
@ -1,8 +1,20 @@
|
||||
<%@ page class="RegisterPage" %>
|
||||
<%@ page form="true" %>
|
||||
<%@ page compressed="true" %>
|
||||
<%!
|
||||
|
||||
<%!
|
||||
#include "../SingletonManager/SessionManager.h"
|
||||
%>
|
||||
<%
|
||||
auto session = SessionManager::getInstance()->getNewSession();
|
||||
bool userReturned = false;
|
||||
if(!form.empty()) {
|
||||
userReturned = session->createUser(
|
||||
form.get("register-name"),
|
||||
form.get("register-email"),
|
||||
form.get("register-password"),
|
||||
form.get("register-key-existing")
|
||||
);
|
||||
}
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@ -12,17 +24,34 @@
|
||||
<title>Gradido Login Server: Register</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>
|
||||
<h1>Login</h1>
|
||||
<h1>Einen neuen Account anlegen</h1>
|
||||
|
||||
<form method="POST">
|
||||
<div class="grd_container">
|
||||
<% if(!form.empty() && !userReturned) {%>
|
||||
<%= session->getErrorsHtml() %>
|
||||
<%} %>
|
||||
<fieldset class="grd_container_small">
|
||||
<legend>Account anlegen</legend>
|
||||
<p>Bitte gebe deine Daten um einen Account anzulegen</p>
|
||||
<p class="grd_small">
|
||||
<label for="register-username">Benutzernamen</label>
|
||||
<input id="register-username" type="text" name="register-username"/>
|
||||
<label for="register-name">Vorname</label>
|
||||
<input id="register-name" type="text" name="register-name" value="<%= !form.empty() ? form.get("register-name") : "" %>"/>
|
||||
</p>
|
||||
<p class="grd_small">
|
||||
<label for="register-email">E-Mail</label>
|
||||
<input id="register-email" type="email" name="register-email" value="<%= !form.empty() ? form.get("register-email") : "" %>"/>
|
||||
</p>
|
||||
<p class="grd_small">
|
||||
<label for="register-password">Passwort</label>
|
||||
@ -31,13 +60,13 @@
|
||||
<p>Hast du bereits schonmal ein Gradido Konto besessen?</p>
|
||||
<p class="grd_small">
|
||||
<input id="register-key-new-yes" type="radio" name="register-key" value="yes" checked/>
|
||||
<label for="register-key-new-yes">Nein, bitte ein neues erstellen!</label>
|
||||
<label class="grd_radio_label" for="register-key-new-yes">Nein, bitte ein neues erstellen!</label>
|
||||
</p>
|
||||
<p class="grd_small">
|
||||
<input id="register-key-new-no" type="radio" name="register-key" value="no"/>
|
||||
<label for="register-key-new-no">Ja, bitte wiederherstellen!</label>
|
||||
<label class="grd_radio_label" for="register-key-new-no">Ja, bitte wiederherstellen!</label>
|
||||
</p>
|
||||
<textarea style="width:100%;height:100px" name="register-key-existing"></textarea>
|
||||
<textarea style="width:100%;height:100px" name="register-key-existing"><%= !form.empty() ? form.get("register-key-existing") : "" %></textarea>
|
||||
</fieldset>
|
||||
<input class="grd_bn_succeed" type="submit" name="submit" value="Einloggen">
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user