From f09a0017f977848c569ffe88ec3f47bc5f73c1f8 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 30 Mar 2021 17:06:41 +0200 Subject: [PATCH] lineendings login_server --- login_server/CMakeLists.txt | 354 +-- login_server/skeema/gradido_login/users.sql | 32 +- login_server/src/cpp/Gradido_LoginServer.cpp | 534 ++-- login_server/src/cpp/Gradido_LoginServer.h | 84 +- .../src/cpp/HTTPInterface/LoginPage.cpp | 730 ++--- .../src/cpp/HTTPInterface/LoginPage.h | 40 +- login_server/src/cpp/ImportantTests.cpp | 2 +- .../src/cpp/JSONInterface/JsonCreateUser.cpp | 214 +- .../cpp/JSONInterface/JsonGetUserInfos.cpp | 286 +- .../src/cpp/JSONInterface/JsonLogout.cpp | 86 +- .../src/cpp/JSONInterface/JsonLogout.h | 34 +- .../cpp/JSONInterface/JsonRequestHandler.cpp | 282 +- .../JsonRequestHandlerFactory.cpp | 164 +- .../src/cpp/JSONInterface/JsonTransaction.cpp | 350 +-- .../src/cpp/JSONInterface/JsonTransaction.h | 36 +- login_server/src/cpp/ServerConfig.cpp | 696 ++--- login_server/src/cpp/ServerConfig.h | 178 +- .../cpp/SingletonManager/SessionManager.cpp | 1252 ++++---- login_server/src/cpp/lib/Error.h | 126 +- login_server/src/cpp/lib/ErrorList.cpp | 400 +-- login_server/src/cpp/lib/ErrorList.h | 152 +- login_server/src/cpp/main.cpp | 112 +- login_server/src/cpp/model/Session.cpp | 2646 ++++++++--------- login_server/src/cpp/model/Session.h | 564 ++-- .../src/cpp/model/TransactionCreation.cpp | 144 +- .../src/cpp/model/TransactionTransfer.cpp | 344 +-- login_server/src/cpp/model/email/Email.cpp | 2 +- .../AuthenticatedEncryptionCreateKeyTask.cpp | 78 +- .../src/cpp/tasks/ProcessingTransaction.cpp | 2 +- .../src/cpp/tasks/SigningTransaction.cpp | 566 ++-- .../src/cpp/tasks/SigningTransaction.h | 90 +- login_server/src/cpsp/login.cpsp | 408 +-- 32 files changed, 5494 insertions(+), 5494 deletions(-) diff --git a/login_server/CMakeLists.txt b/login_server/CMakeLists.txt index 5a484c3e9..177c6a5c6 100644 --- a/login_server/CMakeLists.txt +++ b/login_server/CMakeLists.txt @@ -1,177 +1,177 @@ -cmake_minimum_required(VERSION 3.0) -project(Gradido_LoginServer C CXX) -SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" ) - -SET ( CMAKE_CXX_FLAGS "-std=c++17" ) - -include_directories( - "dependencies" - "dependencies/tinf/src/" - "dependencies/iroha-ed25519/include" - "dependencies/mariadb-connector-c/include" - "dependencies/mariadb-connector-c/build/include" - "dependencies/spirit-po/include" - "src/cpp/proto" - #"dependencies/mariadb-connector-c/build/include" - #"dependencies/mariadb-connector-c/include" - #"import/mariadb/include" -) - - -FILE(GLOB CONTROLLER "src/cpp/controller/*.cpp" "src/cpp/controller/*.h") -FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h") -FILE(GLOB HTTPInterface "src/cpp/HTTPInterface/*.h" "src/cpp/HTTPInterface/*.cpp") -FILE(GLOB JSONInterface "src/cpp/JSONInterface/*.h" "src/cpp/JSONInterface/*.cpp") -FILE(GLOB TASKS "src/cpp/tasks/*.cpp" "src/cpp/tasks/*.h") -FILE(GLOB SINGLETON_MANAGER "src/cpp/SingletonManager/*.h" "src/cpp/SingletonManager/*.cpp") -FILE(GLOB LIB_SRC "src/cpp/lib/*.h" "src/cpp/lib/*.cpp") -FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp") -FILE(GLOB MODEL_TABLE "src/cpp/model/table/*.h" "src/cpp/model/table/*.cpp") -FILE(GLOB MODEL_EMAIL "src/cpp/model/email/*.h" "src/cpp/model/email/*.cpp") -FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp") -FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h") -FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h") -FILE(GLOB PROTO_GRADIDO "src/cpp/proto/gradido/*.cc" "src/cpp/proto/gradido/*.h") -FILE(GLOB PROTO_HEDERA "src/cpp/proto/hedera/*.cc" "src/cpp/proto/hedera/*.h") - -# used only for test project -FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h") -FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h") -FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h") -FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h") -FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h") - -SET(LOCAL_SRCS - ${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} - ${JSONInterface} ${CRYPTO} ${MODEL} ${MODEL_TABLE} ${MODEL_EMAIL} - ${SINGLETON_MANAGER} ${LIB_SRC} ${MYSQL} ${TASKS} - ${PROTO_GRADIDO} ${PROTO_HEDERA} -) -SET(LOCAL_TEST_SRC - ${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} -) -aux_source_directory("src/cpp" LOCAL_SRCS) - -if(MSVC) -# src -source_group("controller" FILES ${CONTROLLER}) -source_group("proto\\gradido" FILES ${PROTO_GRADIDO}) -source_group("proto\\hedera" FILES ${PROTO_HEDERA}) -source_group("tinf" FILES ${TINF}) -source_group("Crypto" FILES ${CRYPTO}) -source_group("tasks" FILES ${TASKS}) -source_group("model\\table" FILES ${MODEL_TABLE}) -source_group("model\\email" FILES ${MODEL_EMAIL}) -source_group("model" FILES ${MODEL}) -source_group("mysql" FILES ${MYSQL}) -source_group("SingletonManager" FILES ${SINGLETON_MANAGER}) -source_group("lib" FILES ${LIB_SRC}) -source_group("HTTP-Interface" FILES ${HTTPInterface}) -source_group("Json-Interface" FILES ${JSONInterface}) -source_group("Test\\crypto" FILES ${TEST_CRYPTO}) -source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE}) -source_group("Test\\model" FILES ${TEST_MODEL}) -source_group("Test\\controller" FILES ${TEST_CONTROLLER}) -source_group("Test" FILES ${TEST}) -endif(MSVC) - -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}) -#SUBDIRS("src/test") - -if(WIN32) - -find_library(MYSQL_LIBRARIES mariadbclient.lib PATHS "dependencies/mariadb-connector-c/build/libmariadb/Release" REQUIRED) -#find_library(MYSQL_LIBRARIES_DEBUG mariadbclient.lib PATHS "import/mariadb/lib/debug") -find_library(COMPILED_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 "dependencies/mariadb-connector-c/include") - -#set(POCO_DEBUG_PATH "I:/FremdCode/C++/poco/win64/lib/Debug") - -#find_library(POCO_DEBUG_FOUNDATION PocoFoundationd PocoFoundation PATHS ${POCO_DEBUG_PATH} REQUIRED) -#find_library(POCO_DEBUG_DATA PocoDatad PocoData PATHS ${POCO_DEBUG_PATH} REQUIRED) -#find_library(POCO_DEBUG_NET PocoNetd PocoNet PATHS ${POCO_DEBUG_PATH} REQUIRED) -#find_library(POCO_DEBUG_NET_SSL PocoNetSSLd PocoNetSSL PATHS ${POCO_DEBUG_PATH} REQUIRED) -#find_library(POCO_DEBUG_UTIL PocoUtild PocoUtil PATHS ${POCO_DEBUG_PATH} REQUIRED) -#find_library(POCO_DEBUG_CRYPTO PocoCryptod PocoCrypto PATHS ${POCO_DEBUG_PATH} REQUIRED) - -#set(POCO_DEBUG_LIBS ${POCO_DEBUG_FOUNDATION} ${POCO_DEBUG_UTIL} ${POCO_DEBUG_DATA} ${POCO_DEBUG_NET} ${POCO_DEBUG_NET_SSL} ${POCO_DEBUG_CRYPTO}) -#include_directories( -# "I:/FremdCode/C++/poco/Foundation/include" -# "I:/FremdCode/C++/poco/Data/include" -# "I:/FremdCode/C++/poco/Net/include" - #"I:/FremdCode/C++/poco/NetSSL_Win/include" -# "I:/FremdCode/C++/poco/NetSSL_OpenSSL/include" -# "I:/FremdCode/C++/poco/Crypto/include" -# "I:/FremdCode/C++/poco/Util/include" -# "I:/FremdCode/C++/ssl/include" -#) - -set(CMAKE_CXX_FLAGS "/MP /EHsc") -#set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") -#set(CMAKE_CXX_FLAGS_RELEASE "-O3") - -else() - -find_library(IROHA_ED25519 ed25519 PATHS "dependencies/iroha-ed25519/build" REQUIRED) -# set vars for mariadb cmake files -set(INSTALL_BINDIR "bin") -set(INSTALL_PLUGINDIR "bin") -add_subdirectory("dependencies/mariadb-connector-c") - - -include_directories( - "dependencies/mariadb-connector-c/include" - "build/dependencies/mariadb-connector-c/include" -) - - - -endif() - -target_link_libraries(Gradido_LoginServer ${CONAN_LIBS} ${IROHA_ED25519}) -if(WIN32) -TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi) -TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) -else() -target_link_libraries(Gradido_LoginServer libmariadb -pthread) -endif() - -# install -if(UNIX) -install(TARGETS Gradido_LoginServer RUNTIME DESTINATION /usr/local/bin) -#install(FILES lib/libmariadb /usr/local/lib) -install(FILES DESTINATION lib COMPONENT libmariadb) -install(DIRECTORY src/LOCALE DESTINATION /etc/grd_login/ - FILES_MATCHING PATTERN "*.po(t)") - - -endif(UNIX) - -enable_testing() - -# ---------------------- Test ----------------------------------------- -#project(Gradido_LoginServer_Test C CXX) -#_TEST_BUILD - - -add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC}) -target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD") - -target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} ${IROHA_ED25519}) - -if(WIN32) - TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi) - TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) -else() - target_link_libraries(Gradido_LoginServer_Test libmariadb -pthread) -endif() - -add_test(NAME main COMMAND Gradido_LoginServer_Test) +cmake_minimum_required(VERSION 3.0) +project(Gradido_LoginServer C CXX) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" ) + +SET ( CMAKE_CXX_FLAGS "-std=c++17" ) + +include_directories( + "dependencies" + "dependencies/tinf/src/" + "dependencies/iroha-ed25519/include" + "dependencies/mariadb-connector-c/include" + "dependencies/mariadb-connector-c/build/include" + "dependencies/spirit-po/include" + "src/cpp/proto" + #"dependencies/mariadb-connector-c/build/include" + #"dependencies/mariadb-connector-c/include" + #"import/mariadb/include" +) + + +FILE(GLOB CONTROLLER "src/cpp/controller/*.cpp" "src/cpp/controller/*.h") +FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h") +FILE(GLOB HTTPInterface "src/cpp/HTTPInterface/*.h" "src/cpp/HTTPInterface/*.cpp") +FILE(GLOB JSONInterface "src/cpp/JSONInterface/*.h" "src/cpp/JSONInterface/*.cpp") +FILE(GLOB TASKS "src/cpp/tasks/*.cpp" "src/cpp/tasks/*.h") +FILE(GLOB SINGLETON_MANAGER "src/cpp/SingletonManager/*.h" "src/cpp/SingletonManager/*.cpp") +FILE(GLOB LIB_SRC "src/cpp/lib/*.h" "src/cpp/lib/*.cpp") +FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp") +FILE(GLOB MODEL_TABLE "src/cpp/model/table/*.h" "src/cpp/model/table/*.cpp") +FILE(GLOB MODEL_EMAIL "src/cpp/model/email/*.h" "src/cpp/model/email/*.cpp") +FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp") +FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h") +FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h") +FILE(GLOB PROTO_GRADIDO "src/cpp/proto/gradido/*.cc" "src/cpp/proto/gradido/*.h") +FILE(GLOB PROTO_HEDERA "src/cpp/proto/hedera/*.cc" "src/cpp/proto/hedera/*.h") + +# used only for test project +FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h") +FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h") +FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h") +FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h") +FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h") + +SET(LOCAL_SRCS + ${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} + ${JSONInterface} ${CRYPTO} ${MODEL} ${MODEL_TABLE} ${MODEL_EMAIL} + ${SINGLETON_MANAGER} ${LIB_SRC} ${MYSQL} ${TASKS} + ${PROTO_GRADIDO} ${PROTO_HEDERA} +) +SET(LOCAL_TEST_SRC + ${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} +) +aux_source_directory("src/cpp" LOCAL_SRCS) + +if(MSVC) +# src +source_group("controller" FILES ${CONTROLLER}) +source_group("proto\\gradido" FILES ${PROTO_GRADIDO}) +source_group("proto\\hedera" FILES ${PROTO_HEDERA}) +source_group("tinf" FILES ${TINF}) +source_group("Crypto" FILES ${CRYPTO}) +source_group("tasks" FILES ${TASKS}) +source_group("model\\table" FILES ${MODEL_TABLE}) +source_group("model\\email" FILES ${MODEL_EMAIL}) +source_group("model" FILES ${MODEL}) +source_group("mysql" FILES ${MYSQL}) +source_group("SingletonManager" FILES ${SINGLETON_MANAGER}) +source_group("lib" FILES ${LIB_SRC}) +source_group("HTTP-Interface" FILES ${HTTPInterface}) +source_group("Json-Interface" FILES ${JSONInterface}) +source_group("Test\\crypto" FILES ${TEST_CRYPTO}) +source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE}) +source_group("Test\\model" FILES ${TEST_MODEL}) +source_group("Test\\controller" FILES ${TEST_CONTROLLER}) +source_group("Test" FILES ${TEST}) +endif(MSVC) + +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}) +#SUBDIRS("src/test") + +if(WIN32) + +find_library(MYSQL_LIBRARIES mariadbclient.lib PATHS "dependencies/mariadb-connector-c/build/libmariadb/Release" REQUIRED) +#find_library(MYSQL_LIBRARIES_DEBUG mariadbclient.lib PATHS "import/mariadb/lib/debug") +find_library(COMPILED_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 "dependencies/mariadb-connector-c/include") + +#set(POCO_DEBUG_PATH "I:/FremdCode/C++/poco/win64/lib/Debug") + +#find_library(POCO_DEBUG_FOUNDATION PocoFoundationd PocoFoundation PATHS ${POCO_DEBUG_PATH} REQUIRED) +#find_library(POCO_DEBUG_DATA PocoDatad PocoData PATHS ${POCO_DEBUG_PATH} REQUIRED) +#find_library(POCO_DEBUG_NET PocoNetd PocoNet PATHS ${POCO_DEBUG_PATH} REQUIRED) +#find_library(POCO_DEBUG_NET_SSL PocoNetSSLd PocoNetSSL PATHS ${POCO_DEBUG_PATH} REQUIRED) +#find_library(POCO_DEBUG_UTIL PocoUtild PocoUtil PATHS ${POCO_DEBUG_PATH} REQUIRED) +#find_library(POCO_DEBUG_CRYPTO PocoCryptod PocoCrypto PATHS ${POCO_DEBUG_PATH} REQUIRED) + +#set(POCO_DEBUG_LIBS ${POCO_DEBUG_FOUNDATION} ${POCO_DEBUG_UTIL} ${POCO_DEBUG_DATA} ${POCO_DEBUG_NET} ${POCO_DEBUG_NET_SSL} ${POCO_DEBUG_CRYPTO}) +#include_directories( +# "I:/FremdCode/C++/poco/Foundation/include" +# "I:/FremdCode/C++/poco/Data/include" +# "I:/FremdCode/C++/poco/Net/include" + #"I:/FremdCode/C++/poco/NetSSL_Win/include" +# "I:/FremdCode/C++/poco/NetSSL_OpenSSL/include" +# "I:/FremdCode/C++/poco/Crypto/include" +# "I:/FremdCode/C++/poco/Util/include" +# "I:/FremdCode/C++/ssl/include" +#) + +set(CMAKE_CXX_FLAGS "/MP /EHsc") +#set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") +#set(CMAKE_CXX_FLAGS_RELEASE "-O3") + +else() + +find_library(IROHA_ED25519 ed25519 PATHS "dependencies/iroha-ed25519/build" REQUIRED) +# set vars for mariadb cmake files +set(INSTALL_BINDIR "bin") +set(INSTALL_PLUGINDIR "bin") +add_subdirectory("dependencies/mariadb-connector-c") + + +include_directories( + "dependencies/mariadb-connector-c/include" + "build/dependencies/mariadb-connector-c/include" +) + + + +endif() + +target_link_libraries(Gradido_LoginServer ${CONAN_LIBS} ${IROHA_ED25519}) +if(WIN32) +TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi) +TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) +else() +target_link_libraries(Gradido_LoginServer libmariadb -pthread) +endif() + +# install +if(UNIX) +install(TARGETS Gradido_LoginServer RUNTIME DESTINATION /usr/local/bin) +#install(FILES lib/libmariadb /usr/local/lib) +install(FILES DESTINATION lib COMPONENT libmariadb) +install(DIRECTORY src/LOCALE DESTINATION /etc/grd_login/ + FILES_MATCHING PATTERN "*.po(t)") + + +endif(UNIX) + +enable_testing() + +# ---------------------- Test ----------------------------------------- +#project(Gradido_LoginServer_Test C CXX) +#_TEST_BUILD + + +add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC}) +target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD") + +target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} ${IROHA_ED25519}) + +if(WIN32) + TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi) + TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) +else() + target_link_libraries(Gradido_LoginServer_Test libmariadb -pthread) +endif() + +add_test(NAME main COMMAND Gradido_LoginServer_Test) diff --git a/login_server/skeema/gradido_login/users.sql b/login_server/skeema/gradido_login/users.sql index 6c3eb5b82..71c2d09e8 100644 --- a/login_server/skeema/gradido_login/users.sql +++ b/login_server/skeema/gradido_login/users.sql @@ -1,16 +1,16 @@ -CREATE TABLE `users` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, - `email` varchar(191) NOT NULL, - `first_name` varchar(150) NOT NULL, - `last_name` varchar(255) DEFAULT '', - `password` bigint unsigned DEFAULT 0, - `pubkey` binary(32) DEFAULT NULL, - `privkey` binary(80) DEFAULT NULL, - `created` datetime NOT NULL DEFAULT current_timestamp(), - `email_checked` tinyint NOT NULL DEFAULT 0, - `passphrase_shown` tinyint NOT NULL DEFAULT 0, - `language` varchar(4) NOT NULL DEFAULT 'de', - `disabled` BOOLEAN NULL DEFAULT FALSE, - PRIMARY KEY (`id`), - UNIQUE KEY `email` (`email`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE TABLE `users` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `email` varchar(191) NOT NULL, + `first_name` varchar(150) NOT NULL, + `last_name` varchar(255) DEFAULT '', + `password` bigint unsigned DEFAULT 0, + `pubkey` binary(32) DEFAULT NULL, + `privkey` binary(80) DEFAULT NULL, + `created` datetime NOT NULL DEFAULT current_timestamp(), + `email_checked` tinyint NOT NULL DEFAULT 0, + `passphrase_shown` tinyint NOT NULL DEFAULT 0, + `language` varchar(4) NOT NULL DEFAULT 'de', + `disabled` BOOLEAN NULL DEFAULT FALSE, + PRIMARY KEY (`id`), + UNIQUE KEY `email` (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/src/cpp/Gradido_LoginServer.cpp b/login_server/src/cpp/Gradido_LoginServer.cpp index 2ad89e19b..423f603df 100644 --- a/login_server/src/cpp/Gradido_LoginServer.cpp +++ b/login_server/src/cpp/Gradido_LoginServer.cpp @@ -1,267 +1,267 @@ -#include "Gradido_LoginServer.h" -#include "ServerConfig.h" -#include "HTTPInterface/PageRequestHandlerFactory.h" -#include "JSONInterface/JsonRequestHandlerFactory.h" - -#include "lib/Profiler.h" - -#include "SingletonManager/ConnectionManager.h" -#include "SingletonManager/SessionManager.h" -#include "SingletonManager/EmailManager.h" - -#include "controller/User.h" - -#include "Poco/Util/HelpFormatter.h" -#include "Poco/Net/ServerSocket.h" -#include "Poco/Net/HTTPServer.h" -#include "Poco/Net/SSLManager.h" -#include "Poco/Environment.h" -#include "Poco/Logger.h" -#include "Poco/Path.h" -#include "Poco/AsyncChannel.h" -#include "Poco/SimpleFileChannel.h" -#include "Poco/ConsoleChannel.h" -#include "Poco/SplitterChannel.h" -#include "MySQL/Poco/Connector.h" - - -#include - - - -Gradido_LoginServer::Gradido_LoginServer() - : _helpRequested(false) -{ -} - -Gradido_LoginServer::~Gradido_LoginServer() -{ -} - - -void Gradido_LoginServer::initialize(Application& self) -{ - loadConfiguration(); // load default configuration files, if present - ServerApplication::initialize(self); -} - -void Gradido_LoginServer::uninitialize() -{ - ServerApplication::uninitialize(); -} - -void Gradido_LoginServer::defineOptions(Poco::Util::OptionSet& options) -{ - ServerApplication::defineOptions(options); - - /*options.addOption( - Poco::Util::Option("help", "h", "display help information on command line arguments") - .required(false) - .repeatable(false));*/ - options.addOption( - Poco::Util::Option("config", "c", "use non default config file (default is /etc/grd_login.properties)", false) - .repeatable(false) - .argument("Gradido_LoginServer.properties", true) - .callback(Poco::Util::OptionCallback(this, &Gradido_LoginServer::handleOption))); - -} - -void Gradido_LoginServer::handleOption(const std::string& name, const std::string& value) -{ - //printf("handle option: %s with value: %s\n", name.data(), value.data()); - if (name == "config") { - mConfigPath = value; - return; - } - ServerApplication::handleOption(name, value); - if (name == "help") _helpRequested = true; - -} - -void Gradido_LoginServer::displayHelp() -{ - Poco::Util::HelpFormatter helpFormatter(options()); - helpFormatter.setCommand(commandName()); - helpFormatter.setUsage("OPTIONS"); - helpFormatter.setHeader("Gradido Login Server"); - helpFormatter.format(std::cout); -} - -void Gradido_LoginServer::createConsoleFileAsyncLogger(std::string name, std::string filePath) -{ - Poco::AutoPtr logConsoleChannel(new Poco::ConsoleChannel); - Poco::AutoPtr logFileChannel(new Poco::SimpleFileChannel(filePath)); - logFileChannel->setProperty("rotation", "500 K"); - Poco::AutoPtr logSplitter(new Poco::SplitterChannel); - logSplitter->addChannel(logConsoleChannel); - logSplitter->addChannel(logFileChannel); - - Poco::AutoPtr logAsyncChannel(new Poco::AsyncChannel(logSplitter)); - - Poco::Logger& log = Poco::Logger::get(name); - log.setChannel(logAsyncChannel); - log.setLevel("information"); -} - -int Gradido_LoginServer::main(const std::vector& args) -{ - - Profiler usedTime; - if (_helpRequested) - { - displayHelp(); - } - else - { - // ********** logging ************************************ - std::string log_Path = "/var/log/grd_login/"; -//#ifdef _WIN32 -#if defined(_WIN32) || defined(_WIN64) - log_Path = "./"; -#endif - - // init speed logger - Poco::AutoPtr speedLogFileChannel(new Poco::SimpleFileChannel(log_Path + "speedLog.txt")); - /* - The optional log file rotation mode: - never: no rotation (default) - : rotate if file size exceeds bytes - K: rotate if file size exceeds Kilobytes - M: rotate if file size exceeds Megabytes - */ - speedLogFileChannel->setProperty("rotation", "500 K"); - Poco::AutoPtr speedLogAsyncChannel(new Poco::AsyncChannel(speedLogFileChannel)); - - Poco::Logger& speedLogger = Poco::Logger::get("SpeedLog"); - speedLogger.setChannel(speedLogAsyncChannel); - speedLogger.setLevel("information"); - - // logging for request handling - createConsoleFileAsyncLogger("requestLog", log_Path + "requestLog.txt"); - - // error logging - createConsoleFileAsyncLogger("errorLog", log_Path + "errorLog.txt"); - Poco::Logger& errorLog = Poco::Logger::get("errorLog"); - - createConsoleFileAsyncLogger("emailLog", log_Path + "emailLog.txt"); - - // *************** load from config ******************************************** - - std::string cfg_Path = Poco::Path::config() + "grd_login/grd_login.properties"; - if (mConfigPath != "") { - cfg_Path = mConfigPath; - } - - try { - loadConfiguration(cfg_Path); - } - catch (Poco::Exception& ex) { - errorLog.error("error loading config: %s from path: %s", ex.displayText(), cfg_Path); - } - - unsigned short port = (unsigned short)config().getInt("HTTPServer.port", 9980); - unsigned short json_port = (unsigned short)config().getInt("JSONServer.port", 1201); - - - //printf("show mnemonic list: \n"); - //printf(ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER].getCompleteWordList().data()); - if (!ServerConfig::initServerCrypto(config())) { - //printf("[Gradido_LoginServer::%s] error init server crypto\n", __FUNCTION__); - errorLog.error("[Gradido_LoginServer::main] error init server crypto"); - return Application::EXIT_CONFIG; - } - - // first check time for crypto - auto testUser = new User("email@google.de", "Max", "Mustermann"); - Profiler timeUsed; - testUser->validatePwd("haz27Newpassword", nullptr); - ServerConfig::g_FakeLoginSleepTime = (int)std::round(timeUsed.millis()); - delete testUser; - - Poco::Int64 i1 = randombytes_random(); - Poco::Int64 i2 = randombytes_random(); - ServerConfig::g_ServerKeySeed->put(1, i1 | (i2 << 8)); - - ServerConfig::initEMailAccount(config()); - EmailManager::getInstance()->init(config()); - - // start cpu scheduler - uint8_t worker_count = Poco::Environment::processorCount() * 2; - - ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker"); - ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker"); - - // load up connection configs - // register MySQL connector - Poco::Data::MySQL::Connector::registerConnector(); - //Poco::Data::MySQL::Connector::KEY; - auto conn = ConnectionManager::getInstance(); - //conn->setConnection() - //printf("try connect login server mysql db\n"); - try { - conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_LOGIN_SERVER); - } - catch (Poco::Exception& ex) { - // maybe we in docker environment and db needs some time to start up - // let's wait 10 seconds - int count = 10; - while (count > 0) { - printf("\rwait on mysql/mariadb %d seconds...", count); - count--; - Poco::Thread::sleep(1000); - } - conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_LOGIN_SERVER); - } - //printf("try connect php server mysql \n"); - //conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_PHP_SERVER); - - SessionManager::getInstance()->init(); - // put urandom on linux servers - //srand(); - - Poco::Net::initializeSSL(); - if(!ServerConfig::initSSLClientContext()) { - //printf("[Gradido_LoginServer::%s] error init server SSL Client\n", __FUNCTION__); - errorLog.error("[Gradido_LoginServer::main] error init server SSL Client\n"); - return Application::EXIT_CONFIG; - } - - // schedule email verification resend - controller::User::checkIfVerificationEmailsShouldBeResend(ServerConfig::g_CronJobsTimer); - - // HTTP Interface Server - // set-up a server socket - Poco::Net::ServerSocket svs(port); - // set-up a HTTPServer instance - Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool(); - Poco::Net::HTTPServer srv(new PageRequestHandlerFactory, svs, new Poco::Net::HTTPServerParams); - ServerConfig::g_ServerKeySeed->put(7, 918276611); - - // start the HTTPServer - srv.start(); - - // JSON Interface Server - Poco::Net::ServerSocket json_svs(json_port); - Poco::Net::HTTPServer json_srv(new JsonRequestHandlerFactory, json_svs, new Poco::Net::HTTPServerParams); - - // start the json server - json_srv.start(); - - printf("[Gradido_LoginServer::main] started in %s\n", usedTime.string().data()); - // wait for CTRL-C or kill - waitForTerminationRequest(); - - // Stop the HTTPServer - srv.stop(); - // Stop the json server - json_srv.stop(); - - ServerConfig::unload(); - Poco::Net::uninitializeSSL(); - // Optional: Delete all global objects allocated by libprotobuf. - google::protobuf::ShutdownProtobufLibrary(); - - } - return Application::EXIT_OK; -} - +#include "Gradido_LoginServer.h" +#include "ServerConfig.h" +#include "HTTPInterface/PageRequestHandlerFactory.h" +#include "JSONInterface/JsonRequestHandlerFactory.h" + +#include "lib/Profiler.h" + +#include "SingletonManager/ConnectionManager.h" +#include "SingletonManager/SessionManager.h" +#include "SingletonManager/EmailManager.h" + +#include "controller/User.h" + +#include "Poco/Util/HelpFormatter.h" +#include "Poco/Net/ServerSocket.h" +#include "Poco/Net/HTTPServer.h" +#include "Poco/Net/SSLManager.h" +#include "Poco/Environment.h" +#include "Poco/Logger.h" +#include "Poco/Path.h" +#include "Poco/AsyncChannel.h" +#include "Poco/SimpleFileChannel.h" +#include "Poco/ConsoleChannel.h" +#include "Poco/SplitterChannel.h" +#include "MySQL/Poco/Connector.h" + + +#include + + + +Gradido_LoginServer::Gradido_LoginServer() + : _helpRequested(false) +{ +} + +Gradido_LoginServer::~Gradido_LoginServer() +{ +} + + +void Gradido_LoginServer::initialize(Application& self) +{ + loadConfiguration(); // load default configuration files, if present + ServerApplication::initialize(self); +} + +void Gradido_LoginServer::uninitialize() +{ + ServerApplication::uninitialize(); +} + +void Gradido_LoginServer::defineOptions(Poco::Util::OptionSet& options) +{ + ServerApplication::defineOptions(options); + + /*options.addOption( + Poco::Util::Option("help", "h", "display help information on command line arguments") + .required(false) + .repeatable(false));*/ + options.addOption( + Poco::Util::Option("config", "c", "use non default config file (default is /etc/grd_login.properties)", false) + .repeatable(false) + .argument("Gradido_LoginServer.properties", true) + .callback(Poco::Util::OptionCallback(this, &Gradido_LoginServer::handleOption))); + +} + +void Gradido_LoginServer::handleOption(const std::string& name, const std::string& value) +{ + //printf("handle option: %s with value: %s\n", name.data(), value.data()); + if (name == "config") { + mConfigPath = value; + return; + } + ServerApplication::handleOption(name, value); + if (name == "help") _helpRequested = true; + +} + +void Gradido_LoginServer::displayHelp() +{ + Poco::Util::HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName()); + helpFormatter.setUsage("OPTIONS"); + helpFormatter.setHeader("Gradido Login Server"); + helpFormatter.format(std::cout); +} + +void Gradido_LoginServer::createConsoleFileAsyncLogger(std::string name, std::string filePath) +{ + Poco::AutoPtr logConsoleChannel(new Poco::ConsoleChannel); + Poco::AutoPtr logFileChannel(new Poco::SimpleFileChannel(filePath)); + logFileChannel->setProperty("rotation", "500 K"); + Poco::AutoPtr logSplitter(new Poco::SplitterChannel); + logSplitter->addChannel(logConsoleChannel); + logSplitter->addChannel(logFileChannel); + + Poco::AutoPtr logAsyncChannel(new Poco::AsyncChannel(logSplitter)); + + Poco::Logger& log = Poco::Logger::get(name); + log.setChannel(logAsyncChannel); + log.setLevel("information"); +} + +int Gradido_LoginServer::main(const std::vector& args) +{ + + Profiler usedTime; + if (_helpRequested) + { + displayHelp(); + } + else + { + // ********** logging ************************************ + std::string log_Path = "/var/log/grd_login/"; +//#ifdef _WIN32 +#if defined(_WIN32) || defined(_WIN64) + log_Path = "./"; +#endif + + // init speed logger + Poco::AutoPtr speedLogFileChannel(new Poco::SimpleFileChannel(log_Path + "speedLog.txt")); + /* + The optional log file rotation mode: + never: no rotation (default) + : rotate if file size exceeds bytes + K: rotate if file size exceeds Kilobytes + M: rotate if file size exceeds Megabytes + */ + speedLogFileChannel->setProperty("rotation", "500 K"); + Poco::AutoPtr speedLogAsyncChannel(new Poco::AsyncChannel(speedLogFileChannel)); + + Poco::Logger& speedLogger = Poco::Logger::get("SpeedLog"); + speedLogger.setChannel(speedLogAsyncChannel); + speedLogger.setLevel("information"); + + // logging for request handling + createConsoleFileAsyncLogger("requestLog", log_Path + "requestLog.txt"); + + // error logging + createConsoleFileAsyncLogger("errorLog", log_Path + "errorLog.txt"); + Poco::Logger& errorLog = Poco::Logger::get("errorLog"); + + createConsoleFileAsyncLogger("emailLog", log_Path + "emailLog.txt"); + + // *************** load from config ******************************************** + + std::string cfg_Path = Poco::Path::config() + "grd_login/grd_login.properties"; + if (mConfigPath != "") { + cfg_Path = mConfigPath; + } + + try { + loadConfiguration(cfg_Path); + } + catch (Poco::Exception& ex) { + errorLog.error("error loading config: %s from path: %s", ex.displayText(), cfg_Path); + } + + unsigned short port = (unsigned short)config().getInt("HTTPServer.port", 9980); + unsigned short json_port = (unsigned short)config().getInt("JSONServer.port", 1201); + + + //printf("show mnemonic list: \n"); + //printf(ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER].getCompleteWordList().data()); + if (!ServerConfig::initServerCrypto(config())) { + //printf("[Gradido_LoginServer::%s] error init server crypto\n", __FUNCTION__); + errorLog.error("[Gradido_LoginServer::main] error init server crypto"); + return Application::EXIT_CONFIG; + } + + // first check time for crypto + auto testUser = new User("email@google.de", "Max", "Mustermann"); + Profiler timeUsed; + testUser->validatePwd("haz27Newpassword", nullptr); + ServerConfig::g_FakeLoginSleepTime = (int)std::round(timeUsed.millis()); + delete testUser; + + Poco::Int64 i1 = randombytes_random(); + Poco::Int64 i2 = randombytes_random(); + ServerConfig::g_ServerKeySeed->put(1, i1 | (i2 << 8)); + + ServerConfig::initEMailAccount(config()); + EmailManager::getInstance()->init(config()); + + // start cpu scheduler + uint8_t worker_count = Poco::Environment::processorCount() * 2; + + ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker"); + ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker"); + + // load up connection configs + // register MySQL connector + Poco::Data::MySQL::Connector::registerConnector(); + //Poco::Data::MySQL::Connector::KEY; + auto conn = ConnectionManager::getInstance(); + //conn->setConnection() + //printf("try connect login server mysql db\n"); + try { + conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_LOGIN_SERVER); + } + catch (Poco::Exception& ex) { + // maybe we in docker environment and db needs some time to start up + // let's wait 10 seconds + int count = 10; + while (count > 0) { + printf("\rwait on mysql/mariadb %d seconds...", count); + count--; + Poco::Thread::sleep(1000); + } + conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_LOGIN_SERVER); + } + //printf("try connect php server mysql \n"); + //conn->setConnectionsFromConfig(config(), CONNECTION_MYSQL_PHP_SERVER); + + SessionManager::getInstance()->init(); + // put urandom on linux servers + //srand(); + + Poco::Net::initializeSSL(); + if(!ServerConfig::initSSLClientContext()) { + //printf("[Gradido_LoginServer::%s] error init server SSL Client\n", __FUNCTION__); + errorLog.error("[Gradido_LoginServer::main] error init server SSL Client\n"); + return Application::EXIT_CONFIG; + } + + // schedule email verification resend + controller::User::checkIfVerificationEmailsShouldBeResend(ServerConfig::g_CronJobsTimer); + + // HTTP Interface Server + // set-up a server socket + Poco::Net::ServerSocket svs(port); + // set-up a HTTPServer instance + Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool(); + Poco::Net::HTTPServer srv(new PageRequestHandlerFactory, svs, new Poco::Net::HTTPServerParams); + ServerConfig::g_ServerKeySeed->put(7, 918276611); + + // start the HTTPServer + srv.start(); + + // JSON Interface Server + Poco::Net::ServerSocket json_svs(json_port); + Poco::Net::HTTPServer json_srv(new JsonRequestHandlerFactory, json_svs, new Poco::Net::HTTPServerParams); + + // start the json server + json_srv.start(); + + printf("[Gradido_LoginServer::main] started in %s\n", usedTime.string().data()); + // wait for CTRL-C or kill + waitForTerminationRequest(); + + // Stop the HTTPServer + srv.stop(); + // Stop the json server + json_srv.stop(); + + ServerConfig::unload(); + Poco::Net::uninitializeSSL(); + // Optional: Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + + } + return Application::EXIT_OK; +} + diff --git a/login_server/src/cpp/Gradido_LoginServer.h b/login_server/src/cpp/Gradido_LoginServer.h index 98c3c882c..0a14d9000 100644 --- a/login_server/src/cpp/Gradido_LoginServer.h +++ b/login_server/src/cpp/Gradido_LoginServer.h @@ -1,42 +1,42 @@ -#ifndef Gradido_LoginServer_INCLUDED -#define Gradido_LoginServer_INCLUDED - -#include "Poco/Util/ServerApplication.h" - -class Gradido_LoginServer : public Poco::Util::ServerApplication -{ - - /// The main application class. - /// - /// This class handles command-line arguments and - /// configuration files. - /// Start the Gradido_LoginServer executable with the help - /// option (/help on Windows, --help on Unix) for - /// the available command line options. - /// - - -public: - Gradido_LoginServer(); - ~Gradido_LoginServer(); - -protected: - void initialize(Application& self); - - void uninitialize(); - - void defineOptions(Poco::Util::OptionSet& options); - - void handleOption(const std::string& name, const std::string& value); - void displayHelp(); - - int main(const std::vector& args); - - void createConsoleFileAsyncLogger(std::string name, std::string filePath); - -private: - bool _helpRequested; - std::string mConfigPath; -}; - -#endif //Gradido_LoginServer_INCLUDED +#ifndef Gradido_LoginServer_INCLUDED +#define Gradido_LoginServer_INCLUDED + +#include "Poco/Util/ServerApplication.h" + +class Gradido_LoginServer : public Poco::Util::ServerApplication +{ + + /// The main application class. + /// + /// This class handles command-line arguments and + /// configuration files. + /// Start the Gradido_LoginServer executable with the help + /// option (/help on Windows, --help on Unix) for + /// the available command line options. + /// + + +public: + Gradido_LoginServer(); + ~Gradido_LoginServer(); + +protected: + void initialize(Application& self); + + void uninitialize(); + + void defineOptions(Poco::Util::OptionSet& options); + + void handleOption(const std::string& name, const std::string& value); + void displayHelp(); + + int main(const std::vector& args); + + void createConsoleFileAsyncLogger(std::string name, std::string filePath); + +private: + bool _helpRequested; + std::string mConfigPath; +}; + +#endif //Gradido_LoginServer_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/LoginPage.cpp b/login_server/src/cpp/HTTPInterface/LoginPage.cpp index f3e6aa077..65d144c9e 100644 --- a/login_server/src/cpp/HTTPInterface/LoginPage.cpp +++ b/login_server/src/cpp/HTTPInterface/LoginPage.cpp @@ -1,365 +1,365 @@ -#include "LoginPage.h" -#include "Poco/Net/HTTPServerRequest.h" -#include "Poco/Net/HTTPServerResponse.h" -#include "Poco/Net/HTMLForm.h" -#include "Poco/DeflatingStream.h" - - -#line 7 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - -#include "../gettext.h" - -#include "Poco/Net/HTTPCookie.h" -#include "Poco/Net/HTTPServerParams.h" -#include "Poco/Logger.h" -#include "../SingletonManager/SessionManager.h" -#include "../SingletonManager/LanguageManager.h" -#include "../SingletonManager/ErrorManager.h" - -#line 1 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" - -#include "../ServerConfig.h" - - -LoginPage::LoginPage(Session* arg): - SessionHTTPRequestHandler(arg) -{ -} - - -void LoginPage::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 18 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - - const char* pageName = "Login"; - auto sm = SessionManager::getInstance(); - auto lm = LanguageManager::getInstance(); - auto em = ErrorManager::getInstance(); - - auto lang = chooseLanguage(request); - //printf("choose language return: %d\n", lang); - auto langCatalog = lm->getFreeCatalog(lang); - - std::string presetEmail(""); - if(mSession && mSession->getUser()) { - presetEmail = mSession->getUser()->getEmail(); - } - - if(!form.empty()) { - - bool langUpdatedByBtn = false; - auto langBtn = form.get("lang", ""); - if(langBtn != "") { - langUpdatedByBtn = true; - } - /* - auto langInput = form.get("lang", ""); - auto updatedLang = LANG_NULL; - if(langBtn != "") { - updatedLang = chooseLanguage(request, langBtn); - langUpdatedByBtn = true; - } else if(langInput != "") { - updatedLang = chooseLanguage(request, langInput); - } - - if(updatedLang != LANG_NULL && updatedLang != lang) { - lang = updatedLang; - langCatalog = lm->getFreeCatalog(lang); - } - */ - auto email = form.get("login-email", ""); - auto password = form.get("login-password", ""); - - if(email != "" && password != "") { - //auto session = sm->getSession(request); - //if(!mSession) mSession = sm->findByEmail(email); - if(!mSession) { - mSession = sm->getNewSession(); - mSession->setLanguageCatalog(langCatalog); - // get language - // first check url, second check language header - // for debugging client ip - auto client_host = request.clientAddress().host(); - //auto client_ip = request.clientAddress(); - // X-Real-IP forwarded ip from nginx config - auto client_host_string = request.get("X-Real-IP", client_host.toString()); - std::string clientIpString = "client ip: "; - client_host = Poco::Net::IPAddress(client_host_string); - clientIpString += client_host_string; - Poco::Logger::get("requestLog").information(clientIpString); - // debugging end - mSession->setClientIp(client_host); - response.addCookie(mSession->getLoginCookie()); - } else { - langCatalog = mSession->getLanguageCatalog(); - } - UserStates user_state; - try { - user_state = mSession->loadUser(email, password); - } catch (Poco::Exception& ex) { - addError(new ParamError("login", "exception by calling loadUser: ", ex.displayText())); - sendErrorsAsEmail(); - addError(new Error("Error", "Intern Server error, please try again later")); - } - auto user = mSession->getNewUser(); - - if(user_state >= USER_LOADED_FROM_DB && !user.isNull() && !user->getModel()->getPublicKey()) { - if(mSession->generateKeys(true, true)) { - user_state = USER_COMPLETE; - if(user->getModel()->isDisabled()) { - user_state = USER_DISABLED; - } - } - } else { - //printf("pubkey exist: %p\n",user->getModel()->getPublicKey()); - } - getErrors(mSession); - - auto uri_start = request.serverParams().getServerName(); - auto lastExternReferer = mSession->getLastReferer(); - - printf("user_state: %d\n", user_state); - - switch(user_state) { - case USER_EMPTY: - case USER_PASSWORD_INCORRECT: - addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("E-Mail or password isn't right, please try again!")), false); - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - break; - case USER_PASSWORD_ENCRYPTION_IN_PROCESS: - addError(new Error(langCatalog->gettext("Passwort"), langCatalog->gettext("Passwort wird noch berechnet, bitte versuche es in etwa 1 Minute erneut.")), false); - break; - case USER_KEYS_DONT_MATCH: - addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); - break; - case USER_DISABLED: - addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Benutzer ist deaktiviert, kein Login möglich!"))); - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - break; - case USER_NO_PRIVATE_KEY: - case USER_COMPLETE: - case USER_EMAIL_NOT_ACTIVATED: - auto referer = request.find("Referer"); - std::string refererString; - if (referer != request.end()) { - refererString = referer->second; - } - if(lastExternReferer != "") { - //printf("redirect to: %s\n", lastExternReferer.data()); - response.redirect(lastExternReferer); - } else if(refererString != "" && - refererString.find("login") == std::string::npos && - refererString.find("logout") == std::string::npos && - refererString.find("user_delete") == std::string::npos && - refererString != ServerConfig::g_serverPath + request.getURI()) { - std::string uri = request.getURI(); - printf("request uri: %s, redirect to: %s\n", uri.data(), refererString.data()); - response.redirect(refererString); - } else { - //printf("redirect to: %s\n", ServerConfig::g_php_serverPath.data()); - response.redirect(ServerConfig::g_php_serverPath + "/"); - } - return; - } - - } else if(!langUpdatedByBtn) { - addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("Username and password are needed!")), false); - } - - } else { - - // on enter login page with empty form - //auto session = sm->getSession(request); - // remove old cookies and session if exist - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - } - -#line 3 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" - - bool withMaterialIcons = false; - std::ostream& _responseStream = response.send(); - Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); - std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; - responseStream << "\n"; - // begin include header.cpsp - responseStream << "\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "Gradido Login Server: "; -#line 11 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" - responseStream << ( pageName ); - responseStream << "\n"; - responseStream << "\n"; -#line 13 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" - if(withMaterialIcons) { responseStream << "\n"; - responseStream << "\n"; -#line 15 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" - } responseStream << "\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << " "; - // end include header.cpsp - responseStream << "\n"; -#line 175 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - responseStream << ( getErrorsHtml() ); - responseStream << "\n"; - responseStream << "\n"; - responseStream << "
\n"; - responseStream << " "; - // begin include flags.cpsp - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "\t\n"; - responseStream << "\t\n"; - responseStream << "
\n"; - responseStream << "
"; - // end include flags.cpsp - responseStream << "\n"; - responseStream << "
\n"; - responseStream << "\t\t
\n"; - responseStream << "\t\t\tgettext("E-Mail") ); - responseStream << "\" value=\""; -#line 181 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - responseStream << ( presetEmail ); - responseStream << "\"/>\n"; - responseStream << "\t\t\tgettext("Password") ); - responseStream << "\" />\n"; - responseStream << "\t\t \n"; - responseStream << "\t\t
\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "\t

"; -#line 188 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - responseStream << ( langCatalog->gettext("You haven't any account yet? Please follow the link to create one.") ); - responseStream << "

\n"; - responseStream << "\t \n"; - responseStream << "\t\t\t"; -#line 190 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" - responseStream << ( langCatalog->gettext("Create New Account") ); - responseStream << "\n"; - responseStream << "\t\t \n"; - responseStream << "\t
\n"; - responseStream << "\t\t\n"; - responseStream << "\t
\n"; - responseStream << "
\n"; - responseStream << "

 

\n"; - responseStream << "
\n"; - responseStream << "\tZum Whitepaper\n"; - responseStream << "\t
\n"; - responseStream << "\t
\n"; - responseStream << "\tTo the Whitepaper\n"; - responseStream << "
\n"; - // begin include footer.cpsp - responseStream << "
\n"; - responseStream << "

Copyright © Gradido 2020

\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << " "; -#line 6 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp" - responseStream << ( mTimeProfiler.string() ); - responseStream << "\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "

Login Server in Entwicklung

\n"; - responseStream << "

Alpha "; -#line 10 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp" - responseStream << ( ServerConfig::g_versionString ); - responseStream << "

\n"; - responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << ""; - // end include footer.cpsp - if (_compressResponse) _gzipStream.close(); -} +#include "LoginPage.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/DeflatingStream.h" + + +#line 7 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + +#include "../gettext.h" + +#include "Poco/Net/HTTPCookie.h" +#include "Poco/Net/HTTPServerParams.h" +#include "Poco/Logger.h" +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/LanguageManager.h" +#include "../SingletonManager/ErrorManager.h" + +#line 1 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" + +#include "../ServerConfig.h" + + +LoginPage::LoginPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void LoginPage::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 18 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + + const char* pageName = "Login"; + auto sm = SessionManager::getInstance(); + auto lm = LanguageManager::getInstance(); + auto em = ErrorManager::getInstance(); + + auto lang = chooseLanguage(request); + //printf("choose language return: %d\n", lang); + auto langCatalog = lm->getFreeCatalog(lang); + + std::string presetEmail(""); + if(mSession && mSession->getUser()) { + presetEmail = mSession->getUser()->getEmail(); + } + + if(!form.empty()) { + + bool langUpdatedByBtn = false; + auto langBtn = form.get("lang", ""); + if(langBtn != "") { + langUpdatedByBtn = true; + } + /* + auto langInput = form.get("lang", ""); + auto updatedLang = LANG_NULL; + if(langBtn != "") { + updatedLang = chooseLanguage(request, langBtn); + langUpdatedByBtn = true; + } else if(langInput != "") { + updatedLang = chooseLanguage(request, langInput); + } + + if(updatedLang != LANG_NULL && updatedLang != lang) { + lang = updatedLang; + langCatalog = lm->getFreeCatalog(lang); + } + */ + auto email = form.get("login-email", ""); + auto password = form.get("login-password", ""); + + if(email != "" && password != "") { + //auto session = sm->getSession(request); + //if(!mSession) mSession = sm->findByEmail(email); + if(!mSession) { + mSession = sm->getNewSession(); + mSession->setLanguageCatalog(langCatalog); + // get language + // first check url, second check language header + // for debugging client ip + auto client_host = request.clientAddress().host(); + //auto client_ip = request.clientAddress(); + // X-Real-IP forwarded ip from nginx config + auto client_host_string = request.get("X-Real-IP", client_host.toString()); + std::string clientIpString = "client ip: "; + client_host = Poco::Net::IPAddress(client_host_string); + clientIpString += client_host_string; + Poco::Logger::get("requestLog").information(clientIpString); + // debugging end + mSession->setClientIp(client_host); + response.addCookie(mSession->getLoginCookie()); + } else { + langCatalog = mSession->getLanguageCatalog(); + } + UserStates user_state; + try { + user_state = mSession->loadUser(email, password); + } catch (Poco::Exception& ex) { + addError(new ParamError("login", "exception by calling loadUser: ", ex.displayText())); + sendErrorsAsEmail(); + addError(new Error("Error", "Intern Server error, please try again later")); + } + auto user = mSession->getNewUser(); + + if(user_state >= USER_LOADED_FROM_DB && !user.isNull() && !user->getModel()->getPublicKey()) { + if(mSession->generateKeys(true, true)) { + user_state = USER_COMPLETE; + if(user->getModel()->isDisabled()) { + user_state = USER_DISABLED; + } + } + } else { + //printf("pubkey exist: %p\n",user->getModel()->getPublicKey()); + } + getErrors(mSession); + + auto uri_start = request.serverParams().getServerName(); + auto lastExternReferer = mSession->getLastReferer(); + + printf("user_state: %d\n", user_state); + + switch(user_state) { + case USER_EMPTY: + case USER_PASSWORD_INCORRECT: + addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("E-Mail or password isn't right, please try again!")), false); + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + break; + case USER_PASSWORD_ENCRYPTION_IN_PROCESS: + addError(new Error(langCatalog->gettext("Passwort"), langCatalog->gettext("Passwort wird noch berechnet, bitte versuche es in etwa 1 Minute erneut.")), false); + break; + case USER_KEYS_DONT_MATCH: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); + break; + case USER_DISABLED: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Benutzer ist deaktiviert, kein Login möglich!"))); + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + break; + case USER_NO_PRIVATE_KEY: + case USER_COMPLETE: + case USER_EMAIL_NOT_ACTIVATED: + auto referer = request.find("Referer"); + std::string refererString; + if (referer != request.end()) { + refererString = referer->second; + } + if(lastExternReferer != "") { + //printf("redirect to: %s\n", lastExternReferer.data()); + response.redirect(lastExternReferer); + } else if(refererString != "" && + refererString.find("login") == std::string::npos && + refererString.find("logout") == std::string::npos && + refererString.find("user_delete") == std::string::npos && + refererString != ServerConfig::g_serverPath + request.getURI()) { + std::string uri = request.getURI(); + printf("request uri: %s, redirect to: %s\n", uri.data(), refererString.data()); + response.redirect(refererString); + } else { + //printf("redirect to: %s\n", ServerConfig::g_php_serverPath.data()); + response.redirect(ServerConfig::g_php_serverPath + "/"); + } + return; + } + + } else if(!langUpdatedByBtn) { + addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("Username and password are needed!")), false); + } + + } else { + + // on enter login page with empty form + //auto session = sm->getSession(request); + // remove old cookies and session if exist + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + } + +#line 3 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" + + bool withMaterialIcons = false; + std::ostream& _responseStream = response.send(); + Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); + std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; + responseStream << "\n"; + // begin include header.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << " "; + // end include header.cpsp + responseStream << "\n"; +#line 175 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << " "; + // begin include flags.cpsp + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "\t\n"; + responseStream << "\t\n"; + responseStream << "
\n"; + responseStream << "
"; + // end include flags.cpsp + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\tgettext("E-Mail") ); + responseStream << "\" value=\""; +#line 181 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + responseStream << ( presetEmail ); + responseStream << "\"/>\n"; + responseStream << "\t\t\tgettext("Password") ); + responseStream << "\" />\n"; + responseStream << "\t\t \n"; + responseStream << "\t\t
\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "\t

"; +#line 188 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + responseStream << ( langCatalog->gettext("You haven't any account yet? Please follow the link to create one.") ); + responseStream << "

\n"; + responseStream << "\t \n"; + responseStream << "\t\t\t"; +#line 190 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\login.cpsp" + responseStream << ( langCatalog->gettext("Create New Account") ); + responseStream << "\n"; + responseStream << "\t\t \n"; + responseStream << "\t
\n"; + responseStream << "\t\t\n"; + responseStream << "\t
\n"; + responseStream << "
\n"; + responseStream << "

 

\n"; + responseStream << "
\n"; + responseStream << "\tZum Whitepaper\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\tTo the Whitepaper\n"; + responseStream << "
\n"; + // begin include footer.cpsp + responseStream << "
\n"; + responseStream << "

Copyright © Gradido 2020

\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << " "; +#line 6 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp" + responseStream << ( mTimeProfiler.string() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "

Login Server in Entwicklung

\n"; + responseStream << "

Alpha "; +#line 10 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp" + responseStream << ( ServerConfig::g_versionString ); + responseStream << "

\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << ""; + // end include footer.cpsp + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/LoginPage.h b/login_server/src/cpp/HTTPInterface/LoginPage.h index be3dfd97d..30c617eaf 100644 --- a/login_server/src/cpp/HTTPInterface/LoginPage.h +++ b/login_server/src/cpp/HTTPInterface/LoginPage.h @@ -1,20 +1,20 @@ -#ifndef LoginPage_INCLUDED -#define LoginPage_INCLUDED - - -#include "Poco/Net/HTTPRequestHandler.h" - - -#include "SessionHTTPRequestHandler.h" - - -class LoginPage: public SessionHTTPRequestHandler -{ -public: - LoginPage(Session*); - - void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); -}; - - -#endif // LoginPage_INCLUDED +#ifndef LoginPage_INCLUDED +#define LoginPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class LoginPage: public SessionHTTPRequestHandler +{ +public: + LoginPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // LoginPage_INCLUDED diff --git a/login_server/src/cpp/ImportantTests.cpp b/login_server/src/cpp/ImportantTests.cpp index d321bab5f..a80af3cec 100644 --- a/login_server/src/cpp/ImportantTests.cpp +++ b/login_server/src/cpp/ImportantTests.cpp @@ -1,4 +1,4 @@ -#include "ImportantTests.h" +#include "ImportantTests.h" #include #include "ServerConfig.h" diff --git a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp index 6b5ecf33d..7b5cf8270 100644 --- a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp +++ b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp @@ -1,108 +1,108 @@ -#include "JsonCreateUser.h" - -#include "../model/email/Email.h" -#include "../controller/User.h" -#include "../controller/EmailVerificationCode.h" - -#include "../SingletonManager/EmailManager.h" -#include "../SingletonManager/SessionManager.h" - -#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" - -Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) -{ - std::string email; - std::string first_name; - std::string last_name; - std::string password; - bool login_after_register = false; - int emailType; - auto em = EmailManager::getInstance(); - auto sm = SessionManager::getInstance(); - - // if is json object - if (params.type() == typeid(Poco::JSON::Object::Ptr)) { - Poco::JSON::Object::Ptr paramJsonObject = params.extract(); - /// Throws a RangeException if the value does not fit - /// into the result variable. - /// Throws a NotImplementedException if conversion is - /// not available for the given type. - /// Throws InvalidAccessException if Var is empty. - try { - paramJsonObject->get("email").convert(email); - paramJsonObject->get("first_name").convert(first_name); - paramJsonObject->get("last_name").convert(last_name); - paramJsonObject->get("emailType").convert(emailType); - - if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { - paramJsonObject->get("password").convert(password); - } - if (!paramJsonObject->isNull("login_after_register")) { - paramJsonObject->get("login_after_register").convert(login_after_register); - } - } - catch (Poco::Exception& ex) { - return stateError("json exception", ex.displayText()); - } - } - else { - return stateError("parameter format unknown"); - } - - auto user = controller::User::create(); - if (user->load(email) > 0) { - return customStateError("exist", "user already exist"); - } - - if (password.size()) { - ErrorList errors; - if (!sm->checkPwdValidation(password, &errors)) { - Poco::JSON::Object* result = new Poco::JSON::Object; - result->set("state", "error"); - result->set("msg", errors.getLastError()->getString(false)); - if (errors.errorCount()) { - result->set("details", errors.getLastError()->getString(false)); - } - return result; - } - } - - // create user - user = controller::User::create(email, first_name, last_name); - auto userModel = user->getModel(); - Session* session = nullptr; - - if (!userModel->insertIntoDB(true)) { - userModel->sendErrorsAsEmail(); - return stateError("insert user failed"); - } - if (password.size()) { - session = sm->getNewSession(); - session->setUser(user); - session->generateKeys(true, true); - session->setClientIp(mClientIP); - - // calculate encryption key, could need some time, will save encrypted privkey to db - UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(user, password); - create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); - } - - auto emailOptIn = controller::EmailVerificationCode::create(userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); - auto emailOptInModel = emailOptIn->getModel(); - if (!emailOptInModel->insertIntoDB(false)) { - emailOptInModel->sendErrorsAsEmail(); - return stateError("insert emailOptIn failed"); - } - - em->addEmail(new model::Email(emailOptIn, user, model::Email::convertTypeFromInt(emailType))); - - if (login_after_register && session) { - Poco::JSON::Object* result = stateSuccess(); - - result->set("session_id", session->getHandle()); - return result; - } - - return stateSuccess(); - +#include "JsonCreateUser.h" + +#include "../model/email/Email.h" +#include "../controller/User.h" +#include "../controller/EmailVerificationCode.h" + +#include "../SingletonManager/EmailManager.h" +#include "../SingletonManager/SessionManager.h" + +#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" + +Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) +{ + std::string email; + std::string first_name; + std::string last_name; + std::string password; + bool login_after_register = false; + int emailType; + auto em = EmailManager::getInstance(); + auto sm = SessionManager::getInstance(); + + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + try { + paramJsonObject->get("email").convert(email); + paramJsonObject->get("first_name").convert(first_name); + paramJsonObject->get("last_name").convert(last_name); + paramJsonObject->get("emailType").convert(emailType); + + if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { + paramJsonObject->get("password").convert(password); + } + if (!paramJsonObject->isNull("login_after_register")) { + paramJsonObject->get("login_after_register").convert(login_after_register); + } + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + auto user = controller::User::create(); + if (user->load(email) > 0) { + return customStateError("exist", "user already exist"); + } + + if (password.size()) { + ErrorList errors; + if (!sm->checkPwdValidation(password, &errors)) { + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "error"); + result->set("msg", errors.getLastError()->getString(false)); + if (errors.errorCount()) { + result->set("details", errors.getLastError()->getString(false)); + } + return result; + } + } + + // create user + user = controller::User::create(email, first_name, last_name); + auto userModel = user->getModel(); + Session* session = nullptr; + + if (!userModel->insertIntoDB(true)) { + userModel->sendErrorsAsEmail(); + return stateError("insert user failed"); + } + if (password.size()) { + session = sm->getNewSession(); + session->setUser(user); + session->generateKeys(true, true); + session->setClientIp(mClientIP); + + // calculate encryption key, could need some time, will save encrypted privkey to db + UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(user, password); + create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); + } + + auto emailOptIn = controller::EmailVerificationCode::create(userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); + auto emailOptInModel = emailOptIn->getModel(); + if (!emailOptInModel->insertIntoDB(false)) { + emailOptInModel->sendErrorsAsEmail(); + return stateError("insert emailOptIn failed"); + } + + em->addEmail(new model::Email(emailOptIn, user, model::Email::convertTypeFromInt(emailType))); + + if (login_after_register && session) { + Poco::JSON::Object* result = stateSuccess(); + + result->set("session_id", session->getHandle()); + return result; + } + + return stateSuccess(); + } \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp b/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp index 5b426782a..c9754a14f 100644 --- a/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp +++ b/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp @@ -1,144 +1,144 @@ -#include "JsonGetUserInfos.h" - -#include "../lib/DataTypeConverter.h" -#include "../SingletonManager/SessionManager.h" -#include "../controller/User.h" -#include "../controller/EmailVerificationCode.h" - -#include "../ServerConfig.h" - -Poco::UInt64 JsonGetUserInfos::readOrCreateEmailVerificationCode(int user_id, model::table::EmailOptInType type) -{ - try { - auto emailVerificationCode = controller::EmailVerificationCode::load(user_id, type); - if (!emailVerificationCode) { - emailVerificationCode = controller::EmailVerificationCode::create(user_id, type); - UniLib::controller::TaskPtr insert = new model::table::ModelInsertTask(emailVerificationCode->getModel(), false); - insert->scheduleTask(insert); - } - return emailVerificationCode->getModel()->getCode(); - } - catch (Poco::Exception& ex) { - ErrorList errors; - //printf("exception: %s\n", ex.displayText().data()); - errors.addError(new ParamError("JsonGetUserInfos::readOrCreateEmailVerificationCode", "exception: ", ex.displayText())); - errors.sendErrorsAsEmail(); - } - return 0; -} - -Poco::JSON::Object* JsonGetUserInfos::handle(Poco::Dynamic::Var params) -{ - /* - 'session_id' => $session_id, - 'email' => $email, - 'ask' => ['EmailOptIn.Register'] - */ - // incoming - int session_id = 0; - std::string email; - Poco::JSON::Array::Ptr askArray; - - auto sm = SessionManager::getInstance(); - - // if is json object - if (params.type() == typeid(Poco::JSON::Object::Ptr)) { - Poco::JSON::Object::Ptr paramJsonObject = params.extract(); - /// Throws a RangeException if the value does not fit - /// into the result variable. - /// Throws a NotImplementedException if conversion is - /// not available for the given type. - /// Throws InvalidAccessException if Var is empty. - try { - paramJsonObject->get("email").convert(email); - paramJsonObject->get("session_id").convert(session_id); - askArray = paramJsonObject->getArray("ask"); - } - catch (Poco::Exception& ex) { - return stateError("json exception", ex.displayText()); - } - } - else { - return stateError("parameter format unknown"); - } - - if (!session_id) { - return stateError("session_id invalid"); - } - if (askArray.isNull()) { - return stateError("ask is zero or not an array"); - } - - auto session = sm->getSession(session_id); - if (!session) { - return customStateError("not found", "session not found"); - } - - auto session_user = session->getNewUser(); - auto session_user_model = session_user->getModel(); - bool isAdmin = false; - bool emailBelongToUser = false; - if (model::table::ROLE_ADMIN == session_user_model->getRole()) { - isAdmin = true; - } - if (session_user_model->getEmail() == email) { - emailBelongToUser = true; - } - - auto user = controller::User::create(); - if (1 != user->load(email)) { - return customStateError("not found", "user not found"); - } - auto user_model = user->getModel(); - - - Poco::JSON::Object* result = new Poco::JSON::Object; - result->set("state", "success"); - Poco::JSON::Array jsonErrorsArray; - Poco::JSON::Object jsonUser; - Poco::JSON::Object jsonServer; - - for (auto it = askArray->begin(); it != askArray->end(); it++) { - auto parameter = *it; - std::string parameterString; - try { - parameter.convert(parameterString); - if (parameterString == "EmailVerificationCode.Register" && isAdmin && !emailBelongToUser) { - auto code = readOrCreateEmailVerificationCode(user_model->getID(), model::table::EMAIL_OPT_IN_REGISTER_DIRECT); - if (code) { - jsonUser.set("EmailVerificationCode.Register", std::to_string(code)); - } - } - else if (parameterString == "loginServer.path") { - jsonServer.set("loginServer.path", ServerConfig::g_serverPath); - } - else if (parameterString == "user.pubkeyhex") { - jsonUser.set("pubkeyhex", user_model->getPublicKeyHex()); - } - else if (parameterString == "user.first_name") { - jsonUser.set("first_name", user_model->getFirstName()); - } - else if (parameterString == "user.last_name") { - jsonUser.set("last_name", user_model->getLastName()); - } - else if (parameterString == "user.disabled") { - jsonUser.set("disabled", user_model->isDisabled()); - } - else if (parameterString == "user.email_checked" && (isAdmin || emailBelongToUser)) { - jsonUser.set("email_checked", user_model->isEmailChecked()); - } - else if (parameterString == "user.identHash") { - auto email = user_model->getEmail(); - jsonUser.set("identHash", DRMakeStringHash(email.data(), email.size())); - } - } - catch (Poco::Exception& ex) { - jsonErrorsArray.add("ask parameter invalid"); - } - } - result->set("errors", jsonErrorsArray); - result->set("userData", jsonUser); - result->set("server", jsonServer); - return result; - +#include "JsonGetUserInfos.h" + +#include "../lib/DataTypeConverter.h" +#include "../SingletonManager/SessionManager.h" +#include "../controller/User.h" +#include "../controller/EmailVerificationCode.h" + +#include "../ServerConfig.h" + +Poco::UInt64 JsonGetUserInfos::readOrCreateEmailVerificationCode(int user_id, model::table::EmailOptInType type) +{ + try { + auto emailVerificationCode = controller::EmailVerificationCode::load(user_id, type); + if (!emailVerificationCode) { + emailVerificationCode = controller::EmailVerificationCode::create(user_id, type); + UniLib::controller::TaskPtr insert = new model::table::ModelInsertTask(emailVerificationCode->getModel(), false); + insert->scheduleTask(insert); + } + return emailVerificationCode->getModel()->getCode(); + } + catch (Poco::Exception& ex) { + ErrorList errors; + //printf("exception: %s\n", ex.displayText().data()); + errors.addError(new ParamError("JsonGetUserInfos::readOrCreateEmailVerificationCode", "exception: ", ex.displayText())); + errors.sendErrorsAsEmail(); + } + return 0; +} + +Poco::JSON::Object* JsonGetUserInfos::handle(Poco::Dynamic::Var params) +{ + /* + 'session_id' => $session_id, + 'email' => $email, + 'ask' => ['EmailOptIn.Register'] + */ + // incoming + int session_id = 0; + std::string email; + Poco::JSON::Array::Ptr askArray; + + auto sm = SessionManager::getInstance(); + + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + try { + paramJsonObject->get("email").convert(email); + paramJsonObject->get("session_id").convert(session_id); + askArray = paramJsonObject->getArray("ask"); + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + if (!session_id) { + return stateError("session_id invalid"); + } + if (askArray.isNull()) { + return stateError("ask is zero or not an array"); + } + + auto session = sm->getSession(session_id); + if (!session) { + return customStateError("not found", "session not found"); + } + + auto session_user = session->getNewUser(); + auto session_user_model = session_user->getModel(); + bool isAdmin = false; + bool emailBelongToUser = false; + if (model::table::ROLE_ADMIN == session_user_model->getRole()) { + isAdmin = true; + } + if (session_user_model->getEmail() == email) { + emailBelongToUser = true; + } + + auto user = controller::User::create(); + if (1 != user->load(email)) { + return customStateError("not found", "user not found"); + } + auto user_model = user->getModel(); + + + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + Poco::JSON::Array jsonErrorsArray; + Poco::JSON::Object jsonUser; + Poco::JSON::Object jsonServer; + + for (auto it = askArray->begin(); it != askArray->end(); it++) { + auto parameter = *it; + std::string parameterString; + try { + parameter.convert(parameterString); + if (parameterString == "EmailVerificationCode.Register" && isAdmin && !emailBelongToUser) { + auto code = readOrCreateEmailVerificationCode(user_model->getID(), model::table::EMAIL_OPT_IN_REGISTER_DIRECT); + if (code) { + jsonUser.set("EmailVerificationCode.Register", std::to_string(code)); + } + } + else if (parameterString == "loginServer.path") { + jsonServer.set("loginServer.path", ServerConfig::g_serverPath); + } + else if (parameterString == "user.pubkeyhex") { + jsonUser.set("pubkeyhex", user_model->getPublicKeyHex()); + } + else if (parameterString == "user.first_name") { + jsonUser.set("first_name", user_model->getFirstName()); + } + else if (parameterString == "user.last_name") { + jsonUser.set("last_name", user_model->getLastName()); + } + else if (parameterString == "user.disabled") { + jsonUser.set("disabled", user_model->isDisabled()); + } + else if (parameterString == "user.email_checked" && (isAdmin || emailBelongToUser)) { + jsonUser.set("email_checked", user_model->isEmailChecked()); + } + else if (parameterString == "user.identHash") { + auto email = user_model->getEmail(); + jsonUser.set("identHash", DRMakeStringHash(email.data(), email.size())); + } + } + catch (Poco::Exception& ex) { + jsonErrorsArray.add("ask parameter invalid"); + } + } + result->set("errors", jsonErrorsArray); + result->set("userData", jsonUser); + result->set("server", jsonServer); + return result; + } \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonLogout.cpp b/login_server/src/cpp/JSONInterface/JsonLogout.cpp index 0b347f767..03cb25fb3 100644 --- a/login_server/src/cpp/JSONInterface/JsonLogout.cpp +++ b/login_server/src/cpp/JSONInterface/JsonLogout.cpp @@ -1,44 +1,44 @@ -#include "JsonLogout.h" - - - -#include "../SingletonManager/SessionManager.h" - - -Poco::JSON::Object* JsonLogout::handle(Poco::Dynamic::Var params) -{ - - auto sm = SessionManager::getInstance(); - int session_id = 0; - - // if is json object - if (params.type() == typeid(Poco::JSON::Object::Ptr)) { - Poco::JSON::Object::Ptr paramJsonObject = params.extract(); - /// Throws a RangeException if the value does not fit - /// into the result variable. - /// Throws a NotImplementedException if conversion is - /// not available for the given type. - /// Throws InvalidAccessException if Var is empty. - try { - paramJsonObject->get("session_id").convert(session_id); - } - catch (Poco::Exception& ex) { - return stateError("json exception", ex.displayText()); - } - } - else { - return stateError("parameter format unknown"); - } - - auto session = sm->getSession(session_id); - if (!session) { - return stateError("session not found", std::to_string(session_id)); - } - if (sm->releaseSession(session_id)) { - return stateSuccess(); - } - return stateError("error by releasing session"); - - - +#include "JsonLogout.h" + + + +#include "../SingletonManager/SessionManager.h" + + +Poco::JSON::Object* JsonLogout::handle(Poco::Dynamic::Var params) +{ + + auto sm = SessionManager::getInstance(); + int session_id = 0; + + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + try { + paramJsonObject->get("session_id").convert(session_id); + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + auto session = sm->getSession(session_id); + if (!session) { + return stateError("session not found", std::to_string(session_id)); + } + if (sm->releaseSession(session_id)) { + return stateSuccess(); + } + return stateError("error by releasing session"); + + + } \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonLogout.h b/login_server/src/cpp/JSONInterface/JsonLogout.h index 7243d2b8c..8b3def105 100644 --- a/login_server/src/cpp/JSONInterface/JsonLogout.h +++ b/login_server/src/cpp/JSONInterface/JsonLogout.h @@ -1,18 +1,18 @@ -#ifndef __JSON_INTERFACE_JSON_LOGOUT_ -#define __JSON_INTERFACE_JSON_LOGOUT_ - -#include "JsonRequestHandler.h" - -class JsonLogout : public JsonRequestHandler -{ -public: - JsonLogout(Poco::Net::IPAddress ip) : mClientIP(ip) {} - Poco::JSON::Object* handle(Poco::Dynamic::Var params); - -protected: - Poco::Net::IPAddress mClientIP; - - -}; - +#ifndef __JSON_INTERFACE_JSON_LOGOUT_ +#define __JSON_INTERFACE_JSON_LOGOUT_ + +#include "JsonRequestHandler.h" + +class JsonLogout : public JsonRequestHandler +{ +public: + JsonLogout(Poco::Net::IPAddress ip) : mClientIP(ip) {} + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + Poco::Net::IPAddress mClientIP; + + +}; + #endif // __JSON_INTERFACE_JSON_LOGOUT_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp index b66cba495..3f9bd35b3 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp @@ -1,141 +1,141 @@ -#include "JsonRequestHandler.h" - -#include "Poco/Net/HTTPServerRequest.h" -#include "Poco/Net/HTTPServerResponse.h" - -#include "Poco/URI.h" -#include "Poco/DeflatingStream.h" - -#include "Poco/JSON/Parser.h" - -#include "../ServerConfig.h" - -#include "../lib/DataTypeConverter.h" -#include "../SingletonManager/SessionManager.h" - - -void JsonRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) -{ - - response.setChunkedTransferEncoding(false); - response.setContentType("application/json"); - if (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_CORS_ALL) { - response.set("Access-Control-Allow-Origin", "*"); - response.set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); - } - //bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); - //if (_compressResponse) response.set("Content-Encoding", "gzip"); - - std::ostream& responseStream = response.send(); - //Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); - //std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; - - auto method = request.getMethod(); - std::istream& request_stream = request.stream(); - Poco::JSON::Object* json_result = nullptr; - if (method == "POST" || method == "PUT") { - // extract parameter from request - Poco::Dynamic::Var parsedResult = parseJsonWithErrorPrintFile(request_stream); - - if (parsedResult.size() != 0) { - json_result = handle(parsedResult); - } - else { - json_result = stateError("empty body"); - } - - } - else if(method == "GET") { - Poco::URI uri(request.getURI()); - auto queryParameters = uri.getQueryParameters(); - json_result = handle(queryParameters); - } - - if (json_result) { - if (!json_result->isNull("session_id")) { - int session_id = 0; - try { - json_result->get("session_id").convert(session_id); - } - catch (Poco::Exception& e) { - ErrorList erros; - erros.addError(new Error("json request", "invalid session_id")); - erros.sendErrorsAsEmail(); - } - if (session_id) { - auto session = SessionManager::getInstance()->getSession(session_id); - response.addCookie(session->getLoginCookie()); - } - } - json_result->stringify(responseStream); - delete json_result; - } - - //if (_compressResponse) _gzipStream.close(); -} - - -Poco::Dynamic::Var JsonRequestHandler::parseJsonWithErrorPrintFile(std::istream& request_stream, ErrorList* errorHandler /* = nullptr*/, const char* functionName /* = nullptr*/) -{ - // debugging answer - - std::stringstream responseStringStream; - for (std::string line; std::getline(request_stream, line); ) { - responseStringStream << line << std::endl; - } - - // extract parameter from request - Poco::JSON::Parser jsonParser; - Poco::Dynamic::Var parsedJson; - try { - parsedJson = jsonParser.parse(responseStringStream.str()); - - return parsedJson; - } - catch (Poco::Exception& ex) { - if (errorHandler) { - errorHandler->addError(new ParamError(functionName, "error parsing request answer", ex.displayText().data())); - errorHandler->sendErrorsAsEmail(responseStringStream.str()); - } - std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d_%m_%yT%H_%M_%S"); - std::string filename = dateTimeString + "_response.html"; - FILE* f = fopen(filename.data(), "wt"); - if (f) { - std::string responseString = responseStringStream.str(); - fwrite(responseString.data(), 1, responseString.size(), f); - fclose(f); - } - return Poco::Dynamic::Var(); - } - return Poco::Dynamic::Var(); -} - -Poco::JSON::Object* JsonRequestHandler::stateError(const char* msg, std::string details) -{ - Poco::JSON::Object* result = new Poco::JSON::Object; - result->set("state", "error"); - result->set("msg", msg); - if (details != "") { - result->set("details", details); - } - return result; -} - -Poco::JSON::Object* JsonRequestHandler::stateSuccess() -{ - Poco::JSON::Object* result = new Poco::JSON::Object; - result->set("state", "success"); - return result; -} - -Poco::JSON::Object* JsonRequestHandler::customStateError(const char* state, const char* msg, std::string details/* = ""*/) -{ - Poco::JSON::Object* result = new Poco::JSON::Object; - result->set("state", state); - result->set("msg", msg); - if (details != "") { - result->set("details", details); - } - return result; -} - +#include "JsonRequestHandler.h" + +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" + +#include "Poco/URI.h" +#include "Poco/DeflatingStream.h" + +#include "Poco/JSON/Parser.h" + +#include "../ServerConfig.h" + +#include "../lib/DataTypeConverter.h" +#include "../SingletonManager/SessionManager.h" + + +void JsonRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) +{ + + response.setChunkedTransferEncoding(false); + response.setContentType("application/json"); + if (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_CORS_ALL) { + response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); + } + //bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); + //if (_compressResponse) response.set("Content-Encoding", "gzip"); + + std::ostream& responseStream = response.send(); + //Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); + //std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; + + auto method = request.getMethod(); + std::istream& request_stream = request.stream(); + Poco::JSON::Object* json_result = nullptr; + if (method == "POST" || method == "PUT") { + // extract parameter from request + Poco::Dynamic::Var parsedResult = parseJsonWithErrorPrintFile(request_stream); + + if (parsedResult.size() != 0) { + json_result = handle(parsedResult); + } + else { + json_result = stateError("empty body"); + } + + } + else if(method == "GET") { + Poco::URI uri(request.getURI()); + auto queryParameters = uri.getQueryParameters(); + json_result = handle(queryParameters); + } + + if (json_result) { + if (!json_result->isNull("session_id")) { + int session_id = 0; + try { + json_result->get("session_id").convert(session_id); + } + catch (Poco::Exception& e) { + ErrorList erros; + erros.addError(new Error("json request", "invalid session_id")); + erros.sendErrorsAsEmail(); + } + if (session_id) { + auto session = SessionManager::getInstance()->getSession(session_id); + response.addCookie(session->getLoginCookie()); + } + } + json_result->stringify(responseStream); + delete json_result; + } + + //if (_compressResponse) _gzipStream.close(); +} + + +Poco::Dynamic::Var JsonRequestHandler::parseJsonWithErrorPrintFile(std::istream& request_stream, ErrorList* errorHandler /* = nullptr*/, const char* functionName /* = nullptr*/) +{ + // debugging answer + + std::stringstream responseStringStream; + for (std::string line; std::getline(request_stream, line); ) { + responseStringStream << line << std::endl; + } + + // extract parameter from request + Poco::JSON::Parser jsonParser; + Poco::Dynamic::Var parsedJson; + try { + parsedJson = jsonParser.parse(responseStringStream.str()); + + return parsedJson; + } + catch (Poco::Exception& ex) { + if (errorHandler) { + errorHandler->addError(new ParamError(functionName, "error parsing request answer", ex.displayText().data())); + errorHandler->sendErrorsAsEmail(responseStringStream.str()); + } + std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d_%m_%yT%H_%M_%S"); + std::string filename = dateTimeString + "_response.html"; + FILE* f = fopen(filename.data(), "wt"); + if (f) { + std::string responseString = responseStringStream.str(); + fwrite(responseString.data(), 1, responseString.size(), f); + fclose(f); + } + return Poco::Dynamic::Var(); + } + return Poco::Dynamic::Var(); +} + +Poco::JSON::Object* JsonRequestHandler::stateError(const char* msg, std::string details) +{ + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "error"); + result->set("msg", msg); + if (details != "") { + result->set("details", details); + } + return result; +} + +Poco::JSON::Object* JsonRequestHandler::stateSuccess() +{ + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + return result; +} + +Poco::JSON::Object* JsonRequestHandler::customStateError(const char* state, const char* msg, std::string details/* = ""*/) +{ + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", state); + result->set("msg", msg); + if (details != "") { + result->set("details", details); + } + return result; +} + diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp index 903ccfdfb..d6eff52f9 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -1,82 +1,82 @@ -#include "JsonRequestHandlerFactory.h" - -#include "Poco/Net/HTTPServerRequest.h" - -#include "../SingletonManager/SessionManager.h" - -#include "JsonAdminEmailVerificationResend.h" -#include "JsonCheckSessionState.h" -#include "JsonCreateUser.h" -#include "JsonGetLogin.h" -#include "JsonUnknown.h" -#include "JsonTransaction.h" -#include "JsonGetRunningUserTasks.h" -#include "JsonGetUsers.h" -#include "JsonLoginViaEmailVerificationCode.h" -#include "JsonGetUserInfos.h" -#include "JsonUpdateUserInfos.h" -#include "JsonUnsecureLogin.h" -#include "JsonLogout.h" - -JsonRequestHandlerFactory::JsonRequestHandlerFactory() - : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)"), mLogging(Poco::Logger::get("requestLog")) -{ -} - -Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) -{ - std::string uri = request.getURI(); - std::string url_first_part; - std::stringstream logStream; - - mRemoveGETParameters.extract(uri, url_first_part); - - std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); - logStream << dateTimeString << " call " << uri; - - mLogging.information(logStream.str()); - - auto client_host = request.clientAddress().host(); - //auto client_ip = request.clientAddress(); - // X-Real-IP forwarded ip from nginx config - auto client_host_string = request.get("X-Real-IP", client_host.toString()); - client_host = Poco::Net::IPAddress(client_host_string); - - if (url_first_part == "/login") { - return new JsonGetLogin; - } - else if (url_first_part == "/checkSessionState") { - return new JsonCheckSessionState; - } - else if (url_first_part == "/checkTransaction") { - return new JsonTransaction; - } - else if (url_first_part == "/getRunningUserTasks") { - return new JsonGetRunningUserTasks; - } - else if (url_first_part == "/getUsers") { - return new JsonGetUsers; - } - else if (url_first_part == "/createUser") { - return new JsonCreateUser(client_host); - } - else if (url_first_part == "/adminEmailVerificationResend") { - return new JsonAdminEmailVerificationResend; - } - else if (url_first_part == "/getUserInfos") { - return new JsonGetUserInfos; - } - else if (url_first_part == "/updateUserInfos") { - return new JsonUpdateUserInfos; - } - else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { - return new JsonUnsecureLogin(client_host); - } - else if (url_first_part == "/loginViaEmailVerificationCode") { - return new JsonLoginViaEmailVerificationCode(client_host); - } - else if (url_first_part == "/logout") { - return new JsonLogout(client_host); - } - return new JsonUnknown; -} +#include "JsonRequestHandlerFactory.h" + +#include "Poco/Net/HTTPServerRequest.h" + +#include "../SingletonManager/SessionManager.h" + +#include "JsonAdminEmailVerificationResend.h" +#include "JsonCheckSessionState.h" +#include "JsonCreateUser.h" +#include "JsonGetLogin.h" +#include "JsonUnknown.h" +#include "JsonTransaction.h" +#include "JsonGetRunningUserTasks.h" +#include "JsonGetUsers.h" +#include "JsonLoginViaEmailVerificationCode.h" +#include "JsonGetUserInfos.h" +#include "JsonUpdateUserInfos.h" +#include "JsonUnsecureLogin.h" +#include "JsonLogout.h" + +JsonRequestHandlerFactory::JsonRequestHandlerFactory() + : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)"), mLogging(Poco::Logger::get("requestLog")) +{ +} + +Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) +{ + std::string uri = request.getURI(); + std::string url_first_part; + std::stringstream logStream; + + mRemoveGETParameters.extract(uri, url_first_part); + + std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); + logStream << dateTimeString << " call " << uri; + + mLogging.information(logStream.str()); + + auto client_host = request.clientAddress().host(); + //auto client_ip = request.clientAddress(); + // X-Real-IP forwarded ip from nginx config + auto client_host_string = request.get("X-Real-IP", client_host.toString()); + client_host = Poco::Net::IPAddress(client_host_string); + + if (url_first_part == "/login") { + return new JsonGetLogin; + } + else if (url_first_part == "/checkSessionState") { + return new JsonCheckSessionState; + } + else if (url_first_part == "/checkTransaction") { + return new JsonTransaction; + } + else if (url_first_part == "/getRunningUserTasks") { + return new JsonGetRunningUserTasks; + } + else if (url_first_part == "/getUsers") { + return new JsonGetUsers; + } + else if (url_first_part == "/createUser") { + return new JsonCreateUser(client_host); + } + else if (url_first_part == "/adminEmailVerificationResend") { + return new JsonAdminEmailVerificationResend; + } + else if (url_first_part == "/getUserInfos") { + return new JsonGetUserInfos; + } + else if (url_first_part == "/updateUserInfos") { + return new JsonUpdateUserInfos; + } + else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { + return new JsonUnsecureLogin(client_host); + } + else if (url_first_part == "/loginViaEmailVerificationCode") { + return new JsonLoginViaEmailVerificationCode(client_host); + } + else if (url_first_part == "/logout") { + return new JsonLogout(client_host); + } + return new JsonUnknown; +} diff --git a/login_server/src/cpp/JSONInterface/JsonTransaction.cpp b/login_server/src/cpp/JSONInterface/JsonTransaction.cpp index 62f001469..dcc5023f9 100644 --- a/login_server/src/cpp/JSONInterface/JsonTransaction.cpp +++ b/login_server/src/cpp/JSONInterface/JsonTransaction.cpp @@ -1,175 +1,175 @@ -#include "JsonTransaction.h" -#include "Poco/URI.h" -#include "Poco/Dynamic/Struct.h" - -#include "../SingletonManager/SessionManager.h" -#include "../ServerConfig.h" - -Poco::JSON::Object* JsonTransaction::handle(Poco::Dynamic::Var params) -{ - Poco::JSON::Object* result = new Poco::JSON::Object; - int session_id = 0; - - // if is json object - if (params.type() == typeid(Poco::JSON::Object::Ptr)) { - Poco::JSON::Object::Ptr paramJsonObject = params.extract(); - - try { - /// Throws a RangeException if the value does not fit - /// into the result variable. - /// Throws a NotImplementedException if conversion is - /// not available for the given type. - /// Throws InvalidAccessException if Var is empty. - paramJsonObject->get("session_id").convert(session_id); - auto sm = SessionManager::getInstance(); - if (session_id != 0) { - auto session = sm->getSession(session_id); - if (!session) { - result->set("state", "error"); - result->set("msg", "session not found"); - return result; - } - - int balance = 0; - - if (!paramJsonObject->isNull("balance")) { - paramJsonObject->get("balance").convert(balance); - if (balance) { - auto u = session->getUser(); - if (u) { - u->setBalance(balance); - } - auto nu = session->getNewUser(); - if (!nu.isNull()) { - nu->setBalance(balance); - } - } - } - - std::string transactionBase64String; - Poco::Dynamic::Var transaction_base64 = paramJsonObject->get("transaction_base64"); - bool auto_sign = false; - auto auto_sign_json = paramJsonObject->get("auto_sign"); - if (!auto_sign_json.isEmpty()) { - auto_sign_json.convert(auto_sign); - } - - if (transaction_base64.isString()) { - paramJsonObject->get("transaction_base64").convert(transactionBase64String); - - if (!session->startProcessingTransaction(transactionBase64String, auto_sign)) { - if (auto_sign) { - auto errorJson = session->getErrorsArray(); - result->set("state", "error"); - result->set("msg", "error processing transaction"); - result->set("details", errorJson); - return result; - } - auto lastError = session->getLastError(); - if (lastError) delete lastError; - result->set("state", "error"); - result->set("msg", "already enlisted"); - return result; - } - - } else { - Poco::DynamicStruct ds = *paramJsonObject; - int alreadyEnlisted = 0; - - for (int i = 0; i < ds["transaction_base64"].size(); i++) { - ds["transaction_base64"][i].convert(transactionBase64String); - if (!session->startProcessingTransaction(transactionBase64String, auto_sign)) { - auto lastError = session->getLastError(); - if (lastError) delete lastError; - alreadyEnlisted++; - } - } - - if (alreadyEnlisted > 0) { - result->set("state", "warning"); - result->set("msg", std::to_string(alreadyEnlisted) + " already enlisted"); - return result; - } - } - - - - result->set("state", "success"); - return result; - } - - } - catch (Poco::Exception& ex) { - printf("[JsonTransaction::handle] try to use params as jsonObject: %s\n", ex.displayText().data()); - result->set("state", "error"); - result->set("msg", "json exception"); - result->set("details", ex.displayText()); - return result; - } - } - else if (params.isVector()) { - const Poco::URI::QueryParameters queryParams = params.extract(); - auto transactionIT = queryParams.begin(); - for (auto it = queryParams.begin(); it != queryParams.end(); it++) { - if (it->first == "session_id") { - session_id = stoi(it->second); - //break; - } - else if (it->first == "transaction_base64") { - transactionIT = it; - } - } - if (session_id) { - auto sm = SessionManager::getInstance(); - auto session = sm->getSession(session_id); - if (!session) { - result->set("state", "error"); - result->set("msg", "session not found"); - return result; - } - if (!session->startProcessingTransaction(transactionIT->second)) { - auto lastError = session->getLastError(); - if (lastError) delete lastError; - result->set("state", "error"); - result->set("msg", "already enlisted"); - return result; - } - result->set("state", "success"); - return result; - } - else { - result->set("state", "error"); - result->set("msg", "session id not set"); - return result; - } - } - else if (params.isStruct()) { - result->set("state", "error"); - result->set("msg", "struct not implemented yet"); - } - else if (params.isArray()) { - result->set("state", "error"); - result->set("msg", "array not implemented yet"); - } - else if (params.isList()) { - result->set("state", "error"); - result->set("msg", "list not implemented yet"); - } - else if (params.isString()) { - result->set("state", "error"); - result->set("msg", "string not implemented yet"); - } - else if (params.isDeque()) { - result->set("state", "error"); - result->set("msg", "deque not implemented yet"); - } - else { - - result->set("state", "error"); - result->set("msg", "format not implemented"); - result->set("details", std::string(params.type().name())); - } - - return result; -} - +#include "JsonTransaction.h" +#include "Poco/URI.h" +#include "Poco/Dynamic/Struct.h" + +#include "../SingletonManager/SessionManager.h" +#include "../ServerConfig.h" + +Poco::JSON::Object* JsonTransaction::handle(Poco::Dynamic::Var params) +{ + Poco::JSON::Object* result = new Poco::JSON::Object; + int session_id = 0; + + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + + try { + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + paramJsonObject->get("session_id").convert(session_id); + auto sm = SessionManager::getInstance(); + if (session_id != 0) { + auto session = sm->getSession(session_id); + if (!session) { + result->set("state", "error"); + result->set("msg", "session not found"); + return result; + } + + int balance = 0; + + if (!paramJsonObject->isNull("balance")) { + paramJsonObject->get("balance").convert(balance); + if (balance) { + auto u = session->getUser(); + if (u) { + u->setBalance(balance); + } + auto nu = session->getNewUser(); + if (!nu.isNull()) { + nu->setBalance(balance); + } + } + } + + std::string transactionBase64String; + Poco::Dynamic::Var transaction_base64 = paramJsonObject->get("transaction_base64"); + bool auto_sign = false; + auto auto_sign_json = paramJsonObject->get("auto_sign"); + if (!auto_sign_json.isEmpty()) { + auto_sign_json.convert(auto_sign); + } + + if (transaction_base64.isString()) { + paramJsonObject->get("transaction_base64").convert(transactionBase64String); + + if (!session->startProcessingTransaction(transactionBase64String, auto_sign)) { + if (auto_sign) { + auto errorJson = session->getErrorsArray(); + result->set("state", "error"); + result->set("msg", "error processing transaction"); + result->set("details", errorJson); + return result; + } + auto lastError = session->getLastError(); + if (lastError) delete lastError; + result->set("state", "error"); + result->set("msg", "already enlisted"); + return result; + } + + } else { + Poco::DynamicStruct ds = *paramJsonObject; + int alreadyEnlisted = 0; + + for (int i = 0; i < ds["transaction_base64"].size(); i++) { + ds["transaction_base64"][i].convert(transactionBase64String); + if (!session->startProcessingTransaction(transactionBase64String, auto_sign)) { + auto lastError = session->getLastError(); + if (lastError) delete lastError; + alreadyEnlisted++; + } + } + + if (alreadyEnlisted > 0) { + result->set("state", "warning"); + result->set("msg", std::to_string(alreadyEnlisted) + " already enlisted"); + return result; + } + } + + + + result->set("state", "success"); + return result; + } + + } + catch (Poco::Exception& ex) { + printf("[JsonTransaction::handle] try to use params as jsonObject: %s\n", ex.displayText().data()); + result->set("state", "error"); + result->set("msg", "json exception"); + result->set("details", ex.displayText()); + return result; + } + } + else if (params.isVector()) { + const Poco::URI::QueryParameters queryParams = params.extract(); + auto transactionIT = queryParams.begin(); + for (auto it = queryParams.begin(); it != queryParams.end(); it++) { + if (it->first == "session_id") { + session_id = stoi(it->second); + //break; + } + else if (it->first == "transaction_base64") { + transactionIT = it; + } + } + if (session_id) { + auto sm = SessionManager::getInstance(); + auto session = sm->getSession(session_id); + if (!session) { + result->set("state", "error"); + result->set("msg", "session not found"); + return result; + } + if (!session->startProcessingTransaction(transactionIT->second)) { + auto lastError = session->getLastError(); + if (lastError) delete lastError; + result->set("state", "error"); + result->set("msg", "already enlisted"); + return result; + } + result->set("state", "success"); + return result; + } + else { + result->set("state", "error"); + result->set("msg", "session id not set"); + return result; + } + } + else if (params.isStruct()) { + result->set("state", "error"); + result->set("msg", "struct not implemented yet"); + } + else if (params.isArray()) { + result->set("state", "error"); + result->set("msg", "array not implemented yet"); + } + else if (params.isList()) { + result->set("state", "error"); + result->set("msg", "list not implemented yet"); + } + else if (params.isString()) { + result->set("state", "error"); + result->set("msg", "string not implemented yet"); + } + else if (params.isDeque()) { + result->set("state", "error"); + result->set("msg", "deque not implemented yet"); + } + else { + + result->set("state", "error"); + result->set("msg", "format not implemented"); + result->set("details", std::string(params.type().name())); + } + + return result; +} + diff --git a/login_server/src/cpp/JSONInterface/JsonTransaction.h b/login_server/src/cpp/JSONInterface/JsonTransaction.h index 7d842fac0..95e9885be 100644 --- a/login_server/src/cpp/JSONInterface/JsonTransaction.h +++ b/login_server/src/cpp/JSONInterface/JsonTransaction.h @@ -1,19 +1,19 @@ -#ifndef __JSON_INTERFACE_JSON_TRANSACTION_ -#define __JSON_INTERFACE_JSON_TRANSACTION_ - -#include "JsonRequestHandler.h" - -class Session; - -class JsonTransaction : public JsonRequestHandler -{ -public: - Poco::JSON::Object* handle(Poco::Dynamic::Var params); - -protected: - bool startProcessingTransaction(Session* session, const std::string& transactionBase64); - - -}; - +#ifndef __JSON_INTERFACE_JSON_TRANSACTION_ +#define __JSON_INTERFACE_JSON_TRANSACTION_ + +#include "JsonRequestHandler.h" + +class Session; + +class JsonTransaction : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + bool startProcessingTransaction(Session* session, const std::string& transactionBase64); + + +}; + #endif // __JSON_INTERFACE_JSON_TRANSACTION_ \ No newline at end of file diff --git a/login_server/src/cpp/ServerConfig.cpp b/login_server/src/cpp/ServerConfig.cpp index f319ea460..d37480a80 100644 --- a/login_server/src/cpp/ServerConfig.cpp +++ b/login_server/src/cpp/ServerConfig.cpp @@ -1,349 +1,349 @@ -#include "ServerConfig.h" -#include "Crypto/mnemonic_german.h" -#include "Crypto/mnemonic_german2.h" -#include "Crypto/mnemonic_bip0039.h" -#include "Crypto/DRRandom.h" -#include "lib/DataTypeConverter.h" -#include "sodium.h" - - -#include "Poco/Net/SSLManager.h" -#include "Poco/Net/KeyConsoleHandler.h" -#include "Poco/Net/RejectCertificateHandler.h" -#include "Poco/Net/DNS.h" -#include "Poco/SharedPtr.h" - -#include "Poco/Mutex.h" -#include "Poco/Path.h" -#include "Poco/FileStream.h" -#include "Poco/LocalDateTime.h" -#include "Poco/DateTimeFormat.h" -#include "Poco/DateTimeFormatter.h" - - -using Poco::Net::SSLManager; -using Poco::Net::Context; -using Poco::Net::KeyConsoleHandler; -using Poco::Net::PrivateKeyPassphraseHandler; -using Poco::Net::InvalidCertificateHandler; -using Poco::Net::RejectCertificateHandler; -using Poco::SharedPtr; - -namespace ServerConfig { - -#define SESSION_TIMEOUT_DEFAULT 10 - - Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; - ObfusArray* g_ServerCryptoKey = nullptr; - ObfusArray* g_ServerKeySeed = nullptr; -// std::string g_ServerAdminPublic; - UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr; - UniLib::controller::CPUSheduler* g_CryptoCPUScheduler = nullptr; - Context::Ptr g_SSL_CLient_Context = nullptr; - Poco::Util::Timer g_CronJobsTimer; - EmailAccount g_EmailAccount; - int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT; - std::string g_serverPath; - int g_serverPort = 0; - Languages g_default_locale; - std::string g_php_serverPath; - std::string g_php_serverHost; - int g_phpServerPort; - Poco::Mutex g_TimeMutex; - int g_FakeLoginSleepTime = 820; - std::string g_versionString = ""; - bool g_disableEmail = false; - ServerSetupType g_ServerSetupType = SERVER_TYPE_PRODUCTION; - std::string g_gRPCRelayServerFullURL; - MemoryBin* g_CryptoAppSecret = nullptr; - AllowUnsecure g_AllowUnsecureFlags = NOT_UNSECURE; - -#ifdef __linux__ -#include -#include -#include -#include -#include -#include -#endif //#ifdef __linux__ - - std::string getHostIpString() - { -#ifdef __linux__ - struct ifaddrs * ifAddrStruct = NULL; - struct ifaddrs * ifa = NULL; - void * tmpAddrPtr = NULL; - - getifaddrs(&ifAddrStruct); - std::string ipAddressString; - - for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) { - continue; - } - if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 - // is a valid IP4 Address - tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - char addressBuffer[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); - ipAddressString = addressBuffer; - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6 - // is a valid IP6 Address - tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; - char addressBuffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - } - if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct); - return ipAddressString; -#else //__linux__ - std::string ipAddressString = ""; - auto host = Poco::Net::DNS::thisHost(); - for (auto it = host.addresses().begin(); it != host.addresses().end(); it++) { - auto ipAddress = *it; - if (!ipAddress.isIPv4Compatible() && !ipAddress.isIPv4Mapped()) { - continue; - } - if (ipAddress.isLoopback()) { - continue; - } - ipAddressString = ipAddress.toString(); - //isIPv4Compatible - //!isLoopback - //printf("ipaddress: %s\n", ipAddressString.data()); - break; - //break; - } - return ipAddressString; -#endif // __linux__ - } - - bool replaceZeroIPWithLocalhostIP(std::string& url) - { - auto pos = url.find("0.0.0.0", 0); - if (pos != std::string::npos) { - std::string ipAddressString = getHostIpString(); - if ("" != ipAddressString) { - url.replace(pos, 7, ipAddressString); - } - } - - //printf("ipaddress: %s\n", ipAddress.data()); - - return true; - } - - ServerSetupType getServerSetupTypeFromString(const std::string& serverSetupTypeString) { - if ("test" == serverSetupTypeString) { - return SERVER_TYPE_TEST; - } - if ("staging" == serverSetupTypeString) { - return SERVER_TYPE_STAGING; - } - if ("production" == serverSetupTypeString) { - return SERVER_TYPE_PRODUCTION; - } - return SERVER_TYPE_PRODUCTION; - } - - - bool 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 false; - } - g_Mnemonic_WordLists[i].printToFile("de_words.txt"); - break; - case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES: - iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german2, g_mnemonic_german2_original_size, g_mnemonic_german2_compressed_size); - if (iResult) { - printf("[%s] error init german mnemonic set 2, error nr: %d\n", __FUNCTION__, iResult); - return false; - } - g_Mnemonic_WordLists[i].printToFile("de_words2.txt"); - 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); - return false; - } - //g_Mnemonic_WordLists[i].printToFile("en_words.txt"); - break; - default: printf("[%s] unknown MnemonicType\n", __FUNCTION__); return false; - } - } - return true; - } - - bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg) - { - auto serverKey = cfg.getString("crypto.server_key"); - unsigned char key[crypto_shorthash_KEYBYTES]; - size_t realBinSize = 0; - NULLPAD_10; - if (sodium_hex2bin(key, crypto_shorthash_KEYBYTES, serverKey.data(), serverKey.size(), nullptr, &realBinSize, nullptr)) { - printf("[%s] serverKey isn't valid hex: %s\n", __FUNCTION__, serverKey.data()); - return false; - } - if (realBinSize != crypto_shorthash_KEYBYTES) { - printf("[%s] serverKey hasn't valid size, expecting: %u, get: %lu\n", - __FUNCTION__, crypto_shorthash_KEYBYTES, realBinSize); - return false; - } - g_ServerCryptoKey = new ObfusArray(realBinSize, key); - g_ServerKeySeed = new ObfusArray(9*8); - Poco::Int64 i1 = randombytes_random(); - Poco::Int64 i2 = randombytes_random(); - g_ServerKeySeed->put(0, i1 | (i2 << 8)); - - //g_ServerAdminPublic = cfg.getString("crypto.server_admin_public"); - - DISASM_FALSERET; - g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT); - g_serverPath = cfg.getString("loginServer.path", ""); - replaceZeroIPWithLocalhostIP(g_serverPath); - g_default_locale = LanguageManager::languageFromString(cfg.getString("loginServer.default_locale")); - g_serverPort = cfg.getInt("loginServer.port", 0); - g_phpServerPort = cfg.getInt("phpServer.port", 0); - // replace 0.0.0.0 with actual server ip - - g_php_serverPath = cfg.getString("phpServer.url", ""); - replaceZeroIPWithLocalhostIP(g_php_serverPath); - g_php_serverHost = cfg.getString("phpServer.host", ""); - replaceZeroIPWithLocalhostIP(g_php_serverHost); - //g_ServerSetupType - auto serverSetupTypeString = cfg.getString("ServerSetupType", ""); - g_ServerSetupType = getServerSetupTypeFromString(serverSetupTypeString); - - // app secret for encrypt user private keys - // TODO: encrypt with server admin key - auto app_secret_string = cfg.getString("crypto.app_secret", ""); - if ("" != app_secret_string) { - g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string); - } - //g_CryptoAppSecret - - g_gRPCRelayServerFullURL = cfg.getString("grpc.server", ""); - - // unsecure flags - //g_AllowUnsecureFlags - if (cfg.getInt("unsecure.allow_passwort_via_json_request", 0) == 1) { - g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_PASSWORD_REQUESTS); - } - if (cfg.getInt("unsecure.allow_auto_sign_transactions", 0) == 1) { - g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_AUTO_SIGN_TRANSACTIONS); - } - if (cfg.getInt("unsecure.allow_cors_all", 0) == 1) { - g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_CORS_ALL); - } - if (cfg.getInt("unsecure.allow_all_passwords", 0) == 1) { - g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_ALLOW_ALL_PASSWORDS); - } - - return true; - } - - bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg) - { - g_disableEmail = cfg.getBool("email.disable", false); - if (g_disableEmail) { - printf("Email is disabled!\n"); - } - else { - g_EmailAccount.sender = cfg.getString("email.sender"); - g_EmailAccount.username = cfg.getString("email.username"); - g_EmailAccount.password = cfg.getString("email.password"); - g_EmailAccount.url = cfg.getString("email.smtp.url"); - g_EmailAccount.port = cfg.getInt("email.smtp.port"); - } - DISASM_FALSERET; - //g_ServerKeySeed->put(3, DRRandom::r64()); - return true; - } - - bool initSSLClientContext() - { - SharedPtr pCert = new RejectCertificateHandler(false); // reject invalid certificates - /* - Context(Usage usage, - const std::string& certificateNameOrPath, - VerificationMode verMode = VERIFY_RELAXED, - int options = OPT_DEFAULTS, - const std::string& certificateStoreName = CERT_STORE_MY); - */ - try { -#ifdef POCO_NETSSL_WIN - g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "cacert.pem", Context::VERIFY_RELAXED, Context::OPT_DEFAULTS); -#else - - g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "", "", Poco::Path::config() + "grd_login/cacert.pem", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); -#endif - } catch(Poco::Exception& ex) { - printf("[ServerConfig::initSSLClientContext] error init ssl context, maybe no cacert.pem found?\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n"); - return false; - } - DISASM_FALSERET; - SSLManager::instance().initializeClient(0, pCert, g_SSL_CLient_Context); - - g_ServerKeySeed->put(5, DRRandom::r64()); - - return true; - } - - void unload() { - if (g_ServerCryptoKey) { - delete g_ServerCryptoKey; - } - if (g_ServerKeySeed) { - delete g_ServerKeySeed; - } - if (g_CPUScheduler) { - delete g_CPUScheduler; - } - - if (g_CryptoCPUScheduler) { - delete g_CryptoCPUScheduler; - } - if (g_CryptoAppSecret) { - MemoryManager::getInstance()->releaseMemory(g_CryptoAppSecret); - g_CryptoAppSecret = nullptr; - } - } - - void writeToFile(std::istream& datas, std::string fileName) - { - static Poco::Mutex mutex; - - mutex.lock(); - - Poco::FileOutputStream file(fileName, std::ios::out | std::ios::app); - - if (!file.good()) { - printf("[ServerConfig::writeToFile] error creating file with name: %s\n", fileName.data()); - mutex.unlock(); - return; - } - - Poco::LocalDateTime now; - - std::string dateTimeStr = Poco::DateTimeFormatter::format(now, Poco::DateTimeFormat::ISO8601_FORMAT); - file << dateTimeStr << std::endl; - - for (std::string line; std::getline(datas, line); ) { - file << line << std::endl; - } - file << std::endl; - file.close(); - mutex.unlock(); - } +#include "ServerConfig.h" +#include "Crypto/mnemonic_german.h" +#include "Crypto/mnemonic_german2.h" +#include "Crypto/mnemonic_bip0039.h" +#include "Crypto/DRRandom.h" +#include "lib/DataTypeConverter.h" +#include "sodium.h" + + +#include "Poco/Net/SSLManager.h" +#include "Poco/Net/KeyConsoleHandler.h" +#include "Poco/Net/RejectCertificateHandler.h" +#include "Poco/Net/DNS.h" +#include "Poco/SharedPtr.h" + +#include "Poco/Mutex.h" +#include "Poco/Path.h" +#include "Poco/FileStream.h" +#include "Poco/LocalDateTime.h" +#include "Poco/DateTimeFormat.h" +#include "Poco/DateTimeFormatter.h" + + +using Poco::Net::SSLManager; +using Poco::Net::Context; +using Poco::Net::KeyConsoleHandler; +using Poco::Net::PrivateKeyPassphraseHandler; +using Poco::Net::InvalidCertificateHandler; +using Poco::Net::RejectCertificateHandler; +using Poco::SharedPtr; + +namespace ServerConfig { + +#define SESSION_TIMEOUT_DEFAULT 10 + + Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; + ObfusArray* g_ServerCryptoKey = nullptr; + ObfusArray* g_ServerKeySeed = nullptr; +// std::string g_ServerAdminPublic; + UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr; + UniLib::controller::CPUSheduler* g_CryptoCPUScheduler = nullptr; + Context::Ptr g_SSL_CLient_Context = nullptr; + Poco::Util::Timer g_CronJobsTimer; + EmailAccount g_EmailAccount; + int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT; + std::string g_serverPath; + int g_serverPort = 0; + Languages g_default_locale; + std::string g_php_serverPath; + std::string g_php_serverHost; + int g_phpServerPort; + Poco::Mutex g_TimeMutex; + int g_FakeLoginSleepTime = 820; + std::string g_versionString = ""; + bool g_disableEmail = false; + ServerSetupType g_ServerSetupType = SERVER_TYPE_PRODUCTION; + std::string g_gRPCRelayServerFullURL; + MemoryBin* g_CryptoAppSecret = nullptr; + AllowUnsecure g_AllowUnsecureFlags = NOT_UNSECURE; + +#ifdef __linux__ +#include +#include +#include +#include +#include +#include +#endif //#ifdef __linux__ + + std::string getHostIpString() + { +#ifdef __linux__ + struct ifaddrs * ifAddrStruct = NULL; + struct ifaddrs * ifa = NULL; + void * tmpAddrPtr = NULL; + + getifaddrs(&ifAddrStruct); + std::string ipAddressString; + + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) { + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 + // is a valid IP4 Address + tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + ipAddressString = addressBuffer; + printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); + } + else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6 + // is a valid IP6 Address + tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + char addressBuffer[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); + printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); + } + } + if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct); + return ipAddressString; +#else //__linux__ + std::string ipAddressString = ""; + auto host = Poco::Net::DNS::thisHost(); + for (auto it = host.addresses().begin(); it != host.addresses().end(); it++) { + auto ipAddress = *it; + if (!ipAddress.isIPv4Compatible() && !ipAddress.isIPv4Mapped()) { + continue; + } + if (ipAddress.isLoopback()) { + continue; + } + ipAddressString = ipAddress.toString(); + //isIPv4Compatible + //!isLoopback + //printf("ipaddress: %s\n", ipAddressString.data()); + break; + //break; + } + return ipAddressString; +#endif // __linux__ + } + + bool replaceZeroIPWithLocalhostIP(std::string& url) + { + auto pos = url.find("0.0.0.0", 0); + if (pos != std::string::npos) { + std::string ipAddressString = getHostIpString(); + if ("" != ipAddressString) { + url.replace(pos, 7, ipAddressString); + } + } + + //printf("ipaddress: %s\n", ipAddress.data()); + + return true; + } + + ServerSetupType getServerSetupTypeFromString(const std::string& serverSetupTypeString) { + if ("test" == serverSetupTypeString) { + return SERVER_TYPE_TEST; + } + if ("staging" == serverSetupTypeString) { + return SERVER_TYPE_STAGING; + } + if ("production" == serverSetupTypeString) { + return SERVER_TYPE_PRODUCTION; + } + return SERVER_TYPE_PRODUCTION; + } + + + bool 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 false; + } + g_Mnemonic_WordLists[i].printToFile("de_words.txt"); + break; + case MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES: + iResult = g_Mnemonic_WordLists[i].init(populate_mnemonic_german2, g_mnemonic_german2_original_size, g_mnemonic_german2_compressed_size); + if (iResult) { + printf("[%s] error init german mnemonic set 2, error nr: %d\n", __FUNCTION__, iResult); + return false; + } + g_Mnemonic_WordLists[i].printToFile("de_words2.txt"); + 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); + return false; + } + //g_Mnemonic_WordLists[i].printToFile("en_words.txt"); + break; + default: printf("[%s] unknown MnemonicType\n", __FUNCTION__); return false; + } + } + return true; + } + + bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg) + { + auto serverKey = cfg.getString("crypto.server_key"); + unsigned char key[crypto_shorthash_KEYBYTES]; + size_t realBinSize = 0; + NULLPAD_10; + if (sodium_hex2bin(key, crypto_shorthash_KEYBYTES, serverKey.data(), serverKey.size(), nullptr, &realBinSize, nullptr)) { + printf("[%s] serverKey isn't valid hex: %s\n", __FUNCTION__, serverKey.data()); + return false; + } + if (realBinSize != crypto_shorthash_KEYBYTES) { + printf("[%s] serverKey hasn't valid size, expecting: %u, get: %lu\n", + __FUNCTION__, crypto_shorthash_KEYBYTES, realBinSize); + return false; + } + g_ServerCryptoKey = new ObfusArray(realBinSize, key); + g_ServerKeySeed = new ObfusArray(9*8); + Poco::Int64 i1 = randombytes_random(); + Poco::Int64 i2 = randombytes_random(); + g_ServerKeySeed->put(0, i1 | (i2 << 8)); + + //g_ServerAdminPublic = cfg.getString("crypto.server_admin_public"); + + DISASM_FALSERET; + g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT); + g_serverPath = cfg.getString("loginServer.path", ""); + replaceZeroIPWithLocalhostIP(g_serverPath); + g_default_locale = LanguageManager::languageFromString(cfg.getString("loginServer.default_locale")); + g_serverPort = cfg.getInt("loginServer.port", 0); + g_phpServerPort = cfg.getInt("phpServer.port", 0); + // replace 0.0.0.0 with actual server ip + + g_php_serverPath = cfg.getString("phpServer.url", ""); + replaceZeroIPWithLocalhostIP(g_php_serverPath); + g_php_serverHost = cfg.getString("phpServer.host", ""); + replaceZeroIPWithLocalhostIP(g_php_serverHost); + //g_ServerSetupType + auto serverSetupTypeString = cfg.getString("ServerSetupType", ""); + g_ServerSetupType = getServerSetupTypeFromString(serverSetupTypeString); + + // app secret for encrypt user private keys + // TODO: encrypt with server admin key + auto app_secret_string = cfg.getString("crypto.app_secret", ""); + if ("" != app_secret_string) { + g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string); + } + //g_CryptoAppSecret + + g_gRPCRelayServerFullURL = cfg.getString("grpc.server", ""); + + // unsecure flags + //g_AllowUnsecureFlags + if (cfg.getInt("unsecure.allow_passwort_via_json_request", 0) == 1) { + g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_PASSWORD_REQUESTS); + } + if (cfg.getInt("unsecure.allow_auto_sign_transactions", 0) == 1) { + g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_AUTO_SIGN_TRANSACTIONS); + } + if (cfg.getInt("unsecure.allow_cors_all", 0) == 1) { + g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_CORS_ALL); + } + if (cfg.getInt("unsecure.allow_all_passwords", 0) == 1) { + g_AllowUnsecureFlags = (AllowUnsecure)(g_AllowUnsecureFlags | UNSECURE_ALLOW_ALL_PASSWORDS); + } + + return true; + } + + bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg) + { + g_disableEmail = cfg.getBool("email.disable", false); + if (g_disableEmail) { + printf("Email is disabled!\n"); + } + else { + g_EmailAccount.sender = cfg.getString("email.sender"); + g_EmailAccount.username = cfg.getString("email.username"); + g_EmailAccount.password = cfg.getString("email.password"); + g_EmailAccount.url = cfg.getString("email.smtp.url"); + g_EmailAccount.port = cfg.getInt("email.smtp.port"); + } + DISASM_FALSERET; + //g_ServerKeySeed->put(3, DRRandom::r64()); + return true; + } + + bool initSSLClientContext() + { + SharedPtr pCert = new RejectCertificateHandler(false); // reject invalid certificates + /* + Context(Usage usage, + const std::string& certificateNameOrPath, + VerificationMode verMode = VERIFY_RELAXED, + int options = OPT_DEFAULTS, + const std::string& certificateStoreName = CERT_STORE_MY); + */ + try { +#ifdef POCO_NETSSL_WIN + g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "cacert.pem", Context::VERIFY_RELAXED, Context::OPT_DEFAULTS); +#else + + g_SSL_CLient_Context = new Context(Context::CLIENT_USE, "", "", Poco::Path::config() + "grd_login/cacert.pem", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); +#endif + } catch(Poco::Exception& ex) { + printf("[ServerConfig::initSSLClientContext] error init ssl context, maybe no cacert.pem found?\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n"); + return false; + } + DISASM_FALSERET; + SSLManager::instance().initializeClient(0, pCert, g_SSL_CLient_Context); + + g_ServerKeySeed->put(5, DRRandom::r64()); + + return true; + } + + void unload() { + if (g_ServerCryptoKey) { + delete g_ServerCryptoKey; + } + if (g_ServerKeySeed) { + delete g_ServerKeySeed; + } + if (g_CPUScheduler) { + delete g_CPUScheduler; + } + + if (g_CryptoCPUScheduler) { + delete g_CryptoCPUScheduler; + } + if (g_CryptoAppSecret) { + MemoryManager::getInstance()->releaseMemory(g_CryptoAppSecret); + g_CryptoAppSecret = nullptr; + } + } + + void writeToFile(std::istream& datas, std::string fileName) + { + static Poco::Mutex mutex; + + mutex.lock(); + + Poco::FileOutputStream file(fileName, std::ios::out | std::ios::app); + + if (!file.good()) { + printf("[ServerConfig::writeToFile] error creating file with name: %s\n", fileName.data()); + mutex.unlock(); + return; + } + + Poco::LocalDateTime now; + + std::string dateTimeStr = Poco::DateTimeFormatter::format(now, Poco::DateTimeFormat::ISO8601_FORMAT); + file << dateTimeStr << std::endl; + + for (std::string line; std::getline(datas, line); ) { + file << line << std::endl; + } + file << std::endl; + file.close(); + mutex.unlock(); + } } \ No newline at end of file diff --git a/login_server/src/cpp/ServerConfig.h b/login_server/src/cpp/ServerConfig.h index aef4ea28d..444fb524c 100644 --- a/login_server/src/cpp/ServerConfig.h +++ b/login_server/src/cpp/ServerConfig.h @@ -1,90 +1,90 @@ -#ifndef __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ -#define __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ - -#include "Crypto/mnemonic.h" -#include "Crypto/Obfus_array.h" -#include "Poco/Util/LayeredConfiguration.h" -#include "Poco/Net/Context.h" -#include "Poco/Types.h" -#include "Poco/Util/Timer.h" - -#include "tasks/CPUSheduler.h" - -#include "SingletonManager/LanguageManager.h" -#include "SingletonManager/MemoryManager.h" - -#define DISABLE_EMAIL - -namespace ServerConfig { - - enum Mnemonic_Types { - MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER, - MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES, - MNEMONIC_BIP0039_SORTED_ORDER, - MNEMONIC_MAX - }; - // depracted, moved to email manager - struct EmailAccount { - std::string sender; - std::string admin_receiver; - std::string username; - std::string password; - std::string url; - int port; - }; - - enum ServerSetupType { - SERVER_TYPE_TEST, - SERVER_TYPE_STAGING, - SERVER_TYPE_PRODUCTION - }; - - // used with bit-operators, so only use numbers with control exactly one bit (1,2,4,8,16...) - enum AllowUnsecure { - NOT_UNSECURE = 0, - UNSECURE_PASSWORD_REQUESTS = 1, - UNSECURE_AUTO_SIGN_TRANSACTIONS = 2, - UNSECURE_CORS_ALL = 4, - UNSECURE_ALLOW_ALL_PASSWORDS = 8 - }; - - - extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; - - extern ObfusArray* g_ServerCryptoKey; - extern ObfusArray* g_ServerKeySeed; - - //extern unsigned char g_ServerAdminPublic[]; - extern UniLib::controller::CPUSheduler* g_CPUScheduler; - extern UniLib::controller::CPUSheduler* g_CryptoCPUScheduler; - extern Poco::Net::Context::Ptr g_SSL_CLient_Context; - extern Poco::Util::Timer g_CronJobsTimer; - extern EmailAccount g_EmailAccount; - extern int g_SessionTimeout; - extern std::string g_serverPath; - extern int g_serverPort; - extern Languages g_default_locale; - extern std::string g_php_serverPath; - extern std::string g_php_serverHost; - extern int g_phpServerPort; - extern Poco::Mutex g_TimeMutex; - extern int g_FakeLoginSleepTime; - extern std::string g_versionString; - extern bool g_disableEmail; - extern ServerSetupType g_ServerSetupType; - extern std::string g_gRPCRelayServerFullURL; - extern MemoryBin* g_CryptoAppSecret; - extern AllowUnsecure g_AllowUnsecureFlags; - - bool loadMnemonicWordLists(); - bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg); - bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg); - bool initSSLClientContext(); - - - void writeToFile(std::istream& datas, std::string fileName); - - void unload(); -}; - +#ifndef __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ +#define __GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ + +#include "Crypto/mnemonic.h" +#include "Crypto/Obfus_array.h" +#include "Poco/Util/LayeredConfiguration.h" +#include "Poco/Net/Context.h" +#include "Poco/Types.h" +#include "Poco/Util/Timer.h" + +#include "tasks/CPUSheduler.h" + +#include "SingletonManager/LanguageManager.h" +#include "SingletonManager/MemoryManager.h" + +#define DISABLE_EMAIL + +namespace ServerConfig { + + enum Mnemonic_Types { + MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER, + MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES, + MNEMONIC_BIP0039_SORTED_ORDER, + MNEMONIC_MAX + }; + // depracted, moved to email manager + struct EmailAccount { + std::string sender; + std::string admin_receiver; + std::string username; + std::string password; + std::string url; + int port; + }; + + enum ServerSetupType { + SERVER_TYPE_TEST, + SERVER_TYPE_STAGING, + SERVER_TYPE_PRODUCTION + }; + + // used with bit-operators, so only use numbers with control exactly one bit (1,2,4,8,16...) + enum AllowUnsecure { + NOT_UNSECURE = 0, + UNSECURE_PASSWORD_REQUESTS = 1, + UNSECURE_AUTO_SIGN_TRANSACTIONS = 2, + UNSECURE_CORS_ALL = 4, + UNSECURE_ALLOW_ALL_PASSWORDS = 8 + }; + + + extern Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; + + extern ObfusArray* g_ServerCryptoKey; + extern ObfusArray* g_ServerKeySeed; + + //extern unsigned char g_ServerAdminPublic[]; + extern UniLib::controller::CPUSheduler* g_CPUScheduler; + extern UniLib::controller::CPUSheduler* g_CryptoCPUScheduler; + extern Poco::Net::Context::Ptr g_SSL_CLient_Context; + extern Poco::Util::Timer g_CronJobsTimer; + extern EmailAccount g_EmailAccount; + extern int g_SessionTimeout; + extern std::string g_serverPath; + extern int g_serverPort; + extern Languages g_default_locale; + extern std::string g_php_serverPath; + extern std::string g_php_serverHost; + extern int g_phpServerPort; + extern Poco::Mutex g_TimeMutex; + extern int g_FakeLoginSleepTime; + extern std::string g_versionString; + extern bool g_disableEmail; + extern ServerSetupType g_ServerSetupType; + extern std::string g_gRPCRelayServerFullURL; + extern MemoryBin* g_CryptoAppSecret; + extern AllowUnsecure g_AllowUnsecureFlags; + + bool loadMnemonicWordLists(); + bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg); + bool initEMailAccount(const Poco::Util::LayeredConfiguration& cfg); + bool initSSLClientContext(); + + + void writeToFile(std::istream& datas, std::string fileName); + + void unload(); +}; + #endif //__GRADIDO_LOGIN_SERVER_SERVER_CONFIG__ \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/SessionManager.cpp b/login_server/src/cpp/SingletonManager/SessionManager.cpp index 743f11d19..e583c8eaf 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.cpp +++ b/login_server/src/cpp/SingletonManager/SessionManager.cpp @@ -1,626 +1,626 @@ -#include "SessionManager.h" -#include "ErrorManager.h" -#include "../ServerConfig.h" -#include "../Crypto/DRRandom.h" -#include "../controller/EmailVerificationCode.h" - -#include - - -SessionManager* SessionManager::getInstance() -{ - static SessionManager only; - return &only; -} - -SessionManager::SessionManager() - : mInitalized(false), mDeadLockedSessionCount(0) -{ - -} - -SessionManager::~SessionManager() -{ - if (mInitalized) { - deinitalize(); - } -} - - -bool SessionManager::init() -{ - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::init] exception timout mutex: %s\n", ex.displayText().data()); - return false; - } - //mWorkingMutex.lock(); - int i; - DISASM_MISALIGN; - for (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("^[^<>&;]{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; - case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break; - case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break; - case VALIDATE_HAS_UPPERCASE_LETTER: - mValidations[i] = new Poco::RegularExpression(".*[A-Z].*"); - ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64()); - break; - case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break; - default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__); - } - } - - - mInitalized = true; - mWorkingMutex.unlock(); - return true; -} - -void SessionManager::deinitalize() -{ - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::deinitalize] exception timout mutex: %s\n", ex.displayText().data()); - return; - } - //mWorkingMutex.lock(); - - while (mEmptyRequestStack.size()) { - mEmptyRequestStack.pop(); - } - - for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { - delete it->second; - } - mRequestSessionMap.clear(); - - for (int i = 0; i < VALIDATE_MAX; i++) { - delete mValidations[i]; - } - - printf("[SessionManager::deinitalize] count of dead locked sessions: %d\n", mDeadLockedSessionCount); - - mInitalized = false; - mWorkingMutex.unlock(); -} - -bool SessionManager::isValid(const std::string& subject, SessionValidationTypes validationType) -{ - if (validationType >= VALIDATE_MAX) { - return false; - } - return *mValidations[validationType] == subject; -} - -int SessionManager::generateNewUnusedHandle() -{ - int newHandle = 0; - int maxTrys = 0; - do { - newHandle = randombytes_random(); - maxTrys++; - } while (mRequestSessionMap.find(newHandle) != mRequestSessionMap.end() && maxTrys < 100); - - if (maxTrys >= 100 || 0 == newHandle) { - auto em = ErrorManager::getInstance(); - em->addError(new ParamError("SessionManager::generateNewUnusedHandle", "can't find new handle, have already ", std::to_string(mRequestSessionMap.size()))); - em->sendErrorsAsEmail(); - //printf("[SessionManager::%s] can't find new handle, have already: %d", - //__FUNCTION__, mRequestSessionMap.size()); - return 0; - } - return newHandle; -} - -Session* SessionManager::getNewSession(int* handle) -{ - const static char* functionName = "SessionManager::getNewSession"; - if (!mInitalized) { - printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); - return nullptr; - } - - // first check if we have any timeouted session to directly reuse it - checkTimeoutSession(); - - // lock - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[%s] exception timout mutex: %s\n", functionName, ex.displayText().data()); - return nullptr; - } - //mWorkingMutex.lock(); - - //UniLib::controller::TaskPtr checkSessionTimeout(new CheckSessionTimeouted); - //checkSessionTimeout->scheduleTask(checkSessionTimeout); - - // check if we have an existing session ready to use - while (mEmptyRequestStack.size() > 0) { - int local_handle = mEmptyRequestStack.top(); - mEmptyRequestStack.pop(); - auto resultIt = mRequestSessionMap.find(local_handle); - if (resultIt != mRequestSessionMap.end()) { - Session* result = resultIt->second; - // check if dead locked - if (result->tryLock()) { - result->unlock(); - if (!result->isActive()) { - result->reset(); - //mWorkingMutex.unlock(); - - if (handle) { - *handle = local_handle; - } - result->setActive(true); - mWorkingMutex.unlock(); - return result; - } - } - else { - ErrorList errors; - errors.addError(new Error(functionName, "found dead locked session, keeping in memory without reference")); - errors.addError(new ParamError(functionName, "last succeeded lock:", result->getLastSucceededLock().data())); - errors.sendErrorsAsEmail(); - - mRequestSessionMap.erase(local_handle); - } - - } - } - - // else create new RequestSession Object - // calculate random handle - // check if already exist, if get new - int newHandle = generateNewUnusedHandle(); - if (!newHandle) { - mWorkingMutex.unlock(); - return nullptr; - } - - auto requestSession = new Session(newHandle); - mRequestSessionMap.insert(std::pair(newHandle, requestSession)); - - requestSession->setActive(true); - //mWorkingMutex.unlock(); - - if (handle) { - *handle = newHandle; - } - //printf("[SessionManager::getNewSession] handle: %ld, sum: %u\n", newHandle, mRequestSessionMap.size()); - mWorkingMutex.unlock(); - return requestSession; - - - //return nullptr; -} - -bool SessionManager::releaseSession(int requestHandleSession) -{ - if (!mInitalized) { - printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); - return false; - } - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::releaseSession] exception timout mutex: %s\n", ex.displayText().data()); - return false; - } - //mWorkingMutex.lock(); - - auto it = mRequestSessionMap.find(requestHandleSession); - if (it == mRequestSessionMap.end()) { - //printf("[SessionManager::releaseRequestSession] requestSession with handle: %d not found\n", requestHandleSession); - mWorkingMutex.unlock(); - return false; - } - Session* session = it->second; - - // delete session, not reuse as workaround for server freeze bug - mRequestSessionMap.erase(requestHandleSession); - delete session; - mWorkingMutex.unlock(); - return true; - - // check if dead locked - if (session->tryLock()) { - session->unlock(); - session->reset(); - session->setActive(false); - } - else { - ErrorList errors; - errors.addError(new Error("SessionManager::releaseSession", "found dead locked session")); - errors.sendErrorsAsEmail(); - mRequestSessionMap.erase(requestHandleSession); - delete session; - mWorkingMutex.unlock(); - return true; - } - - // change request handle we don't want session hijacking - - // hardcoded disabled session max - if (mEmptyRequestStack.size() > 100) { - mRequestSessionMap.erase(requestHandleSession); - delete session; - mWorkingMutex.unlock(); - return true; - } - - int newHandle = generateNewUnusedHandle(); - //printf("[SessionManager::releseSession] oldHandle: %ld, newHandle: %ld\n", requestHandleSession, newHandle); - // erase after generating new number to prevent to getting the same number again - mRequestSessionMap.erase(requestHandleSession); - - if (!newHandle) { - delete session; - mWorkingMutex.unlock(); - return true; - } - - session->setHandle(newHandle); - mRequestSessionMap.insert(std::pair(newHandle, session)); - mEmptyRequestStack.push(newHandle); - - mWorkingMutex.unlock(); - return true; -} - -bool SessionManager::isExist(int requestHandleSession) -{ - static const char* function_name = "SessionManager::isExist"; - if (!mInitalized) { - printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); - return false; - } - bool result = false; - //mWorkingMutex.lock(); - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::isExist] exception timout mutex: %s\n", ex.displayText().data()); - return false; - } - auto it = mRequestSessionMap.find(requestHandleSession); - if (it != mRequestSessionMap.end()) { - result = true; - int iResult = it->second->isActive(); - if (-1 == iResult) { - auto em = ErrorManager::getInstance(); - em->addError(new Error(function_name, "session return locked")); - em->sendErrorsAsEmail(); - } - if (0 == iResult) { - printf("[SessionManager::isExist] session isn't active\n"); - } - } - mWorkingMutex.unlock(); - return result; -} - -Session* SessionManager::getSession(const Poco::Net::HTTPServerRequest& request) -{ - // check if user has valid session - Poco::Net::NameValueCollection cookies; - request.getCookies(cookies); - - int session_id = 0; - - try { - session_id = atoi(cookies.get("GRADIDO_LOGIN").data()); - return getSession(session_id); - } - catch (...) {} - - return nullptr; -} - -Session* SessionManager::getSession(int handle) -{ - static const char* function_name = "SessionManager::getSession"; - if (!mInitalized) { - printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); - return nullptr; - } - if (0 == handle) return nullptr; - Session* result = nullptr; - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::getSession] exception timout mutex: %s\n", ex.displayText().data()); - return result; - } - //mWorkingMutex.lock(); - auto it = mRequestSessionMap.find(handle); - if (it != mRequestSessionMap.end()) { - result = it->second; - int iResult = result->isActive(); - if (iResult == -1) { - auto em = ErrorManager::getInstance(); - em->addError(new Error(function_name, "session is locked")); - em->sendErrorsAsEmail(); - mWorkingMutex.unlock(); - return nullptr; - } - if (0 == iResult) { - //printf("[SessionManager::getSession] session isn't active\n"); - mWorkingMutex.unlock(); - return nullptr; - } - //result->setActive(true); - result->updateTimeout(); - } - //printf("[SessionManager::getSession] handle: %ld\n", handle); - mWorkingMutex.unlock(); - return result; -} - -Session* SessionManager::findByEmailVerificationCode(const Poco::UInt64& emailVerificationCode) -{ - - auto email_verification = controller::EmailVerificationCode::load(emailVerificationCode); - if (email_verification.isNull()) return nullptr; - auto email_verification_model = email_verification->getModel(); - assert(email_verification_model && email_verification_model->getUserId() > 0); - - auto session = findByUserId(email_verification_model->getUserId()); - if (session) { - session->setEmailVerificationCodeObject(email_verification); - } - - return session; -} - -Session* SessionManager::findByUserId(int userId) -{ - assert(userId > 0); - static const char* function_name = "SessionManager::findByUserId"; - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::findByUserId] exception timout mutex: %s\n", ex.displayText().data()); - return nullptr; - } - //mWorkingMutex.lock(); - for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { - while (it->second->isDeadLocked()) - { - it = mRequestSessionMap.erase(it); - mDeadLockedSessionCount++; - auto em = ErrorManager::getInstance(); - em->addError(new ParamError("SessionManager::findByUserId", "new dead locked session found, sum dead lock sessions:", mDeadLockedSessionCount)); - em->sendErrorsAsEmail(); - } - auto user = it->second->getNewUser(); - auto em = ErrorManager::getInstance(); - if(!user) continue; - if (!user->getModel()) { - em->addError(new Error(function_name, "user getModel return nullptr")); - em->addError(new ParamError(function_name, "user id: ", userId)); - em->sendErrorsAsEmail(); - continue; - } - if (!user->getModel()->getID()) { - em->addError(new Error(function_name, "user id is zero")); - em->addError(new ParamError(function_name, "user id: ", userId)); - em->sendErrorsAsEmail(); - continue; - } - //assert(user->getModel() && user->getModel()->getID()); - if (userId == user->getModel()->getID()) { - mWorkingMutex.unlock(); - return it->second; - } - } - mWorkingMutex.unlock(); - return nullptr; -} - -std::vector SessionManager::findAllByUserId(int userId) -{ - assert(userId > 0); - std::vector result; - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::findAllByUserId] exception timout mutex: %s\n", ex.displayText().data()); - //mWorkingMutex.unlock(); - return result; - } - //mWorkingMutex.lock(); - for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { - if (it->second->isDeadLocked()) { - it = mRequestSessionMap.erase(it); - mDeadLockedSessionCount++; - } - auto user = it->second->getNewUser(); - if (userId == user->getModel()->getID()) { - //return it->second; - result.push_back(it->second); - } - } - //mWorkingMutex.unlock(); - mWorkingMutex.unlock(); - return result; -} - -Session* SessionManager::findByEmail(const std::string& email) -{ - assert(email.size() > 0); - - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException &ex) { - printf("[SessionManager::findByEmail] exception timout mutex: %s\n", ex.displayText().data()); - //mWorkingMutex.unlock(); - return nullptr; - } - //mWorkingMutex.lock(); - for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { - if (it->second->isDeadLocked()) { - it = mRequestSessionMap.erase(it); - mDeadLockedSessionCount++; - } - auto user = it->second->getNewUser(); -if (email == user->getModel()->getEmail()) { - return it->second; -} - } - mWorkingMutex.unlock(); - return nullptr; -} - -void SessionManager::checkTimeoutSession() -{ - - try { - //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); - mWorkingMutex.tryLock(500); - } - catch (Poco::TimeoutException& ex) { - printf("[SessionManager::checkTimeoutSession] exception timeout mutex: %s\n", ex.displayText().data()); - return; - } - //mWorkingMutex.lock(); - auto now = Poco::DateTime(); - // random variance within 10 seconds for timeout to make it harder to get information and hack the server - auto timeout = Poco::Timespan(ServerConfig::g_SessionTimeout * 60, randombytes_random() % 10000000); - //auto timeout = Poco::Timespan(1, 0); - std::stack toRemove; - for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { - - if (it->second->tryLock()) { - // skip already disabled sessions - if (!it->second->isActive()) { - it->second->unlock(); - continue; - } - } - else { - // skip dead locked sessions - continue; - } - - Poco::Timespan timeElapsed(now - it->second->getLastActivity()); - it->second->unlock(); - if (timeElapsed > timeout) { - toRemove.push(it->first); - } - } - mWorkingMutex.unlock(); - - while (toRemove.size() > 0) { - int handle = toRemove.top(); - toRemove.pop(); - releaseSession(handle); - } - -} - -void SessionManager::deleteLoginCookies(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response, Session* activeSession/* = nullptr*/) -{ - Poco::Net::NameValueCollection cookies; - request.getCookies(cookies); - // go from first login cookie - for (auto it = cookies.find("GRADIDO_LOGIN"); it != cookies.end(); it++) { - // break if no login any more - if (it->first != "GRADIDO_LOGIN") break; - // skip if it is from the active session - if (activeSession) { - try { - int session_id = atoi(it->second.data()); - if (activeSession->tryLock()) { - bool session_id_is_handle = session_id == activeSession->getHandle(); - activeSession->unlock(); - if (session_id_is_handle) continue; - } - } - catch (...) {} - } - // delete cookie - auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", it->second); - keks.setPath("/"); - // max age of 0 delete cookie - keks.setMaxAge(0); - response.addCookie(keks); - } - // delete also cake php session cookie - for (auto it = cookies.find("CAKEPHP"); it != cookies.end(); it++) { - if (it->first != "CAKEPHP") break; - // delete cookie - auto keks = Poco::Net::HTTPCookie("CAKEPHP", it->second); - keks.setPath("/"); - // max age of 0 delete cookie - keks.setMaxAge(0); - response.addCookie(keks); - //printf("remove PHP Kekse\n"); - } - - - //session_id = atoi(cookies.get("GRADIDO_LOGIN").data()); -} - -bool SessionManager::checkPwdValidation(const std::string& pwd, ErrorList* errorReciver) -{ - if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) { - return true; - } - - if (!isValid(pwd, VALIDATE_PASSWORD)) { - errorReciver->addError(new Error("Passwort", "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen (@$!%*?&+-_) ein!")); - - // @$!%*?&+- - if (pwd.size() < 8) { - errorReciver->addError(new Error("Passwort", "Dein Passwort ist zu kurz!")); - } - else if (!isValid(pwd, VALIDATE_HAS_LOWERCASE_LETTER)) { - errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Kleinbuchstaben!")); - } - else if (!isValid(pwd, VALIDATE_HAS_UPPERCASE_LETTER)) { - errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Großbuchstaben!")); - } - else if (!isValid(pwd, VALIDATE_HAS_NUMBER)) { - errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Zahlen!")); - } - else if (!isValid(pwd, VALIDATE_HAS_SPECIAL_CHARACTER)) { - errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Sonderzeichen (@$!%*?&+-)!")); - } - - return false; - } - return true; -} - - -int CheckSessionTimeouted::run() -{ - SessionManager::getInstance()->checkTimeoutSession(); - return 0; -} +#include "SessionManager.h" +#include "ErrorManager.h" +#include "../ServerConfig.h" +#include "../Crypto/DRRandom.h" +#include "../controller/EmailVerificationCode.h" + +#include + + +SessionManager* SessionManager::getInstance() +{ + static SessionManager only; + return &only; +} + +SessionManager::SessionManager() + : mInitalized(false), mDeadLockedSessionCount(0) +{ + +} + +SessionManager::~SessionManager() +{ + if (mInitalized) { + deinitalize(); + } +} + + +bool SessionManager::init() +{ + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::init] exception timout mutex: %s\n", ex.displayText().data()); + return false; + } + //mWorkingMutex.lock(); + int i; + DISASM_MISALIGN; + for (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("^[^<>&;]{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; + case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break; + case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break; + case VALIDATE_HAS_UPPERCASE_LETTER: + mValidations[i] = new Poco::RegularExpression(".*[A-Z].*"); + ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64()); + break; + case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break; + default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__); + } + } + + + mInitalized = true; + mWorkingMutex.unlock(); + return true; +} + +void SessionManager::deinitalize() +{ + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::deinitalize] exception timout mutex: %s\n", ex.displayText().data()); + return; + } + //mWorkingMutex.lock(); + + while (mEmptyRequestStack.size()) { + mEmptyRequestStack.pop(); + } + + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + delete it->second; + } + mRequestSessionMap.clear(); + + for (int i = 0; i < VALIDATE_MAX; i++) { + delete mValidations[i]; + } + + printf("[SessionManager::deinitalize] count of dead locked sessions: %d\n", mDeadLockedSessionCount); + + mInitalized = false; + mWorkingMutex.unlock(); +} + +bool SessionManager::isValid(const std::string& subject, SessionValidationTypes validationType) +{ + if (validationType >= VALIDATE_MAX) { + return false; + } + return *mValidations[validationType] == subject; +} + +int SessionManager::generateNewUnusedHandle() +{ + int newHandle = 0; + int maxTrys = 0; + do { + newHandle = randombytes_random(); + maxTrys++; + } while (mRequestSessionMap.find(newHandle) != mRequestSessionMap.end() && maxTrys < 100); + + if (maxTrys >= 100 || 0 == newHandle) { + auto em = ErrorManager::getInstance(); + em->addError(new ParamError("SessionManager::generateNewUnusedHandle", "can't find new handle, have already ", std::to_string(mRequestSessionMap.size()))); + em->sendErrorsAsEmail(); + //printf("[SessionManager::%s] can't find new handle, have already: %d", + //__FUNCTION__, mRequestSessionMap.size()); + return 0; + } + return newHandle; +} + +Session* SessionManager::getNewSession(int* handle) +{ + const static char* functionName = "SessionManager::getNewSession"; + if (!mInitalized) { + printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); + return nullptr; + } + + // first check if we have any timeouted session to directly reuse it + checkTimeoutSession(); + + // lock + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[%s] exception timout mutex: %s\n", functionName, ex.displayText().data()); + return nullptr; + } + //mWorkingMutex.lock(); + + //UniLib::controller::TaskPtr checkSessionTimeout(new CheckSessionTimeouted); + //checkSessionTimeout->scheduleTask(checkSessionTimeout); + + // check if we have an existing session ready to use + while (mEmptyRequestStack.size() > 0) { + int local_handle = mEmptyRequestStack.top(); + mEmptyRequestStack.pop(); + auto resultIt = mRequestSessionMap.find(local_handle); + if (resultIt != mRequestSessionMap.end()) { + Session* result = resultIt->second; + // check if dead locked + if (result->tryLock()) { + result->unlock(); + if (!result->isActive()) { + result->reset(); + //mWorkingMutex.unlock(); + + if (handle) { + *handle = local_handle; + } + result->setActive(true); + mWorkingMutex.unlock(); + return result; + } + } + else { + ErrorList errors; + errors.addError(new Error(functionName, "found dead locked session, keeping in memory without reference")); + errors.addError(new ParamError(functionName, "last succeeded lock:", result->getLastSucceededLock().data())); + errors.sendErrorsAsEmail(); + + mRequestSessionMap.erase(local_handle); + } + + } + } + + // else create new RequestSession Object + // calculate random handle + // check if already exist, if get new + int newHandle = generateNewUnusedHandle(); + if (!newHandle) { + mWorkingMutex.unlock(); + return nullptr; + } + + auto requestSession = new Session(newHandle); + mRequestSessionMap.insert(std::pair(newHandle, requestSession)); + + requestSession->setActive(true); + //mWorkingMutex.unlock(); + + if (handle) { + *handle = newHandle; + } + //printf("[SessionManager::getNewSession] handle: %ld, sum: %u\n", newHandle, mRequestSessionMap.size()); + mWorkingMutex.unlock(); + return requestSession; + + + //return nullptr; +} + +bool SessionManager::releaseSession(int requestHandleSession) +{ + if (!mInitalized) { + printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); + return false; + } + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::releaseSession] exception timout mutex: %s\n", ex.displayText().data()); + return false; + } + //mWorkingMutex.lock(); + + auto it = mRequestSessionMap.find(requestHandleSession); + if (it == mRequestSessionMap.end()) { + //printf("[SessionManager::releaseRequestSession] requestSession with handle: %d not found\n", requestHandleSession); + mWorkingMutex.unlock(); + return false; + } + Session* session = it->second; + + // delete session, not reuse as workaround for server freeze bug + mRequestSessionMap.erase(requestHandleSession); + delete session; + mWorkingMutex.unlock(); + return true; + + // check if dead locked + if (session->tryLock()) { + session->unlock(); + session->reset(); + session->setActive(false); + } + else { + ErrorList errors; + errors.addError(new Error("SessionManager::releaseSession", "found dead locked session")); + errors.sendErrorsAsEmail(); + mRequestSessionMap.erase(requestHandleSession); + delete session; + mWorkingMutex.unlock(); + return true; + } + + // change request handle we don't want session hijacking + + // hardcoded disabled session max + if (mEmptyRequestStack.size() > 100) { + mRequestSessionMap.erase(requestHandleSession); + delete session; + mWorkingMutex.unlock(); + return true; + } + + int newHandle = generateNewUnusedHandle(); + //printf("[SessionManager::releseSession] oldHandle: %ld, newHandle: %ld\n", requestHandleSession, newHandle); + // erase after generating new number to prevent to getting the same number again + mRequestSessionMap.erase(requestHandleSession); + + if (!newHandle) { + delete session; + mWorkingMutex.unlock(); + return true; + } + + session->setHandle(newHandle); + mRequestSessionMap.insert(std::pair(newHandle, session)); + mEmptyRequestStack.push(newHandle); + + mWorkingMutex.unlock(); + return true; +} + +bool SessionManager::isExist(int requestHandleSession) +{ + static const char* function_name = "SessionManager::isExist"; + if (!mInitalized) { + printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); + return false; + } + bool result = false; + //mWorkingMutex.lock(); + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::isExist] exception timout mutex: %s\n", ex.displayText().data()); + return false; + } + auto it = mRequestSessionMap.find(requestHandleSession); + if (it != mRequestSessionMap.end()) { + result = true; + int iResult = it->second->isActive(); + if (-1 == iResult) { + auto em = ErrorManager::getInstance(); + em->addError(new Error(function_name, "session return locked")); + em->sendErrorsAsEmail(); + } + if (0 == iResult) { + printf("[SessionManager::isExist] session isn't active\n"); + } + } + mWorkingMutex.unlock(); + return result; +} + +Session* SessionManager::getSession(const Poco::Net::HTTPServerRequest& request) +{ + // check if user has valid session + Poco::Net::NameValueCollection cookies; + request.getCookies(cookies); + + int session_id = 0; + + try { + session_id = atoi(cookies.get("GRADIDO_LOGIN").data()); + return getSession(session_id); + } + catch (...) {} + + return nullptr; +} + +Session* SessionManager::getSession(int handle) +{ + static const char* function_name = "SessionManager::getSession"; + if (!mInitalized) { + printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); + return nullptr; + } + if (0 == handle) return nullptr; + Session* result = nullptr; + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::getSession] exception timout mutex: %s\n", ex.displayText().data()); + return result; + } + //mWorkingMutex.lock(); + auto it = mRequestSessionMap.find(handle); + if (it != mRequestSessionMap.end()) { + result = it->second; + int iResult = result->isActive(); + if (iResult == -1) { + auto em = ErrorManager::getInstance(); + em->addError(new Error(function_name, "session is locked")); + em->sendErrorsAsEmail(); + mWorkingMutex.unlock(); + return nullptr; + } + if (0 == iResult) { + //printf("[SessionManager::getSession] session isn't active\n"); + mWorkingMutex.unlock(); + return nullptr; + } + //result->setActive(true); + result->updateTimeout(); + } + //printf("[SessionManager::getSession] handle: %ld\n", handle); + mWorkingMutex.unlock(); + return result; +} + +Session* SessionManager::findByEmailVerificationCode(const Poco::UInt64& emailVerificationCode) +{ + + auto email_verification = controller::EmailVerificationCode::load(emailVerificationCode); + if (email_verification.isNull()) return nullptr; + auto email_verification_model = email_verification->getModel(); + assert(email_verification_model && email_verification_model->getUserId() > 0); + + auto session = findByUserId(email_verification_model->getUserId()); + if (session) { + session->setEmailVerificationCodeObject(email_verification); + } + + return session; +} + +Session* SessionManager::findByUserId(int userId) +{ + assert(userId > 0); + static const char* function_name = "SessionManager::findByUserId"; + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::findByUserId] exception timout mutex: %s\n", ex.displayText().data()); + return nullptr; + } + //mWorkingMutex.lock(); + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + while (it->second->isDeadLocked()) + { + it = mRequestSessionMap.erase(it); + mDeadLockedSessionCount++; + auto em = ErrorManager::getInstance(); + em->addError(new ParamError("SessionManager::findByUserId", "new dead locked session found, sum dead lock sessions:", mDeadLockedSessionCount)); + em->sendErrorsAsEmail(); + } + auto user = it->second->getNewUser(); + auto em = ErrorManager::getInstance(); + if(!user) continue; + if (!user->getModel()) { + em->addError(new Error(function_name, "user getModel return nullptr")); + em->addError(new ParamError(function_name, "user id: ", userId)); + em->sendErrorsAsEmail(); + continue; + } + if (!user->getModel()->getID()) { + em->addError(new Error(function_name, "user id is zero")); + em->addError(new ParamError(function_name, "user id: ", userId)); + em->sendErrorsAsEmail(); + continue; + } + //assert(user->getModel() && user->getModel()->getID()); + if (userId == user->getModel()->getID()) { + mWorkingMutex.unlock(); + return it->second; + } + } + mWorkingMutex.unlock(); + return nullptr; +} + +std::vector SessionManager::findAllByUserId(int userId) +{ + assert(userId > 0); + std::vector result; + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::findAllByUserId] exception timout mutex: %s\n", ex.displayText().data()); + //mWorkingMutex.unlock(); + return result; + } + //mWorkingMutex.lock(); + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + if (it->second->isDeadLocked()) { + it = mRequestSessionMap.erase(it); + mDeadLockedSessionCount++; + } + auto user = it->second->getNewUser(); + if (userId == user->getModel()->getID()) { + //return it->second; + result.push_back(it->second); + } + } + //mWorkingMutex.unlock(); + mWorkingMutex.unlock(); + return result; +} + +Session* SessionManager::findByEmail(const std::string& email) +{ + assert(email.size() > 0); + + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException &ex) { + printf("[SessionManager::findByEmail] exception timout mutex: %s\n", ex.displayText().data()); + //mWorkingMutex.unlock(); + return nullptr; + } + //mWorkingMutex.lock(); + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + if (it->second->isDeadLocked()) { + it = mRequestSessionMap.erase(it); + mDeadLockedSessionCount++; + } + auto user = it->second->getNewUser(); +if (email == user->getModel()->getEmail()) { + return it->second; +} + } + mWorkingMutex.unlock(); + return nullptr; +} + +void SessionManager::checkTimeoutSession() +{ + + try { + //Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500); + mWorkingMutex.tryLock(500); + } + catch (Poco::TimeoutException& ex) { + printf("[SessionManager::checkTimeoutSession] exception timeout mutex: %s\n", ex.displayText().data()); + return; + } + //mWorkingMutex.lock(); + auto now = Poco::DateTime(); + // random variance within 10 seconds for timeout to make it harder to get information and hack the server + auto timeout = Poco::Timespan(ServerConfig::g_SessionTimeout * 60, randombytes_random() % 10000000); + //auto timeout = Poco::Timespan(1, 0); + std::stack toRemove; + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + + if (it->second->tryLock()) { + // skip already disabled sessions + if (!it->second->isActive()) { + it->second->unlock(); + continue; + } + } + else { + // skip dead locked sessions + continue; + } + + Poco::Timespan timeElapsed(now - it->second->getLastActivity()); + it->second->unlock(); + if (timeElapsed > timeout) { + toRemove.push(it->first); + } + } + mWorkingMutex.unlock(); + + while (toRemove.size() > 0) { + int handle = toRemove.top(); + toRemove.pop(); + releaseSession(handle); + } + +} + +void SessionManager::deleteLoginCookies(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response, Session* activeSession/* = nullptr*/) +{ + Poco::Net::NameValueCollection cookies; + request.getCookies(cookies); + // go from first login cookie + for (auto it = cookies.find("GRADIDO_LOGIN"); it != cookies.end(); it++) { + // break if no login any more + if (it->first != "GRADIDO_LOGIN") break; + // skip if it is from the active session + if (activeSession) { + try { + int session_id = atoi(it->second.data()); + if (activeSession->tryLock()) { + bool session_id_is_handle = session_id == activeSession->getHandle(); + activeSession->unlock(); + if (session_id_is_handle) continue; + } + } + catch (...) {} + } + // delete cookie + auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", it->second); + keks.setPath("/"); + // max age of 0 delete cookie + keks.setMaxAge(0); + response.addCookie(keks); + } + // delete also cake php session cookie + for (auto it = cookies.find("CAKEPHP"); it != cookies.end(); it++) { + if (it->first != "CAKEPHP") break; + // delete cookie + auto keks = Poco::Net::HTTPCookie("CAKEPHP", it->second); + keks.setPath("/"); + // max age of 0 delete cookie + keks.setMaxAge(0); + response.addCookie(keks); + //printf("remove PHP Kekse\n"); + } + + + //session_id = atoi(cookies.get("GRADIDO_LOGIN").data()); +} + +bool SessionManager::checkPwdValidation(const std::string& pwd, ErrorList* errorReciver) +{ + if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) { + return true; + } + + if (!isValid(pwd, VALIDATE_PASSWORD)) { + errorReciver->addError(new Error("Passwort", "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen (@$!%*?&+-_) ein!")); + + // @$!%*?&+- + if (pwd.size() < 8) { + errorReciver->addError(new Error("Passwort", "Dein Passwort ist zu kurz!")); + } + else if (!isValid(pwd, VALIDATE_HAS_LOWERCASE_LETTER)) { + errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Kleinbuchstaben!")); + } + else if (!isValid(pwd, VALIDATE_HAS_UPPERCASE_LETTER)) { + errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Großbuchstaben!")); + } + else if (!isValid(pwd, VALIDATE_HAS_NUMBER)) { + errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Zahlen!")); + } + else if (!isValid(pwd, VALIDATE_HAS_SPECIAL_CHARACTER)) { + errorReciver->addError(new Error("Passwort", "Dein Passwort enthält keine Sonderzeichen (@$!%*?&+-)!")); + } + + return false; + } + return true; +} + + +int CheckSessionTimeouted::run() +{ + SessionManager::getInstance()->checkTimeoutSession(); + return 0; +} diff --git a/login_server/src/cpp/lib/Error.h b/login_server/src/cpp/lib/Error.h index 2a4d79e85..7988a9345 100644 --- a/login_server/src/cpp/lib/Error.h +++ b/login_server/src/cpp/lib/Error.h @@ -1,63 +1,63 @@ -/*! -* -* \author: einhornimmond -* -* \date: 07.03.19 -* -* \brief: error data -*/ - -#ifndef DR_LUA_WEB_MODULE_ERROR_ERROR_H -#define DR_LUA_WEB_MODULE_ERROR_ERROR_H - -#include -#include - -class Error -{ -public: - Error(const char* functionName, const char* message); - ~Error(); - - const char* getFunctionName() { return mFunctionName.data(); } - const char* getMessage() { return mMessage.data(); } - virtual std::string getString(bool withNewline = true); - virtual std::string getHtmlString(); - - - -protected: - std::string mFunctionName; - std::string mMessage; -}; - -class ParamError : public Error -{ -public: - ParamError(const char* functionName, const char* message, const char* param) - : Error(functionName, message), mParam(param) {} - ParamError(const char* functionName, const char* message, const std::string& param) - : Error(functionName, message), mParam(param) {} - - ParamError(const char* functioName, const char* message, int param) - : Error(functioName, message) { - std::stringstream ss; - ss << param; - mParam = ss.str(); - } - - virtual std::string getString(bool withNewline = true); - virtual std::string getHtmlString(); -protected: - std::string mParam; -}; - - - -class IErrorCollection -{ -public: - virtual void addError(Error*, bool log = true) = 0; -}; - -#endif // DR_LUA_WEB_MODULE_ERROR_ERROR_H +/*! +* +* \author: einhornimmond +* +* \date: 07.03.19 +* +* \brief: error data +*/ + +#ifndef DR_LUA_WEB_MODULE_ERROR_ERROR_H +#define DR_LUA_WEB_MODULE_ERROR_ERROR_H + +#include +#include + +class Error +{ +public: + Error(const char* functionName, const char* message); + ~Error(); + + const char* getFunctionName() { return mFunctionName.data(); } + const char* getMessage() { return mMessage.data(); } + virtual std::string getString(bool withNewline = true); + virtual std::string getHtmlString(); + + + +protected: + std::string mFunctionName; + std::string mMessage; +}; + +class ParamError : public Error +{ +public: + ParamError(const char* functionName, const char* message, const char* param) + : Error(functionName, message), mParam(param) {} + ParamError(const char* functionName, const char* message, const std::string& param) + : Error(functionName, message), mParam(param) {} + + ParamError(const char* functioName, const char* message, int param) + : Error(functioName, message) { + std::stringstream ss; + ss << param; + mParam = ss.str(); + } + + virtual std::string getString(bool withNewline = true); + virtual std::string getHtmlString(); +protected: + std::string mParam; +}; + + + +class IErrorCollection +{ +public: + virtual void addError(Error*, bool log = true) = 0; +}; + +#endif // DR_LUA_WEB_MODULE_ERROR_ERROR_H diff --git a/login_server/src/cpp/lib/ErrorList.cpp b/login_server/src/cpp/lib/ErrorList.cpp index a663b67b2..32c408acb 100644 --- a/login_server/src/cpp/lib/ErrorList.cpp +++ b/login_server/src/cpp/lib/ErrorList.cpp @@ -1,201 +1,201 @@ -#include "ErrorList.h" - -#include "../ServerConfig.h" - -//#include "Poco/Net/MailMessage.h" -#include "Poco/Net/MediaType.h" - -#include "../SingletonManager/EmailManager.h" - -SendErrorMessage::~SendErrorMessage() -{ - if (mMessage) { - delete mMessage; - mMessage = nullptr; - } -} - -int SendErrorMessage::run() -{ - if (ServerConfig::g_disableEmail) return 0; - - auto mailClientSession = new Poco::Net::SecureSMTPClientSession(ServerConfig::g_EmailAccount.url, ServerConfig::g_EmailAccount.port); - mailClientSession->login(); - mailClientSession->startTLS(ServerConfig::g_SSL_CLient_Context); - - - mailClientSession->login(Poco::Net::SMTPClientSession::AUTH_LOGIN, ServerConfig::g_EmailAccount.username, ServerConfig::g_EmailAccount.password); - - try { - mMessage->setSender(ServerConfig::g_EmailAccount.sender); - mailClientSession->sendMessage(*mMessage); - mailClientSession->close(); - } - catch (Poco::Exception& exc) { - printf("[SendErrorMessage::%s] error sending error message to admin: %s\n", - __FUNCTION__, exc.displayText().data()); - return -1; - } - return 0; -} - -// ------------------------------------------------------------------------------------ - - -ErrorList::ErrorList() - : mLogging(Poco::Logger::get("errorLog")) -{ - -} - -ErrorList::~ErrorList() -{ - while (mErrorStack.size() > 0) { - delete mErrorStack.top(); - mErrorStack.pop(); - } -} - -void ErrorList::addError(Error* error, bool log/* = true */) -{ - - if (log) { - std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); - mLogging.error("%s [ErrorList::addError] %s", dateTimeString, error->getString(false)); - - } - mErrorStack.push(error); -} - -Error* ErrorList::getLastError() -{ - if (mErrorStack.size() == 0) { - return nullptr; - } - - Error* error = mErrorStack.top(); - if (error) { - mErrorStack.pop(); - } - - return error; -} - -void ErrorList::clearErrors() -{ - while (mErrorStack.size()) { - auto error = mErrorStack.top(); - if (error) { - delete error; - } - mErrorStack.pop(); - } -} - - -int ErrorList::getErrors(ErrorList* send) -{ - Error* error = nullptr; - int iCount = 0; - while (error = send->getLastError()) { - addError(error, false); - iCount++; - } - return iCount; -} - -void ErrorList::printErrors() -{ - while (mErrorStack.size() > 0) { - auto error = mErrorStack.top(); - mErrorStack.pop(); - printf(error->getString().data()); - delete error; - } -} - -std::vector ErrorList::getErrorsArray() -{ - std::vector result; - result.reserve(mErrorStack.size()); - - while (mErrorStack.size() > 0) { - auto error = mErrorStack.top(); - mErrorStack.pop(); - //result->add(error->getString()); - result.push_back(error->getString()); - delete error; - } - return result; -} - -std::string ErrorList::getErrorsHtml() -{ - std::string res; - res = "
    "; - while (mErrorStack.size() > 0) { - auto error = mErrorStack.top(); - mErrorStack.pop(); - res += "
  • "; - res += error->getHtmlString(); - res += "
  • "; - delete error; - } - res += "
"; - return res; -} - -std::string ErrorList::getErrorsHtmlNewFormat() -{ - std::string html; - - while (mErrorStack.size() > 0) { - auto error = std::unique_ptr(mErrorStack.top()); - mErrorStack.pop(); - html += "
"; - html += "report_problem"; - html += ""; - html += error->getHtmlString(); - html += ""; - html += "
"; - } - return html; -} -/* - -*/ - - -void ErrorList::sendErrorsAsEmail(std::string rawHtml/* = ""*/) -{ - auto em = EmailManager::getInstance(); - /*auto message = new Poco::Net::MailMessage(); - message->setSender("gradido_loginServer@gradido.net"); - message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, "***REMOVED***")); - message->setSubject("Error from Gradido Login Server"); - */ - std::string content; - while (mErrorStack.size() > 0) { - auto error = mErrorStack.top(); - mErrorStack.pop(); - content += error->getString(); - delete error; - } - auto email = new model::Email(content, model::EMAIL_ERROR); - - //message->addContent(new Poco::Net::StringPartSource(content)); - if (rawHtml != "") { - Poco::Net::MediaType mt("text", "html"); - mt.setParameter("charset", "utf-8"); - - email->addContent(new Poco::Net::StringPartSource(rawHtml, mt.toString())); - } - em->addEmail(email); - - //UniLib::controller::TaskPtr sendErrorMessageTask(new SendErrorMessage(message, ServerConfig::g_CPUScheduler)); - //sendErrorMessageTask->scheduleTask(sendErrorMessageTask); - +#include "ErrorList.h" + +#include "../ServerConfig.h" + +//#include "Poco/Net/MailMessage.h" +#include "Poco/Net/MediaType.h" + +#include "../SingletonManager/EmailManager.h" + +SendErrorMessage::~SendErrorMessage() +{ + if (mMessage) { + delete mMessage; + mMessage = nullptr; + } +} + +int SendErrorMessage::run() +{ + if (ServerConfig::g_disableEmail) return 0; + + auto mailClientSession = new Poco::Net::SecureSMTPClientSession(ServerConfig::g_EmailAccount.url, ServerConfig::g_EmailAccount.port); + mailClientSession->login(); + mailClientSession->startTLS(ServerConfig::g_SSL_CLient_Context); + + + mailClientSession->login(Poco::Net::SMTPClientSession::AUTH_LOGIN, ServerConfig::g_EmailAccount.username, ServerConfig::g_EmailAccount.password); + + try { + mMessage->setSender(ServerConfig::g_EmailAccount.sender); + mailClientSession->sendMessage(*mMessage); + mailClientSession->close(); + } + catch (Poco::Exception& exc) { + printf("[SendErrorMessage::%s] error sending error message to admin: %s\n", + __FUNCTION__, exc.displayText().data()); + return -1; + } + return 0; +} + +// ------------------------------------------------------------------------------------ + + +ErrorList::ErrorList() + : mLogging(Poco::Logger::get("errorLog")) +{ + +} + +ErrorList::~ErrorList() +{ + while (mErrorStack.size() > 0) { + delete mErrorStack.top(); + mErrorStack.pop(); + } +} + +void ErrorList::addError(Error* error, bool log/* = true */) +{ + + if (log) { + std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); + mLogging.error("%s [ErrorList::addError] %s", dateTimeString, error->getString(false)); + + } + mErrorStack.push(error); +} + +Error* ErrorList::getLastError() +{ + if (mErrorStack.size() == 0) { + return nullptr; + } + + Error* error = mErrorStack.top(); + if (error) { + mErrorStack.pop(); + } + + return error; +} + +void ErrorList::clearErrors() +{ + while (mErrorStack.size()) { + auto error = mErrorStack.top(); + if (error) { + delete error; + } + mErrorStack.pop(); + } +} + + +int ErrorList::getErrors(ErrorList* send) +{ + Error* error = nullptr; + int iCount = 0; + while (error = send->getLastError()) { + addError(error, false); + iCount++; + } + return iCount; +} + +void ErrorList::printErrors() +{ + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + printf(error->getString().data()); + delete error; + } +} + +std::vector ErrorList::getErrorsArray() +{ + std::vector result; + result.reserve(mErrorStack.size()); + + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + //result->add(error->getString()); + result.push_back(error->getString()); + delete error; + } + return result; +} + +std::string ErrorList::getErrorsHtml() +{ + std::string res; + res = "
    "; + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + res += "
  • "; + res += error->getHtmlString(); + res += "
  • "; + delete error; + } + res += "
"; + return res; +} + +std::string ErrorList::getErrorsHtmlNewFormat() +{ + std::string html; + + while (mErrorStack.size() > 0) { + auto error = std::unique_ptr(mErrorStack.top()); + mErrorStack.pop(); + html += "
"; + html += "report_problem"; + html += ""; + html += error->getHtmlString(); + html += ""; + html += "
"; + } + return html; +} +/* + +*/ + + +void ErrorList::sendErrorsAsEmail(std::string rawHtml/* = ""*/) +{ + auto em = EmailManager::getInstance(); + /*auto message = new Poco::Net::MailMessage(); + message->setSender("gradido_loginServer@gradido.net"); + message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, "***REMOVED***")); + message->setSubject("Error from Gradido Login Server"); + */ + std::string content; + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + content += error->getString(); + delete error; + } + auto email = new model::Email(content, model::EMAIL_ERROR); + + //message->addContent(new Poco::Net::StringPartSource(content)); + if (rawHtml != "") { + Poco::Net::MediaType mt("text", "html"); + mt.setParameter("charset", "utf-8"); + + email->addContent(new Poco::Net::StringPartSource(rawHtml, mt.toString())); + } + em->addEmail(email); + + //UniLib::controller::TaskPtr sendErrorMessageTask(new SendErrorMessage(message, ServerConfig::g_CPUScheduler)); + //sendErrorMessageTask->scheduleTask(sendErrorMessageTask); + } \ No newline at end of file diff --git a/login_server/src/cpp/lib/ErrorList.h b/login_server/src/cpp/lib/ErrorList.h index d2913a241..1e937ebfe 100644 --- a/login_server/src/cpp/lib/ErrorList.h +++ b/login_server/src/cpp/lib/ErrorList.h @@ -1,76 +1,76 @@ -/*! -* -* \author: einhornimmond -* -* \date: 07.03.19 -* -* \brief: error -*/ - -#ifndef DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H -#define DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H - -#include "Error.h" -#include - -#include "../tasks/CPUTask.h" - -#include "Poco/Net/SecureSMTPClientSession.h" -#include "Poco/Net/StringPartSource.h" -#include "Poco/Logger.h" -#include "Poco/JSON/Array.h" - -class ErrorList : public IErrorCollection -{ -public: - ErrorList(); - ~ErrorList(); - - // push error, error will be deleted in deconstructor - virtual void addError(Error* error, bool log = true); - - // return error on top of stack, please delete after using - Error* getLastError(); - - inline size_t errorCount() { return mErrorStack.size(); } - - // delete all errors - void clearErrors(); - - static int moveErrors(ErrorList* recv, ErrorList* send) { - return recv->getErrors(send); - } - int getErrors(ErrorList* send); - - void printErrors(); - std::string getErrorsHtml(); - std::string getErrorsHtmlNewFormat(); - - std::vector getErrorsArray(); - - void sendErrorsAsEmail(std::string rawHtml = ""); - -protected: - std::stack mErrorStack; - // poco logging - Poco::Logger& mLogging; -}; - -class SendErrorMessage : public UniLib::controller::CPUTask -{ -public: - SendErrorMessage(Poco::Net::MailMessage* message, UniLib::controller::CPUSheduler* scheduler) - : UniLib::controller::CPUTask(scheduler), mMessage(message) {} - - ~SendErrorMessage(); - - virtual int run(); - const char* getResourceType() const { return "SendErrorMessage"; }; - - -protected: - Poco::Net::MailMessage* mMessage; - -}; - -#endif // DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H +/*! +* +* \author: einhornimmond +* +* \date: 07.03.19 +* +* \brief: error +*/ + +#ifndef DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H +#define DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H + +#include "Error.h" +#include + +#include "../tasks/CPUTask.h" + +#include "Poco/Net/SecureSMTPClientSession.h" +#include "Poco/Net/StringPartSource.h" +#include "Poco/Logger.h" +#include "Poco/JSON/Array.h" + +class ErrorList : public IErrorCollection +{ +public: + ErrorList(); + ~ErrorList(); + + // push error, error will be deleted in deconstructor + virtual void addError(Error* error, bool log = true); + + // return error on top of stack, please delete after using + Error* getLastError(); + + inline size_t errorCount() { return mErrorStack.size(); } + + // delete all errors + void clearErrors(); + + static int moveErrors(ErrorList* recv, ErrorList* send) { + return recv->getErrors(send); + } + int getErrors(ErrorList* send); + + void printErrors(); + std::string getErrorsHtml(); + std::string getErrorsHtmlNewFormat(); + + std::vector getErrorsArray(); + + void sendErrorsAsEmail(std::string rawHtml = ""); + +protected: + std::stack mErrorStack; + // poco logging + Poco::Logger& mLogging; +}; + +class SendErrorMessage : public UniLib::controller::CPUTask +{ +public: + SendErrorMessage(Poco::Net::MailMessage* message, UniLib::controller::CPUSheduler* scheduler) + : UniLib::controller::CPUTask(scheduler), mMessage(message) {} + + ~SendErrorMessage(); + + virtual int run(); + const char* getResourceType() const { return "SendErrorMessage"; }; + + +protected: + Poco::Net::MailMessage* mMessage; + +}; + +#endif // DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H diff --git a/login_server/src/cpp/main.cpp b/login_server/src/cpp/main.cpp index be08da820..54de9810b 100644 --- a/login_server/src/cpp/main.cpp +++ b/login_server/src/cpp/main.cpp @@ -1,57 +1,57 @@ -#include "Gradido_LoginServer.h" -#include - -#include "proto/gradido/TransactionBody.pb.h" - -#include "model/User.h" -#include "model/Session.h" -#include "lib/Profiler.h" -#include "ServerConfig.h" -#include "ImportantTests.h" - -#include "model/table/User.h" -#include "model/table/EmailOptIn.h" - -#include "Poco/DateTimeParser.h" - -#ifndef _TEST_BUILD - - -int main(int argc, char** argv) -{ - GOOGLE_PROTOBUF_VERIFY_VERSION; - if (sodium_init() < 0) { - /* panic! the library couldn't be initialized, it is not safe to use */ - printf("error initializing sodium, early exit\n"); - return -1; - } - - std::string dateTimeString = __DATE__; - //printf("Building date time string: %s\n", dateTimeString.data()); - std::string formatString("%b %d %Y"); - int timeZone = 0; - - Poco::DateTime buildDateTime = Poco::DateTimeParser::parse(formatString, dateTimeString, timeZone); - ServerConfig::g_versionString = Poco::DateTimeFormatter::format(buildDateTime, "0.%y.%m.%d"); - //ServerConfig::g_versionString = "0.20.KW13.02"; - printf("Version: %s\n", ServerConfig::g_versionString.data()); - printf("User size: %d Bytes, Session size: %d Bytes\n", sizeof(User), sizeof(Session)); - printf("model sizes: User: %d Bytes, EmailOptIn: %d Bytes\n", sizeof(model::table::User), sizeof(model::table::EmailOptIn)); - - // load word lists - if (!ServerConfig::loadMnemonicWordLists()) { - //printf("[Gradido_LoginServer::%s] error loading mnemonic Word List\n", __FUNCTION__); - printf("[Gradido_LoginServer::main] error loading mnemonic Word List"); - return -2; - } - - if (!ImportantTests::passphraseGenerationAndTransformation()) { - printf("test passphrase generation and transformation failed\n"); - return -3; - } - - Gradido_LoginServer app; - app.setUnixOptions(true); - return app.run(argc, argv); -} +#include "Gradido_LoginServer.h" +#include + +#include "proto/gradido/TransactionBody.pb.h" + +#include "model/User.h" +#include "model/Session.h" +#include "lib/Profiler.h" +#include "ServerConfig.h" +#include "ImportantTests.h" + +#include "model/table/User.h" +#include "model/table/EmailOptIn.h" + +#include "Poco/DateTimeParser.h" + +#ifndef _TEST_BUILD + + +int main(int argc, char** argv) +{ + GOOGLE_PROTOBUF_VERIFY_VERSION; + if (sodium_init() < 0) { + /* panic! the library couldn't be initialized, it is not safe to use */ + printf("error initializing sodium, early exit\n"); + return -1; + } + + std::string dateTimeString = __DATE__; + //printf("Building date time string: %s\n", dateTimeString.data()); + std::string formatString("%b %d %Y"); + int timeZone = 0; + + Poco::DateTime buildDateTime = Poco::DateTimeParser::parse(formatString, dateTimeString, timeZone); + ServerConfig::g_versionString = Poco::DateTimeFormatter::format(buildDateTime, "0.%y.%m.%d"); + //ServerConfig::g_versionString = "0.20.KW13.02"; + printf("Version: %s\n", ServerConfig::g_versionString.data()); + printf("User size: %d Bytes, Session size: %d Bytes\n", sizeof(User), sizeof(Session)); + printf("model sizes: User: %d Bytes, EmailOptIn: %d Bytes\n", sizeof(model::table::User), sizeof(model::table::EmailOptIn)); + + // load word lists + if (!ServerConfig::loadMnemonicWordLists()) { + //printf("[Gradido_LoginServer::%s] error loading mnemonic Word List\n", __FUNCTION__); + printf("[Gradido_LoginServer::main] error loading mnemonic Word List"); + return -2; + } + + if (!ImportantTests::passphraseGenerationAndTransformation()) { + printf("test passphrase generation and transformation failed\n"); + return -3; + } + + Gradido_LoginServer app; + app.setUnixOptions(true); + return app.run(argc, argv); +} #endif \ No newline at end of file diff --git a/login_server/src/cpp/model/Session.cpp b/login_server/src/cpp/model/Session.cpp index 86fad389c..2e135fb90 100644 --- a/login_server/src/cpp/model/Session.cpp +++ b/login_server/src/cpp/model/Session.cpp @@ -1,1323 +1,1323 @@ -#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 "../SingletonManager/EmailManager.h" -#include "../SingletonManager/SingletonTaskObserver.h" - -#include "../tasks/PrepareEmailTask.h" -#include "../tasks/SendEmailTask.h" -#include "../tasks/SigningTransaction.h" -#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" -#include "../tasks/VerificationEmailResendTask.h" - -#include "../lib/JsonRequest.h" - -#include "../Crypto/Passphrase.h" - - -#include "../controller/User.h" -#include "../controller/UserBackups.h" -#include "../controller/EmailVerificationCode.h" - -#include "table/ModelBase.h" - - -#include "sodium.h" - -using namespace Poco::Data::Keywords; - -int WriteEmailVerification::run() -{ - auto em = ErrorManager::getInstance(); - - mEmailVerificationCode->getModel()->setUserId(mUser->getDBId()); - auto emailVerificationModel = mEmailVerificationCode->getModel(); - emailVerificationModel->setUserId(mUser->getDBId()); - if (!emailVerificationModel->insertIntoDB(true) || emailVerificationModel->errorCount() > 0) { - emailVerificationModel->sendErrorsAsEmail(); - return -1; - } - - 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), 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"); - std::unique_lock _lock(mSharedMutex); - mSessionUser.assign(nullptr); - mNewUser.assign(nullptr); - mEmailVerificationCodeObject.assign(nullptr); - - // watch out - //updateTimeout(); - mLastActivity = Poco::DateTime(); - - mState = SESSION_STATE_EMPTY; - - mPassphrase = ""; - mLastExternReferer = ""; - mClientLoginIP = Poco::Net::IPAddress(); - unlock(); - - // reset transactions - mCurrentActiveProcessingTransaction = nullptr; - mProcessingTransactions.clear(); - - //printf("[Session::reset] finished\n"); -} - -int Session::isActive() -{ - int ret = 0; - try { - mWorkMutex.tryLock(100); - } - catch (Poco::TimeoutException &ex) { - return -1; - } - ret = (int)mActive; - unlock(); - return ret; - -} - -bool Session::isDeadLocked() -{ - try { - mWorkMutex.tryLock(200); - unlock(); - return false; - } - catch (Poco::Exception& ex) { - - } - return true; -} - -bool Session::setActive(bool active) -{ - try { - mWorkMutex.tryLock(100); - } - catch (Poco::TimeoutException &ex) { - return false; - } - mActive = active; - unlock(); - return true; -} - -void Session::updateTimeout() -{ - lock("Session::updateTimeout"); - mLastActivity = Poco::DateTime(); - unlock(); -} - -Poco::AutoPtr Session::getEmailVerificationCodeObject() -{ - lock("Session::getEmailVerificationCodeObject"); - std::shared_lock _lock(mSharedMutex); - auto ret = mEmailVerificationCodeObject; - unlock(); - return ret; -} - -bool Session::adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email) -{ - Profiler usedTime; - - if (mNewUser->getModel()->getRole() != model::table::ROLE_ADMIN) { - addError(new Error(gettext("Benutzer"), gettext("Eingeloggter Benutzer ist kein Admin")), false); - return false; - } - - 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 <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - return false; - } - - - // check if user with that email already exist - if (mNewUser->getModel()->isExistInDB("email", email)) { - addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); - return false; - } - - auto newUser = controller::User::create(email, first_name, last_name); - updateTimeout(); - - - auto newUserModel = newUser->getModel(); - if (!newUserModel->insertIntoDB(true)) { - addError(new Error(gettext("Benutzer"), gettext("Fehler beim speichern!"))); - return false; - } - - auto email_verification_code = controller::EmailVerificationCode::create(newUserModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); - if (!email_verification_code->getModel()->insertIntoDB(false)) { - addError(new Error(gettext("Email Verification Code"), gettext("Fehler beim speichern!"))); - return false; - } - - EmailManager::getInstance()->addEmail(new model::Email(email_verification_code, newUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE)); - - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = email_verification_code; - - - return true; -} -// -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 <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - 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")), false); - 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()); - mNewUser = controller::User::create(email, first_name, last_name); - 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, mNewUser, 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); - - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = controller::EmailVerificationCode::create(model::table::EMAIL_OPT_IN_REGISTER); - UniLib::controller::TaskPtr writeEmailVerification(new WriteEmailVerification(mSessionUser, mEmailVerificationCodeObject, 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üß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)); - //Email(AutoPtr emailVerification, AutoPtr user, EmailType type); - UniLib::controller::TaskPtr sendEmail(new SendEmailTask(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_VERIFICATION_CODE), ServerConfig::g_CPUScheduler, 1)); - //sendEmail->setParentTaskPtrInArray(prepareEmail, 0); - sendEmail->setParentTaskPtrInArray(writeEmailVerification, 0); - 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::createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) -{ - std::unique_lock _lock(mSharedMutex); - static const char* function_name = "Session::createUserDirect"; - auto sm = SessionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto email_manager = EmailManager::getInstance(); - - if (!sm->isValid(first_name, VALIDATE_NAME)) { - addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(last_name, VALIDATE_NAME)) { - addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); - return false; - } - if (!sm->isValid(email, VALIDATE_EMAIL)) { - addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); - return false; - } - if (!sm->checkPwdValidation(password, this)) { - return false; - } - - // check if email already exist - auto user = controller::User::create(); - if (user->load(email) >= 1) { - addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits ein Konto")), false); - return false; - } - - // user - mNewUser = controller::User::create(email, first_name, last_name); - auto user_model = mNewUser->getModel(); - user_model->insertIntoDB(true); - auto user_id = user_model->getID(); - - - // one retry in case of connection error - if (!user_id) { - user_model->insertIntoDB(true); - auto user_id = user_model->getID(); - if (!user_id) { - em->addError(new ParamError(function_name, "error saving new user in db, after one retry with email", email)); - em->sendErrorsAsEmail(); - addError(new Error(gettext("Server"), gettext("Fehler beim speichen des Kontos bitte versuche es später noch einmal")), false); - return false; - } - } - - generateKeys(true, true); - - // calculate encryption key, could need some time, will save encrypted privkey to db - UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(mNewUser, password); - create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); - - // email verification code - auto email_verification = controller::EmailVerificationCode::create(user_id, model::table::EMAIL_OPT_IN_REGISTER_DIRECT); - email_verification->getModel()->insertIntoDB(false); - mEmailVerificationCodeObject = email_verification; - - auto _7days_later = Poco::DateTime() + Poco::Timespan(7, 0, 0, 0, 0); - ServerConfig::g_CronJobsTimer.schedule(new VerificationEmailResendTimerTask(user_id), Poco::Timestamp(_7days_later.timestamp())); - - email_manager->addEmail(new model::Email(email_verification, mNewUser, model::EMAIL_USER_VERIFICATION_CODE)); - - 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"; - Poco::ScopedLock _lock(mWorkMutex); - // new mutex, will replace the Poco Mutex complete in the future - std::unique_lock _lock_shared(mSharedMutex); - Profiler usedTime; - - auto em = ErrorManager::getInstance(); - if (mEmailVerificationCodeObject.isNull()) { - em->addError(new Error(funcName, "email verification object is zero")); - em->sendErrorsAsEmail(); - - return -2; - } - auto email_verification_code_model = mEmailVerificationCodeObject->getModel(); - assert(email_verification_code_model); - if(email_verification_code_model->getCode() == 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; - return -2; - } - - // load correct user from db - if (mNewUser.isNull() || !mNewUser->getModel() || mNewUser->getModel()->getID() != email_verification_code_model->getUserId()) { - mNewUser = controller::User::create(); - if (1 != mNewUser->load(email_verification_code_model->getUserId())) { - em->addError(new ParamError(funcName, "user load didn't return 1 with user_id ", email_verification_code_model->getUserId())); - em->sendErrorsAsEmail(); - - return -2; - } - } - - auto user_model = mNewUser->getModel(); - assert(user_model); - bool first_email_activation = false; - auto verification_type = email_verification_code_model->getType(); - if (model::table::EMAIL_OPT_IN_REGISTER == verification_type || - model::table::EMAIL_OPT_IN_EMPTY == verification_type || - model::table::EMAIL_OPT_IN_REGISTER_DIRECT == verification_type) { - first_email_activation = true; - } - if (first_email_activation && user_model->isEmailChecked()) { - mSessionUser = new User(mNewUser); - addError(new Error(gettext("E-Mail Verification"), gettext("Du hast dein Konto bereits aktiviert!")), false); - - return 1; - } - if (first_email_activation) { - user_model->setEmailChecked(true); - - user_model->updateIntoDB("email_checked", 1); - if (user_model->errorCount() > 0) { - user_model->sendErrorsAsEmail(); - } - - // no find all active sessions - - updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); - return 0; - } - - if (email_verification_code_model->getType() == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - - if (mEmailVerificationCodeObject->deleteFromDB()) { - mEmailVerificationCodeObject.assign(nullptr); - } - else { - em->getErrors(mEmailVerificationCodeObject->getModel()); - em->addError(new Error(funcName, "error deleting email verification code")); - em->sendErrorsAsEmail(); - return -2; - } - updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - return 0; - } - - em->addError(new Error(funcName, "invalid code path")); - em->sendErrorsAsEmail(); - - 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()); - - return -1; - } - //printf("[%s] time: %s\n", funcName, usedTime.string().data()); - - return 0; -} - - -int Session::sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized) -{ - mNewUser = user; - mSessionUser = new User(user); - auto em = EmailManager::getInstance(); - - std::unique_lock _lock(mSharedMutex); - - // creating email verification code also for user without passphrase - // first check if already exist - // check if email was already send shortly before - bool frequent_resend = false; - bool email_already_send = false; - - mEmailVerificationCodeObject = controller::EmailVerificationCode::load(user->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); - if (mEmailVerificationCodeObject.isNull()) { - mEmailVerificationCodeObject = controller::EmailVerificationCode::create(mNewUser->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); - mEmailVerificationCodeObject->getModel()->insertIntoDB(false); - } - else { - email_already_send = true; - } - auto email_verification_model = mEmailVerificationCodeObject->getModel(); - if (email_already_send) { - auto time_elapsed = Poco::DateTime() - email_verification_model->getUpdated(); - if (time_elapsed.totalHours() < 1) { - frequent_resend = true; - } - } - - if (!frequent_resend) { - if (passphraseMemorized) { - em->addEmail(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_RESET_PASSWORD)); - } - else { - em->addEmail(new model::Email(user, model::EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE)); - } - } - - if (frequent_resend) return 2; - if (email_already_send) return 1; - - return 0; -} - -int Session::comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource) -{ - KeyPair keys; - static const char* functionName = "Session::comparePassphraseWithSavedKeys"; - if (!wordSource) { - addError(new Error(functionName, "wordSource is empty")); - sendErrorsAsEmail(); - return -2; - } - if (!keys.generateFromPassphrase(inputPassphrase.data(), wordSource)) { - addError(new ParamError(functionName, "invalid passphrase", inputPassphrase)); - if (!mNewUser.isNull() && mNewUser->getModel()) { - addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); - } - sendErrorsAsEmail(); - addError(new Error(gettext("Passphrase"), gettext("Deine Passphrase ist ungütig")), false); - return 0; - } - auto userModel = mNewUser->getModel(); - auto existingPublic = userModel->getPublicKey(); - if (!existingPublic) { - userModel->loadFromDB("email", userModel->getEmail()); - existingPublic = userModel->getPublicKey(); - if (!existingPublic) { - addError(new Error(functionName, "cannot load existing public key from db")); - addError(new ParamError(functionName, "user email", userModel->getEmail())); - sendErrorsAsEmail(); - addError(new Error(gettext("Passphrase"), gettext("Ein Fehler trat auf, bitte versuche es erneut")), false); - return -1; - } - } - if (0 == memcmp(userModel->getPublicKey(), keys.getPublicKey(), crypto_sign_PUBLICKEYBYTES)) { - mPassphrase = inputPassphrase; - return 1; - } - addError(new Error(gettext("Passphrase"), gettext("Das ist nicht die richtige Passphrase.")), false); - return 0; -} - -bool Session::startProcessingTransaction(const std::string& proto_message_base64, bool autoSign/* = false*/) -{ - static const char* funcName = "Session::startProcessingTransaction"; - lock(funcName); - 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(funcName, "transaction already in list")); - unlock(); - return false; - } - } - if (mSessionUser.isNull() || !mSessionUser->getEmail()) { - addError(new Error(funcName, "user is zero")); - unlock(); - return false; - } - - Poco::AutoPtr processorTask( - new ProcessingTransaction( - proto_message_base64, - DRMakeStringHash(mSessionUser->getEmail()), - mSessionUser->getLanguage()) - ); - if (autoSign && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) == ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) { - if (processorTask->run() != 0) { - getErrors(processorTask); - unlock(); - return false; - } - Poco::AutoPtr signingTransaction(new SigningTransaction(processorTask, mNewUser)); - //signingTransaction->scheduleTask(signingTransaction); - if (signingTransaction->run() != 0) { - getErrors(signingTransaction); - unlock(); - return false; - } - - } - else { - processorTask->scheduleTask(processorTask); - mProcessingTransactions.push_back(processorTask); - } - unlock(); - return true; - -} - -Poco::AutoPtr 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; -} - -bool Session::finalizeTransaction(bool sign, bool reject) -{ - int result = -1; - lock("Session::finalizeTransaction"); - if (mCurrentActiveProcessingTransaction.isNull()) { - unlock(); - return false; - } - mProcessingTransactions.remove(mCurrentActiveProcessingTransaction); - - if (!reject) { - if (sign) { - Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mNewUser)); - //signingTransaction->scheduleTask(signingTransaction); - result = signingTransaction->run(); - } - } - mCurrentActiveProcessingTransaction.assign(nullptr); - unlock(); - return result == 0; -} - -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) -{ - static const char* functionName = "Session::loadUser"; - auto observer = SingletonTaskObserver::getInstance(); - if (email != "") { - if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) { - return USER_PASSWORD_ENCRYPTION_IN_PROCESS; - } - } - //Profiler usedTime; - //printf("before lock\n"); - lock(functionName); - //printf("locked \n"); - if (!mSessionUser.isNull() && mSessionUser->getEmail() != email) { - mSessionUser.assign(nullptr); - mNewUser.assign(nullptr); - //printf("user nullptr assigned\n"); - } - //printf("after checking if session user is null\n"); - //if (!mSessionUser) { - if (mNewUser.isNull()) { - //printf("new user is null\n"); - mNewUser = controller::User::create(); - //printf("new user created\n"); - // load user for email only once from db - mNewUser->load(email); - //printf("load new user from db with email: %s\n", email.data()); - mSessionUser = new User(mNewUser); - //mSessionUser = new User(email.data()); - - //printf("user loaded from email\n"); - } - //printf("before get model\n"); - auto user_model = mNewUser->getModel(); - if (user_model && user_model->isDisabled()) { - return USER_DISABLED; - } - //printf("before if login\n"); - if (!mSessionUser.isNull() && mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { - //printf("before login\n"); - int loginResult = 0; - int exitCount = 0; - do { - loginResult = mNewUser->login(password); - Poco::Thread::sleep(100); - exitCount++; - } while (-3 == loginResult && exitCount < 15); - if (exitCount > 1) { - addError(new ParamError(functionName, "login succeed, retrys: ", exitCount)); - addError(new ParamError(functionName, "email: ", email)); - sendErrorsAsEmail(); - } - - if (exitCount >= 15) - { - auto running_password_creations = observer->getTasksCount(TASK_OBSERVER_PASSWORD_CREATION); - - addError(new ParamError(functionName, "login failed after 15 retrys and 100 ms sleep between, currently running passwort creation tasks: ", running_password_creations)); - addError(new ParamError(functionName, "email: ", email)); - sendErrorsAsEmail(); - return USER_PASSWORD_ENCRYPTION_IN_PROCESS; - } - - //printf("new user login with result: %d\n", loginResult); - - if (-1 == loginResult) { - addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key")); - addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); - sendErrorsAsEmail(); - //unlock(); - //return USER_KEYS_DONT_MATCH; - } - if (0 == loginResult) { - unlock(); - return USER_PASSWORD_INCORRECT; - } - // error decrypting private key - if (-2 == loginResult) { - // check if we have access to the passphrase, if so we can reencrypt the private key - printf("try reencrypting key\n"); - auto user_model = mNewUser->getModel(); - auto user_backups = controller::UserBackups::load(user_model->getID()); - for (auto it = user_backups.begin(); it != user_backups.end(); it++) { - auto key = std::unique_ptr((*it)->createGradidoKeyPair()); - if (key->isTheSame(user_model->getPublicKey())) - { - - // set valid key pair - if (1 == mNewUser->setGradidoKeyPair(key.release())) { - // save new encrypted private key - user_model->updatePrivkey(); - } - else { - auto em = ErrorManager::getInstance(); - em->addError(new Error(functionName, "error reencrypt private key")); - em->addError(new ParamError(functionName, "for user with email", user_model->getEmail())); - em->sendErrorsAsEmail(); - } - break; - } - } - } - // can be removed if session user isn't used any more - // don't calculate password two times anymore - mSessionUser->login(mNewUser); - //printf("after old user login\n"); - /*if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { - unlock(); - return USER_PASSWORD_INCORRECT; - }*/ - } - else { - //printf("before sleep\n"); - 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; - }*/ - //printf("before detect session state\n"); - detectSessionState(); - unlock(); - //printf("before return user state\n"); - 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) -{ - //printf("[Session::setLanguage] new language: %d\n", 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.isNull() || !mSessionUser->hasCryptoKey()) { - return; - } - UserStates userState = mSessionUser->getUserState(); - - int checkEmail = -1, resetPasswd = -1; - try { - auto emailVerificationCodeObjects = controller::EmailVerificationCode::load(mSessionUser->getDBId()); - - for (int i = 0; i < emailVerificationCodeObjects.size(); i++) { - auto type = emailVerificationCodeObjects[i]->getModel()->getType(); - if (type == model::table::EMAIL_OPT_IN_EMPTY || type == model::table::EMAIL_OPT_IN_REGISTER) { - checkEmail = i; - } - else if (type == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - resetPasswd = i; - } - } - std::unique_lock _lock_shared(mSharedMutex); - if (resetPasswd != -1) { - mEmailVerificationCodeObject = emailVerificationCodeObjects[resetPasswd]; - } - else if (checkEmail != -1) { - mEmailVerificationCodeObject = emailVerificationCodeObjects[checkEmail]; - } - - } - catch (Poco::Exception& ex) { - printf("[Session::detectSessionState] exception: %s\n", ex.displayText().data()); - //return; - } - - if (userState <= USER_EMAIL_NOT_ACTIVATED) { - - if (checkEmail != -1) { - updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); - return; - } - - updateState(SESSION_STATE_USER_WRITTEN); - return; - } - - if (USER_NO_KEYS == userState) { - - auto user_id = mSessionUser->getDBId(); - auto userBackups = controller::UserBackups::load(user_id); - - // check passphrase, only possible while passphrase isn't crypted in db - bool correctPassphraseFound = false; - // always trigger SESSION_STATE_PASSPHRASE_WRITTEN, else lost of data possible - bool cryptedPassphrase = userBackups.size() > 0; - for (auto it = userBackups.begin(); it != userBackups.end(); it++) { - KeyPair keys; - auto passphrase = (*it)->getModel()->getPassphrase(); - Mnemonic* wordSource = nullptr; - if (User::validatePassphrase(passphrase, &wordSource)) { - if (keys.generateFromPassphrase((*it)->getModel()->getPassphrase().data(), wordSource)) { - if (sodium_memcmp(mSessionUser->getPublicKey(), keys.getPublicKey(), ed25519_pubkey_SIZE) == 0) { - correctPassphraseFound = true; - break; - } - } - } - else { - cryptedPassphrase = true; - } - } - /* - auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement select(dbConnection); - Poco::Nullable passphrase; - - select << "SELECT passphrase from user_backups where user_id = ?;", - into(passphrase), use(user_id); - try { - if (select.execute() == 1 && !passphrase.isNull()) { - //KeyPair keys;keys.generateFromPassphrase(passphrase.value().rawContent()) - updateState(SESSION_STATE_PASSPHRASE_WRITTEN); - return; - } - } - catch (Poco::Exception& exc) { - printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data()); - }*/ - if (correctPassphraseFound || cryptedPassphrase) { - updateState(SESSION_STATE_PASSPHRASE_WRITTEN); - return; - } - if (mPassphrase != "") { - updateState(SESSION_STATE_PASSPHRASE_GENERATED); - return; - } - updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); - return; - } - - updateState(SESSION_STATE_KEY_PAIR_WRITTEN); - - if (resetPasswd != -1) { - // don't go to reset password screen after login, only throw checkEmail - //updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - return; - } - -} - -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, on linux, except in test builds -#ifndef WIN32 - if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || - ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { - keks.setSecure(true); - } -#endif - - return keks; -} - -bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode) -{ - Profiler usedTime; - auto em = ErrorManager::getInstance(); - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = controller::EmailVerificationCode::load(emailVerificationCode); - if (mEmailVerificationCodeObject.isNull()) { - addError(new Error(gettext("E-Mail Verification"), gettext("Konnte kein passendes Konto finden."))); - return false; - } - - mNewUser = controller::User::create(); - assert(mEmailVerificationCodeObject->getModel() && mEmailVerificationCodeObject->getModel()->getUserId()); - mNewUser->load(mEmailVerificationCodeObject->getModel()->getUserId()); - if (mNewUser->getModel()->errorCount() > 0) { - mNewUser->getModel()->sendErrorsAsEmail(); - addError(new Error(gettext("E-Mail Verification"), gettext("Fehler beim laden des Benutzers."))); - return false; - } - mSessionUser = new User(mNewUser); - mSessionUser->setLanguage(getLanguage()); - - auto verificationType = mEmailVerificationCodeObject->getModel()->getType(); - if (verificationType == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { - updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); - } - else { - updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); - } - - return true; -} - -void Session::updateState(SessionStates newState) -{ - lock("Session::updateState"); - if (!mActive) { - unlock(); - 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"; - case SESSION_STATE_RESET_PASSWORD_REQUEST: return "Passwort reset requested"; - case SESSION_STATE_RESET_PASSWORD_SUCCEED: return "Passwort reset succeeded"; - default: return "unknown"; - } - - return "error"; -} - - -/* -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() -{ - if (mNewUser.isNull()) return false; - - auto lang = getLanguage(); - if (lang == LANG_EN) { - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); - } - else { - mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); - } - //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); - updateState(SESSION_STATE_PASSPHRASE_GENERATED); - return true; -} - -bool Session::generateKeys(bool savePrivkey, bool savePassphrase) -{ - if (mNewUser.isNull()) { - addError(new Error(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); - return false; - } - static const char* function_name = "Session::generateKeys"; - auto lang = getLanguage(); - auto user_model = mNewUser->getModel(); - auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; - /*if (LANG_DE == lang) { - mnemonic_type = ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES; - }*/ - - auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); - if (!passphrase) { - addError(new ParamError(function_name, "Error generating passphrase with mnemonic: ", mnemonic_type)); - addError(new ParamError(function_name, "user email: ", mNewUser->getModel()->getEmail())); - sendErrorsAsEmail(); - addError(new Error(gettext("Benutzer"), gettext("Fehler beim generieren der Passphrase, der Admin bekommt eine E-Mail. "))); - return false; - } - - if (savePassphrase) { - auto user_backup = controller::UserBackups::create(user_model->getID(), passphrase->getString(), mnemonic_type); - // sync version - //user_backup->getModel()->insertIntoDB(false); - - // async version - UniLib::controller::TaskPtr save_user_backup_task = new model::table::ModelInsertTask(user_backup->getModel(), false, true); - save_user_backup_task->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this)); - save_user_backup_task->scheduleTask(save_user_backup_task); - } - - // keys - auto gradido_key_pair = KeyPairEd25519::create(passphrase); - auto set_key_result = mNewUser->setGradidoKeyPair(gradido_key_pair); - size_t result_save_key = 0; - if (1 == set_key_result && savePrivkey) { - // save public key and private key in db - result_save_key = user_model->updatePubkeyAndPrivkey(); - } - else { - // save public key in db - result_save_key = user_model->updatePublickey(); - } - if (!result_save_key) { - user_model->addError(new Error(function_name, "Error saving new generated pubkey")); - user_model->addError(new ParamError(function_name, "e-mail: ", user_model->getEmail())); - user_model->sendErrorsAsEmail(); - //addError(new Error(gettext("Benutzer"), gettext("Fehler beim Speichern der Keys, der Admin bekommt eine E-Mail. Evt. nochmal versuchen oder abwarten!"))); - return false; - } - return true; - /* - - 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; - */ -} +#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 "../SingletonManager/EmailManager.h" +#include "../SingletonManager/SingletonTaskObserver.h" + +#include "../tasks/PrepareEmailTask.h" +#include "../tasks/SendEmailTask.h" +#include "../tasks/SigningTransaction.h" +#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h" +#include "../tasks/VerificationEmailResendTask.h" + +#include "../lib/JsonRequest.h" + +#include "../Crypto/Passphrase.h" + + +#include "../controller/User.h" +#include "../controller/UserBackups.h" +#include "../controller/EmailVerificationCode.h" + +#include "table/ModelBase.h" + + +#include "sodium.h" + +using namespace Poco::Data::Keywords; + +int WriteEmailVerification::run() +{ + auto em = ErrorManager::getInstance(); + + mEmailVerificationCode->getModel()->setUserId(mUser->getDBId()); + auto emailVerificationModel = mEmailVerificationCode->getModel(); + emailVerificationModel->setUserId(mUser->getDBId()); + if (!emailVerificationModel->insertIntoDB(true) || emailVerificationModel->errorCount() > 0) { + emailVerificationModel->sendErrorsAsEmail(); + return -1; + } + + 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), 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"); + std::unique_lock _lock(mSharedMutex); + mSessionUser.assign(nullptr); + mNewUser.assign(nullptr); + mEmailVerificationCodeObject.assign(nullptr); + + // watch out + //updateTimeout(); + mLastActivity = Poco::DateTime(); + + mState = SESSION_STATE_EMPTY; + + mPassphrase = ""; + mLastExternReferer = ""; + mClientLoginIP = Poco::Net::IPAddress(); + unlock(); + + // reset transactions + mCurrentActiveProcessingTransaction = nullptr; + mProcessingTransactions.clear(); + + //printf("[Session::reset] finished\n"); +} + +int Session::isActive() +{ + int ret = 0; + try { + mWorkMutex.tryLock(100); + } + catch (Poco::TimeoutException &ex) { + return -1; + } + ret = (int)mActive; + unlock(); + return ret; + +} + +bool Session::isDeadLocked() +{ + try { + mWorkMutex.tryLock(200); + unlock(); + return false; + } + catch (Poco::Exception& ex) { + + } + return true; +} + +bool Session::setActive(bool active) +{ + try { + mWorkMutex.tryLock(100); + } + catch (Poco::TimeoutException &ex) { + return false; + } + mActive = active; + unlock(); + return true; +} + +void Session::updateTimeout() +{ + lock("Session::updateTimeout"); + mLastActivity = Poco::DateTime(); + unlock(); +} + +Poco::AutoPtr Session::getEmailVerificationCodeObject() +{ + lock("Session::getEmailVerificationCodeObject"); + std::shared_lock _lock(mSharedMutex); + auto ret = mEmailVerificationCodeObject; + unlock(); + return ret; +} + +bool Session::adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email) +{ + Profiler usedTime; + + if (mNewUser->getModel()->getRole() != model::table::ROLE_ADMIN) { + addError(new Error(gettext("Benutzer"), gettext("Eingeloggter Benutzer ist kein Admin")), false); + return false; + } + + 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 <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + return false; + } + + + // check if user with that email already exist + if (mNewUser->getModel()->isExistInDB("email", email)) { + addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits einen Account")), false); + return false; + } + + auto newUser = controller::User::create(email, first_name, last_name); + updateTimeout(); + + + auto newUserModel = newUser->getModel(); + if (!newUserModel->insertIntoDB(true)) { + addError(new Error(gettext("Benutzer"), gettext("Fehler beim speichern!"))); + return false; + } + + auto email_verification_code = controller::EmailVerificationCode::create(newUserModel->getID(), model::table::EMAIL_OPT_IN_REGISTER); + if (!email_verification_code->getModel()->insertIntoDB(false)) { + addError(new Error(gettext("Email Verification Code"), gettext("Fehler beim speichern!"))); + return false; + } + + EmailManager::getInstance()->addEmail(new model::Email(email_verification_code, newUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE)); + + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = email_verification_code; + + + return true; +} +// +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 <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + 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")), false); + 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()); + mNewUser = controller::User::create(email, first_name, last_name); + 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, mNewUser, 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); + + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = controller::EmailVerificationCode::create(model::table::EMAIL_OPT_IN_REGISTER); + UniLib::controller::TaskPtr writeEmailVerification(new WriteEmailVerification(mSessionUser, mEmailVerificationCodeObject, 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üß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)); + //Email(AutoPtr emailVerification, AutoPtr user, EmailType type); + UniLib::controller::TaskPtr sendEmail(new SendEmailTask(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_VERIFICATION_CODE), ServerConfig::g_CPUScheduler, 1)); + //sendEmail->setParentTaskPtrInArray(prepareEmail, 0); + sendEmail->setParentTaskPtrInArray(writeEmailVerification, 0); + 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::createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password) +{ + std::unique_lock _lock(mSharedMutex); + static const char* function_name = "Session::createUserDirect"; + auto sm = SessionManager::getInstance(); + auto em = ErrorManager::getInstance(); + auto email_manager = EmailManager::getInstance(); + + if (!sm->isValid(first_name, VALIDATE_NAME)) { + addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(last_name, VALIDATE_NAME)) { + addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")), false); + return false; + } + if (!sm->isValid(email, VALIDATE_EMAIL)) { + addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine gültige E-Mail Adresse an.")), false); + return false; + } + if (!sm->checkPwdValidation(password, this)) { + return false; + } + + // check if email already exist + auto user = controller::User::create(); + if (user->load(email) >= 1) { + addError(new Error(gettext("E-Mail"), gettext("Für diese E-Mail Adresse gibt es bereits ein Konto")), false); + return false; + } + + // user + mNewUser = controller::User::create(email, first_name, last_name); + auto user_model = mNewUser->getModel(); + user_model->insertIntoDB(true); + auto user_id = user_model->getID(); + + + // one retry in case of connection error + if (!user_id) { + user_model->insertIntoDB(true); + auto user_id = user_model->getID(); + if (!user_id) { + em->addError(new ParamError(function_name, "error saving new user in db, after one retry with email", email)); + em->sendErrorsAsEmail(); + addError(new Error(gettext("Server"), gettext("Fehler beim speichen des Kontos bitte versuche es später noch einmal")), false); + return false; + } + } + + generateKeys(true, true); + + // calculate encryption key, could need some time, will save encrypted privkey to db + UniLib::controller::TaskPtr create_authenticated_encrypten_key = new AuthenticatedEncryptionCreateKeyTask(mNewUser, password); + create_authenticated_encrypten_key->scheduleTask(create_authenticated_encrypten_key); + + // email verification code + auto email_verification = controller::EmailVerificationCode::create(user_id, model::table::EMAIL_OPT_IN_REGISTER_DIRECT); + email_verification->getModel()->insertIntoDB(false); + mEmailVerificationCodeObject = email_verification; + + auto _7days_later = Poco::DateTime() + Poco::Timespan(7, 0, 0, 0, 0); + ServerConfig::g_CronJobsTimer.schedule(new VerificationEmailResendTimerTask(user_id), Poco::Timestamp(_7days_later.timestamp())); + + email_manager->addEmail(new model::Email(email_verification, mNewUser, model::EMAIL_USER_VERIFICATION_CODE)); + + 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"; + Poco::ScopedLock _lock(mWorkMutex); + // new mutex, will replace the Poco Mutex complete in the future + std::unique_lock _lock_shared(mSharedMutex); + Profiler usedTime; + + auto em = ErrorManager::getInstance(); + if (mEmailVerificationCodeObject.isNull()) { + em->addError(new Error(funcName, "email verification object is zero")); + em->sendErrorsAsEmail(); + + return -2; + } + auto email_verification_code_model = mEmailVerificationCodeObject->getModel(); + assert(email_verification_code_model); + if(email_verification_code_model->getCode() == 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; + return -2; + } + + // load correct user from db + if (mNewUser.isNull() || !mNewUser->getModel() || mNewUser->getModel()->getID() != email_verification_code_model->getUserId()) { + mNewUser = controller::User::create(); + if (1 != mNewUser->load(email_verification_code_model->getUserId())) { + em->addError(new ParamError(funcName, "user load didn't return 1 with user_id ", email_verification_code_model->getUserId())); + em->sendErrorsAsEmail(); + + return -2; + } + } + + auto user_model = mNewUser->getModel(); + assert(user_model); + bool first_email_activation = false; + auto verification_type = email_verification_code_model->getType(); + if (model::table::EMAIL_OPT_IN_REGISTER == verification_type || + model::table::EMAIL_OPT_IN_EMPTY == verification_type || + model::table::EMAIL_OPT_IN_REGISTER_DIRECT == verification_type) { + first_email_activation = true; + } + if (first_email_activation && user_model->isEmailChecked()) { + mSessionUser = new User(mNewUser); + addError(new Error(gettext("E-Mail Verification"), gettext("Du hast dein Konto bereits aktiviert!")), false); + + return 1; + } + if (first_email_activation) { + user_model->setEmailChecked(true); + + user_model->updateIntoDB("email_checked", 1); + if (user_model->errorCount() > 0) { + user_model->sendErrorsAsEmail(); + } + + // no find all active sessions + + updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); + return 0; + } + + if (email_verification_code_model->getType() == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + + if (mEmailVerificationCodeObject->deleteFromDB()) { + mEmailVerificationCodeObject.assign(nullptr); + } + else { + em->getErrors(mEmailVerificationCodeObject->getModel()); + em->addError(new Error(funcName, "error deleting email verification code")); + em->sendErrorsAsEmail(); + return -2; + } + updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + return 0; + } + + em->addError(new Error(funcName, "invalid code path")); + em->sendErrorsAsEmail(); + + 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()); + + return -1; + } + //printf("[%s] time: %s\n", funcName, usedTime.string().data()); + + return 0; +} + + +int Session::sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized) +{ + mNewUser = user; + mSessionUser = new User(user); + auto em = EmailManager::getInstance(); + + std::unique_lock _lock(mSharedMutex); + + // creating email verification code also for user without passphrase + // first check if already exist + // check if email was already send shortly before + bool frequent_resend = false; + bool email_already_send = false; + + mEmailVerificationCodeObject = controller::EmailVerificationCode::load(user->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); + if (mEmailVerificationCodeObject.isNull()) { + mEmailVerificationCodeObject = controller::EmailVerificationCode::create(mNewUser->getModel()->getID(), model::table::EMAIL_OPT_IN_RESET_PASSWORD); + mEmailVerificationCodeObject->getModel()->insertIntoDB(false); + } + else { + email_already_send = true; + } + auto email_verification_model = mEmailVerificationCodeObject->getModel(); + if (email_already_send) { + auto time_elapsed = Poco::DateTime() - email_verification_model->getUpdated(); + if (time_elapsed.totalHours() < 1) { + frequent_resend = true; + } + } + + if (!frequent_resend) { + if (passphraseMemorized) { + em->addEmail(new model::Email(mEmailVerificationCodeObject, mNewUser, model::EMAIL_USER_RESET_PASSWORD)); + } + else { + em->addEmail(new model::Email(user, model::EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE)); + } + } + + if (frequent_resend) return 2; + if (email_already_send) return 1; + + return 0; +} + +int Session::comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource) +{ + KeyPair keys; + static const char* functionName = "Session::comparePassphraseWithSavedKeys"; + if (!wordSource) { + addError(new Error(functionName, "wordSource is empty")); + sendErrorsAsEmail(); + return -2; + } + if (!keys.generateFromPassphrase(inputPassphrase.data(), wordSource)) { + addError(new ParamError(functionName, "invalid passphrase", inputPassphrase)); + if (!mNewUser.isNull() && mNewUser->getModel()) { + addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); + } + sendErrorsAsEmail(); + addError(new Error(gettext("Passphrase"), gettext("Deine Passphrase ist ungütig")), false); + return 0; + } + auto userModel = mNewUser->getModel(); + auto existingPublic = userModel->getPublicKey(); + if (!existingPublic) { + userModel->loadFromDB("email", userModel->getEmail()); + existingPublic = userModel->getPublicKey(); + if (!existingPublic) { + addError(new Error(functionName, "cannot load existing public key from db")); + addError(new ParamError(functionName, "user email", userModel->getEmail())); + sendErrorsAsEmail(); + addError(new Error(gettext("Passphrase"), gettext("Ein Fehler trat auf, bitte versuche es erneut")), false); + return -1; + } + } + if (0 == memcmp(userModel->getPublicKey(), keys.getPublicKey(), crypto_sign_PUBLICKEYBYTES)) { + mPassphrase = inputPassphrase; + return 1; + } + addError(new Error(gettext("Passphrase"), gettext("Das ist nicht die richtige Passphrase.")), false); + return 0; +} + +bool Session::startProcessingTransaction(const std::string& proto_message_base64, bool autoSign/* = false*/) +{ + static const char* funcName = "Session::startProcessingTransaction"; + lock(funcName); + 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(funcName, "transaction already in list")); + unlock(); + return false; + } + } + if (mSessionUser.isNull() || !mSessionUser->getEmail()) { + addError(new Error(funcName, "user is zero")); + unlock(); + return false; + } + + Poco::AutoPtr processorTask( + new ProcessingTransaction( + proto_message_base64, + DRMakeStringHash(mSessionUser->getEmail()), + mSessionUser->getLanguage()) + ); + if (autoSign && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) == ServerConfig::UNSECURE_AUTO_SIGN_TRANSACTIONS) { + if (processorTask->run() != 0) { + getErrors(processorTask); + unlock(); + return false; + } + Poco::AutoPtr signingTransaction(new SigningTransaction(processorTask, mNewUser)); + //signingTransaction->scheduleTask(signingTransaction); + if (signingTransaction->run() != 0) { + getErrors(signingTransaction); + unlock(); + return false; + } + + } + else { + processorTask->scheduleTask(processorTask); + mProcessingTransactions.push_back(processorTask); + } + unlock(); + return true; + +} + +Poco::AutoPtr 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; +} + +bool Session::finalizeTransaction(bool sign, bool reject) +{ + int result = -1; + lock("Session::finalizeTransaction"); + if (mCurrentActiveProcessingTransaction.isNull()) { + unlock(); + return false; + } + mProcessingTransactions.remove(mCurrentActiveProcessingTransaction); + + if (!reject) { + if (sign) { + Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mNewUser)); + //signingTransaction->scheduleTask(signingTransaction); + result = signingTransaction->run(); + } + } + mCurrentActiveProcessingTransaction.assign(nullptr); + unlock(); + return result == 0; +} + +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) +{ + static const char* functionName = "Session::loadUser"; + auto observer = SingletonTaskObserver::getInstance(); + if (email != "") { + if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) { + return USER_PASSWORD_ENCRYPTION_IN_PROCESS; + } + } + //Profiler usedTime; + //printf("before lock\n"); + lock(functionName); + //printf("locked \n"); + if (!mSessionUser.isNull() && mSessionUser->getEmail() != email) { + mSessionUser.assign(nullptr); + mNewUser.assign(nullptr); + //printf("user nullptr assigned\n"); + } + //printf("after checking if session user is null\n"); + //if (!mSessionUser) { + if (mNewUser.isNull()) { + //printf("new user is null\n"); + mNewUser = controller::User::create(); + //printf("new user created\n"); + // load user for email only once from db + mNewUser->load(email); + //printf("load new user from db with email: %s\n", email.data()); + mSessionUser = new User(mNewUser); + //mSessionUser = new User(email.data()); + + //printf("user loaded from email\n"); + } + //printf("before get model\n"); + auto user_model = mNewUser->getModel(); + if (user_model && user_model->isDisabled()) { + return USER_DISABLED; + } + //printf("before if login\n"); + if (!mSessionUser.isNull() && mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { + //printf("before login\n"); + int loginResult = 0; + int exitCount = 0; + do { + loginResult = mNewUser->login(password); + Poco::Thread::sleep(100); + exitCount++; + } while (-3 == loginResult && exitCount < 15); + if (exitCount > 1) { + addError(new ParamError(functionName, "login succeed, retrys: ", exitCount)); + addError(new ParamError(functionName, "email: ", email)); + sendErrorsAsEmail(); + } + + if (exitCount >= 15) + { + auto running_password_creations = observer->getTasksCount(TASK_OBSERVER_PASSWORD_CREATION); + + addError(new ParamError(functionName, "login failed after 15 retrys and 100 ms sleep between, currently running passwort creation tasks: ", running_password_creations)); + addError(new ParamError(functionName, "email: ", email)); + sendErrorsAsEmail(); + return USER_PASSWORD_ENCRYPTION_IN_PROCESS; + } + + //printf("new user login with result: %d\n", loginResult); + + if (-1 == loginResult) { + addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key")); + addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); + sendErrorsAsEmail(); + //unlock(); + //return USER_KEYS_DONT_MATCH; + } + if (0 == loginResult) { + unlock(); + return USER_PASSWORD_INCORRECT; + } + // error decrypting private key + if (-2 == loginResult) { + // check if we have access to the passphrase, if so we can reencrypt the private key + printf("try reencrypting key\n"); + auto user_model = mNewUser->getModel(); + auto user_backups = controller::UserBackups::load(user_model->getID()); + for (auto it = user_backups.begin(); it != user_backups.end(); it++) { + auto key = std::unique_ptr((*it)->createGradidoKeyPair()); + if (key->isTheSame(user_model->getPublicKey())) + { + + // set valid key pair + if (1 == mNewUser->setGradidoKeyPair(key.release())) { + // save new encrypted private key + user_model->updatePrivkey(); + } + else { + auto em = ErrorManager::getInstance(); + em->addError(new Error(functionName, "error reencrypt private key")); + em->addError(new ParamError(functionName, "for user with email", user_model->getEmail())); + em->sendErrorsAsEmail(); + } + break; + } + } + } + // can be removed if session user isn't used any more + // don't calculate password two times anymore + mSessionUser->login(mNewUser); + //printf("after old user login\n"); + /*if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { + unlock(); + return USER_PASSWORD_INCORRECT; + }*/ + } + else { + //printf("before sleep\n"); + 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; + }*/ + //printf("before detect session state\n"); + detectSessionState(); + unlock(); + //printf("before return user state\n"); + 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) +{ + //printf("[Session::setLanguage] new language: %d\n", 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.isNull() || !mSessionUser->hasCryptoKey()) { + return; + } + UserStates userState = mSessionUser->getUserState(); + + int checkEmail = -1, resetPasswd = -1; + try { + auto emailVerificationCodeObjects = controller::EmailVerificationCode::load(mSessionUser->getDBId()); + + for (int i = 0; i < emailVerificationCodeObjects.size(); i++) { + auto type = emailVerificationCodeObjects[i]->getModel()->getType(); + if (type == model::table::EMAIL_OPT_IN_EMPTY || type == model::table::EMAIL_OPT_IN_REGISTER) { + checkEmail = i; + } + else if (type == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + resetPasswd = i; + } + } + std::unique_lock _lock_shared(mSharedMutex); + if (resetPasswd != -1) { + mEmailVerificationCodeObject = emailVerificationCodeObjects[resetPasswd]; + } + else if (checkEmail != -1) { + mEmailVerificationCodeObject = emailVerificationCodeObjects[checkEmail]; + } + + } + catch (Poco::Exception& ex) { + printf("[Session::detectSessionState] exception: %s\n", ex.displayText().data()); + //return; + } + + if (userState <= USER_EMAIL_NOT_ACTIVATED) { + + if (checkEmail != -1) { + updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); + return; + } + + updateState(SESSION_STATE_USER_WRITTEN); + return; + } + + if (USER_NO_KEYS == userState) { + + auto user_id = mSessionUser->getDBId(); + auto userBackups = controller::UserBackups::load(user_id); + + // check passphrase, only possible while passphrase isn't crypted in db + bool correctPassphraseFound = false; + // always trigger SESSION_STATE_PASSPHRASE_WRITTEN, else lost of data possible + bool cryptedPassphrase = userBackups.size() > 0; + for (auto it = userBackups.begin(); it != userBackups.end(); it++) { + KeyPair keys; + auto passphrase = (*it)->getModel()->getPassphrase(); + Mnemonic* wordSource = nullptr; + if (User::validatePassphrase(passphrase, &wordSource)) { + if (keys.generateFromPassphrase((*it)->getModel()->getPassphrase().data(), wordSource)) { + if (sodium_memcmp(mSessionUser->getPublicKey(), keys.getPublicKey(), ed25519_pubkey_SIZE) == 0) { + correctPassphraseFound = true; + break; + } + } + } + else { + cryptedPassphrase = true; + } + } + /* + auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(dbConnection); + Poco::Nullable passphrase; + + select << "SELECT passphrase from user_backups where user_id = ?;", + into(passphrase), use(user_id); + try { + if (select.execute() == 1 && !passphrase.isNull()) { + //KeyPair keys;keys.generateFromPassphrase(passphrase.value().rawContent()) + updateState(SESSION_STATE_PASSPHRASE_WRITTEN); + return; + } + } + catch (Poco::Exception& exc) { + printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data()); + }*/ + if (correctPassphraseFound || cryptedPassphrase) { + updateState(SESSION_STATE_PASSPHRASE_WRITTEN); + return; + } + if (mPassphrase != "") { + updateState(SESSION_STATE_PASSPHRASE_GENERATED); + return; + } + updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); + return; + } + + updateState(SESSION_STATE_KEY_PAIR_WRITTEN); + + if (resetPasswd != -1) { + // don't go to reset password screen after login, only throw checkEmail + //updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + return; + } + +} + +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, on linux, except in test builds +#ifndef WIN32 + if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || + ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { + keks.setSecure(true); + } +#endif + + return keks; +} + +bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode) +{ + Profiler usedTime; + auto em = ErrorManager::getInstance(); + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = controller::EmailVerificationCode::load(emailVerificationCode); + if (mEmailVerificationCodeObject.isNull()) { + addError(new Error(gettext("E-Mail Verification"), gettext("Konnte kein passendes Konto finden."))); + return false; + } + + mNewUser = controller::User::create(); + assert(mEmailVerificationCodeObject->getModel() && mEmailVerificationCodeObject->getModel()->getUserId()); + mNewUser->load(mEmailVerificationCodeObject->getModel()->getUserId()); + if (mNewUser->getModel()->errorCount() > 0) { + mNewUser->getModel()->sendErrorsAsEmail(); + addError(new Error(gettext("E-Mail Verification"), gettext("Fehler beim laden des Benutzers."))); + return false; + } + mSessionUser = new User(mNewUser); + mSessionUser->setLanguage(getLanguage()); + + auto verificationType = mEmailVerificationCodeObject->getModel()->getType(); + if (verificationType == model::table::EMAIL_OPT_IN_RESET_PASSWORD) { + updateState(SESSION_STATE_RESET_PASSWORD_REQUEST); + } + else { + updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN); + } + + return true; +} + +void Session::updateState(SessionStates newState) +{ + lock("Session::updateState"); + if (!mActive) { + unlock(); + 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"; + case SESSION_STATE_RESET_PASSWORD_REQUEST: return "Passwort reset requested"; + case SESSION_STATE_RESET_PASSWORD_SUCCEED: return "Passwort reset succeeded"; + default: return "unknown"; + } + + return "error"; +} + + +/* +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() +{ + if (mNewUser.isNull()) return false; + + auto lang = getLanguage(); + if (lang == LANG_EN) { + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); + } + else { + mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); + } + //mPassphrase = User::generateNewPassphrase(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]); + updateState(SESSION_STATE_PASSPHRASE_GENERATED); + return true; +} + +bool Session::generateKeys(bool savePrivkey, bool savePassphrase) +{ + if (mNewUser.isNull()) { + addError(new Error(gettext("Benutzer"), gettext("Kein gültiger Benutzer, bitte logge dich erneut ein."))); + return false; + } + static const char* function_name = "Session::generateKeys"; + auto lang = getLanguage(); + auto user_model = mNewUser->getModel(); + auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; + /*if (LANG_DE == lang) { + mnemonic_type = ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES; + }*/ + + auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + if (!passphrase) { + addError(new ParamError(function_name, "Error generating passphrase with mnemonic: ", mnemonic_type)); + addError(new ParamError(function_name, "user email: ", mNewUser->getModel()->getEmail())); + sendErrorsAsEmail(); + addError(new Error(gettext("Benutzer"), gettext("Fehler beim generieren der Passphrase, der Admin bekommt eine E-Mail. "))); + return false; + } + + if (savePassphrase) { + auto user_backup = controller::UserBackups::create(user_model->getID(), passphrase->getString(), mnemonic_type); + // sync version + //user_backup->getModel()->insertIntoDB(false); + + // async version + UniLib::controller::TaskPtr save_user_backup_task = new model::table::ModelInsertTask(user_backup->getModel(), false, true); + save_user_backup_task->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_PASSPHRASE_WRITTEN, this)); + save_user_backup_task->scheduleTask(save_user_backup_task); + } + + // keys + auto gradido_key_pair = KeyPairEd25519::create(passphrase); + auto set_key_result = mNewUser->setGradidoKeyPair(gradido_key_pair); + size_t result_save_key = 0; + if (1 == set_key_result && savePrivkey) { + // save public key and private key in db + result_save_key = user_model->updatePubkeyAndPrivkey(); + } + else { + // save public key in db + result_save_key = user_model->updatePublickey(); + } + if (!result_save_key) { + user_model->addError(new Error(function_name, "Error saving new generated pubkey")); + user_model->addError(new ParamError(function_name, "e-mail: ", user_model->getEmail())); + user_model->sendErrorsAsEmail(); + //addError(new Error(gettext("Benutzer"), gettext("Fehler beim Speichern der Keys, der Admin bekommt eine E-Mail. Evt. nochmal versuchen oder abwarten!"))); + return false; + } + return true; + /* + + 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; + */ +} diff --git a/login_server/src/cpp/model/Session.h b/login_server/src/cpp/model/Session.h index ec60b6fc3..e10beef89 100644 --- a/login_server/src/cpp/model/Session.h +++ b/login_server/src/cpp/model/Session.h @@ -1,282 +1,282 @@ -/*! -* -* \author: einhornimmond -* -* \date: 02.03.19 -* -* \brief: store session data -*/ - -#ifndef DR_LUA_WEB_MODULE_SESSION_SESSION_H -#define DR_LUA_WEB_MODULE_SESSION_SESSION_H - -#include "../lib/ErrorList.h" -#include "User.h" -#include "../controller/User.h" - -#include "../lib/MultithreadContainer.h" -#include "../tasks/ProcessingTransaction.h" - -#include "../SingletonManager/LanguageManager.h" - -#include "../controller/EmailVerificationCode.h" - -#include "Poco/Thread.h" -#include "Poco/Types.h" -#include "Poco/DateTime.h" -#include "Poco/Net/IPAddress.h" -#include "Poco/Net/HTTPCookie.h" - -#include - - -class WriteEmailVerification; - -enum SessionStates { - SESSION_STATE_EMPTY, - 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_RESET_PASSWORD_REQUEST, - SESSION_STATE_RESET_PASSWORD_SUCCEED, - SESSION_STATE_COUNT -}; - -class SessionManager; - -class UpdateUserPasswordPage; -class PassphrasePage; -class RepairDefectPassphrase; - -class Session : public ErrorList, public UniLib::lib::MultithreadContainer -{ - friend WriteEmailVerification; - friend SessionManager; - friend UpdateUserPasswordPage; - friend PassphrasePage; - friend RepairDefectPassphrase; -public: - Session(int handle); - ~Session(); - - // get new model objects - Poco::AutoPtr getEmailVerificationCodeObject(); - - // set new model objects - inline void setUser(Poco::AutoPtr user) { mNewUser = user; } - inline Poco::AutoPtr getNewUser() { return mNewUser; } - - // ---------------- User functions ---------------------------- - // TODO: register state: written into db, mails sended, update state only if new state is higher as old state - // create User send e-mail activation link - bool createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); - - //! \brief new register function, without showing user pubkeys, using controller/user - bool createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); - - - // adminRegister without passwort - bool adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email); - - // TODO: check if email exist and if not, fake waiting on password hashing with profiled times of real password hashing - UserStates loadUser(const std::string& email, const std::string& password); - bool ifUserExist(const std::string& email); - - inline void setUser(Poco::AutoPtr user) { mSessionUser = user; } - - - bool deleteUser(); - - Poco::AutoPtr getUser() { - return mSessionUser; - } - - // ------------------------- Email Verification Code functions ------------------------------- - - bool loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode); - - //! \return 1 = konto already exist - //! -1 = invalid code - //! -2 = critical error - //! 0 = ok - int updateEmailVerification(Poco::UInt64 emailVerificationCode); - - // called from page with same name - //! \return 1 = reset password email already send - //! \return 2 = reset password email already shortly before - //! \return 0 = ok - int sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized); - // - //! \return 0 = not the same - //! \return 1 = same - //! \return -1 = error - //! \return -2 = critical error - int comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource); - - Poco::Net::HTTPCookie getLoginCookie(); - - - inline int getHandle() { return mHandleId; } - - // ------------------------ Passphrase functions ---------------------------- - - inline void setPassphrase(Poco::AutoPtr passphrase) { mNewPassphrase = passphrase; } - inline Poco::AutoPtr getPassphrase() { return mNewPassphrase; } - - inline void setPassphrase(const std::string& passphrase) { mPassphrase = passphrase; } - - inline const std::string& getOldPassphrase() { return mPassphrase; } - bool generatePassphrase(); - bool generateKeys(bool savePrivkey, bool savePassphrase); - - inline void setClientIp(Poco::Net::IPAddress ip) { mClientLoginIP = ip; } - inline Poco::Net::IPAddress getClientIp() { return mClientLoginIP; } - - inline bool isIPValid(Poco::Net::IPAddress ip) { return mClientLoginIP == ip; } - bool isPwdValid(const std::string& pwd); - void reset(); - - void updateState(SessionStates newState); - const char* getSessionStateString(); - inline SessionStates getSessionState() { SessionStates s; lock("Session::getSessionState"); s = mState; unlock(); return s; } - - inline Poco::UInt64 getEmailVerificationCode() { - std::shared_lock _lock(mSharedMutex); - if (mEmailVerificationCodeObject.isNull()) return 0; return mEmailVerificationCodeObject->getModel()->getCode(); - } - inline void setEmailVerificationCodeObject(Poco::AutoPtr emailVerficationObject) { - std::unique_lock _lock(mSharedMutex); - mEmailVerificationCodeObject = emailVerficationObject; - } - inline model::table::EmailOptInType getEmailVerificationType() { - std::shared_lock _lock(mSharedMutex); - if (mEmailVerificationCodeObject.isNull()) { - return model::table::EMAIL_OPT_IN_EMPTY; - } - return mEmailVerificationCodeObject->getModel()->getType(); - } - - //! \return -1 if session is locked - //! \return 1 if session is active - //! \return 0 - int isActive(); - //! \return false if session is locked - bool setActive(bool active); - - bool isDeadLocked(); - - inline Poco::DateTime getLastActivity() { return mLastActivity; } - - // ------------------------ transactions functions ---------------------------- - - //! \return true if succeed - bool startProcessingTransaction(const std::string& proto_message_base64, bool autoSign = false); - //! \param working if set will filled with transaction running - Poco::AutoPtr getNextReadyTransaction(size_t* working = nullptr); - bool finalizeTransaction(bool sign, bool reject); - size_t getProcessingTransactionCount(); - - inline LanguageCatalog* getLanguageCatalog() { return mLanguageCatalog.isNull() ? nullptr : mLanguageCatalog; } - void setLanguage(Languages lang); - inline void setLanguageCatalog(Poco::AutoPtr languageCatalog) { mLanguageCatalog = languageCatalog; } - Languages getLanguage(); - inline const char* gettext(const char* text) { if (mLanguageCatalog.isNull()) return text; return mLanguageCatalog->gettext(text); } - - // last referer - inline void setLastReferer(const std::string& lastReferer) { mLastExternReferer = lastReferer; } - inline const std::string& getLastReferer() const { return mLastExternReferer; } - -protected: - void updateTimeout(); - inline void setHandle(int newHandle) { mHandleId = newHandle; } - - void detectSessionState(); - static const char* translateSessionStateToString(SessionStates state); - - inline const std::string& getPassphrase() const { return mPassphrase; } - - -private: - int mHandleId; - Poco::AutoPtr mSessionUser; - Poco::AutoPtr mNewUser; - std::string mPassphrase; - Poco::AutoPtr mNewPassphrase; - Poco::DateTime mLastActivity; - Poco::Net::IPAddress mClientLoginIP; - std::string mLastExternReferer; - Poco::AutoPtr mEmailVerificationCodeObject; - std::shared_mutex mSharedMutex; - - - SessionStates mState; - - bool mActive; - std::list> mProcessingTransactions; - Poco::AutoPtr mCurrentActiveProcessingTransaction; - - Poco::AutoPtr mLanguageCatalog; -}; - - -class WriteEmailVerification : public UniLib::controller::CPUTask -{ -public: - WriteEmailVerification(Poco::AutoPtr user, Poco::AutoPtr emailVerificationCode, UniLib::controller::CPUSheduler* cpuScheduler, size_t taskDependenceCount = 0) - : UniLib::controller::CPUTask(cpuScheduler, taskDependenceCount), mUser(user), mEmailVerificationCode(emailVerificationCode) { -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif - } - - virtual const char* getResourceType() const { return "WriteEmailVerification"; }; - virtual int run(); - -private: - Poco::AutoPtr mUser; - Poco::AutoPtr mEmailVerificationCode; - -}; - -class WritePassphraseIntoDB : public UniLib::controller::CPUTask -{ -public: - WritePassphraseIntoDB(int userId, const std::string& passphrase) - : mUserId(userId), mPassphrase(passphrase) { -#ifdef _UNI_LIB_DEBUG - setName(std::to_string(userId).data()); -#endif - } - - - virtual int run(); - virtual const char* getResourceType() const { return "WritePassphraseIntoDB"; }; - -protected: - int mUserId; - std::string mPassphrase; -}; - -class SessionStateUpdateCommand : public UniLib::controller::Command -{ -public: - SessionStateUpdateCommand(SessionStates state, Session* session) - : mState(state), mSession(session) {} - virtual int taskFinished(UniLib::controller::Task* task) { - mSession->updateState(mState); - return 0; - } - -protected: - SessionStates mState; - Session* mSession; -}; - -#endif // DR_LUA_WEB_MODULE_SESSION_SESSION_H +/*! +* +* \author: einhornimmond +* +* \date: 02.03.19 +* +* \brief: store session data +*/ + +#ifndef DR_LUA_WEB_MODULE_SESSION_SESSION_H +#define DR_LUA_WEB_MODULE_SESSION_SESSION_H + +#include "../lib/ErrorList.h" +#include "User.h" +#include "../controller/User.h" + +#include "../lib/MultithreadContainer.h" +#include "../tasks/ProcessingTransaction.h" + +#include "../SingletonManager/LanguageManager.h" + +#include "../controller/EmailVerificationCode.h" + +#include "Poco/Thread.h" +#include "Poco/Types.h" +#include "Poco/DateTime.h" +#include "Poco/Net/IPAddress.h" +#include "Poco/Net/HTTPCookie.h" + +#include + + +class WriteEmailVerification; + +enum SessionStates { + SESSION_STATE_EMPTY, + 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_RESET_PASSWORD_REQUEST, + SESSION_STATE_RESET_PASSWORD_SUCCEED, + SESSION_STATE_COUNT +}; + +class SessionManager; + +class UpdateUserPasswordPage; +class PassphrasePage; +class RepairDefectPassphrase; + +class Session : public ErrorList, public UniLib::lib::MultithreadContainer +{ + friend WriteEmailVerification; + friend SessionManager; + friend UpdateUserPasswordPage; + friend PassphrasePage; + friend RepairDefectPassphrase; +public: + Session(int handle); + ~Session(); + + // get new model objects + Poco::AutoPtr getEmailVerificationCodeObject(); + + // set new model objects + inline void setUser(Poco::AutoPtr user) { mNewUser = user; } + inline Poco::AutoPtr getNewUser() { return mNewUser; } + + // ---------------- User functions ---------------------------- + // TODO: register state: written into db, mails sended, update state only if new state is higher as old state + // create User send e-mail activation link + bool createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); + + //! \brief new register function, without showing user pubkeys, using controller/user + bool createUserDirect(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); + + + // adminRegister without passwort + bool adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email); + + // TODO: check if email exist and if not, fake waiting on password hashing with profiled times of real password hashing + UserStates loadUser(const std::string& email, const std::string& password); + bool ifUserExist(const std::string& email); + + inline void setUser(Poco::AutoPtr user) { mSessionUser = user; } + + + bool deleteUser(); + + Poco::AutoPtr getUser() { + return mSessionUser; + } + + // ------------------------- Email Verification Code functions ------------------------------- + + bool loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode); + + //! \return 1 = konto already exist + //! -1 = invalid code + //! -2 = critical error + //! 0 = ok + int updateEmailVerification(Poco::UInt64 emailVerificationCode); + + // called from page with same name + //! \return 1 = reset password email already send + //! \return 2 = reset password email already shortly before + //! \return 0 = ok + int sendResetPasswordEmail(Poco::AutoPtr user, bool passphraseMemorized); + // + //! \return 0 = not the same + //! \return 1 = same + //! \return -1 = error + //! \return -2 = critical error + int comparePassphraseWithSavedKeys(const std::string& inputPassphrase, Mnemonic* wordSource); + + Poco::Net::HTTPCookie getLoginCookie(); + + + inline int getHandle() { return mHandleId; } + + // ------------------------ Passphrase functions ---------------------------- + + inline void setPassphrase(Poco::AutoPtr passphrase) { mNewPassphrase = passphrase; } + inline Poco::AutoPtr getPassphrase() { return mNewPassphrase; } + + inline void setPassphrase(const std::string& passphrase) { mPassphrase = passphrase; } + + inline const std::string& getOldPassphrase() { return mPassphrase; } + bool generatePassphrase(); + bool generateKeys(bool savePrivkey, bool savePassphrase); + + inline void setClientIp(Poco::Net::IPAddress ip) { mClientLoginIP = ip; } + inline Poco::Net::IPAddress getClientIp() { return mClientLoginIP; } + + inline bool isIPValid(Poco::Net::IPAddress ip) { return mClientLoginIP == ip; } + bool isPwdValid(const std::string& pwd); + void reset(); + + void updateState(SessionStates newState); + const char* getSessionStateString(); + inline SessionStates getSessionState() { SessionStates s; lock("Session::getSessionState"); s = mState; unlock(); return s; } + + inline Poco::UInt64 getEmailVerificationCode() { + std::shared_lock _lock(mSharedMutex); + if (mEmailVerificationCodeObject.isNull()) return 0; return mEmailVerificationCodeObject->getModel()->getCode(); + } + inline void setEmailVerificationCodeObject(Poco::AutoPtr emailVerficationObject) { + std::unique_lock _lock(mSharedMutex); + mEmailVerificationCodeObject = emailVerficationObject; + } + inline model::table::EmailOptInType getEmailVerificationType() { + std::shared_lock _lock(mSharedMutex); + if (mEmailVerificationCodeObject.isNull()) { + return model::table::EMAIL_OPT_IN_EMPTY; + } + return mEmailVerificationCodeObject->getModel()->getType(); + } + + //! \return -1 if session is locked + //! \return 1 if session is active + //! \return 0 + int isActive(); + //! \return false if session is locked + bool setActive(bool active); + + bool isDeadLocked(); + + inline Poco::DateTime getLastActivity() { return mLastActivity; } + + // ------------------------ transactions functions ---------------------------- + + //! \return true if succeed + bool startProcessingTransaction(const std::string& proto_message_base64, bool autoSign = false); + //! \param working if set will filled with transaction running + Poco::AutoPtr getNextReadyTransaction(size_t* working = nullptr); + bool finalizeTransaction(bool sign, bool reject); + size_t getProcessingTransactionCount(); + + inline LanguageCatalog* getLanguageCatalog() { return mLanguageCatalog.isNull() ? nullptr : mLanguageCatalog; } + void setLanguage(Languages lang); + inline void setLanguageCatalog(Poco::AutoPtr languageCatalog) { mLanguageCatalog = languageCatalog; } + Languages getLanguage(); + inline const char* gettext(const char* text) { if (mLanguageCatalog.isNull()) return text; return mLanguageCatalog->gettext(text); } + + // last referer + inline void setLastReferer(const std::string& lastReferer) { mLastExternReferer = lastReferer; } + inline const std::string& getLastReferer() const { return mLastExternReferer; } + +protected: + void updateTimeout(); + inline void setHandle(int newHandle) { mHandleId = newHandle; } + + void detectSessionState(); + static const char* translateSessionStateToString(SessionStates state); + + inline const std::string& getPassphrase() const { return mPassphrase; } + + +private: + int mHandleId; + Poco::AutoPtr mSessionUser; + Poco::AutoPtr mNewUser; + std::string mPassphrase; + Poco::AutoPtr mNewPassphrase; + Poco::DateTime mLastActivity; + Poco::Net::IPAddress mClientLoginIP; + std::string mLastExternReferer; + Poco::AutoPtr mEmailVerificationCodeObject; + std::shared_mutex mSharedMutex; + + + SessionStates mState; + + bool mActive; + std::list> mProcessingTransactions; + Poco::AutoPtr mCurrentActiveProcessingTransaction; + + Poco::AutoPtr mLanguageCatalog; +}; + + +class WriteEmailVerification : public UniLib::controller::CPUTask +{ +public: + WriteEmailVerification(Poco::AutoPtr user, Poco::AutoPtr emailVerificationCode, UniLib::controller::CPUSheduler* cpuScheduler, size_t taskDependenceCount = 0) + : UniLib::controller::CPUTask(cpuScheduler, taskDependenceCount), mUser(user), mEmailVerificationCode(emailVerificationCode) { +#ifdef _UNI_LIB_DEBUG + setName(user->getEmail()); +#endif + } + + virtual const char* getResourceType() const { return "WriteEmailVerification"; }; + virtual int run(); + +private: + Poco::AutoPtr mUser; + Poco::AutoPtr mEmailVerificationCode; + +}; + +class WritePassphraseIntoDB : public UniLib::controller::CPUTask +{ +public: + WritePassphraseIntoDB(int userId, const std::string& passphrase) + : mUserId(userId), mPassphrase(passphrase) { +#ifdef _UNI_LIB_DEBUG + setName(std::to_string(userId).data()); +#endif + } + + + virtual int run(); + virtual const char* getResourceType() const { return "WritePassphraseIntoDB"; }; + +protected: + int mUserId; + std::string mPassphrase; +}; + +class SessionStateUpdateCommand : public UniLib::controller::Command +{ +public: + SessionStateUpdateCommand(SessionStates state, Session* session) + : mState(state), mSession(session) {} + virtual int taskFinished(UniLib::controller::Task* task) { + mSession->updateState(mState); + return 0; + } + +protected: + SessionStates mState; + Session* mSession; +}; + +#endif // DR_LUA_WEB_MODULE_SESSION_SESSION_H diff --git a/login_server/src/cpp/model/TransactionCreation.cpp b/login_server/src/cpp/model/TransactionCreation.cpp index a04c424c7..6e8e38369 100644 --- a/login_server/src/cpp/model/TransactionCreation.cpp +++ b/login_server/src/cpp/model/TransactionCreation.cpp @@ -1,72 +1,72 @@ -#include "TransactionCreation.h" -#include "Poco/DateTimeFormatter.h" -#include - -TransactionCreation::TransactionCreation(const std::string& memo, const model::messages::gradido::TransactionCreation& protoCreation) - : TransactionBase(memo), mProtoCreation(protoCreation), mReceiverUser(nullptr) -{ - memset(mReceiverPublicHex, 0, 65); -} - -TransactionCreation::~TransactionCreation() -{ - if (mReceiverUser) { - delete mReceiverUser; - mReceiverUser = nullptr; - } -} - -int TransactionCreation::prepare() -{ - const static char functionName[] = { "TransactionCreation::prepare" }; - if (!mProtoCreation.has_receiveramount()) { - addError(new Error(functionName, "hasn't receiver amount")); - return -1; - } - auto receiverAmount = mProtoCreation.receiveramount(); - - if (receiverAmount.amount() <= 0) { - addError(new Error(functionName, "amount must be > 0")); - return -4; - } - if (receiverAmount.amount() > 10000000) { - addError(new Error(functionName, "amount must be <= 1000 GDD")); - return -5; - } - - auto receiverPublic = receiverAmount.ed25519_receiver_pubkey(); - if (receiverPublic.size() != 32) { - addError(new Error(functionName, "receiver public invalid (size not 32)")); - return -2; - } - mReceiverUser = new User((const unsigned char*)receiverPublic.data()); - getErrors(mReceiverUser); - if (mReceiverUser->getUserState() == USER_EMPTY) { - sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); - delete mReceiverUser; - mReceiverUser = nullptr; - } - else { - memcpy(mReceiverPublicHex, mReceiverUser->getPublicKeyHex().data(), 64); - // uncomment because not correctly working - /*if (!mReceiverUser->validateIdentHash(mProtoCreation.ident_hash())) { - addError(new Error(functionName, "ident hash isn't the same")); - addError(new ParamError(functionName, "hash calculated from email: ", mReceiverUser->getEmail())); - addError(new ParamError(functionName, "hash: ", std::to_string(mProtoCreation.ident_hash()))); - return -3; - }*/ - } - // - - - return 0; -} - -std::string TransactionCreation::getTargetDateString() -{ - // proto format is seconds, poco timestamp format is microseconds - Poco::Timestamp pocoStamp(mProtoCreation.target_date().seconds() * 1000*1000); - //Poco::DateTime(pocoStamp); - return Poco::DateTimeFormatter::format(pocoStamp, "%d. %b %y"); -} - +#include "TransactionCreation.h" +#include "Poco/DateTimeFormatter.h" +#include + +TransactionCreation::TransactionCreation(const std::string& memo, const model::messages::gradido::TransactionCreation& protoCreation) + : TransactionBase(memo), mProtoCreation(protoCreation), mReceiverUser(nullptr) +{ + memset(mReceiverPublicHex, 0, 65); +} + +TransactionCreation::~TransactionCreation() +{ + if (mReceiverUser) { + delete mReceiverUser; + mReceiverUser = nullptr; + } +} + +int TransactionCreation::prepare() +{ + const static char functionName[] = { "TransactionCreation::prepare" }; + if (!mProtoCreation.has_receiveramount()) { + addError(new Error(functionName, "hasn't receiver amount")); + return -1; + } + auto receiverAmount = mProtoCreation.receiveramount(); + + if (receiverAmount.amount() <= 0) { + addError(new Error(functionName, "amount must be > 0")); + return -4; + } + if (receiverAmount.amount() > 10000000) { + addError(new Error(functionName, "amount must be <= 1000 GDD")); + return -5; + } + + auto receiverPublic = receiverAmount.ed25519_receiver_pubkey(); + if (receiverPublic.size() != 32) { + addError(new Error(functionName, "receiver public invalid (size not 32)")); + return -2; + } + mReceiverUser = new User((const unsigned char*)receiverPublic.data()); + getErrors(mReceiverUser); + if (mReceiverUser->getUserState() == USER_EMPTY) { + sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); + delete mReceiverUser; + mReceiverUser = nullptr; + } + else { + memcpy(mReceiverPublicHex, mReceiverUser->getPublicKeyHex().data(), 64); + // uncomment because not correctly working + /*if (!mReceiverUser->validateIdentHash(mProtoCreation.ident_hash())) { + addError(new Error(functionName, "ident hash isn't the same")); + addError(new ParamError(functionName, "hash calculated from email: ", mReceiverUser->getEmail())); + addError(new ParamError(functionName, "hash: ", std::to_string(mProtoCreation.ident_hash()))); + return -3; + }*/ + } + // + + + return 0; +} + +std::string TransactionCreation::getTargetDateString() +{ + // proto format is seconds, poco timestamp format is microseconds + Poco::Timestamp pocoStamp(mProtoCreation.target_date().seconds() * 1000*1000); + //Poco::DateTime(pocoStamp); + return Poco::DateTimeFormatter::format(pocoStamp, "%d. %b %y"); +} + diff --git a/login_server/src/cpp/model/TransactionTransfer.cpp b/login_server/src/cpp/model/TransactionTransfer.cpp index 136258816..4c89d7ad0 100644 --- a/login_server/src/cpp/model/TransactionTransfer.cpp +++ b/login_server/src/cpp/model/TransactionTransfer.cpp @@ -1,172 +1,172 @@ -#include "TransactionTransfer.h" - -const std::string TransactionTransfer::mInvalidIndexMessage("invalid index"); - -TransactionTransfer::KontoTableEntry::KontoTableEntry(model::table::User* user, google::protobuf::int64 amount, bool negativeAmount/* = false*/) -{ - //Normaler User <info@software-labor.de> - if (!user) return; - - composeAmountCellString(amount, negativeAmount); - - /*kontoNameCell = ""; - kontoNameCell += user->getFirstName(); - kontoNameCell += " "; - kontoNameCell += user->getLastName(); - kontoNameCell += " <"; - kontoNameCell += user->getEmail(); - kontoNameCell += ">";*/ - kontoNameCell = ""; - kontoNameCell += user->getNameWithEmailHtml(); - kontoNameCell += ""; -} - -TransactionTransfer::KontoTableEntry::KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount/* = false*/) -{ - composeAmountCellString(amount, negativeAmount); - //kontoNameCell = "0x" + pubkeyHex + ""; - kontoNameCell = "" + pubkeyHex + ""; -} - -void TransactionTransfer::KontoTableEntry::composeAmountCellString(google::protobuf::int64 amount, bool negativeAmount) -{ - //-10 GDD - //10 GDD - amountCell = "-"; - } - else { - amountCell += "success-color\">"; - } - amountCell += amountToString(amount); - //amountCell += " GDD"; - amountCell += " GDD"; -} - -// ******************************************************************************************************************************** - -TransactionTransfer::TransactionTransfer(const std::string& memo, const model::messages::gradido::Transfer& protoTransfer) - : TransactionBase(memo), mProtoTransfer(protoTransfer) -{ - -} - -TransactionTransfer::~TransactionTransfer() -{ - mKontoTable.clear(); -} - -int TransactionTransfer::prepare() -{ - lock(); - const static char functionName[] = { "TransactionTransfer::prepare" }; - if (mProtoTransfer.senderamounts_size() == 0) { - addError(new Error(functionName, "hasn't sender amount(s)")); - unlock(); - return -1; - } - if (mProtoTransfer.receiveramounts_size() == 0) { - addError(new Error(functionName, "hasn't receiver amount(s)")); - unlock(); - return -2; - } - mKontoTable.reserve(mProtoTransfer.senderamounts_size() + mProtoTransfer.receiveramounts_size()); - - //auto receiverAmount = mProtoTransfer.receiveramount(); - //auto senderAmount - int senderSum = 0; - int receiverSum = 0; - - char pubkeyHexTemp[65]; - - for (int i = 0; i < mProtoTransfer.senderamounts_size(); i++) { - auto senderAmount = mProtoTransfer.senderamounts(i); - auto pubkey = senderAmount.ed25519_sender_pubkey(); - senderSum += senderAmount.amount(); - if (pubkey.size() != 32) { - addError(new ParamError(functionName, "invalid public key for sender ", i)); - unlock(); - return -3; - } - //User user((const unsigned char*)pubkey.data()); - auto user = controller::User::create(); - if (!user->load((const unsigned char*)pubkey.data())) { - sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)pubkey.data(), pubkey.size()); - mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, senderAmount.amount(), true)); - } - else { - mKontoTable.push_back(KontoTableEntry(user->getModel(), senderAmount.amount(), true)); - } - } - for (int i = 0; i < mProtoTransfer.receiveramounts_size(); i++) { - auto receiverAmount = mProtoTransfer.receiveramounts(i); - auto pubkey = receiverAmount.ed25519_receiver_pubkey(); - receiverSum += receiverAmount.amount(); - if (receiverAmount.ed25519_receiver_pubkey().size() != 32) { - addError(new ParamError(functionName, "invalid public key for receiver ", i)); - unlock(); - return -4; - } - auto user = controller::User::create(); - if (!user->load((const unsigned char*)pubkey.data())) { - sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)pubkey.data(), pubkey.size()); - mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, receiverAmount.amount(), false)); - } - else { - mKontoTable.push_back(KontoTableEntry(user->getModel(), receiverAmount.amount(), false)); - } - } - if (senderSum != receiverSum) { - addError(new Error(functionName, "sender amounts sum != receiver amounts sum")); - unlock(); - return -5; - } - if (senderSum < 0) { - addError(new Error(functionName, "negative amount not supported")); - unlock(); - return -6; - } - - /* - mReceiverUser = new User(receiverPublic.data()); - getErrors(mReceiverUser); - if (mReceiverUser->getUserState() == USER_EMPTY) { - sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); - delete mReceiverUser; - mReceiverUser = nullptr; - } - else { - memcpy(mReceiverPublicHex, mReceiverUser->getPublicKeyHex().data(), 64); - } - //*/ - - unlock(); - return 0; -} - -const std::string& TransactionTransfer::getKontoNameCell(int index) -{ - - lock(); - if (index >= mKontoTable.size()) { - unlock(); - return mInvalidIndexMessage; - } - unlock(); - - return mKontoTable[index].kontoNameCell; -} - -const std::string& TransactionTransfer::getAmountCell(int index) -{ - lock(); - if (index >= mKontoTable.size()) { - unlock(); - return mInvalidIndexMessage; - } - unlock(); - - return mKontoTable[index].amountCell; -} - +#include "TransactionTransfer.h" + +const std::string TransactionTransfer::mInvalidIndexMessage("invalid index"); + +TransactionTransfer::KontoTableEntry::KontoTableEntry(model::table::User* user, google::protobuf::int64 amount, bool negativeAmount/* = false*/) +{ + //Normaler User <info@software-labor.de> + if (!user) return; + + composeAmountCellString(amount, negativeAmount); + + /*kontoNameCell = ""; + kontoNameCell += user->getFirstName(); + kontoNameCell += " "; + kontoNameCell += user->getLastName(); + kontoNameCell += " <"; + kontoNameCell += user->getEmail(); + kontoNameCell += ">";*/ + kontoNameCell = ""; + kontoNameCell += user->getNameWithEmailHtml(); + kontoNameCell += ""; +} + +TransactionTransfer::KontoTableEntry::KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount/* = false*/) +{ + composeAmountCellString(amount, negativeAmount); + //kontoNameCell = "0x" + pubkeyHex + ""; + kontoNameCell = "" + pubkeyHex + ""; +} + +void TransactionTransfer::KontoTableEntry::composeAmountCellString(google::protobuf::int64 amount, bool negativeAmount) +{ + //-10 GDD + //10 GDD + amountCell = "-"; + } + else { + amountCell += "success-color\">"; + } + amountCell += amountToString(amount); + //amountCell += " GDD"; + amountCell += " GDD"; +} + +// ******************************************************************************************************************************** + +TransactionTransfer::TransactionTransfer(const std::string& memo, const model::messages::gradido::Transfer& protoTransfer) + : TransactionBase(memo), mProtoTransfer(protoTransfer) +{ + +} + +TransactionTransfer::~TransactionTransfer() +{ + mKontoTable.clear(); +} + +int TransactionTransfer::prepare() +{ + lock(); + const static char functionName[] = { "TransactionTransfer::prepare" }; + if (mProtoTransfer.senderamounts_size() == 0) { + addError(new Error(functionName, "hasn't sender amount(s)")); + unlock(); + return -1; + } + if (mProtoTransfer.receiveramounts_size() == 0) { + addError(new Error(functionName, "hasn't receiver amount(s)")); + unlock(); + return -2; + } + mKontoTable.reserve(mProtoTransfer.senderamounts_size() + mProtoTransfer.receiveramounts_size()); + + //auto receiverAmount = mProtoTransfer.receiveramount(); + //auto senderAmount + int senderSum = 0; + int receiverSum = 0; + + char pubkeyHexTemp[65]; + + for (int i = 0; i < mProtoTransfer.senderamounts_size(); i++) { + auto senderAmount = mProtoTransfer.senderamounts(i); + auto pubkey = senderAmount.ed25519_sender_pubkey(); + senderSum += senderAmount.amount(); + if (pubkey.size() != 32) { + addError(new ParamError(functionName, "invalid public key for sender ", i)); + unlock(); + return -3; + } + //User user((const unsigned char*)pubkey.data()); + auto user = controller::User::create(); + if (!user->load((const unsigned char*)pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)pubkey.data(), pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, senderAmount.amount(), true)); + } + else { + mKontoTable.push_back(KontoTableEntry(user->getModel(), senderAmount.amount(), true)); + } + } + for (int i = 0; i < mProtoTransfer.receiveramounts_size(); i++) { + auto receiverAmount = mProtoTransfer.receiveramounts(i); + auto pubkey = receiverAmount.ed25519_receiver_pubkey(); + receiverSum += receiverAmount.amount(); + if (receiverAmount.ed25519_receiver_pubkey().size() != 32) { + addError(new ParamError(functionName, "invalid public key for receiver ", i)); + unlock(); + return -4; + } + auto user = controller::User::create(); + if (!user->load((const unsigned char*)pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)pubkey.data(), pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, receiverAmount.amount(), false)); + } + else { + mKontoTable.push_back(KontoTableEntry(user->getModel(), receiverAmount.amount(), false)); + } + } + if (senderSum != receiverSum) { + addError(new Error(functionName, "sender amounts sum != receiver amounts sum")); + unlock(); + return -5; + } + if (senderSum < 0) { + addError(new Error(functionName, "negative amount not supported")); + unlock(); + return -6; + } + + /* + mReceiverUser = new User(receiverPublic.data()); + getErrors(mReceiverUser); + if (mReceiverUser->getUserState() == USER_EMPTY) { + sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); + delete mReceiverUser; + mReceiverUser = nullptr; + } + else { + memcpy(mReceiverPublicHex, mReceiverUser->getPublicKeyHex().data(), 64); + } + //*/ + + unlock(); + return 0; +} + +const std::string& TransactionTransfer::getKontoNameCell(int index) +{ + + lock(); + if (index >= mKontoTable.size()) { + unlock(); + return mInvalidIndexMessage; + } + unlock(); + + return mKontoTable[index].kontoNameCell; +} + +const std::string& TransactionTransfer::getAmountCell(int index) +{ + lock(); + if (index >= mKontoTable.size()) { + unlock(); + return mInvalidIndexMessage; + } + unlock(); + + return mKontoTable[index].amountCell; +} + diff --git a/login_server/src/cpp/model/email/Email.cpp b/login_server/src/cpp/model/email/Email.cpp index c04ab417c..ca6dde125 100644 --- a/login_server/src/cpp/model/email/Email.cpp +++ b/login_server/src/cpp/model/email/Email.cpp @@ -1,4 +1,4 @@ -#include "Email.h" +#include "Email.h" #include "../../SingletonManager/EmailManager.h" #include "Poco/Net/MediaType.h" diff --git a/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp b/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp index fa8048e6a..ac7a6461b 100644 --- a/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp +++ b/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp @@ -1,40 +1,40 @@ -#include "AuthenticatedEncryptionCreateKeyTask.h" - -#include "../ServerConfig.h" -#include "../SingletonManager/SingletonTaskObserver.h" -#include "../SingletonManager/ErrorManager.h" - -#include "../lib/Profiler.h" - -AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr user, const std::string& passwd) - : UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd) -{ - assert(!mUser.isNull()); - SingletonTaskObserver::getInstance()->addTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION); -} - -AuthenticatedEncryptionCreateKeyTask::~AuthenticatedEncryptionCreateKeyTask() -{ - SingletonTaskObserver::getInstance()->removeTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION); -} - -int AuthenticatedEncryptionCreateKeyTask::run() -{ - auto em = ErrorManager::getInstance(); - const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run"; - auto authenticated_encryption = new AuthenticatedEncryption; - Profiler timeUsed; - if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) { - em->addError(new Error(function_name, "error creating key")); - em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail())); - em->addError(new ParamError(function_name, "strerror: ", strerror(errno))); - em->sendErrorsAsEmail(); - return -1; - } - //printf("create password time: %s\n", timeUsed.string().data()); - timeUsed.reset(); - mUser->setNewPassword(authenticated_encryption); - //printf("set password time: %s\n", timeUsed.string().data()); - - return 0; +#include "AuthenticatedEncryptionCreateKeyTask.h" + +#include "../ServerConfig.h" +#include "../SingletonManager/SingletonTaskObserver.h" +#include "../SingletonManager/ErrorManager.h" + +#include "../lib/Profiler.h" + +AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr user, const std::string& passwd) + : UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd) +{ + assert(!mUser.isNull()); + SingletonTaskObserver::getInstance()->addTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION); +} + +AuthenticatedEncryptionCreateKeyTask::~AuthenticatedEncryptionCreateKeyTask() +{ + SingletonTaskObserver::getInstance()->removeTask(mUser->getModel()->getEmail(), TASK_OBSERVER_PASSWORD_CREATION); +} + +int AuthenticatedEncryptionCreateKeyTask::run() +{ + auto em = ErrorManager::getInstance(); + const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run"; + auto authenticated_encryption = new AuthenticatedEncryption; + Profiler timeUsed; + if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) { + em->addError(new Error(function_name, "error creating key")); + em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail())); + em->addError(new ParamError(function_name, "strerror: ", strerror(errno))); + em->sendErrorsAsEmail(); + return -1; + } + //printf("create password time: %s\n", timeUsed.string().data()); + timeUsed.reset(); + mUser->setNewPassword(authenticated_encryption); + //printf("set password time: %s\n", timeUsed.string().data()); + + return 0; } \ No newline at end of file diff --git a/login_server/src/cpp/tasks/ProcessingTransaction.cpp b/login_server/src/cpp/tasks/ProcessingTransaction.cpp index 3cf9905a8..6ed76f974 100644 --- a/login_server/src/cpp/tasks/ProcessingTransaction.cpp +++ b/login_server/src/cpp/tasks/ProcessingTransaction.cpp @@ -1,4 +1,4 @@ -#include "ProcessingTransaction.h" +#include "ProcessingTransaction.h" #include #include "../model/TransactionCreation.h" diff --git a/login_server/src/cpp/tasks/SigningTransaction.cpp b/login_server/src/cpp/tasks/SigningTransaction.cpp index f25d37bb4..ed87a03d0 100644 --- a/login_server/src/cpp/tasks/SigningTransaction.cpp +++ b/login_server/src/cpp/tasks/SigningTransaction.cpp @@ -1,284 +1,284 @@ -#include "SigningTransaction.h" - -#include - -#include "../SingletonManager/ErrorManager.h" -#include "../SingletonManager/MemoryManager.h" -#include "../SingletonManager/SingletonTaskObserver.h" - -#include "../lib/Profiler.h" - -#include "../proto/gradido/Transaction.pb.h" - -#include "sodium.h" - -#include "../ServerConfig.h" -#include "Poco/JSON/Object.h" -#include "Poco/JSON/Parser.h" -#include "Poco/StreamCopier.h" -#include "Poco/Net/HTTPSClientSession.h" -#include "Poco/Net/HTTPRequest.h" -#include "Poco/Net/HTTPResponse.h" - -SigningTransaction::SigningTransaction( - Poco::AutoPtr processingeTransaction, - Poco::AutoPtr newUser - , bool sendErrorsToAdmin/* = true*/) - : mProcessingeTransaction(processingeTransaction), mNewUser(newUser), mSendErrorsToAdminEmail(sendErrorsToAdmin) -{ - auto ob = SingletonTaskObserver::getInstance(); - auto email = getUserEmail(); - - if (email != "") { - ob->addTask(email, TASK_OBSERVER_SIGN_TRANSACTION); - } -} - -SigningTransaction::~SigningTransaction() -{ - auto ob = SingletonTaskObserver::getInstance(); - auto email = getUserEmail(); - - if (email != "") { - ob->removeTask(email, TASK_OBSERVER_SIGN_TRANSACTION); - } -} - -std::string SigningTransaction::getUserEmail() -{ - model::table::User* user_model = nullptr; - - if (!mNewUser.isNull()) { - user_model = mNewUser->getModel(); - } - if (user_model) { - return user_model->getEmail(); - } - return ""; -} - -int SigningTransaction::run() { - auto mm = MemoryManager::getInstance(); - - Error* transactionError = new Error("SigningTransaction", mProcessingeTransaction->mProtoMessageBase64.data()); - addError(transactionError, false); - - //= new Error("SigningTransaction start", mProcessingeTransaction->g) - //if (mUser.isNull() || !mUser->hasCryptoKey()) { - if(mNewUser.isNull() || !mNewUser->hasPassword()) { - addError(new Error("SigningTransaction", "user hasn't crypto key or is null")); - if(mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -1; - } - - //auto privKey = mUser->getPrivKey(); - //if (!mUser->hasPrivKey()) { - auto gradido_key_pair = mNewUser->getGradidoKeyPair(); - KeyPairEd25519* recovered_gradido_key_pair = nullptr; - if(!gradido_key_pair || !gradido_key_pair->hasPrivateKey()) { - - if (!mNewUser->tryLoadPassphraseUserBackup(&recovered_gradido_key_pair)) { - if(mNewUser->setGradidoKeyPair(recovered_gradido_key_pair)) - { - mNewUser->getModel()->updatePrivkey(); - } - } - else { - addError(new Error("SigningTransaction", "user cannot decrypt private key")); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -2; - } - } - // get body bytes - model::messages::gradido::Transaction transaction; - auto bodyBytes = transaction.mutable_bodybytes(); - *bodyBytes = mProcessingeTransaction->getBodyBytes(); - if (*bodyBytes == "") { - getErrors(mProcessingeTransaction); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -3; - } - // sign - //auto sign = mUser->sign((const unsigned char*)bodyBytes->data(), bodyBytes->size()); - MemoryBin* sign = nullptr; - if (gradido_key_pair) { - sign = gradido_key_pair->sign(*bodyBytes); - } - else if (recovered_gradido_key_pair) { - sign = recovered_gradido_key_pair->sign(*bodyBytes); - } - if (!sign) { - ErrorManager::getInstance()->sendErrorsAsEmail(); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - mm->releaseMemory(sign); - return -4; - } - - // pubkey for signature - /*auto pubkeyBin = mm->getFreeMemory(ed25519_pubkey_SIZE); - size_t realBin = 0; - if (sodium_hex2bin(*pubkeyBin, *pubkeyBin, pubkeyHex.data(), pubkeyHex.size(), nullptr, &realBin, nullptr)) { - addError(new Error("SigningTransaction", "error in sodium_hex2bin")); - sendErrorsAsEmail(); - mm->releaseMemory(pubkeyBin); - mm->releaseMemory(sign); - return -5; - } - */ - // add to message - auto sigMap = transaction.mutable_sigmap(); - auto sigPair = sigMap->add_sigpair(); - - auto pubkeyBytes = sigPair->mutable_pubkey(); - auto pubkeyBin = mNewUser->getModel()->getPublicKey(); - *pubkeyBytes = std::string((const char*)pubkeyBin, crypto_sign_PUBLICKEYBYTES); - - - auto sigBytes = sigPair->mutable_ed25519(); - *sigBytes = std::string((char*)*sign, sign->size()); - mm->releaseMemory(sign); - - /*std::string protoPrettyPrint; - google::protobuf::TextFormat::PrintToString(transaction, &protoPrettyPrint); - printf("transaction pretty: %s\n", protoPrettyPrint.data()); - model::messages::gradido::TransactionBody transactionBody; - transactionBody.MergeFromString(transaction.bodybytes()); - google::protobuf::TextFormat::PrintToString(transactionBody, &protoPrettyPrint); - printf("transaction body pretty: \n%s\n", protoPrettyPrint.data()); - */ - // finalize - //printf("sigpair size: %d\n", transaction.sigmap().sigpair_size()); - std::string finalTransactionBin = transaction.SerializeAsString(); - if (finalTransactionBin == "") { - addError(new Error("SigningTransaction", "error serializing final transaction")); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -6; - } - - // finale to base64 - auto finalBase64Size = sodium_base64_encoded_len(finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING); - auto finalBase64Bin = mm->getFreeMemory(finalBase64Size); - if (!sodium_bin2base64(*finalBase64Bin, finalBase64Size, (const unsigned char*)finalTransactionBin.data(), finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING)) { - addError(new Error("SigningTransaction", "error convert final transaction to base64")); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - mm->releaseMemory(finalBase64Bin); - return -7; - } - addError(new Error("Signing transaction final", *finalBase64Bin), false); - - // create json request - - Poco::JSON::Object requestJson; - requestJson.set("method", "putTransaction"); - requestJson.set("transaction", std::string((char*)*finalBase64Bin)); - //printf("\nbase64 transaction: \n%s\n\n", (char*)*finalBase64Bin); - mm->releaseMemory(finalBase64Bin); - - - //std::string request = requestJson.stringify(); - - // send post request via https - // 443 = HTTPS Default - // or http via port 80 if it is a test server - // TODO: adding port into ServerConfig - bool choose_ssl = false; - try { - Profiler phpRequestTime; - Poco::Net::HTTPClientSession* clientSession = nullptr; - - if (ServerConfig::g_phpServerPort) { - clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, ServerConfig::g_phpServerPort); - choose_ssl = true; - } - else if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || - ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { - clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, 443); - choose_ssl = true; - } - else { - clientSession = new Poco::Net::HTTPClientSession(ServerConfig::g_php_serverHost, 80); - choose_ssl = false; - } - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/JsonRequestHandler"); - - request.setChunkedTransferEncoding(true); - std::ostream& requestStream = clientSession->sendRequest(request); - requestJson.stringify(requestStream); - - Poco::Net::HTTPResponse response; - std::istream& request_stream = clientSession->receiveResponse(response); - - // debugging answer - - std::stringstream responseStringStream; - for (std::string line; std::getline(request_stream, line); ) { - responseStringStream << line << std::endl; - } - Poco::Logger& speedLog= Poco::Logger::get("SpeedLog"); - speedLog.information("[putTransaction] php server time: %s", phpRequestTime.string()); - - // extract parameter from request - Poco::JSON::Parser jsonParser; - Poco::Dynamic::Var parsedJson; - try { - parsedJson = jsonParser.parse(responseStringStream.str()); - } - catch (Poco::Exception& ex) { - //printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data()); - addError(new ParamError("SigningTransaction", "error parsing request answer", ex.displayText().data())); - - std::string log_Path = "/var/log/grd_login/"; - //#ifdef _WIN32 -#if defined(_WIN32) || defined(_WIN64) - log_Path = "./"; -#endif - log_Path += "response.html"; - FILE* f = fopen(log_Path.data(), "wt"); - if (f) { - std::string responseString = responseStringStream.str(); - fwrite(responseString.data(), 1, responseString.size(), f); - fclose(f); - } - // */ - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(responseStringStream.str()); - return -9; - } - - //sendErrorsAsEmail("HalloRote Test "); - - Poco::JSON::Object object = *parsedJson.extract(); - - std::string stateString = ""; - if (!object.isNull("state")) { - auto state = object.get("state"); - stateString = state.convert(); - } - if (stateString != "success") { - addError(new Error("SigningTransaction", "php server don't return success")); - if (!object.isNull("msg")) { - addError(new ParamError("SigningTransaction", "msg:", object.get("msg").convert().data())); - } - if (!object.isNull("details")) { - addError(new ParamError("SigningTransaction", "details:", object.get("details").convert().data())); - } - if (!object.isNull("user_error")) { - addError(new ParamError("SigningTransaction", "user_error", object.get("user_error").convert().data())); - } - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -10; - } - delete clientSession; - //printf("state: %s\n", stateString.data()); - //int zahl = 1; - } - catch (Poco::Exception& e) { - addError(new ParamError("SigningTransaction", "connect error to php server", e.displayText().data())); - addError(new ParamError("SigningTransaction", "url", ServerConfig::g_php_serverHost.data())); - addError(new ParamError("SigningTransaction", "choose_ssl", choose_ssl)); - if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); - return -8; - } - - - return 0; +#include "SigningTransaction.h" + +#include + +#include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/MemoryManager.h" +#include "../SingletonManager/SingletonTaskObserver.h" + +#include "../lib/Profiler.h" + +#include "../proto/gradido/Transaction.pb.h" + +#include "sodium.h" + +#include "../ServerConfig.h" +#include "Poco/JSON/Object.h" +#include "Poco/JSON/Parser.h" +#include "Poco/StreamCopier.h" +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" + +SigningTransaction::SigningTransaction( + Poco::AutoPtr processingeTransaction, + Poco::AutoPtr newUser + , bool sendErrorsToAdmin/* = true*/) + : mProcessingeTransaction(processingeTransaction), mNewUser(newUser), mSendErrorsToAdminEmail(sendErrorsToAdmin) +{ + auto ob = SingletonTaskObserver::getInstance(); + auto email = getUserEmail(); + + if (email != "") { + ob->addTask(email, TASK_OBSERVER_SIGN_TRANSACTION); + } +} + +SigningTransaction::~SigningTransaction() +{ + auto ob = SingletonTaskObserver::getInstance(); + auto email = getUserEmail(); + + if (email != "") { + ob->removeTask(email, TASK_OBSERVER_SIGN_TRANSACTION); + } +} + +std::string SigningTransaction::getUserEmail() +{ + model::table::User* user_model = nullptr; + + if (!mNewUser.isNull()) { + user_model = mNewUser->getModel(); + } + if (user_model) { + return user_model->getEmail(); + } + return ""; +} + +int SigningTransaction::run() { + auto mm = MemoryManager::getInstance(); + + Error* transactionError = new Error("SigningTransaction", mProcessingeTransaction->mProtoMessageBase64.data()); + addError(transactionError, false); + + //= new Error("SigningTransaction start", mProcessingeTransaction->g) + //if (mUser.isNull() || !mUser->hasCryptoKey()) { + if(mNewUser.isNull() || !mNewUser->hasPassword()) { + addError(new Error("SigningTransaction", "user hasn't crypto key or is null")); + if(mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -1; + } + + //auto privKey = mUser->getPrivKey(); + //if (!mUser->hasPrivKey()) { + auto gradido_key_pair = mNewUser->getGradidoKeyPair(); + KeyPairEd25519* recovered_gradido_key_pair = nullptr; + if(!gradido_key_pair || !gradido_key_pair->hasPrivateKey()) { + + if (!mNewUser->tryLoadPassphraseUserBackup(&recovered_gradido_key_pair)) { + if(mNewUser->setGradidoKeyPair(recovered_gradido_key_pair)) + { + mNewUser->getModel()->updatePrivkey(); + } + } + else { + addError(new Error("SigningTransaction", "user cannot decrypt private key")); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -2; + } + } + // get body bytes + model::messages::gradido::Transaction transaction; + auto bodyBytes = transaction.mutable_bodybytes(); + *bodyBytes = mProcessingeTransaction->getBodyBytes(); + if (*bodyBytes == "") { + getErrors(mProcessingeTransaction); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -3; + } + // sign + //auto sign = mUser->sign((const unsigned char*)bodyBytes->data(), bodyBytes->size()); + MemoryBin* sign = nullptr; + if (gradido_key_pair) { + sign = gradido_key_pair->sign(*bodyBytes); + } + else if (recovered_gradido_key_pair) { + sign = recovered_gradido_key_pair->sign(*bodyBytes); + } + if (!sign) { + ErrorManager::getInstance()->sendErrorsAsEmail(); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + mm->releaseMemory(sign); + return -4; + } + + // pubkey for signature + /*auto pubkeyBin = mm->getFreeMemory(ed25519_pubkey_SIZE); + size_t realBin = 0; + if (sodium_hex2bin(*pubkeyBin, *pubkeyBin, pubkeyHex.data(), pubkeyHex.size(), nullptr, &realBin, nullptr)) { + addError(new Error("SigningTransaction", "error in sodium_hex2bin")); + sendErrorsAsEmail(); + mm->releaseMemory(pubkeyBin); + mm->releaseMemory(sign); + return -5; + } + */ + // add to message + auto sigMap = transaction.mutable_sigmap(); + auto sigPair = sigMap->add_sigpair(); + + auto pubkeyBytes = sigPair->mutable_pubkey(); + auto pubkeyBin = mNewUser->getModel()->getPublicKey(); + *pubkeyBytes = std::string((const char*)pubkeyBin, crypto_sign_PUBLICKEYBYTES); + + + auto sigBytes = sigPair->mutable_ed25519(); + *sigBytes = std::string((char*)*sign, sign->size()); + mm->releaseMemory(sign); + + /*std::string protoPrettyPrint; + google::protobuf::TextFormat::PrintToString(transaction, &protoPrettyPrint); + printf("transaction pretty: %s\n", protoPrettyPrint.data()); + model::messages::gradido::TransactionBody transactionBody; + transactionBody.MergeFromString(transaction.bodybytes()); + google::protobuf::TextFormat::PrintToString(transactionBody, &protoPrettyPrint); + printf("transaction body pretty: \n%s\n", protoPrettyPrint.data()); + */ + // finalize + //printf("sigpair size: %d\n", transaction.sigmap().sigpair_size()); + std::string finalTransactionBin = transaction.SerializeAsString(); + if (finalTransactionBin == "") { + addError(new Error("SigningTransaction", "error serializing final transaction")); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -6; + } + + // finale to base64 + auto finalBase64Size = sodium_base64_encoded_len(finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING); + auto finalBase64Bin = mm->getFreeMemory(finalBase64Size); + if (!sodium_bin2base64(*finalBase64Bin, finalBase64Size, (const unsigned char*)finalTransactionBin.data(), finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING)) { + addError(new Error("SigningTransaction", "error convert final transaction to base64")); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + mm->releaseMemory(finalBase64Bin); + return -7; + } + addError(new Error("Signing transaction final", *finalBase64Bin), false); + + // create json request + + Poco::JSON::Object requestJson; + requestJson.set("method", "putTransaction"); + requestJson.set("transaction", std::string((char*)*finalBase64Bin)); + //printf("\nbase64 transaction: \n%s\n\n", (char*)*finalBase64Bin); + mm->releaseMemory(finalBase64Bin); + + + //std::string request = requestJson.stringify(); + + // send post request via https + // 443 = HTTPS Default + // or http via port 80 if it is a test server + // TODO: adding port into ServerConfig + bool choose_ssl = false; + try { + Profiler phpRequestTime; + Poco::Net::HTTPClientSession* clientSession = nullptr; + + if (ServerConfig::g_phpServerPort) { + clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, ServerConfig::g_phpServerPort); + choose_ssl = true; + } + else if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType || + ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) { + clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, 443); + choose_ssl = true; + } + else { + clientSession = new Poco::Net::HTTPClientSession(ServerConfig::g_php_serverHost, 80); + choose_ssl = false; + } + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/JsonRequestHandler"); + + request.setChunkedTransferEncoding(true); + std::ostream& requestStream = clientSession->sendRequest(request); + requestJson.stringify(requestStream); + + Poco::Net::HTTPResponse response; + std::istream& request_stream = clientSession->receiveResponse(response); + + // debugging answer + + std::stringstream responseStringStream; + for (std::string line; std::getline(request_stream, line); ) { + responseStringStream << line << std::endl; + } + Poco::Logger& speedLog= Poco::Logger::get("SpeedLog"); + speedLog.information("[putTransaction] php server time: %s", phpRequestTime.string()); + + // extract parameter from request + Poco::JSON::Parser jsonParser; + Poco::Dynamic::Var parsedJson; + try { + parsedJson = jsonParser.parse(responseStringStream.str()); + } + catch (Poco::Exception& ex) { + //printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data()); + addError(new ParamError("SigningTransaction", "error parsing request answer", ex.displayText().data())); + + std::string log_Path = "/var/log/grd_login/"; + //#ifdef _WIN32 +#if defined(_WIN32) || defined(_WIN64) + log_Path = "./"; +#endif + log_Path += "response.html"; + FILE* f = fopen(log_Path.data(), "wt"); + if (f) { + std::string responseString = responseStringStream.str(); + fwrite(responseString.data(), 1, responseString.size(), f); + fclose(f); + } + // */ + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(responseStringStream.str()); + return -9; + } + + //sendErrorsAsEmail("HalloRote Test "); + + Poco::JSON::Object object = *parsedJson.extract(); + + std::string stateString = ""; + if (!object.isNull("state")) { + auto state = object.get("state"); + stateString = state.convert(); + } + if (stateString != "success") { + addError(new Error("SigningTransaction", "php server don't return success")); + if (!object.isNull("msg")) { + addError(new ParamError("SigningTransaction", "msg:", object.get("msg").convert().data())); + } + if (!object.isNull("details")) { + addError(new ParamError("SigningTransaction", "details:", object.get("details").convert().data())); + } + if (!object.isNull("user_error")) { + addError(new ParamError("SigningTransaction", "user_error", object.get("user_error").convert().data())); + } + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -10; + } + delete clientSession; + //printf("state: %s\n", stateString.data()); + //int zahl = 1; + } + catch (Poco::Exception& e) { + addError(new ParamError("SigningTransaction", "connect error to php server", e.displayText().data())); + addError(new ParamError("SigningTransaction", "url", ServerConfig::g_php_serverHost.data())); + addError(new ParamError("SigningTransaction", "choose_ssl", choose_ssl)); + if (mSendErrorsToAdminEmail) sendErrorsAsEmail(); + return -8; + } + + + return 0; } \ No newline at end of file diff --git a/login_server/src/cpp/tasks/SigningTransaction.h b/login_server/src/cpp/tasks/SigningTransaction.h index 2038c0669..a35da915c 100644 --- a/login_server/src/cpp/tasks/SigningTransaction.h +++ b/login_server/src/cpp/tasks/SigningTransaction.h @@ -1,46 +1,46 @@ -#ifndef GRADIDO_LOGIN_SERVER_TASKS_SIGNING_TRANSACTION_INCLUDE -#define GRADIDO_LOGIN_SERVER_TASKS_SIGNING_TRANSACTION_INCLUDE - -#include "CPUTask.h" - -#include "../lib/ErrorList.h" -#include "../model/TransactionBase.h" -#include "../model/User.h" -#include "../controller/User.h" - -#include "../proto/gradido/Transaction.pb.h" - -#include "ProcessingTransaction.h" - -/* -* @author: Dario Rekowski -* -* @date: 28.10.19 -* @desc: Task for signing Transactions -*/ - -class SigningTransaction : public UniLib::controller::CPUTask, public ErrorList -{ -public: - SigningTransaction(Poco::AutoPtr processingeTransaction, Poco::AutoPtr newUser, bool sendErrorsToAdmin = true); - virtual ~SigningTransaction(); - - int run(); - - const char* getResourceType() const { return "SigningTransaction"; }; - - - -protected: - Poco::AutoPtr mProcessingeTransaction; - Poco::AutoPtr mNewUser; - bool mSendErrorsToAdminEmail; - -private: - - std::string getUserEmail(); - -}; - - +#ifndef GRADIDO_LOGIN_SERVER_TASKS_SIGNING_TRANSACTION_INCLUDE +#define GRADIDO_LOGIN_SERVER_TASKS_SIGNING_TRANSACTION_INCLUDE + +#include "CPUTask.h" + +#include "../lib/ErrorList.h" +#include "../model/TransactionBase.h" +#include "../model/User.h" +#include "../controller/User.h" + +#include "../proto/gradido/Transaction.pb.h" + +#include "ProcessingTransaction.h" + +/* +* @author: Dario Rekowski +* +* @date: 28.10.19 +* @desc: Task for signing Transactions +*/ + +class SigningTransaction : public UniLib::controller::CPUTask, public ErrorList +{ +public: + SigningTransaction(Poco::AutoPtr processingeTransaction, Poco::AutoPtr newUser, bool sendErrorsToAdmin = true); + virtual ~SigningTransaction(); + + int run(); + + const char* getResourceType() const { return "SigningTransaction"; }; + + + +protected: + Poco::AutoPtr mProcessingeTransaction; + Poco::AutoPtr mNewUser; + bool mSendErrorsToAdminEmail; + +private: + + std::string getUserEmail(); + +}; + + #endif //GRADIDO_LOGIN_SERVER_TASKS_SIGNING_TRANSACTION_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpsp/login.cpsp b/login_server/src/cpsp/login.cpsp index 87a2aac3d..fc82adf2c 100644 --- a/login_server/src/cpsp/login.cpsp +++ b/login_server/src/cpsp/login.cpsp @@ -1,205 +1,205 @@ -<%@ page class="LoginPage" %> -<%@ page form="true" %> -<%@ page baseClass="SessionHTTPRequestHandler" %> -<%@ page ctorArg="Session*" %> -<%@ header include="SessionHTTPRequestHandler.h" %> -<%@ page compressed="true" %> -<%! -#include "../gettext.h" - -#include "Poco/Net/HTTPCookie.h" -#include "Poco/Net/HTTPServerParams.h" -#include "Poco/Logger.h" -#include "../SingletonManager/SessionManager.h" -#include "../SingletonManager/LanguageManager.h" -#include "../SingletonManager/ErrorManager.h" - -%> -<%% - const char* pageName = "Login"; - auto sm = SessionManager::getInstance(); - auto lm = LanguageManager::getInstance(); - auto em = ErrorManager::getInstance(); - - auto lang = chooseLanguage(request); - //printf("choose language return: %d\n", lang); - auto langCatalog = lm->getFreeCatalog(lang); - - std::string presetEmail(""); - if(mSession && mSession->getUser()) { - presetEmail = mSession->getUser()->getEmail(); - } - - if(!form.empty()) { - - bool langUpdatedByBtn = false; - auto langBtn = form.get("lang", ""); - if(langBtn != "") { - langUpdatedByBtn = true; - } - /* - auto langInput = form.get("lang", ""); - auto updatedLang = LANG_NULL; - if(langBtn != "") { - updatedLang = chooseLanguage(request, langBtn); - langUpdatedByBtn = true; - } else if(langInput != "") { - updatedLang = chooseLanguage(request, langInput); - } - - if(updatedLang != LANG_NULL && updatedLang != lang) { - lang = updatedLang; - langCatalog = lm->getFreeCatalog(lang); - } - */ - auto email = form.get("login-email", ""); - auto password = form.get("login-password", ""); - - if(email != "" && password != "") { - //auto session = sm->getSession(request); - //if(!mSession) mSession = sm->findByEmail(email); - if(!mSession) { - mSession = sm->getNewSession(); - mSession->setLanguageCatalog(langCatalog); - // get language - // first check url, second check language header - // for debugging client ip - auto client_host = request.clientAddress().host(); - //auto client_ip = request.clientAddress(); - // X-Real-IP forwarded ip from nginx config - auto client_host_string = request.get("X-Real-IP", client_host.toString()); - std::string clientIpString = "client ip: "; - client_host = Poco::Net::IPAddress(client_host_string); - clientIpString += client_host_string; - Poco::Logger::get("requestLog").information(clientIpString); - // debugging end - mSession->setClientIp(client_host); - response.addCookie(mSession->getLoginCookie()); - } else { - langCatalog = mSession->getLanguageCatalog(); - } - UserStates user_state; - try { - user_state = mSession->loadUser(email, password); - } catch (Poco::Exception& ex) { - addError(new ParamError("login", "exception by calling loadUser: ", ex.displayText())); - sendErrorsAsEmail(); - addError(new Error("Error", "Intern Server error, please try again later")); - } - auto user = mSession->getNewUser(); - - if(user_state >= USER_LOADED_FROM_DB && !user.isNull() && !user->getModel()->getPublicKey()) { - if(mSession->generateKeys(true, true)) { - user_state = USER_COMPLETE; - if(user->getModel()->isDisabled()) { - user_state = USER_DISABLED; - } - } - } else { - //printf("pubkey exist: %p\n",user->getModel()->getPublicKey()); - } - getErrors(mSession); - - auto uri_start = request.serverParams().getServerName(); - auto lastExternReferer = mSession->getLastReferer(); - - printf("user_state: %d\n", user_state); - - switch(user_state) { - case USER_EMPTY: - case USER_PASSWORD_INCORRECT: - addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("E-Mail or password isn't right, please try again!")), false); - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - break; - case USER_PASSWORD_ENCRYPTION_IN_PROCESS: - addError(new Error(langCatalog->gettext("Passwort"), langCatalog->gettext("Passwort wird noch berechnet, bitte versuche es in etwa 1 Minute erneut.")), false); - break; - case USER_KEYS_DONT_MATCH: - addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); - break; - case USER_DISABLED: - addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Benutzer ist deaktiviert, kein Login möglich!"))); - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - break; - case USER_NO_PRIVATE_KEY: - case USER_COMPLETE: - case USER_EMAIL_NOT_ACTIVATED: - auto referer = request.find("Referer"); - std::string refererString; - if (referer != request.end()) { - refererString = referer->second; - } - if(lastExternReferer != "") { - //printf("redirect to: %s\n", lastExternReferer.data()); - response.redirect(lastExternReferer); - } else if(refererString != "" && - refererString.find("login") == std::string::npos && - refererString.find("logout") == std::string::npos && - refererString.find("user_delete") == std::string::npos && - refererString != ServerConfig::g_serverPath + request.getURI()) { - std::string uri = request.getURI(); - printf("request uri: %s, redirect to: %s\n", uri.data(), refererString.data()); - response.redirect(refererString); - } else { - //printf("redirect to: %s\n", ServerConfig::g_php_serverPath.data()); - response.redirect(ServerConfig::g_php_serverPath + "/"); - } - return; - } - - } else if(!langUpdatedByBtn) { - addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("Username and password are needed!")), false); - } - - } else { - - // on enter login page with empty form - //auto session = sm->getSession(request); - // remove old cookies and session if exist - if(mSession) { - getErrors(mSession); - sm->releaseSession(mSession); - } - sm->deleteLoginCookies(request, response); - } - -%><%@ include file="header.cpsp" %> -<%= getErrorsHtml() %> - -
- <%@ include file="flags.cpsp" %> -
-
- " value="<%= presetEmail %>"/> - " /> - -
-
-
- - -
-
-

 

- +<%@ page class="LoginPage" %> +<%@ page form="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%@ page compressed="true" %> +<%! +#include "../gettext.h" + +#include "Poco/Net/HTTPCookie.h" +#include "Poco/Net/HTTPServerParams.h" +#include "Poco/Logger.h" +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/LanguageManager.h" +#include "../SingletonManager/ErrorManager.h" + +%> +<%% + const char* pageName = "Login"; + auto sm = SessionManager::getInstance(); + auto lm = LanguageManager::getInstance(); + auto em = ErrorManager::getInstance(); + + auto lang = chooseLanguage(request); + //printf("choose language return: %d\n", lang); + auto langCatalog = lm->getFreeCatalog(lang); + + std::string presetEmail(""); + if(mSession && mSession->getUser()) { + presetEmail = mSession->getUser()->getEmail(); + } + + if(!form.empty()) { + + bool langUpdatedByBtn = false; + auto langBtn = form.get("lang", ""); + if(langBtn != "") { + langUpdatedByBtn = true; + } + /* + auto langInput = form.get("lang", ""); + auto updatedLang = LANG_NULL; + if(langBtn != "") { + updatedLang = chooseLanguage(request, langBtn); + langUpdatedByBtn = true; + } else if(langInput != "") { + updatedLang = chooseLanguage(request, langInput); + } + + if(updatedLang != LANG_NULL && updatedLang != lang) { + lang = updatedLang; + langCatalog = lm->getFreeCatalog(lang); + } + */ + auto email = form.get("login-email", ""); + auto password = form.get("login-password", ""); + + if(email != "" && password != "") { + //auto session = sm->getSession(request); + //if(!mSession) mSession = sm->findByEmail(email); + if(!mSession) { + mSession = sm->getNewSession(); + mSession->setLanguageCatalog(langCatalog); + // get language + // first check url, second check language header + // for debugging client ip + auto client_host = request.clientAddress().host(); + //auto client_ip = request.clientAddress(); + // X-Real-IP forwarded ip from nginx config + auto client_host_string = request.get("X-Real-IP", client_host.toString()); + std::string clientIpString = "client ip: "; + client_host = Poco::Net::IPAddress(client_host_string); + clientIpString += client_host_string; + Poco::Logger::get("requestLog").information(clientIpString); + // debugging end + mSession->setClientIp(client_host); + response.addCookie(mSession->getLoginCookie()); + } else { + langCatalog = mSession->getLanguageCatalog(); + } + UserStates user_state; + try { + user_state = mSession->loadUser(email, password); + } catch (Poco::Exception& ex) { + addError(new ParamError("login", "exception by calling loadUser: ", ex.displayText())); + sendErrorsAsEmail(); + addError(new Error("Error", "Intern Server error, please try again later")); + } + auto user = mSession->getNewUser(); + + if(user_state >= USER_LOADED_FROM_DB && !user.isNull() && !user->getModel()->getPublicKey()) { + if(mSession->generateKeys(true, true)) { + user_state = USER_COMPLETE; + if(user->getModel()->isDisabled()) { + user_state = USER_DISABLED; + } + } + } else { + //printf("pubkey exist: %p\n",user->getModel()->getPublicKey()); + } + getErrors(mSession); + + auto uri_start = request.serverParams().getServerName(); + auto lastExternReferer = mSession->getLastReferer(); + + printf("user_state: %d\n", user_state); + + switch(user_state) { + case USER_EMPTY: + case USER_PASSWORD_INCORRECT: + addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("E-Mail or password isn't right, please try again!")), false); + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + break; + case USER_PASSWORD_ENCRYPTION_IN_PROCESS: + addError(new Error(langCatalog->gettext("Passwort"), langCatalog->gettext("Passwort wird noch berechnet, bitte versuche es in etwa 1 Minute erneut.")), false); + break; + case USER_KEYS_DONT_MATCH: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); + break; + case USER_DISABLED: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Benutzer ist deaktiviert, kein Login möglich!"))); + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + break; + case USER_NO_PRIVATE_KEY: + case USER_COMPLETE: + case USER_EMAIL_NOT_ACTIVATED: + auto referer = request.find("Referer"); + std::string refererString; + if (referer != request.end()) { + refererString = referer->second; + } + if(lastExternReferer != "") { + //printf("redirect to: %s\n", lastExternReferer.data()); + response.redirect(lastExternReferer); + } else if(refererString != "" && + refererString.find("login") == std::string::npos && + refererString.find("logout") == std::string::npos && + refererString.find("user_delete") == std::string::npos && + refererString != ServerConfig::g_serverPath + request.getURI()) { + std::string uri = request.getURI(); + printf("request uri: %s, redirect to: %s\n", uri.data(), refererString.data()); + response.redirect(refererString); + } else { + //printf("redirect to: %s\n", ServerConfig::g_php_serverPath.data()); + response.redirect(ServerConfig::g_php_serverPath + "/"); + } + return; + } + + } else if(!langUpdatedByBtn) { + addError(new Error(langCatalog->gettext("Login"), langCatalog->gettext("Username and password are needed!")), false); + } + + } else { + + // on enter login page with empty form + //auto session = sm->getSession(request); + // remove old cookies and session if exist + if(mSession) { + getErrors(mSession); + sm->releaseSession(mSession); + } + sm->deleteLoginCookies(request, response); + } + +%><%@ include file="header.cpsp" %> +<%= getErrorsHtml() %> + +
+ <%@ include file="flags.cpsp" %> +
+
+ " value="<%= presetEmail %>"/> + " /> + +
+
+
+ + +
+
+

 

+ <%@ include file="footer.cpsp" %> \ No newline at end of file