diff --git a/login_server/.gitignore b/login_server/.gitignore index 788c702ad..dd7d9573a 100644 --- a/login_server/.gitignore +++ b/login_server/.gitignore @@ -5,3 +5,4 @@ src/cpsp/*.h src/cpsp/*.cpp src/cpp/proto/ build*/ +/skeema/gradido_login/insert/crypto_key.sql diff --git a/login_server/.gitmodules b/login_server/.gitmodules index f61624046..392836d92 100644 --- a/login_server/.gitmodules +++ b/login_server/.gitmodules @@ -13,3 +13,12 @@ [submodule "dependencies/spirit-po"] path = dependencies/spirit-po url = https://github.com/cbeck88/spirit-po.git +[submodule "dependencies/grpc"] + path = dependencies/grpc + url = https://github.com/grpc/grpc.git +[submodule "dependencies/poco"] + path = dependencies/poco + url = https://github.com/pocoproject/poco.git +[submodule "dependencies/cmake-modules"] + path = dependencies/cmake-modules + url = https://github.com/viaduck/cmake-modules.git diff --git a/login_server/CMakeLists.txt b/login_server/CMakeLists.txt index 5a484c3e9..ffb1b4e6f 100644 --- a/login_server/CMakeLists.txt +++ b/login_server/CMakeLists.txt @@ -1,177 +1,242 @@ -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.18.2) +project(Gradido_LoginServer C CXX) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" ) + +SET ( CMAKE_CXX_FLAGS "-std=c++17" ) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include_directories( + "dependencies" + "dependencies/tinf/src/" + "dependencies/mariadb-connector-c/include" + "dependencies/mariadb-connector-c/build/include" + "dependencies/spirit-po/include" + "dependencies/grpc/include" + "dependencies/grpc/third_party/protobuf/src" + "src/cpp/proto" +) +#if(WIN32) +#include_directories("dependencies/mariadb-connector-c/include", "dependencies/mariadb-connector-c/build/include") +set(MYSQL_INCLUDE_DIR "dependencies/mariadb-connector-c/include") + +#endif(WIN32) + +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 MODEL_HEDERA "src/cpp/model/hedera/*.h" "src/cpp/model/hedera/*.cpp") +FILE(GLOB MODEL_GRADIDO "src/cpp/model/gradido/*.h" "src/cpp/model/gradido/*.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} ${MODEL_HEDERA} ${MODEL_GRADIDO} + ${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\\hedera" FILES ${MODEL_HEDERA}) + source_group("model\\gradido" FILES ${MODEL_GRADIDO}) + 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_executable(Gradido_LoginServer ${LOCAL_SRCS}) +set(CLIENT_PLUGIN_DIALOG OFF) +set(CLIENT_PLUGIN_MYSQL_CLEAR_PASSWORD OFF) +set(CLIENT_PLUGIN_REMOTE_IO OFF) +IF(WIN32) +#set(CLIENT_PLUGIN_caching_sha2_password OFF) +set(CLIENT_PLUGIN_CACHING_SHA2_PASSWORD OFF) +set(CLIENT_PLUGIN_SHA256_PASSWORD OFF) +set(CLIENT_PLUGIN_AUTH_GSSAPI_CLIENT OFF) +set(CLIENT_PLUGIN_PVIO_NPIPE STATIC) +set(CLIENT_PLUGIN_PVIO_SHMEM STATIC) +set(CLIENT_PLUGIN_CLIENT_ED25519 OFF) +ELSEIF() +set(CLIENT_PLUGIN_client_ed25519 OFF) +ENDIF() + +set(WITH_SSL OFF) +add_subdirectory("dependencies/mariadb-connector-c") + +set(DEP_PATH "dependencies") +set(MARIADB_CONNECTOR_PATH "${DEP_PATH}/mariadb-connector-c/build/libmariadb") + +set(GRPC_PATH "${DEP_PATH}/grpc/build") +set(GRPC_ABSL_PATH "${GRPC_PATH}/third_party/abseil-cpp/absl/types") +set(GRPC_CARES_PATH "${GRPC_PATH}/third_party/cares/cares/lib") +set(GRPC_BORING_SSL_PATH "${GRPC_PATH}/third_party/boringssl-with-bazel") +set(GRPC_RE2_PATH "${GRPC_PATH}/third_party/re2") +set(GRPC_PROTOBUF_PATH "${GRPC_PATH}/third_party/protobuf") + + + +if(WIN32) + + find_library(MYSQL_LIBRARIES mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Release" REQUIRED) + find_library(COMPILED_MARIADB_CLIENT_DEBUG mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Debug" REQUIRED) + + find_library(CONAN_OPENSSL_SSL ssleay32 PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + find_library(CONAN_OPENSSL_CRYPTO libeay32 PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + + set(GRPC_PATH "${GRPC_PATH}/Debug") + set(GRPC_ABSL_PATH "${GRPC_ABSL_PATH}/Debug") + set(GRPC_CARES_PATH "${GRPC_CARES_PATH}/Debug") + set(GRPC_BORING_SSL_PATH "${GRPC_CGRPC_BORING_SSL_PATHARES_PATH}/Debug") + set(GRPC_RE2_PATH "${GRPC_RE2_PATH}/Debug") + set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}/Debug") + + + list(REMOVE_ITEM CONAN_LIBS "libeay32.lib") + list(REMOVE_ITEM CONAN_LIBS "ssleay32.lib") + + +else (WIN32) + #find_package(MariaDBClient PATHS "dependencies/cmake-modules") + #find_library(MYSQL_LIBRARIES libmariadb.so PATHS ${MARIADB_CONNECTOR_PATH} REQUIRED) + find_library(CONAN_OPENSSL_SSL ssl PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + find_library(CONAN_OPENSSL_CRYPTO crypto PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}") + + list(REMOVE_ITEM CONAN_LIBS "ssl") + list(REMOVE_ITEM CONAN_LIBS "crypto") + list(REMOVE_ITEM CONAN_LIBS "dl") + +# find_library(MYSQL_LIBRARIES libmariadb.so PATHS ${MARIADB_CONNECTOR_PATH} REQUIRED) + find_library(CONAN_OPENSSL_SSL ssl PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + find_library(CONAN_OPENSSL_CRYPTO crypto PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH ) + set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}") + + list(REMOVE_ITEM CONAN_LIBS "ssl") + list(REMOVE_ITEM CONAN_LIBS "crypto") + list(REMOVE_ITEM CONAN_LIBS "dl") + +endif(WIN32) + +# load same ssl version like used from poco +#find_package(OpenSSL PATHS "../" NO_DEFAULT_PATH) + + +set(CONAN_OPENSSL_CUSTOM_LIBS + ${CONAN_OPENSSL_SSL} + ${CONAN_OPENSSL_CRYPTO} +) +include_directories(${CONAN_INCLUDE_DIRS_OPENSSL}) +# build grpc + + + +if(WIN32) + + set(CMAKE_CXX_FLAGS "/MP /EHsc") + #set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") + #set(CMAKE_CXX_FLAGS_RELEASE "-O3") + +else(WIN32) + + set(INSTALL_BINDIR "bin") + set(INSTALL_PLUGINDIR "bin") + target_link_libraries(Gradido_LoginServer ${CONAN_OPENSSL_CUSTOM_LIBS}) + +endif(WIN32) + +set(BUILD_TESTING OFF) +set(gRPC_SSL_PROVIDER "package") +add_subdirectory("dependencies/grpc/") +set(gRPC_SSL_PROVIDER "package") +message(STATUS "Using gRPC via add_subdirectory.") + +set(GRPC_LIBS libprotobuf grpc++_reflection grpc++) +target_link_libraries(Gradido_LoginServer ${CONAN_LIBS}) + +if(WIN32) + TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi) + TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) + TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS}) +else(WIN32) # unix + target_link_libraries(Gradido_LoginServer libmariadb ${GRPC_LIBS} ${CMAKE_DL_LIBS} ${PROTOBUF_LIBS}) +endif(WIN32) + +# install +if(UNIX) +install(TARGETS Gradido_LoginServer RUNTIME DESTINATION /usr/local/bin) +#install(LIBRARYS DESTINATION /usr/local/lib) +#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 +#find_package(gtest) + +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} ) + + +if(WIN32) + TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi) + TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi) + TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS}) +else(WIN32) + target_link_libraries(Gradido_LoginServer_Test libmariadb ${GRPC_LIBS} ${CMAKE_DL_LIBS} ${PROTOBUF_LIBS}) +endif(WIN32) + +add_test(NAME main COMMAND Gradido_LoginServer_Test) diff --git a/login_server/Dockerfile.debug b/login_server/Dockerfile.debug index 0c7c741d5..6fcea2cef 100644 --- a/login_server/Dockerfile.debug +++ b/login_server/Dockerfile.debug @@ -1,132 +1,114 @@ -######################################################################################################### -# Build protoc -######################################################################################################### -FROM gcc:7.5 as protoc_build -RUN git clone --recurse-submodules https://github.com/protocolbuffers/protobuf.git -WORKDIR /protobuf - -RUN git checkout v3.9.1 -RUN ./autogen.sh -RUN ./configure --enable-static=yes -RUN make -j$(grep processor /proc/cpuinfo | wc -l) -RUN make check - -CMD ["./protobuf"] - -######################################################################################################### -# debug build preparation -######################################################################################################### - -From conanio/gcc7 as debug_preparation - -ENV DOCKER_WORKDIR="/code" - -USER root - -COPY --from=protoc_build /protobuf/src/.libs/protoc /usr/bin/ -COPY --from=protoc_build /protobuf/src/.libs/libprotobuf.so.20.0.1 /usr/lib/libprotobuf.so.20 -COPY --from=protoc_build /protobuf/src/.libs/libprotoc.so.20.0.1 /usr/lib/libprotoc.so.20 -COPY --from=protoc_build /protobuf/src/google/protobuf/*.proto /usr/include/google/protobuf/ -COPY --from=protoc_build /protobuf/src/google/protobuf/*.h /usr/include/google/protobuf/ - -#VOLUME /root/.conan - -RUN mkdir -p ${DOCKER_WORKDIR} -WORKDIR ${DOCKER_WORKDIR} - -COPY ./dependencies ./dependencies -COPY ./conanfile.txt ./conanfile.txt - -RUN ls -la -RUN cd dependencies/iroha-ed25519 && \ - ls -la && \ - mkdir build && \ - cd build && \ - cmake .. -DCMAKE_BUILD_TYPE=Debug -DEDIMPL=ref10 -DHASH=sha2_sphlib -DRANDOM=bcryptgen -DBUILD=STATIC && \ - make -j$(grep processor /proc/cpuinfo | wc -l) - -RUN cd dependencies/mariadb-connector-c && \ - mkdir build && \ - cd build && \ - cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_SSL=OFF .. - - -#RUN chmod +x compile_proto.sh -#RUN chmod +x compile_pot.sh -#RUN ls -la -#RUN ./compile_pot.sh -#RUN ./compile_proto.sh -RUN mkdir build && \ - cd build && \ - conan install .. --build=missing -s build_type=Debug - - - -######################################################################################################### -# Build debug -######################################################################################################### -From debug_preparation as debug - -ENV DOCKER_WORKDIR="/code" - -USER root -#VOLUME /root/.conan - -RUN apt-get update && \ - apt-get install -y --no-install-recommends gdb && \ - apt-get autoclean && \ - apt-get autoremove && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -#COPY --from=protoc_build /protobuf/src/.libs/libprotobuf.so.20.0.1 /usr/lib/libprotobuf.so.20 -#COPY --from=protoc_build /protobuf/src/google/protobuf/*.h /usr/include/google/protobuf/ - - -#COPY --from=debug_preparation /code /code -#COPY --from=debug_preparation /home/conan /home/conan -#RUN ls -la /home/conan/.conan -COPY . . -WORKDIR ${DOCKER_WORKDIR} - -#RUN ls -la -#RUN cat build/conanbuildinfo.cmake -RUN chmod +x compile_proto.sh -RUN chmod +x compile_pot.sh -#RUN ls -la -RUN ./compile_pot.sh -RUN ./compile_proto.sh -RUN cd build && \ - cmake -DCMAKE_BUILD_TYPE=Debug .. && \ - make -j$(grep processor /proc/cpuinfo | wc -l) - - -######################################################################################################### -# run debug -######################################################################################################### -FROM ubuntu:latest as login_server_debug - -WORKDIR "/usr/bin" - -#RUN apt-get update && \ -# apt-get install -y --no-install-recommends gdb && \ -# apt-get autoclean && \ -# apt-get autoremove && \ -# apt-get clean && \ -# rm -rf /var/lib/apt/lists/* - -VOLUME /var/log/grd_login - -COPY --from=debug /code/build/bin/Gradido_LoginServer /usr/bin/ -COPY --from=debug /code/build/lib/libmariadb.so.3 /usr/lib/ -#COPY start_after_mysql.sh . -RUN chmod +x /usr/bin/Gradido_LoginServer -EXPOSE 1200 -EXPOSE 1201 -#ENTRYPOINT ["/usr/bin/Gradido_LoginServer"] -# Wait on mariadb to started -#CMD ["sleep 5", "/usr/bin/Gradido_LoginServer"] -#RUN chmod +x ./start_after_mysql.sh -#ENTRYPOINT ["/usr/bin/Gradido_LoginServer"] -#CMD gdb -ex=r Gradido_LoginServer +######################################################################################################### +# debug build preparation +######################################################################################################### + +From conanio/gcc9 as build_debug_preparation +USER root +#RUN apt-get update && \ +# apt-get install -y --no-install-recommends gcc g++ && \ +# apt-get autoclean && \ +# apt-get autoremove && \ +# apt-get clean && \ +# rm -rf /var/lib/apt/lists/* + +ENV DOCKER_WORKDIR="/code" + + +#VOLUME /root/.conan + +RUN mkdir -p ${DOCKER_WORKDIR} +WORKDIR ${DOCKER_WORKDIR} + +COPY ./dependencies ./dependencies +COPY ./conanfile.txt ./conanfile.txt + +RUN cd dependencies/mariadb-connector-c && \ + mkdir build && \ + cd build && \ + cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_SSL=OFF .. + + +RUN mkdir build && \ + cd build && \ + conan install .. --build=missing -s build_type=Debug + +######################################################################################################### +# debug build proto and grpc +######################################################################################################### +From build_debug_preparation as proto_grpc + +ENV DOCKER_WORKDIR="/code" +WORKDIR ${DOCKER_WORKDIR} + +COPY ./CMakeLists.txt . +RUN cd build && \ + cmake -DCMAKE_BUILD_TYPE=Debug .. && \ + make -j${CPU_COUNT} protoc grpc_cpp_plugin + +######################################################################################################### +# parse proto and gettext +######################################################################################################### +From proto_grpc as proto_parse + +ENV DOCKER_WORKDIR="/code" +WORKDIR ${DOCKER_WORKDIR} + +RUN mkdir src && \ + cd src && \ + mkdir cpp +COPY ./src/proto ./src/proto +COPY ./unix_parse_proto.sh . + +RUN chmod +x unix_parse_proto.sh && \ + ./unix_parse_proto.sh + + +######################################################################################################### +# Build debug +######################################################################################################### +From proto_parse as build_debug + +ENV DOCKER_WORKDIR="/code" + +USER root +WORKDIR ${DOCKER_WORKDIR} + +COPY ./src/cpp ./src/cpp +COPY ./src/LOCALE ./src/LOCALE +COPY ./compile_pot.sh . +COPY ./files_to_translate.txt . + +RUN chmod +x compile_pot.sh && \ + ./compile_pot.sh + +RUN cd build && \ + cmake -DCMAKE_BUILD_TYPE=Debug .. && \ + make -j$(nproc) + +CMD bash + +######################################################################################################### +# run debug +######################################################################################################### +FROM ubuntu:latest as login_server_debug + +WORKDIR "/usr/bin" + +#RUN apt-get update && \ +# apt-get install -y --no-install-recommends gdb && \ +# apt-get autoclean && \ +# apt-get autoremove && \ +# apt-get clean && \ +# rm -rf /var/lib/apt/lists/* + +VOLUME /var/log/grd_login + +COPY --from=build_debug /code/build/bin/Gradido_LoginServer /usr/bin/ +COPY --from=build_debug /code/build/lib/libmariadb.so.3 /usr/lib/ +#COPY --from=build_debug /code/build/lib/libPocoNetSSLd.so.64 /usr/lib/libPocoNetSSLd.so.64 +RUN chmod +x /usr/bin/Gradido_LoginServer +EXPOSE 1200 +EXPOSE 1201 + +#CMD gdb -ex=r Gradido_LoginServer CMD Gradido_LoginServer \ No newline at end of file diff --git a/login_server/FindOpenSSL.cmake b/login_server/FindOpenSSL.cmake new file mode 100644 index 000000000..64fefb4ec --- /dev/null +++ b/login_server/FindOpenSSL.cmake @@ -0,0 +1,111 @@ + + +function(conan_message MESSAGE_OUTPUT) + if(NOT CONAN_CMAKE_SILENT_OUTPUT) + message(${ARGV${0}}) + endif() +endfunction() + + + + +include(FindPackageHandleStandardArgs) + +conan_message(STATUS "Conan: Using autogenerated FindOpenSSL.cmake") +# Global approach +set(OpenSSL_FOUND 1) +set(OpenSSL_VERSION "1.0.2o") + +find_package_handle_standard_args(OpenSSL REQUIRED_VARS + OpenSSL_VERSION VERSION_VAR OpenSSL_VERSION) +mark_as_advanced(OpenSSL_FOUND OpenSSL_VERSION) + + +set(OpenSSL_INCLUDE_DIRS "${CONAN_INCLUDE_DIRS_OPENSSL}") +set(OpenSSL_INCLUDE_DIR "${CONAN_INCLUDE_DIRS_OPENSSL}") +set(OpenSSL_INCLUDES "${CONAN_INCLUDE_DIRS_OPENSSL}") +set(OpenSSL_RES_DIRS "${CONAN_RES_DIRS_OPENSSL}") +set(OPENSSL_ROOT_DIR "${CONAN_OPENSSL_ROOT}") +set(OPENSSL_DIR "${CONAN_OPENSSL_ROOT}") +set(OpenSSL_DEFINITIONS ) +set(OpenSSL_LINKER_FLAGS_LIST + "$<$,SHARED_LIBRARY>:>" + "$<$,MODULE_LIBRARY>:>" + "$<$,EXECUTABLE>:>" +) +set(OpenSSL_COMPILE_DEFINITIONS ) +set(OpenSSL_COMPILE_OPTIONS_LIST "" "") +set(OpenSSL_COMPILE_OPTIONS_C "") +set(OpenSSL_COMPILE_OPTIONS_CXX "") +set(OpenSSL_LIBRARIES_TARGETS "") # Will be filled later, if CMake 3 +set(OpenSSL_LIBRARIES "") # Will be filled later +set(OpenSSL_LIBS "") # Same as OpenSSL_LIBRARIES +set(OpenSSL_FRAMEWORKS_FOUND "") # Will be filled later +set(OpenSSL_BUILD_MODULES_PATHS ) + + +mark_as_advanced(OpenSSL_INCLUDE_DIRS + OpenSSL_INCLUDE_DIR + OpenSSL_INCLUDES + OpenSSL_DEFINITIONS + OpenSSL_LINKER_FLAGS_LIST + OpenSSL_COMPILE_DEFINITIONS + OpenSSL_COMPILE_OPTIONS_LIST + OpenSSL_LIBRARIES + OpenSSL_LIBS + OpenSSL_LIBRARIES_TARGETS) + +# Find the real .lib/.a and add them to OpenSSL_LIBS and OpenSSL_LIBRARY_LIST +set(OpenSSL_LIBRARY_LIST ssl crypto dl pthread) +set(OpenSSL_LIB_DIRS "${CONAN_LIB_DIRS_OPENSSL}") + +# Gather all the libraries that should be linked to the targets (do not touch existing variables): +set(_OpenSSL_DEPENDENCIES "zlib::zlib") + +conan_package_library_targets("${OpenSSL_LIBRARY_LIST}" # libraries + "${OpenSSL_LIB_DIRS}" # package_libdir + "${_OpenSSL_DEPENDENCIES}" # deps + OpenSSL_LIBRARIES # out_libraries + OpenSSL_LIBRARIES_TARGETS # out_libraries_targets + "" # build_type + "OpenSSL") # package_name + +set(OpenSSL_LIBS ${OpenSSL_LIBRARIES}) + +# We need to add our requirements too +set(OpenSSL_LIBRARIES_TARGETS "${OpenSSL_LIBRARIES_TARGETS};zlib::zlib") +set(OpenSSL_LIBRARIES "${OpenSSL_LIBRARIES};zlib::zlib") + +set(CMAKE_MODULE_PATH "/home/dario/.conan/data/OpenSSL/1.0.2o/conan/stable/package/b781af3f476d0aa5070a0a35b544db7a3c193cc8/" ${CMAKE_MODULE_PATH}) +set(CMAKE_PREFIX_PATH "/home/dario/.conan/data/OpenSSL/1.0.2o/conan/stable/package/b781af3f476d0aa5070a0a35b544db7a3c193cc8/" ${CMAKE_PREFIX_PATH}) + +foreach(_BUILD_MODULE_PATH ${OpenSSL_BUILD_MODULES_PATHS}) + include(${_BUILD_MODULE_PATH}) +endforeach() + +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.0") + # Target approach + if(NOT TARGET OpenSSL::OpenSSL) + add_library(OpenSSL::OpenSSL INTERFACE IMPORTED) + if(OpenSSL_INCLUDE_DIRS) + set_target_properties(OpenSSL::OpenSSL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${OpenSSL_INCLUDE_DIRS}") + endif() + set_property(TARGET OpenSSL::OpenSSL PROPERTY INTERFACE_LINK_LIBRARIES + "${OpenSSL_LIBRARIES_TARGETS};${OpenSSL_LINKER_FLAGS_LIST}") + set_property(TARGET OpenSSL::OpenSSL PROPERTY INTERFACE_COMPILE_DEFINITIONS + ${OpenSSL_COMPILE_DEFINITIONS}) + set_property(TARGET OpenSSL::OpenSSL PROPERTY INTERFACE_COMPILE_OPTIONS + "${OpenSSL_COMPILE_OPTIONS_LIST}") + + # Library dependencies + include(CMakeFindDependencyMacro) + + if(NOT zlib_FOUND) + find_dependency(zlib REQUIRED) + else() + message(STATUS "Dependency zlib already found") + endif() + + endif() +endif() diff --git a/login_server/README b/login_server/README index f6ca48a88..85f15134c 100644 --- a/login_server/README +++ b/login_server/README @@ -1,17 +1,6 @@ # get dependencies git submodule update --init --recursive -# build dependencies ed25519 -cd dependencies/iroha-ed25519 -mkdir build -cd build -# for windows with visual studio 14 2015 -# cmake .. -G"Visual Studio 14 2015 Win64" -DEDIMPL=ref10 -DHASH=sha2_sphlib -DRANDOM=bcryptgen -DBUILD=STATIC -# for linux -cmake .. -DEDIMPL=ref10 -DHASH=sha2_sphlib -DRANDOM=bcryptgen -DBUILD=STATIC -make - -cd ../../../ cd dependencies/mariadb-connector-c mkdir build @@ -22,10 +11,19 @@ cd ../../../ # get more dependencies with conan (need conan from https://conan.io/) mkdir build && cd build -conan remote add inexor https://api.bintray.com/conan/inexorgame/inexor-conan +# // not used anymore +# conan remote add inexor https://api.bintray.com/conan/inexorgame/inexor-conan +# not needed, but bincrafter # conan install .. -s build_type=Debug conan install .. # build Makefile with cmake cmake .. +make grpc +# under windows build at least release for protoc.exe and grpc c++ plugin +cd ../ +./unix_parse_proto.sh +cd build +make + diff --git a/login_server/compile_pot.sh b/login_server/compile_pot.sh old mode 100644 new mode 100755 diff --git a/login_server/compile_proto.sh b/login_server/compile_proto.sh deleted file mode 100755 index 5190ae766..000000000 --- a/login_server/compile_proto.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -if [ ! -d "./src/cpp/proto" ] ; then - mkdir ./src/cpp/proto -fi -if [ ! -d "./src/cpp/proto/gradido" ] ; then - mkdir ./src/cpp/proto/gradido -fi - -protoc --cpp_out=./src/cpp/proto --proto_path=./src/proto ./src/proto/gradido/*.proto - -#if [ ! -d "./src/cpp/proto/hedera" ] ; then -# mkdir ./src/cpp/proto/hedera -#fi - - -#./protoc --cpp_out=./src/cpp/proto/hedera --proto_path=./src/proto/hedera/hedera-protobuf/src/main/proto ./src/proto/hedera/hedera-protobuf/src/main/proto/*.proto - diff --git a/login_server/conanfile.txt b/login_server/conanfile.txt index 96bd6f5c8..ae0fcd97b 100644 --- a/login_server/conanfile.txt +++ b/login_server/conanfile.txt @@ -1,10 +1,13 @@ [requires] Poco/1.9.4@pocoproject/stable libsodium/1.0.18@bincrafters/stable -protobuf/3.9.1@bincrafters/stable boost/1.71.0@conan/stable gtest/1.8.1@bincrafters/stable [generators] cmake +[options] +Poco:enable_data_sqlite=False +Poco:enable_mongodb=False +Poco:enable_redis=False diff --git a/login_server/dependencies/cmake-modules b/login_server/dependencies/cmake-modules new file mode 160000 index 000000000..7304f680b --- /dev/null +++ b/login_server/dependencies/cmake-modules @@ -0,0 +1 @@ +Subproject commit 7304f680be32915e772466ebddc5b7d3b453abd9 diff --git a/login_server/dependencies/grpc b/login_server/dependencies/grpc new file mode 160000 index 000000000..7d7e45676 --- /dev/null +++ b/login_server/dependencies/grpc @@ -0,0 +1 @@ +Subproject commit 7d7e4567625db7cfebf8969a225948097a3f9f89 diff --git a/login_server/dependencies/iroha-ed25519 b/login_server/dependencies/iroha-ed25519 deleted file mode 160000 index 1fdf5b6e1..000000000 --- a/login_server/dependencies/iroha-ed25519 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1fdf5b6e10be2b1d7118aa3c32dc7acde02cb0cd diff --git a/login_server/dependencies/mariadb-connector-c b/login_server/dependencies/mariadb-connector-c index 1f7480118..159540fe8 160000 --- a/login_server/dependencies/mariadb-connector-c +++ b/login_server/dependencies/mariadb-connector-c @@ -1 +1 @@ -Subproject commit 1f7480118acfe12be9e356827aa30ae9b9eca9a7 +Subproject commit 159540fe8c8f30b281748fe8a1b79e8b17993a67 diff --git a/login_server/dependencies/poco b/login_server/dependencies/poco new file mode 160000 index 000000000..3fc3e5f5b --- /dev/null +++ b/login_server/dependencies/poco @@ -0,0 +1 @@ +Subproject commit 3fc3e5f5b8462f7666952b43381383a79b8b5d92 diff --git a/login_server/doc/.gitignore b/login_server/doc/.gitignore new file mode 100644 index 000000000..1936cc1d4 --- /dev/null +++ b/login_server/doc/.gitignore @@ -0,0 +1 @@ +html diff --git a/login_server/parse_proto.sh b/login_server/parse_proto.sh new file mode 100644 index 000000000..1ec7c106e --- /dev/null +++ b/login_server/parse_proto.sh @@ -0,0 +1,16 @@ +#!/bin/bash +if [ ! -d "./src/cpp/proto" ] ; then + mkdir ./src/cpp/proto +fi +if [ ! -d "./src/cpp/proto/gradido" ] ; then + mkdir ./src/cpp/proto/gradido +fi + +./protoc --cpp_out=./src/cpp/proto --proto_path=./src/proto ./src/proto/gradido/*.proto + +if [ ! -d "./src/cpp/proto/hedera" ] ; then + mkdir ./src/cpp/proto/hedera +fi + + +./protoc --plugin=protoc-gen-grpc=./grpc_cpp_plugin.exe --cpp_out=./src/cpp/proto/hedera --grpc_out=./src/cpp/proto/hedera --proto_path=./src/proto/hedera/hedera-protobuf/src/main/proto ./src/proto/hedera/hedera-protobuf/src/main/proto/*.proto diff --git a/login_server/skeema/gradido_login/app_access_tokens.sql b/login_server/skeema/gradido_login/app_access_tokens.sql new file mode 100644 index 000000000..d320bba5c --- /dev/null +++ b/login_server/skeema/gradido_login/app_access_tokens.sql @@ -0,0 +1,9 @@ +CREATE TABLE `app_access_tokens` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `access_code` bigint unsigned NOT NULL, + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `access_code` (`access_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/crypto_keys.sql b/login_server/skeema/gradido_login/crypto_keys.sql new file mode 100644 index 000000000..1e5d6bad8 --- /dev/null +++ b/login_server/skeema/gradido_login/crypto_keys.sql @@ -0,0 +1,8 @@ +CREATE TABLE `crypto_keys` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `private_key` varbinary(80) NOT NULL, + `public_key` binary(32) NOT NULL, + `crypto_key_type_id` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE(`public_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/elopage_buys.sql b/login_server/skeema/gradido_login/elopage_buys.sql index be3464846..0be79a34b 100644 --- a/login_server/skeema/gradido_login/elopage_buys.sql +++ b/login_server/skeema/gradido_login/elopage_buys.sql @@ -1,15 +1,15 @@ CREATE TABLE `elopage_buys` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `elopage_user_id` int NOT NULL, `affiliate_program_id` int NOT NULL, `publisher_id` int NOT NULL, `order_id` int NOT NULL, `product_id` int NOT NULL, `product_price` int NOT NULL, - `payer_email` varchar(255) COLLATE utf8_bin NOT NULL, - `publisher_email` varchar(255) COLLATE utf8_bin NOT NULL, + `payer_email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `publisher_email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `payed` tinyint NOT NULL, `success_date` datetime NOT NULL, - `event` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `event` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/email_opt_in.sql b/login_server/skeema/gradido_login/email_opt_in.sql index 1589093e8..da4288475 100644 --- a/login_server/skeema/gradido_login/email_opt_in.sql +++ b/login_server/skeema/gradido_login/email_opt_in.sql @@ -1,11 +1,11 @@ CREATE TABLE `email_opt_in` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `user_id` int NOT NULL, `verification_code` bigint unsigned NOT NULL, `email_opt_in_type_id` int NOT NULL, - `created` datetime NOT NULL DEFAULT current_timestamp(), - `resend_count` int DEFAULT 0, - `updated` DATETIME on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `resend_count` int DEFAULT '0', + `updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `verification_code` (`verification_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/email_opt_in_types.sql b/login_server/skeema/gradido_login/email_opt_in_types.sql index f46275727..dbcd2d272 100644 --- a/login_server/skeema/gradido_login/email_opt_in_types.sql +++ b/login_server/skeema/gradido_login/email_opt_in_types.sql @@ -1,5 +1,5 @@ CREATE TABLE `email_opt_in_types` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `description` varchar(255) NOT NULL, PRIMARY KEY (`id`) diff --git a/login_server/skeema/gradido_login/groups.sql b/login_server/skeema/gradido_login/groups.sql new file mode 100644 index 000000000..240c56ba5 --- /dev/null +++ b/login_server/skeema/gradido_login/groups.sql @@ -0,0 +1,10 @@ +CREATE TABLE `groups` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `alias` varchar(190) NOT NULL, + `name` varchar(255) NOT NULL, + `url` varchar(255) NOT NULL, + `home` varchar(255) DEFAULT "/", + `description` text, + PRIMARY KEY (`id`), + UNIQUE KEY `alias` (`alias`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/login_server/skeema/gradido_login/hedera_accounts.sql b/login_server/skeema/gradido_login/hedera_accounts.sql new file mode 100644 index 000000000..8ce24b54d --- /dev/null +++ b/login_server/skeema/gradido_login/hedera_accounts.sql @@ -0,0 +1,12 @@ +CREATE TABLE `hedera_accounts` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned NOT NULL, + `account_hedera_id` int unsigned NOT NULL, + `account_key_id` int unsigned NOT NULL, + `balance` bigint unsigned NOT NULL DEFAULT '0', + `network_type` int NOT NULL DEFAULT '0', + `updated` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `account_hedera_id` (`account_hedera_id`), + UNIQUE KEY `account_key_id` (`account_key_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/hedera_ids.sql b/login_server/skeema/gradido_login/hedera_ids.sql new file mode 100644 index 000000000..b5fd26682 --- /dev/null +++ b/login_server/skeema/gradido_login/hedera_ids.sql @@ -0,0 +1,7 @@ +CREATE TABLE `hedera_ids` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `shardNum` bigint NOT NULL DEFAULT '0', + `realmNum` bigint NOT NULL DEFAULT '0', + `num` bigint NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/login_server/skeema/gradido_login/hedera_topics.sql b/login_server/skeema/gradido_login/hedera_topics.sql new file mode 100644 index 000000000..43e2529ef --- /dev/null +++ b/login_server/skeema/gradido_login/hedera_topics.sql @@ -0,0 +1,16 @@ +CREATE TABLE `hedera_topics` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `topic_hedera_id` int unsigned NOT NULL, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `auto_renew_account_hedera_id` int unsigned DEFAULT NULL, + `auto_renew_period` int unsigned NOT NULL DEFAULT '0', + `group_id` int unsigned NOT NULL, + `admin_key_id` int unsigned DEFAULT NULL, + `submit_key_id` int unsigned DEFAULT NULL, + `current_timeout` DATETIME NOT NULL DEFAULT '2000-01-01 00:00:00', + `sequence_number` bigint unsigned DEFAULT '0', + `running_hash` VARBINARY(64) DEFAULT NULL, + `running_hash_version` int unsigned DEFAULT 0, + `updated` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/insert/setup_hedera_group.sql b/login_server/skeema/gradido_login/insert/setup_hedera_group.sql new file mode 100644 index 000000000..8dd601b97 --- /dev/null +++ b/login_server/skeema/gradido_login/insert/setup_hedera_group.sql @@ -0,0 +1,19 @@ +INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `home`, `description`) VALUES +(1, 'dockerStage2', 'docker stage2 gradido group', 'localhost', '/', 'gradido test group for docker and stage2'); + +INSERT INTO `hedera_ids` (`id`, `shardNum`, `realmNum`, `num`) VALUES +(1, 0, 0, 3), +(2, 0, 0, 3327), +(3, 0, 0, 413151); + +INSERT INTO `node_servers` (`id`, `url`, `port`, `group_id`, `server_type`, `node_hedera_id`, `last_live_sign`) VALUES +(1, 'http://0.testnet.hedera.com', 50211, 0, 4, 1, '2000-01-01 00:00:00'); + +INSERT INTO `hedera_accounts` (`id`, `user_id`, `account_hedera_id`, `account_key_id`, `balance`, `network_type`, `updated`) VALUES +(1, 1, 2, 1, 1000000000000, 1, '2021-01-07 10:22:52'); + +INSERT INTO `hedera_topics` (`id`, `topic_hedera_id`, `name`, `auto_renew_account_hedera_id`, `auto_renew_period`, `group_id`, `admin_key_id`, `submit_key_id`, `current_timeout`, `sequence_number`, `running_hash`, `running_hash_version`, `updated`) VALUES +(1, 3, 'dockerStage2', 1, 7890000, 1, 0, 0, '2021-06-08 23:17:19', 0, NULL, 0, '2021-03-09 16:42:34'); + + + diff --git a/login_server/skeema/gradido_login/node_servers.sql b/login_server/skeema/gradido_login/node_servers.sql new file mode 100644 index 000000000..88e4d8ac3 --- /dev/null +++ b/login_server/skeema/gradido_login/node_servers.sql @@ -0,0 +1,10 @@ +CREATE TABLE `node_servers` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `url` VARCHAR(255) NOT NULL, + `port` INT UNSIGNED NOT NULL, + `group_id` INT UNSIGNED NULL DEFAULT '0', + `server_type` INT UNSIGNED NOT NULL DEFAULT '0', + `node_hedera_id` INT UNSIGNED NULL DEFAULT '0', + `last_live_sign` DATETIME NOT NULL DEFAULT '2000-01-01 00:00:00', + PRIMARY KEY (`id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/pending_tasks.sql b/login_server/skeema/gradido_login/pending_tasks.sql new file mode 100644 index 000000000..e3ac7016c --- /dev/null +++ b/login_server/skeema/gradido_login/pending_tasks.sql @@ -0,0 +1,13 @@ +CREATE TABLE `pending_tasks` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` int UNSIGNED DEFAULT 0, + `hedera_id` int UNSIGNED DEFAULT 0, + `request` varbinary(2048) NOT NULL, + `created` datetime NOT NULL, + `finished` datetime DEFAULT '2000-01-01 000000', + `result_json` varchar(255) DEFAULT NULL, + `task_type_id` int UNSIGNED NOT NULL, + `child_pending_task_id` int UNSIGNED DEFAULT 0, + `parent_pending_task_id` int UNSIGNED DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/roles.sql b/login_server/skeema/gradido_login/roles.sql index b9d51dd11..c99223961 100644 --- a/login_server/skeema/gradido_login/roles.sql +++ b/login_server/skeema/gradido_login/roles.sql @@ -1,7 +1,7 @@ CREATE TABLE `roles` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `description` varchar(255) NOT NULL, - `flags` bigint NOT NULL DEFAULT 0, + `flags` bigint NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/skeema/gradido_login/user_backups.sql b/login_server/skeema/gradido_login/user_backups.sql index 699c9a2c6..7e3b7d85a 100644 --- a/login_server/skeema/gradido_login/user_backups.sql +++ b/login_server/skeema/gradido_login/user_backups.sql @@ -1,5 +1,5 @@ CREATE TABLE `user_backups` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `user_id` int NOT NULL, `passphrase` text NOT NULL, `mnemonic_type` int DEFAULT '-1', diff --git a/login_server/skeema/gradido_login/user_roles.sql b/login_server/skeema/gradido_login/user_roles.sql index ac9f0834c..a92154ce8 100644 --- a/login_server/skeema/gradido_login/user_roles.sql +++ b/login_server/skeema/gradido_login/user_roles.sql @@ -1,5 +1,5 @@ CREATE TABLE `user_roles` ( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `user_id` int NOT NULL, `role_id` int NOT NULL, PRIMARY KEY (`id`) diff --git a/login_server/skeema/gradido_login/users.sql b/login_server/skeema/gradido_login/users.sql index 6c3eb5b82..9de1bad49 100644 --- a/login_server/skeema/gradido_login/users.sql +++ b/login_server/skeema/gradido_login/users.sql @@ -1,16 +1,19 @@ -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 '', + `username` varchar(255) DEFAULT '', + `password` bigint unsigned DEFAULT '0', + `pubkey` binary(32) DEFAULT NULL, + `privkey` binary(80) DEFAULT NULL, + `email_hash` binary(32) 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` tinyint DEFAULT '0', + `group_id` int unsigned DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY `email` (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/src/cpp/Crypto/KeyPair.cpp b/login_server/src/cpp/Crypto/KeyPair.cpp deleted file mode 100644 index 770f3dedf..000000000 --- a/login_server/src/cpp/Crypto/KeyPair.cpp +++ /dev/null @@ -1,339 +0,0 @@ -#include "KeyPair.h" - -#include -#include - -#include "../SingletonManager/ErrorManager.h" -#include "../SingletonManager/ConnectionManager.h" - -#include "Poco/Types.h" - -#include "Passphrase.h" - -#include "../ServerConfig.h" - -using namespace Poco::Data::Keywords; - -#define STR_BUFFER_SIZE 25 - - - -KeyPair::KeyPair() - : mPrivateKey(nullptr), mSodiumSecret(nullptr) -{ - // TODO: set memory to zero for - // unsigned char mPublicKey[ed25519_pubkey_SIZE]; - // unsigned char mSodiumPublic[crypto_sign_PUBLICKEYBYTES]; - memset(mPublicKey, 0, ed25519_pubkey_SIZE); - memset(mSodiumPublic, 0, crypto_sign_PUBLICKEYBYTES); -} - -KeyPair::~KeyPair() -{ - auto mm = MemoryManager::getInstance(); - //printf("[KeyPair::~KeyPair] privkey: %d, soduium privkey: %d \n", mPrivateKey, mSodiumSecret); - if (mPrivateKey) { - //delete mPrivateKey; - mm->releaseMemory(mPrivateKey); - mPrivateKey = nullptr; - } - if (mSodiumSecret) { - //delete mSodiumSecret; - mm->releaseMemory(mSodiumSecret); - mSodiumSecret = nullptr; - } -} - -std::string KeyPair::passphraseTransform(const std::string& passphrase, const Mnemonic* currentWordSource, const Mnemonic* targetWordSource) -{ - if (!currentWordSource || !targetWordSource) { - return ""; - } - if (targetWordSource == currentWordSource) { - return passphrase; - } - auto word_indices = createWordIndices(passphrase, currentWordSource); - if (!word_indices) { - return ""; - } - - return createClearPassphraseFromWordIndices(word_indices, targetWordSource); -} - -bool KeyPair::generateFromPassphrase(const char* passphrase, const Mnemonic* word_source) -{ - auto er = ErrorManager::getInstance(); - auto mm = MemoryManager::getInstance(); - // libsodium doc: https://libsodium.gitbook.io/doc/advanced/hmac-sha2 - // https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki - //crypto_auth_hmacsha512_keygen - auto word_indices = createWordIndices(passphrase, word_source); - if (!word_indices) { - return false; - } - - std::string clearPassphrase = - createClearPassphraseFromWordIndices(word_indices, &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); - -// printf("clear passphrase: %s\n", clearPassphrase.data()); - sha_context state; - - unsigned char hash[SHA_512_SIZE]; - //crypto_auth_hmacsha512_state state; - size_t word_index_size = sizeof(word_indices); - //crypto_auth_hmacsha512_init(&state, (unsigned char*)word_indices, sizeof(word_indices)); - - sha512_init(&state); - sha512_update(&state, *word_indices, word_indices->size()); - sha512_update(&state, (unsigned char*)clearPassphrase.data(), clearPassphrase.size()); - //crypto_auth_hmacsha512_update(&state, (unsigned char*)passphrase, pass_phrase_size); - sha512_final(&state, hash); - //crypto_auth_hmacsha512_final(&state, hash); - - /* - // debug passphrase - printf("\passsphrase: <%s>\n", passphrase); - printf("size word indices: %u\n", word_indices->size()); - std::string word_indicesHex = getHex(*word_indices, word_indices->size()); - printf("word_indices: \n%s\n", word_indicesHex.data()); - printf("word_indices: \n"); - Poco::UInt64* word_indices_p = (Poco::UInt64*)(word_indices->data()); - for (int i = 0; i < PHRASE_WORD_COUNT; i++) { - if (i > 0) printf(" "); - printf("%4hu", word_indices_p[i]); - } - printf("\n"); - - printf("\nclear passphrase: \n%s\n", clearPassphrase.data()); - std::string hex_clearPassphrase = getHex((const unsigned char*)clearPassphrase.data(), clearPassphrase.size()); - printf("passphrase bin: \n%s\n\n", hex_clearPassphrase.data()); - - //*/ - - mm->releaseMemory(word_indices); - - - //ed25519_create_keypair(public_key, private_key, hash); - private_key_t prv_key_t; - memcpy(prv_key_t.data, hash, 32); - public_key_t pbl_key_t; - ed25519_derive_public_key(&prv_key_t, &pbl_key_t); - - //memcpy(private_key, prv_key_t.data, 32); - if (!mPrivateKey) { - //delete mPrivateKey; - mPrivateKey = mm->getFreeMemory(ed25519_privkey_SIZE); - if (!mPrivateKey) { - return false; - } - } - //mPrivateKey = new ObfusArray(ed25519_privkey_SIZE, prv_key_t.data); - - memcpy(*mPrivateKey, prv_key_t.data, ed25519_privkey_SIZE); - - memcpy(mPublicKey, pbl_key_t.data, ed25519_pubkey_SIZE); - - if (!mSodiumSecret) { - //delete mSodiumSecret; - //mm->releaseMemory(mSodiumSecret); - mSodiumSecret = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); - } - //unsigned char sodium_secret[crypto_sign_SECRETKEYBYTES]; - - - crypto_sign_seed_keypair(mSodiumPublic, *mSodiumSecret, *mPrivateKey); - - - // print hex for all keys for debugging -/* printf("// ********** Keys ************* //\n"); - printf("Public: \t%s\n", getHex(mPublicKey, ed25519_pubkey_SIZE).data()); - printf("Private: \t%s\n", getHex(*mPrivateKey, mPrivateKey->size()).data()); - printf("Sodium Public: \t%s\n", getHex(mSodiumPublic, crypto_sign_PUBLICKEYBYTES).data()); - printf("Sodium Private: \t%s\n", getHex(*mSodiumSecret, mSodiumSecret->size()).data()); - printf("// ********* Keys End ************ //\n"); -*/ - //printf("[KeyPair::generateFromPassphrase] finished!\n"); - // using - return true; -} - -bool KeyPair::generateFromPassphrase(const std::string& passphrase) -{ - //static bool validatePassphrase(const std::string& passphrase, Mnemonic** wordSource = nullptr); - Mnemonic* wordSource = nullptr; - if (validatePassphrase(passphrase, &wordSource)) { - return generateFromPassphrase(passphrase.data(), wordSource); - } - return false; -} - -MemoryBin* KeyPair::createWordIndices(const std::string& passphrase, const Mnemonic* word_source) -{ - auto er = ErrorManager::getInstance(); - auto mm = MemoryManager::getInstance(); - - auto word_indices = mm->getFreeMemory(sizeof(Poco::UInt64) * PHRASE_WORD_COUNT); - Poco::UInt64* word_indices_p = (Poco::UInt64*)(word_indices->data()); - //Poco::UInt64 word_indices_old[PHRASE_WORD_COUNT] = { 0 }; - //memset(word_indices_old, 0, PHRASE_WORD_COUNT * sizeof(Poco::UInt64));// *sizeof(unsigned long)); - memset(*word_indices, 0, word_indices->size()); - - //DHASH key = DRMakeStringHash(passphrase); - size_t pass_phrase_size = passphrase.size(); - - char acBuffer[STR_BUFFER_SIZE]; memset(acBuffer, 0, STR_BUFFER_SIZE); - size_t buffer_cursor = 0; - - // get word indices for hmac key - unsigned char word_cursor = 0; - for (auto it = passphrase.begin(); it != passphrase.end(); it++) - { - if (*it == ' ') { - if (buffer_cursor < 3) { - continue; - } - if (PHRASE_WORD_COUNT > word_cursor && word_source->isWordExist(acBuffer)) { - word_indices_p[word_cursor] = word_source->getWordIndex(acBuffer); - //word_indices_old[word_cursor] = word_source->getWordIndex(acBuffer); - } - else { - er->addError(new ParamError("KeyPair::generateFromPassphrase", "word didn't exist", acBuffer)); - er->sendErrorsAsEmail(); - mm->releaseMemory(word_indices); - return nullptr; - } - word_cursor++; - memset(acBuffer, 0, STR_BUFFER_SIZE); - buffer_cursor = 0; - - } - else { - acBuffer[buffer_cursor++] = *it; - } - } - if (PHRASE_WORD_COUNT > word_cursor && word_source->isWordExist(acBuffer)) { - word_indices_p[word_cursor] = word_source->getWordIndex(acBuffer); - //word_indices_old[word_cursor] = word_source->getWordIndex(acBuffer); - word_cursor++; - } - //printf("word cursor: %d\n", word_cursor); - /*if (memcmp(word_indices_p, word_indices_old, word_indices->size()) != 0) { - - printf("not identical\n"); - memcpy(word_indices_p, word_indices_old, word_indices->size()); - }*/ - return word_indices; -} - -std::string KeyPair::createClearPassphraseFromWordIndices(MemoryBin* word_indices, const Mnemonic* word_source) -{ - Poco::UInt64* word_indices_p = (Poco::UInt64*)word_indices->data(); - std::string clearPassphrase; - for (int i = 0; i < PHRASE_WORD_COUNT; i++) { - if (i * sizeof(Poco::UInt64) >= word_indices->size()) break; - auto word = word_source->getWord(word_indices_p[i]); - if (word) { - clearPassphrase += word; - clearPassphrase += " "; - } - } - return clearPassphrase; -} - -std::string KeyPair::filterPassphrase(const std::string& passphrase) -{ - return Passphrase::filter(passphrase); -} - -std::string KeyPair::getPubkeyHex() -{ - const size_t hexSize = crypto_sign_PUBLICKEYBYTES * 2 + 1; - - char hexString[hexSize]; - memset(hexString, 0, hexSize); - sodium_bin2hex(hexString, hexSize, mSodiumPublic, crypto_sign_PUBLICKEYBYTES); - - return std::string(hexString); -} - -std::string KeyPair::getHex(const unsigned char* data, Poco::UInt32 size) -{ - auto mm = MemoryManager::getInstance(); - - Poco::UInt32 hexSize = size * 2 + 1; - auto hexMem = mm->getFreeMemory(hexSize); - //char* hexString = (char*)malloc(hexSize); - memset(*hexMem, 0, hexSize); - sodium_bin2hex(*hexMem, hexSize, data, size); - std::string hex = (char*)*hexMem; -// free(hexString); - mm->releaseMemory(hexMem); - - return hex; -} - -std::string KeyPair::getHex(const MemoryBin* data) -{ - return getHex(*data, data->size()); -} - -bool KeyPair::savePrivKey(int userId) -{ - auto cm = ConnectionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto mysql_session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement update(mysql_session); - Poco::Data::BLOB privkey_blob((const unsigned char*)(*mPrivateKey), mPrivateKey->size()); - - update << "UPDATE users set privkey = ? where id = ?", - use(privkey_blob), use(userId); - - try { - if (update.execute() != 1) { - em->addError(new ParamError("KeyPair::savePrivKey", "error writing privkey, user not found? ", std::to_string(userId))); - em->sendErrorsAsEmail(); - return false; - } - } catch (Poco::Exception& ex) { - em->addError(new ParamError("KeyPair::savePrivKey", "exception by running mysql", ex.displayText())); - em->sendErrorsAsEmail(); - return false; - } - return true; -} - -bool KeyPair::isPubkeysTheSame(const unsigned char* pubkey) const -{ - return sodium_memcmp(pubkey, mPublicKey, ed25519_pubkey_SIZE) == 0; -} - -bool KeyPair::validatePassphrase(const std::string& passphrase, Mnemonic** wordSource/* = nullptr*/) -{ - std::istringstream iss(passphrase); - std::vector results(std::istream_iterator{iss}, - std::istream_iterator()); - - for (int i = 0; i < ServerConfig::Mnemonic_Types::MNEMONIC_MAX; i++) { - Mnemonic& m = ServerConfig::g_Mnemonic_WordLists[i]; - bool existAll = true; - for (auto it = results.begin(); it != results.end(); it++) { - if (*it == "\0" || *it == "" || it->size() < 3) continue; - if (!m.isWordExist(*it)) { - if (i == 1) { - int zahl = 0; - } - //printf("wordlist: %d, word not found: %s\n", i, it->data()); - existAll = false; - continue; - } - } - if (existAll) { - if (wordSource) { - *wordSource = &m; - } - - return true; - } - } - return false; -} diff --git a/login_server/src/cpp/Crypto/KeyPair.h b/login_server/src/cpp/Crypto/KeyPair.h deleted file mode 100644 index 67a84f6da..000000000 --- a/login_server/src/cpp/Crypto/KeyPair.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR -#define GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR - -#include "Obfus_array.h" -#include "../SingletonManager/MemoryManager.h" -#include "mnemonic.h" - -#include "ed25519/ed25519.h" -#include - -class UserWriteKeysIntoDB; -class UserGenerateKeys; -class DebugPassphrasePage; -class User; -class RepairDefectPassphrase; - -// TODO: https://libsodium.gitbook.io/doc/advanced/ed25519-curve25519 -class KeyPair -{ - friend UserWriteKeysIntoDB; - friend UserGenerateKeys; - friend DebugPassphrasePage; - friend User; - friend RepairDefectPassphrase; -public: - KeyPair(); - ~KeyPair(); - - bool generateFromPassphrase(const char* passphrase, const Mnemonic* word_source); - bool generateFromPassphrase(const std::string& passphrase); - static std::string passphraseTransform(const std::string& passphrase, const Mnemonic* currentWordSource, const Mnemonic* targetWordSource); - static std::string filterPassphrase(const std::string& passphrase); - static bool validatePassphrase(const std::string& passphrase, Mnemonic** wordSource = nullptr); - - std::string getPubkeyHex(); - bool savePrivKey(int userId); - static std::string getHex(const unsigned char* data, Poco::UInt32 size); - static std::string getHex(const MemoryBin* data); - - inline const unsigned char* getPublicKey() const { return mSodiumPublic; } - - bool isPubkeysTheSame(const unsigned char* pubkey) const; - -protected: - const MemoryBin* getPrivateKey() const { return mSodiumSecret; } - - static MemoryBin* createWordIndices(const std::string& passphrase, const Mnemonic* word_source); - static std::string createClearPassphraseFromWordIndices(MemoryBin* word_indices, const Mnemonic* word_source); - - -private: - // 32 Byte - //! \brief ed25519 ref10 private key - MemoryBin* mPrivateKey; - - // 64 Byte - //! \brief ed25519 libsodium private key - MemoryBin* mSodiumSecret; - - // 32 Byte - //! \brief ed25519 ref10 public key - unsigned char mPublicKey[ed25519_pubkey_SIZE]; - - // 32 Byte - //! \brief ed25519 libsodium public key - unsigned char mSodiumPublic[crypto_sign_PUBLICKEYBYTES]; -}; - -#endif //GRADIDO_LOGIN_SERVER_CRYPTO_KEY_PAIR \ No newline at end of file diff --git a/login_server/src/cpp/Crypto/KeyPairEd25519.cpp b/login_server/src/cpp/Crypto/KeyPairEd25519.cpp index ee8cabfa0..73ab02252 100644 --- a/login_server/src/cpp/Crypto/KeyPairEd25519.cpp +++ b/login_server/src/cpp/Crypto/KeyPairEd25519.cpp @@ -151,13 +151,22 @@ MemoryBin* KeyPairEd25519::sign(const unsigned char* message, size_t messageSize } -MemoryBin* KeyPairEd25519::getCryptedPrivKey(const Poco::AutoPtr password) const +bool KeyPairEd25519::verify(const std::string& message, const std::string& signature) const +{ + if (message == "" || signature == "") return false; + if (crypto_sign_verify_detached((const unsigned char*)signature.data(), (const unsigned char*)message.data(), message.size(), mSodiumPublic) != 0) { + return false; + } + return true; +} + +MemoryBin* KeyPairEd25519::getCryptedPrivKey(const Poco::AutoPtr password) const { if (password.isNull()) return nullptr; if (!mSodiumSecret) return nullptr; MemoryBin* encryptedKey = nullptr; - if (AuthenticatedEncryption::AUTH_ENCRYPT_OK == password->encrypt(mSodiumSecret, &encryptedKey)) { + if (SecretKeyCryptography::AUTH_ENCRYPT_OK == password->encrypt(mSodiumSecret, &encryptedKey)) { return encryptedKey; } else { diff --git a/login_server/src/cpp/Crypto/KeyPairEd25519.h b/login_server/src/cpp/Crypto/KeyPairEd25519.h index 7b3f11d4b..a8faca381 100644 --- a/login_server/src/cpp/Crypto/KeyPairEd25519.h +++ b/login_server/src/cpp/Crypto/KeyPairEd25519.h @@ -9,12 +9,14 @@ * \date: 2020-06-04 * * \brief: Key Pairs class for ed25519 keys, used for default gradido transactions + * TODO: add verify method */ #include "sodium.h" -#include "AuthenticatedEncryption.h" +#include "SecretKeyCryptography.h" #include "Passphrase.h" +#include "../lib/DataTypeConverter.h" class KeyPairEd25519 : public IKeyPair { @@ -35,7 +37,11 @@ public: inline MemoryBin* sign(const std::string& bodyBytes) const { return sign((const unsigned char*)bodyBytes.data(), bodyBytes.size()); } MemoryBin* sign(const unsigned char* message, size_t messageSize) const; + bool verify(const std::string& message, const std::string& signature) const; + inline const unsigned char* getPublicKey() const { return mSodiumPublic; } + inline std::string getPublicKeyHex() const { return DataTypeConverter::binToHex(mSodiumPublic, getPublicKeySize()); } + const static size_t getPublicKeySize() { return crypto_sign_PUBLICKEYBYTES; } inline bool isTheSame(const KeyPairEd25519& b) const { return 0 == sodium_memcmp(mSodiumPublic, b.mSodiumPublic, crypto_sign_PUBLICKEYBYTES); @@ -63,7 +69,7 @@ public: inline bool hasPrivateKey() const { return mSodiumSecret != nullptr; } //! \brief only way to get a private key.. encrypted - MemoryBin* getCryptedPrivKey(const Poco::AutoPtr password) const; + MemoryBin* getCryptedPrivKey(const Poco::AutoPtr password) const; protected: @@ -75,6 +81,9 @@ private: //! \brief ed25519 libsodium private key //! //! Why it is a pointer and the public is an array? + //! Because MemoryBin should be replaced by a memory obfuscation class which make it harder to steal the private key from computer memory + //! And because private key can be nullptr for example to verify a signed message + //! TODO: replace MemoryBin by a memory obfuscation class which make it hard to steal the private key from memory MemoryBin* mSodiumSecret; diff --git a/login_server/src/cpp/Crypto/KeyPairHedera.cpp b/login_server/src/cpp/Crypto/KeyPairHedera.cpp new file mode 100644 index 000000000..ac974fdc1 --- /dev/null +++ b/login_server/src/cpp/Crypto/KeyPairHedera.cpp @@ -0,0 +1,221 @@ +#include "KeyPairHedera.h" +#include "../lib/DataTypeConverter.h" +#include + +#include "../SingletonManager/ErrorManager.h" + +KeyPairHedera::KeyPairHedera() + : mPrivateKey(nullptr) +{ + +} + +KeyPairHedera::KeyPairHedera(const unsigned char* privateKey, size_t privateKeySize, const unsigned char* publicKey/* = nullptr*/, size_t publicKeySize/* = 0*/) + : mPrivateKey(nullptr) +{ + auto derPrefixPriv = DataTypeConverter::hexToBin("302e020100300506032b657004220420"); + auto derPrefixPub = DataTypeConverter::hexToBin("302a300506032b6570032100"); + + auto mm = MemoryManager::getInstance(); + + if (privateKey) { + switch (privateKeySize) { + case 48: + // key with prefix + if (0 == sodium_memcmp(privateKey, *derPrefixPriv, derPrefixPriv->size())) { + //int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed); + auto seed = mm->getFreeMemory(crypto_sign_ed25519_SEEDBYTES); + memcpy(*seed, &privateKey[derPrefixPriv->size()], crypto_sign_ed25519_SEEDBYTES); + createKeyFromSeed(seed->data(), seed->size()); + mm->releaseMemory(seed); + break; + } + case 32: + createKeyFromSeed(privateKey, privateKeySize); + break; + case 64: + //mPrivateKey = privateKey; + if (!mPrivateKey || mPrivateKey->size() != privateKeySize) { + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + } + mPrivateKey = mm->getFreeMemory(privateKeySize); + memcpy(*mPrivateKey, privateKey, privateKeySize); + } + break; + default: + throw Poco::Exception("[KeyPairHedera] invalid private key"); + } + + // check public + } + if (publicKey) { + switch (publicKeySize) + { + case 32: { // raw public key + memcpy(mPublicKey, publicKey, publicKeySize); + break; + } + case 44: // DER encoded public key + if (0 == sodium_memcmp(publicKey, *derPrefixPub, derPrefixPub->size())) { + memcpy(mPublicKey, &publicKey[derPrefixPub->size()], crypto_sign_PUBLICKEYBYTES); + } + break; + default: + throw Poco::Exception("[KeyPairHedera] invalid public key"); + } + } + auto public_key_2 = mm->getFreeMemory(crypto_sign_PUBLICKEYBYTES); + crypto_sign_ed25519_sk_to_pk(*public_key_2, *mPrivateKey); + if (sodium_memcmp(*public_key_2, mPublicKey, crypto_sign_PUBLICKEYBYTES) != 0) { + throw "public keys not match"; + } + + mm->releaseMemory(public_key_2); + mm->releaseMemory(derPrefixPriv); + mm->releaseMemory(derPrefixPub); +} +KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey /* = nullptr*/) + : KeyPairHedera(privateKey->data(), privateKey->size(), publicKey->data(), publicKey->size()) +{ + +} + +KeyPairHedera::KeyPairHedera(const std::vector& privateKey, const unsigned char* publicKey/* = nullptr*/, size_t publicKeySize/* = 0*/) + : KeyPairHedera(privateKey.data(), privateKey.size(), publicKey, publicKeySize) +{ + +} + +KeyPairHedera::~KeyPairHedera() +{ + auto mm = MemoryManager::getInstance(); + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + mPrivateKey = nullptr; + } +} + +KeyPairHedera* KeyPairHedera::create() +{ + /* + The crypto_sign_keypair() function randomly generates a secret key and a corresponding public key. + The public key is put into pk (crypto_sign_PUBLICKEYBYTES bytes) + and the secret key into sk (crypto_sign_SECRETKEYBYTES bytes). + */ + + assert(getPublicKeySize() == crypto_sign_PUBLICKEYBYTES); + + auto mm = MemoryManager::getInstance(); + auto private_key = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); + auto public_key = mm->getFreeMemory(getPublicKeySize()); + + crypto_sign_keypair(*public_key, *private_key); + return new KeyPairHedera(private_key, public_key); +} + + +void KeyPairHedera::createKeyFromSeed(const unsigned char* seed, size_t seedSize) +{ + assert(seed && seedSize == crypto_sign_ed25519_SEEDBYTES); + + auto mm = MemoryManager::getInstance(); + auto secret_key = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); + crypto_sign_seed_keypair(mPublicKey, *secret_key, seed); + + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + } + mPrivateKey = secret_key; + + // iroha + //ed25519_privkey_SIZE + //ed25519_derive_public_key(const private_key_t* sk,public_key_t* pk); +} + +MemoryBin* KeyPairHedera::sign(const unsigned char* message, size_t messageSize) const +{ + if (!message || !messageSize) return nullptr; + if (!mPrivateKey) return nullptr; + auto mm = MemoryManager::getInstance(); + auto em = ErrorManager::getInstance(); + + const static char functionName[] = "KeyPairHedera::sign"; + + auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); + unsigned long long actualSignLength = 0; + + if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *mPrivateKey)) { + em->addError(new Error(functionName, "sign failed")); + auto messageHex = DataTypeConverter::binToHex(message, messageSize); + em->addError(new ParamError(functionName, "message as hex", messageHex)); + mm->releaseMemory(signBinBuffer); + return nullptr; + } + + if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mPublicKey) != 0) { + // Incorrect signature! + //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); + em->addError(new Error(functionName, "sign verify failed")); + auto messageHex = DataTypeConverter::binToHex(message, messageSize); + em->addError(new ParamError(functionName, "message as hex", messageHex)); + mm->releaseMemory(signBinBuffer); + return nullptr; + } + + // debug + /*const size_t hex_sig_size = crypto_sign_BYTES * 2 + 1; + char sig_hex[hex_sig_size]; + sodium_bin2hex(sig_hex, hex_sig_size, *signBinBuffer, crypto_sign_BYTES); + printf("[User::sign] signature hex: %s\n", sig_hex); + */ + + return signBinBuffer; + +} + +bool KeyPairHedera::verify(const unsigned char* message, size_t messageSize, MemoryBin* signature) const +{ + if (crypto_sign_verify_detached(*signature, message, messageSize, mPublicKey) != 0) { + return false; + } + return true; +} + +MemoryBin* KeyPairHedera::getCryptedPrivKey(const Poco::AutoPtr password) const +{ + if (password.isNull()) return nullptr; + if (!mPrivateKey) return nullptr; + + auto private_key_hex_string = DataTypeConverter::binToHex(mPrivateKey); + printf("[KeyPairHedera::getCryptedPrivKey] private key hex: %s\n", private_key_hex_string.data()); + + MemoryBin* encryptedKey = nullptr; + if (SecretKeyCryptography::AUTH_ENCRYPT_OK == password->encrypt(mPrivateKey, &encryptedKey)) { + auto encrypted_private_key_hex_string = DataTypeConverter::binToHex(encryptedKey); + printf("[KeyPairHedera::getCryptedPrivKey] encryptet private key hex: %s\n", encrypted_private_key_hex_string.data()); + return encryptedKey; + } + else { + return nullptr; + } + +} + + +MemoryBin* KeyPairHedera::getPrivateKeyCopy() const +{ + if (!mPrivateKey) return nullptr; + auto mm = MemoryManager::getInstance(); + MemoryBin* private_key_copy = mm->getFreeMemory(mPrivateKey->size()); + memcpy(*private_key_copy, *mPrivateKey, mPrivateKey->size()); + return private_key_copy; +} + +MemoryBin* KeyPairHedera::getPublicKeyCopy() const +{ + auto mm = MemoryManager::getInstance(); + auto public_key = mm->getFreeMemory(crypto_sign_PUBLICKEYBYTES); + memcpy(*public_key, mPublicKey, crypto_sign_PUBLICKEYBYTES); + return public_key; +} diff --git a/login_server/src/cpp/Crypto/KeyPairHedera.h b/login_server/src/cpp/Crypto/KeyPairHedera.h new file mode 100644 index 000000000..b8dba9024 --- /dev/null +++ b/login_server/src/cpp/Crypto/KeyPairHedera.h @@ -0,0 +1,95 @@ +#ifndef __GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H +#define __GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H + +#include "IKeyPair.h" + +/*! +* \author: Dario Rekowski +* +* \date: 2020-08-28 +* +* \brief: Key Pairs class for ed25519 keys, used by hedera for transaction sign +*/ + + +#include "sodium.h" +#include "SecretKeyCryptography.h" +#include "../lib/DataTypeConverter.h" + +class KeyPairHedera : public IKeyPair +{ +public: + //! \param privateKey: copy + //! \param publicKey: copy + //! + KeyPairHedera(const unsigned char* privateKey, size_t privateKeySize, const unsigned char* publicKey = nullptr, size_t publicKeySize = 0); + KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey = nullptr); + KeyPairHedera(const std::vector& privateKey, const unsigned char* publicKey = nullptr, size_t publicKeySize = 0); + + + static KeyPairHedera* create(); + + ~KeyPairHedera(); + + + //! \return caller take ownership of return value + MemoryBin* sign(const MemoryBin* message) const { return sign(message->data(), message->size()); } + inline MemoryBin* sign(const std::string& bodyBytes) const { return sign((const unsigned char*)bodyBytes.data(), bodyBytes.size()); } + MemoryBin* sign(const unsigned char* message, size_t messageSize) const; + + bool verify(const unsigned char* message, size_t messageSize, MemoryBin* signature) const; + + inline const unsigned char* getPublicKey() const { return mPublicKey; } + MemoryBin* getPublicKeyCopy() const; + inline std::string getPublicKeyHex() const { return DataTypeConverter::binToHex(mPublicKey, getPublicKeySize()); } + const static size_t getPublicKeySize() {return crypto_sign_PUBLICKEYBYTES;} + + inline bool isTheSame(const KeyPairHedera& b) const { + return 0 == sodium_memcmp(mPublicKey, b.mPublicKey, getPublicKeySize()); + } + inline bool isTheSame(const unsigned char* pubkey) const { + if (!pubkey) + return false; + return 0 == sodium_memcmp(mPublicKey, pubkey, getPublicKeySize()); + } + //! \return 0 if the same + //! \return -1 if not the same + //! \return 1 if hasn't private key + inline int isTheSame(const MemoryBin* privkey) const { + if (!mPrivateKey) return 1; + if (privkey->size() != mPrivateKey->size()) return -1; + return sodium_memcmp(*mPrivateKey, *privkey, privkey->size()); + } + + inline bool operator == (const KeyPairHedera& b) const { return isTheSame(b); } + inline bool operator != (const KeyPairHedera& b) const { return !isTheSame(b); } + + inline bool operator == (const unsigned char* b) const { return isTheSame(b); } + inline bool operator != (const unsigned char* b) const { return !isTheSame(b); } + + inline bool hasPrivateKey() const { return mPrivateKey != nullptr; } + + //! \brief + MemoryBin* getCryptedPrivKey(const Poco::AutoPtr password) const; + MemoryBin* getPrivateKeyCopy() const; + inline std::string getPrivateKeyHex(const Poco::AutoPtr password) const { if (!mPrivateKey) return "0x0"; return DataTypeConverter::binToHex(mPrivateKey); } + +protected: + + KeyPairHedera(); + void createKeyFromSeed(const unsigned char* seed, size_t seedSize); + + +private: + // 64 Byte + //! \brief ed25519 libsodium private key + //! + //! TODO: replace MemoryBin by a memory obfuscation class which make it hard to steal the private key from memory + MemoryBin* mPrivateKey; + + // 32 Byte + //! \brief ed25519 libsodium public key + unsigned char mPublicKey[crypto_sign_PUBLICKEYBYTES]; +}; + +#endif //__GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H \ No newline at end of file diff --git a/login_server/src/cpp/Crypto/Passphrase.cpp b/login_server/src/cpp/Crypto/Passphrase.cpp index 61599a69d..cad034673 100644 --- a/login_server/src/cpp/Crypto/Passphrase.cpp +++ b/login_server/src/cpp/Crypto/Passphrase.cpp @@ -133,6 +133,11 @@ Poco::AutoPtr Passphrase::transform(const Mnemonic* targetWordSource return nullptr; } +Poco::AutoPtr Passphrase::create(const std::string& passphrase, const Mnemonic* wordSource) +{ + return new Passphrase(passphrase, wordSource); +} + Poco::AutoPtr Passphrase::create(const MemoryBin* wordIndices, const Mnemonic* wordSource) { if (PHRASE_WORD_COUNT * sizeof(Poco::UInt16) >= wordIndices->size()) { diff --git a/login_server/src/cpp/Crypto/Passphrase.h b/login_server/src/cpp/Crypto/Passphrase.h index cfd680afd..d83b597e4 100644 --- a/login_server/src/cpp/Crypto/Passphrase.h +++ b/login_server/src/cpp/Crypto/Passphrase.h @@ -16,6 +16,7 @@ public: static Poco::AutoPtr create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], const Mnemonic* wordSource); static Poco::AutoPtr create(const MemoryBin* wordIndices, const Mnemonic* wordSource); + static Poco::AutoPtr create(const std::string& passphrase, const Mnemonic* wordSource); //! \brief generate new passphrase with random static Poco::AutoPtr generate(const Mnemonic* wordSource); static const Mnemonic* detectMnemonic(const std::string& passphrase, const KeyPairEd25519* keyPair = nullptr); diff --git a/login_server/src/cpp/Crypto/AuthenticatedEncryption.cpp b/login_server/src/cpp/Crypto/SecretKeyCryptography.cpp similarity index 86% rename from login_server/src/cpp/Crypto/AuthenticatedEncryption.cpp rename to login_server/src/cpp/Crypto/SecretKeyCryptography.cpp index 421537a66..8710a5b8c 100644 --- a/login_server/src/cpp/Crypto/AuthenticatedEncryption.cpp +++ b/login_server/src/cpp/Crypto/SecretKeyCryptography.cpp @@ -1,22 +1,22 @@ -#include "AuthenticatedEncryption.h" +#include "SecretKeyCryptography.h" #include "sodium.h" #include "../ServerConfig.h" #include #include "../lib/Profiler.h" -AuthenticatedEncryption::AuthenticatedEncryption() +SecretKeyCryptography::SecretKeyCryptography() : mOpsLimit(10), mMemLimit(33554432), mAlgo(2), mEncryptionKey(nullptr), mEncryptionKeyHash(0) { } -AuthenticatedEncryption::AuthenticatedEncryption(unsigned long long opslimit, size_t memlimit, int algo) +SecretKeyCryptography::SecretKeyCryptography(unsigned long long opslimit, size_t memlimit, int algo) : mOpsLimit(opslimit), mMemLimit(memlimit), mAlgo(algo), mEncryptionKey(nullptr), mEncryptionKeyHash(0) { } -AuthenticatedEncryption::~AuthenticatedEncryption() +SecretKeyCryptography::~SecretKeyCryptography() { if (mEncryptionKey) { MemoryManager::getInstance()->releaseMemory(mEncryptionKey); @@ -24,7 +24,7 @@ AuthenticatedEncryption::~AuthenticatedEncryption() } } -AuthenticatedEncryption::ResultType AuthenticatedEncryption::createKey(const std::string& salt_parameter, const std::string& passwd) +SecretKeyCryptography::ResultType SecretKeyCryptography::createKey(const std::string& salt_parameter, const std::string& passwd) { assert(crypto_hash_sha512_BYTES >= crypto_pwhash_SALTBYTES); @@ -76,10 +76,10 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::createKey(const std assert(ServerConfig::g_ServerCryptoKey); crypto_shorthash((unsigned char*)&mEncryptionKeyHash, *mEncryptionKey, crypto_box_SEEDBYTES, *ServerConfig::g_ServerCryptoKey); - return AUTH_ENCRYPT_OK; + return AUTH_CREATE_ENCRYPTION_KEY_SUCCEED; } -AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const +SecretKeyCryptography::ResultType SecretKeyCryptography::encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const { assert(message && encryptedMessage); std::shared_lock _lock(mWorkingMutex); @@ -111,7 +111,7 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const Memor return AUTH_ENCRYPT_OK; } -AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const unsigned char* encryptedMessage, size_t encryptedMessageSize, MemoryBin** message) const +SecretKeyCryptography::ResultType SecretKeyCryptography::decrypt(const unsigned char* encryptedMessage, size_t encryptedMessageSize, MemoryBin** message) const { assert(message); std::shared_lock _lock(mWorkingMutex); @@ -139,7 +139,7 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const unsig return AUTH_DECRYPT_OK; } -const char* AuthenticatedEncryption::getErrorMessage(ResultType type) +const char* SecretKeyCryptography::getErrorMessage(ResultType type) { switch (type) { case AUTH_ENCRYPT_OK: return "everything is ok"; diff --git a/login_server/src/cpp/Crypto/AuthenticatedEncryption.h b/login_server/src/cpp/Crypto/SecretKeyCryptography.h similarity index 84% rename from login_server/src/cpp/Crypto/AuthenticatedEncryption.h rename to login_server/src/cpp/Crypto/SecretKeyCryptography.h index a19e0f856..87d69e4ed 100644 --- a/login_server/src/cpp/Crypto/AuthenticatedEncryption.h +++ b/login_server/src/cpp/Crypto/SecretKeyCryptography.h @@ -17,19 +17,20 @@ * * \date: 07-06-2020 * - * \brief: Wrapper Class for make using libsodium authenticated encryption easy, used for encrypt private keys for user + * \brief: Wrapper Class for make using libsodium secret key encryption easy, used for encrypt private keys for user with pwhash * */ typedef Poco::UInt64 KeyHashed; -class AuthenticatedEncryption : public AutoPtrContainer +class SecretKeyCryptography : public AutoPtrContainer { public: enum ResultType { AUTH_ENCRYPT_OK, AUTH_DECRYPT_OK, + AUTH_CREATE_ENCRYPTION_KEY_SUCCEED, AUTH_CREATE_ENCRYPTION_KEY_FAILED, AUTH_NO_KEY, AUTH_ENCRYPT_MESSAGE_FAILED, @@ -37,20 +38,20 @@ public: }; //! \brief init with default algorithms parameter - AuthenticatedEncryption(); + SecretKeyCryptography(); //! \brief init with custom algorithms parameter //! //! details see in libsodium crypto_pwhash - AuthenticatedEncryption(unsigned long long opslimit, size_t memlimit, int algo); + SecretKeyCryptography(unsigned long long opslimit, size_t memlimit, int algo); - ~AuthenticatedEncryption(); + ~SecretKeyCryptography(); inline KeyHashed getKeyHashed() const { std::shared_lock _lock(mWorkingMutex); return mEncryptionKeyHash; } - inline bool operator == (const Poco::AutoPtr& b) const { + inline bool operator == (const Poco::AutoPtr& b) const { return isTheSame(b); } - inline bool isTheSame(const Poco::AutoPtr& b) const { + inline bool isTheSame(const Poco::AutoPtr& b) const { std::shared_lock _lock(mWorkingMutex); if (b.isNull()) return false; return mEncryptionKeyHash == b->getKeyHashed(); diff --git a/login_server/src/cpp/Gradido_LoginServer.cpp b/login_server/src/cpp/Gradido_LoginServer.cpp index 2ad89e19b..5d3f09f03 100644 --- a/login_server/src/cpp/Gradido_LoginServer.cpp +++ b/login_server/src/cpp/Gradido_LoginServer.cpp @@ -1,267 +1,280 @@ -#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 "SingletonManager/PendingTasksManager.h" +#include "SingletonManager/CronManager.h" + +#include "controller/User.h" + +#include "Crypto/SecretKeyCryptography.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/"; + try { + loadConfiguration(cfg_Path + "grd_login.properties"); + } + catch (Poco::Exception& ex) { + errorLog.error("error loading config: %s", ex.displayText()); + } + + 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 + SecretKeyCryptography test_crypto; + Profiler timeUsed; + if (test_crypto.createKey("email@google.de", "haz27Newpassword") != SecretKeyCryptography::AUTH_CREATE_ENCRYPTION_KEY_SUCCEED) { + errorLog.error("[Gradido_LoginServer::main] error create secure pwd hash"); + return Application::EXIT_SOFTWARE; + } + ServerConfig::g_FakeLoginSleepTime = (int)std::round(timeUsed.millis()); + + 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 = (uint8_t)config().getInt("cpu_worker", 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 + try { + Poco::Data::MySQL::Connector::registerConnector(); + } catch(Poco::Exception& ex) { + errorLog.error("[Gradido_LoginServer::main] Poco Exception by register MySQL Connector: %s", ex.displayText()); + return Application::EXIT_CONFIG; + } + + 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"); + return Application::EXIT_CONFIG; + } + + // schedule email verification resend + controller::User::checkIfVerificationEmailsShouldBeResend(ServerConfig::g_CronJobsTimer); + controller::User::addMissingEmailHashes(); + + // 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(); + + // load pending tasks not finished in last session + PendingTasksManager::getInstance()->load(); + int php_server_ping = config().getInt("phpServer.ping", 600000); + CronManager::getInstance()->init(php_server_ping); + + printf("[Gradido_LoginServer::main] started in %s\n", usedTime.string().data()); + // wait for CTRL-C or kill + waitForTerminationRequest(); + + CronManager::getInstance()->stop(); + + // 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; +} \ No newline at end of file diff --git a/login_server/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp b/login_server/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp index 940d084bc..3139ff59a 100644 --- a/login_server/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp +++ b/login_server/src/cpp/HTTPInterface/AdminCheckUserBackup.cpp @@ -7,10 +7,11 @@ #line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" +#include "../Crypto/Passphrase.h" #include "../SingletonManager/ConnectionManager.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "Poco/Data/Binding.h" using namespace Poco::Data::Keywords; @@ -20,7 +21,7 @@ typedef Poco::Tuple, std::string> UserBack struct SListEntry { Poco::AutoPtr user; - std::vector> backups; + std::vector> backups; }; #line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp" @@ -42,11 +43,11 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 25 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 26 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" const char* pageName = "Admin Check User Backups"; auto cm = ConnectionManager::getInstance(); - KeyPair keys; + std::list notMatchingEntrys; auto con = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); @@ -65,21 +66,24 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, if(pubkey.isNull()) { continue; } - auto passphrase = KeyPair::filterPassphrase(tuple.get<2>()); + auto passphrase = Passphrase::filter(tuple.get<2>()); auto user_id = tuple.get<0>(); - Mnemonic* wordSource = nullptr; - if(!User::validatePassphrase(passphrase, &wordSource)) { + KeyPairEd25519 key_pair(pubkey.value().content().data()); + + auto wordSource = Passphrase::detectMnemonic(passphrase); + if(!wordSource) { addError(new Error("admin Check user backup", "invalid passphrase"), false); addError(new ParamError("admin Check user backup", "passphrase", passphrase.data()), false); addError(new ParamError("admin Check user backup", "user id", user_id), false); continue; - } else { - keys.generateFromPassphrase(passphrase.data(), wordSource); - } + } + auto passphrase_object = Passphrase::create(passphrase, wordSource); + auto key_pair_from_passhrase = KeyPairEd25519::create(passphrase_object); bool matching = false; - if(keys.isPubkeysTheSame(pubkey.value().content().data())) { + if(key_pair_from_passhrase->isTheSame(key_pair)) { matching = true; } + delete key_pair_from_passhrase; if(user_id != last_user_id) { last_user_id = user_id; if(matching) continue; @@ -94,7 +98,7 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, SListEntry entry; entry.user = controller::User::create(); entry.user->load(user_id); - entry.backups = controller::UserBackups::load(user_id); + entry.backups = controller::UserBackup::load(user_id); notMatchingEntrys.push_back(entry); @@ -177,11 +181,11 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "
\n"; responseStream << "\t

Admin Check User Backup

\n"; responseStream << "\t"; -#line 91 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 95 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "\t

Unmatching count: "; -#line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 96 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( notMatchingEntrys.size() ); responseStream << "

\n"; responseStream << "\t\n"; @@ -190,34 +194,34 @@ void AdminCheckUserBackup::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "\t\t\n"; responseStream << "\t\t\n"; responseStream << "\t\t\t"; -#line 98 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 102 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" for(auto it = notMatchingEntrys.begin(); it != notMatchingEntrys.end(); it++) { auto userModel = (*it).user->getModel(); responseStream << "\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t"; -#line 108 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 112 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" } responseStream << "\n"; responseStream << "\t\t\n"; responseStream << "\n"; diff --git a/login_server/src/cpp/HTTPInterface/AdminGroupsPage.cpp b/login_server/src/cpp/HTTPInterface/AdminGroupsPage.cpp new file mode 100644 index 000000000..c83a41564 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminGroupsPage.cpp @@ -0,0 +1,233 @@ +#include "AdminGroupsPage.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_login_server\\src\\cpsp\\adminGroups.cpsp" + + #include "../controller/Group.h" +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + +#include "../ServerConfig.h" + + +AdminGroupsPage::AdminGroupsPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void AdminGroupsPage::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 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + + const char* pageName = "Gruppen"; + + auto user = mSession->getNewUser(); + + // add + if(!form.empty()) { + auto alias = form.get("group-alias"); + if(alias == "") + { + addError(new Error("Add Group", "Alias is empty!")); + } + else + { + auto newGroup = controller::Group::create( + alias, + form.get("group-name", ""), + form.get("group-url", ""), + form.get("group-home", ""), + form.get("group-desc", "") + ); + newGroup->getModel()->insertIntoDB(false); + } + } + + // select all + auto groups = controller::Group::listAll(); + //auto groups = controller::Group::load("gdd1"); + //std::vector> groups; + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.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_large.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t
  • getGroupBaseUrl() ); + responseStream << "/\">Startseite
  • \n"; + responseStream << "\t\t\t\t\t"; +#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
  • Gruppen
  • \n"; + responseStream << "\t\t\t\t\t
  • Node Server
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Accounts
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Topics
  • \n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; +#line 41 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Alle Gruppen

\n"; + responseStream << "\t\t
\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
ID
\n"; + responseStream << "\t\t\t\t
Name
\n"; + responseStream << "\t\t\t\t
Alias
\n"; + responseStream << "\t\t\t\t
Url
\n"; + responseStream << "\t\t\t\t
Home
\n"; + responseStream << "\t\t\t\t
"; +#line 54 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( gettext("Description") ); + responseStream << "
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 56 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); responseStream << "\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t
"; +#line 59 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getID() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 60 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getName() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 61 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getAlias() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 62 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getUrl() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 63 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getHome() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 64 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getDescription()); + responseStream << "
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 66 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + } responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t

Eine neue Gruppe anlegen

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\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_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_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 + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/AdminGroupsPage.h b/login_server/src/cpp/HTTPInterface/AdminGroupsPage.h new file mode 100644 index 000000000..43a99ffb4 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminGroupsPage.h @@ -0,0 +1,20 @@ +#ifndef AdminGroupsPage_INCLUDED +#define AdminGroupsPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class AdminGroupsPage: public SessionHTTPRequestHandler +{ +public: + AdminGroupsPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminGroupsPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp b/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp new file mode 100644 index 000000000..19c843f23 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp @@ -0,0 +1,548 @@ +#include "AdminHederaAccountPage.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_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + + +#include "../controller/HederaAccount.h" +#include "../controller/HederaId.h" +#include "../controller/CryptoKey.h" +#include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" +#include "../lib/Success.h" +#include "../SingletonManager/SessionManager.h" + +#include "../ServerConfig.h" + +#include "Poco/URI.h" + +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + +#include "../ServerConfig.h" + + +AdminHederaAccountPage::AdminHederaAccountPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void AdminHederaAccountPage::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 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + + const char* pageName = "Hedera Account"; + auto sm = SessionManager::getInstance(); + auto mm = MemoryManager::getInstance(); + auto user = mSession->getNewUser(); + int auto_renew_period = 604800; // 7 Tage + int auto_renew_account = 0; + double initial_balance = 0.0; + Profiler hedera_time; + std::string hedera_time_string; + + Poco::URI uri(request.getURI()); + auto uri_query = uri.getQueryParameters(); + std::string action = ""; + Poco::AutoPtr query_hedera_account; + + // parsing get query params + if(uri_query.size() >= 2) { + if(uri_query[0].first == "action") { + action = uri_query[0].second; + } + if(uri_query[1].first == "account_id") { + std::string account_id_from_query; + int account_id = 0; + account_id_from_query = uri_query[1].second; + if(DataTypeConverter::strToInt(account_id_from_query, account_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting account_id_from_query to int")); + } else { + auto hedera_accounts = controller::HederaAccount::load("id", account_id); + if(!hedera_accounts.size() || hedera_accounts[0].isNull()) { + addError(new Error("Action", "hedera account not found")); + } else { + query_hedera_account = hedera_accounts[0]; + } + } + } + } + // actions + if(!query_hedera_account.isNull()) + { + if(action == "updateBalance") + { + hedera_time.reset(); + if(query_hedera_account->hederaAccountGetBalance(user)) { + addNotification(new ParamSuccess("Hedera", "crypto get balance success in ", hedera_time.string())); + } else { + addError(new ParamError("Hedera", "crypto get balance failed in ", hedera_time.string())); + } + } + else if(action == "changeEncryption") + { + if(query_hedera_account->changeEncryption(user)) { + addNotification(new Success("Hedera Account", "success in changing encryption")); + } + } + } + else if(!form.empty()) // add or create + { + auto creationButton = form.get("create",""); + if(creationButton != "") { + + // collect + auto auto_renew_account_string = form.get("account-auto-renew-account", "0"); + auto auto_renew_period_string = form.get("account-auto-renew-period", "604800"); + auto account_initial_balance_string = form.get("account-initial-balance", "0"); + + if(!sm->isValid(auto_renew_account_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account", "auto renew account id not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_account_string, auto_renew_account) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew account id to int")); + } + } + + if(!sm->isValid(auto_renew_period_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account", "auto renew period not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_period_string, auto_renew_period) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew period to int")); + } + } + + if(!sm->isValid(account_initial_balance_string, VALIDATE_ONLY_DECIMAL)) { + addError(new Error("Account", "initial balance not an decimal")); + } else { + if(DataTypeConverter::strToDouble(account_initial_balance_string, initial_balance) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Double convert error", "Error converting initial balance to double")); + } + } + if(0 == errorCount()) + { + } + + } else { + + // collect + auto shardNumString = form.get("account-shard-num", "0"); + auto realmNumString = form.get("account-realm-num", "0"); + auto numString = form.get("account-num", "0"); + auto privateKeyString = form.get("account-private-key", ""); + auto privateKeyEncryptedString = form.get("account-private-key-encrypted", "false"); + auto publicKeyString = form.get("account-public-key", ""); + auto networkTypeString = form.get("account-network-type", "0"); + + //printf("private key encrypted: %s\n", privateKeyEncryptedString.data()); + + int shardNum = 0; + int realmNum = 0; + int num = 0; + int networkType = 0; + + MemoryBin* private_key = nullptr; + MemoryBin* public_key = nullptr; + + // validate + if(!sm->isValid(shardNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "shard num not integer")); + } else { + if(DataTypeConverter::strToInt(shardNumString, shardNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting shardNumString to int")); + } + } + if(!sm->isValid(realmNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "realm num not integer")); + } else { + if(DataTypeConverter::strToInt(realmNumString, realmNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting realmNumString to int")); + } + } + if(!sm->isValid(numString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "num not integer")); + } else { + if(DataTypeConverter::strToInt(numString, num) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting num to int")); + } + } + if(!sm->isValid(privateKeyString, VALIDATE_ONLY_HEX)) { + addError(new Error("Account Keys", "private key not hex")); + } + if(!sm->isValid(publicKeyString, VALIDATE_ONLY_HEX)) { + addError(new Error("Account Keys", "public key not hex")); + } + if(!sm->isValid(networkTypeString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Network Type", "not integer")); + } else { + if(DataTypeConverter::strToInt(networkTypeString, networkType) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting network type to int")); + } + if(networkType < 0 || networkType >= (int)ServerConfig::HEDERA_NET_COUNT) { + addError(new Error("Network Type", "invalid value")); + } + } + + if(0 == errorCount()) { + + auto hedera_id = controller::HederaId::create(shardNum, realmNum, num); + + private_key = DataTypeConverter::hexToBin(privateKeyString); + public_key = DataTypeConverter::hexToBin(publicKeyString); + + + KeyPairHedera key_pair(private_key, public_key); + auto crypto_key = controller::CryptoKey::load(key_pair.getPublicKey(), crypto_sign_PUBLICKEYBYTES); + + if(crypto_key.isNull()) { + crypto_key = controller::CryptoKey::create(&key_pair, user, privateKeyEncryptedString == "true"); + if(!crypto_key->getModel()->insertIntoDB(true)) { + addError(new Error("DB Error", "Error saving crypto key in DB")); + } + } else { + printf("crypto key found in db\n"); + } + if(0 == errorCount()) { + + if(hedera_id->isExistInDB()) { + auto hedera_account = controller::HederaAccount::load(hedera_id); + if(hedera_account.isNull()) { + addError(new Error("DB Error", "Couldn't load hedera account from db, but it should exist")); + } else { + addError(new Error("Hedera Account", "Account already exist (same account id")); + } + + } else { + auto hedera_account = controller::HederaAccount::create( + user->getModel()->getID(), + hedera_id->getModel()->getID(), + crypto_key->getModel()->getID(), + 0, + (ServerConfig::HederaNetworkType)networkType + ); + if(!hedera_account->getModel()->insertIntoDB(false)) { + addError(new Error("DB Error", "Error saving hedera account into DB")); + } + } + } + + mm->releaseMemory(private_key); + mm->releaseMemory(public_key); + } + } + } + if(!query_hedera_account.isNull()) { + getErrors(query_hedera_account); + } + // list accounts + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.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_large.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t
  • getGroupBaseUrl() ); + responseStream << "/\">Startseite
  • \n"; + responseStream << "\t\t\t\t\t"; +#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
  • Gruppen
  • \n"; + responseStream << "\t\t\t\t\t
  • Node Server
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Accounts
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Topics
  • \n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; + responseStream << "\n"; +#line 238 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Deine Hedera Accounts

\n"; + responseStream << "\t\t
\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
Hedera Id
\t\t\t\n"; + responseStream << "\t\t\t\t
Balance
\n"; + responseStream << "\t\t\t\t
Server Type
\n"; + responseStream << "\t\t\t\t
Verschlüsselt?
\n"; + responseStream << "\t\t\t\t
Last Updated
\n"; + responseStream << "\t\t\t\t
Aktionen
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 254 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + for(auto it = hedera_accounts.begin(); it != hedera_accounts.end(); it++) { + auto hedera_account_model = (*it)->getModel(); + auto updateUrl = ServerConfig::g_serverPath + "/hedera_account?action=updateBalance&account_id=" + std::to_string(hedera_account_model->getID()); + std::string changeEncryption(""); + if(hedera_account_model->getUserId() == user->getModel()->getID()) { + changeEncryption = ServerConfig::g_serverPath + "/hedera_account?action=changeEncryption&account_id=" + std::to_string(hedera_account_model->getID()); + } + auto isEncrypted = (*it)->getCryptoKey()->getModel()->isEncrypted(); + //printf("change encryption: %s\n", changeEncryption.data()); + + std::string kabuto_url = "https://explorer.kabuto.sh/";; + + if(hedera_account_model->getNetworkType() == ServerConfig::HEDERA_TESTNET) { + kabuto_url += "testnet/"; + } else if(hedera_account_model->getNetworkType() == ServerConfig::HEDERA_MAINNET) { + kabuto_url += "mainnet/"; + } + kabuto_url += "id/"; + auto hedera_id_string = (*it)->getHederaId()->getModel()->toString(); + kabuto_url += hedera_id_string; + responseStream << "\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t
"; +#line 277 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + responseStream << ( hedera_account_model->getBalanceString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 278 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + responseStream << ( model::table::HederaAccount::hederaNetworkTypeToString(hedera_account_model->getNetworkType()) ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 279 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + responseStream << ( isEncrypted ? "Ja": "Nein" ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 280 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + responseStream << ( hedera_account_model->getUpdatedString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t\t"; +#line 285 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + if(changeEncryption != "") { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t\t"; +#line 289 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 292 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" + } responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t

Ein existierenden Account eintragen

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t

Ein neuen Account anlegen

\n"; + responseStream << "\t\t

Bei Hedera einen neuen Account anlegen und zum Start Hashbars von einem existierenden Account überweisen.

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\n"; + responseStream << "\t
\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_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_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 + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.h b/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.h new file mode 100644 index 000000000..b35f6ffb3 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminHederaAccountPage.h @@ -0,0 +1,20 @@ +#ifndef AdminHederaAccountPage_INCLUDED +#define AdminHederaAccountPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class AdminHederaAccountPage: public SessionHTTPRequestHandler +{ +public: + AdminHederaAccountPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminHederaAccountPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.cpp b/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.cpp new file mode 100644 index 000000000..a71aad5bf --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.cpp @@ -0,0 +1,374 @@ +#include "AdminNodeServerPage.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_login_server\\src\\cpsp\\adminNodeServer.cpsp" + + +#include "../controller/NodeServer.h" +#include "../controller/Group.h" +#include "../SingletonManager/SessionManager.h" +#include "../lib/DataTypeConverter.h" + +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + +#include "../ServerConfig.h" + + +AdminNodeServerPage::AdminNodeServerPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void AdminNodeServerPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) +{ + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); + if (_compressResponse) response.set("Content-Encoding", "gzip"); + + Poco::Net::HTMLForm form(request, request.stream()); +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + + const char* pageName = "Node Server"; + auto sm = SessionManager::getInstance(); + auto user = mSession->getNewUser(); + + // add + if(!form.empty()) { + // collect + auto url = form.get("node-server-url", ""); + auto portString = form.get("node-server-port", ""); + auto nodeServerTypeString = form.get("node-server-type", "0"); + auto shardNumString = form.get("account-shard-num", "0"); + auto realmNumString = form.get("account-realm-num", "0"); + auto numString = form.get("account-num", "0"); + auto nodeServerGroupString = form.get("node-server-group", ""); + + int port = 0; + int shardNum = 0; + int realmNum = 0; + int num = 0; + model::table::NodeServerType nodeServerType = model::table::NODE_SERVER_NONE; + int group_id = 0; + + + // validate + if(!sm->isValid(url, VALIDATE_ONLY_URL)) { + addError(new ParamError("Node Server", "Url not valid, must start with http or https", url)); + + } + if(!sm->isValid(portString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Node Server", "Port isn't valid integer")); + } else { + if(DataTypeConverter::strToInt(portString, port) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting port to int")); + } + } + + if(!sm->isValid(nodeServerTypeString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Node Server Type", "not integer")); + } else { + int node_server_type_int = 0; + if(DataTypeConverter::strToInt(nodeServerTypeString, node_server_type_int) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting node server type to int")); + } + if(node_server_type_int < 0 || node_server_type_int >= (int)model::table::NODE_SERVER_TYPE_COUNT) { + addError(new Error("Node Server Type", "invalid value")); + } else { + nodeServerType = (model::table::NodeServerType)node_server_type_int; + } + } + if(model::table::NodeServerIsHederaNode(nodeServerType)) { + + if(!sm->isValid(shardNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "shard num not integer")); + } else { + if(DataTypeConverter::strToInt(shardNumString, shardNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting shardNumString to int")); + } + } + if(!sm->isValid(realmNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "realm num not integer")); + } else { + if(DataTypeConverter::strToInt(realmNumString, realmNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting realmNumString to int")); + } + } + if(!sm->isValid(numString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "num not integer")); + } else { + if(DataTypeConverter::strToInt(numString, num) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting num to int")); + } + } + } else if(model::table::NodeServerHasGroup(nodeServerType)) { + if(!sm->isValid(nodeServerGroupString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Group id", "group_id not integer")); + } else { + if(DataTypeConverter::strToInt(nodeServerGroupString, group_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting group_id to int")); + } + } + } + + + + if(0 == errorCount()) { + int hedera_id_int = 0; + if(NodeServerIsHederaNode(nodeServerType)) { + auto hedera_id = controller::HederaId::create(shardNum, realmNum, num); + hedera_id_int = hedera_id->getModel()->getID(); + } + + auto node_server = controller::NodeServer::create( + url, port, group_id, (model::table::NodeServerType)nodeServerType, hedera_id_int + ); + if(!node_server->getModel()->insertIntoDB(false)) { + addError(new Error("DB Error", "Error saving Node Server in DB")); + } + } + } + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } + + auto node_servers = controller::NodeServer::listAll(); + + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.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_large.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t
  • getGroupBaseUrl() ); + responseStream << "/\">Startseite
  • \n"; + responseStream << "\t\t\t\t\t"; +#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
  • Gruppen
  • \n"; + responseStream << "\t\t\t\t\t
  • Node Server
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Accounts
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Topics
  • \n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; +#line 127 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Alle Node Server

\n"; + responseStream << "\t\t
\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
Server Type
\n"; + responseStream << "\t\t\t\t
Url:Port
\n"; + responseStream << "\t\t\t\t
Group / Hedera Id
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + for(auto it = node_servers.begin(); it != node_servers.end(); it++) { + auto node_server_model = (*it)->getModel(); + responseStream << "\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t
"; +#line 143 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( model::table::NodeServer::nodeServerTypeToString(node_server_model->getNodeServerType()) ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( node_server_model->getUrlWithPort() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t\t"; +#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + if(node_server_model->isHederaNode()) { + auto hedera_id_model = (*it)->getHederaId()->getModel(); responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t"; +#line 148 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( hedera_id_model->toString() ); + responseStream << "\n"; + responseStream << "\t\t\t\t\t\t"; +#line 149 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + } else if(node_server_model->hasGroup()){ + auto groupIt = group_indices.find(node_server_model->getGroupId()); + if(groupIt != group_indices.end()) { + auto group_model = groups[groupIt->second]->getModel(); responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t\tgetDescription() ); + responseStream << "\">"; +#line 153 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( group_model->getName() ); + responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t"; +#line 154 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t\t"; +#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + responseStream << ( node_server_model->getGroupId() ); + responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\t"; +#line 156 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\t"; +#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 160 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServer.cpsp" + } responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t

Ein Node Server hinzufügen

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\tNur für Hedera Nodes\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\tNur für Gradido Nodes\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\n"; + responseStream << "
\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_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_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 + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.h b/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.h new file mode 100644 index 000000000..4a60b45e7 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminNodeServerPage.h @@ -0,0 +1,20 @@ +#ifndef AdminNodeServerPage_INCLUDED +#define AdminNodeServerPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class AdminNodeServerPage: public SessionHTTPRequestHandler +{ +public: + AdminNodeServerPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminNodeServerPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.cpp b/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.cpp new file mode 100644 index 000000000..84c63a508 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.cpp @@ -0,0 +1,866 @@ +#include "AdminNodeServerTestPage.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/DeflatingStream.h" + + +#line 6 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + +#include "../controller/NodeServer.h" +#include "../controller/User.h" +#include "../controller/HederaTopic.h" +#include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" +#include "../lib/JsonRPCRequest.h" +#include "../model/gradido/Transaction.h" + +#include "Poco/Thread.h" +#include "Poco/DateTime.h" +#include "Poco/JSON/Stringifier.h" + +enum PageType +{ + PAGE_CHOOSE_TEST, + PAGE_RUN_4_SET_TEST, + PAGE_GET_TRANSACTION_RPC_CALL +}; + +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + +#include "../ServerConfig.h" + + +void AdminNodeServerTestPage::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 28 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + const char* pageName = "Node Server Test"; + PageType page = PAGE_CHOOSE_TEST; + Poco::AutoPtr node_server; + Poco::AutoPtr node_server2; + Poco::AutoPtr user; + Poco::AutoPtr hedera_topic; + Poco::AutoPtr hedera_topic2; + int hedera_timeout = 4; + int sleep_ms_between_transactions = 1000; + + bool steps[8]; memset(steps, 1, 8 * sizeof(bool)); + + + if(!form.empty()) + { + auto node_server_id_string = form.get("test-node-servers", ""); + if(node_server_id_string != "") { + int node_server_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) { + node_server = controller::NodeServer::load(node_server_id); + } + } + node_server_id_string = form.get("test-node-servers2", ""); + if(node_server_id_string != "") { + int node_server_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) { + node_server2 = controller::NodeServer::load(node_server_id); + } + } + auto topic_id_string = form.get("test-hedera-topic", ""); + if(topic_id_string != "") { + int topic_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) { + hedera_topic = controller::HederaTopic::load(topic_id); + } + } + topic_id_string = form.get("test-hedera-topic2", ""); + if(topic_id_string != "") { + int topic_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) { + hedera_topic2 = controller::HederaTopic::load(topic_id); + } + } + auto test_timeout_string = form.get("test-timeout", ""); + if(test_timeout_string != "") { + DataTypeConverter::strToInt(test_timeout_string, hedera_timeout); + } + auto test_part_timeout_string = form.get("test-part-timeout", ""); + if(test_part_timeout_string != "") { + DataTypeConverter::strToInt(test_part_timeout_string, sleep_ms_between_transactions); + } + auto submit = form.get("submit", ""); + if(submit == "Run 6-Test") { + page = PAGE_RUN_4_SET_TEST; + } else if(submit == "json-rpc getTransactions") { + page = PAGE_GET_TRANSACTION_RPC_CALL; + } + std::string step_temp; + for(int i = 0; i < 8; i++) { + std::string name = "step-"; + name += std::to_string(i+2); + step_temp = form.get(name, ""); + if(step_temp == "1") { + steps[i] = true; + } else { + steps[i] = false; + } + } + } + + auto node_servers = controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_NODE); + auto hedera_topics = controller::HederaTopic::listAll(); + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.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_large.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t
  • getGroupBaseUrl() ); + responseStream << "/\">Startseite
  • \n"; + responseStream << "\t\t\t\t\t"; +#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
  • Gruppen
  • \n"; + responseStream << "\t\t\t\t\t
  • Node Server
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Accounts
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Topics
  • \n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; +#line 103 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\n"; + responseStream << "\t
\n"; + responseStream << "\t \n"; + responseStream << "\t \n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Test 6-Set (3 AddMember, Creation, 2 Transfer)\n"; + responseStream << "\t\t

\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t

1. Create three new accounts and show user public keys for comparisation

\n"; + responseStream << "\t\t\t\t

2. Send a add-member transaction to hedera topic with one signature (first user)

\n"; + responseStream << "\t\t\t\t

3. Send a add-member transaction to hedera topic with two signatures (first user and second user)

\n"; + responseStream << "\t\t\t\t

4. Send a creation transaction to second user, signed by first user

\n"; + responseStream << "\t\t\t\t

5. Send a transfer transaction from second user to first user signed by second user

\n"; + responseStream << "\t\t\t\t

6. Send a add-member transaction to hedera topic 2 with one signature (third user)

\n"; + responseStream << "\t\t\t\t

7. Send a cross group transfer from second user to third user signed by second user

\n"; + responseStream << "\t\t\t\t

8. Wait x seconds to give hedera time to process transactions

\n"; + responseStream << "\t\t\t\t

9. Ask choosen node for transaction and print result

\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\tGroup 1 \n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 128 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(node_servers.size() == 0) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\tEdit Node-Servers\n"; + responseStream << "\t\t\t\t\t"; +#line 130 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(hedera_topics.size() == 0) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\tEdit Hedera-Topics\n"; + responseStream << "\t\t\t\t\t"; +#line 141 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\tGroup 2 \n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(node_servers.size() == 0) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\tEdit Node-Servers\n"; + responseStream << "\t\t\t\t\t"; +#line 159 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 168 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(hedera_topics.size() == 0) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\tEdit Hedera-Topics\n"; + responseStream << "\t\t\t\t\t"; +#line 170 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t seconds \n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t ms\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Test 4-Set (2 AddMember, Creation, Transfer)\n"; + responseStream << "\t\t

\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t"; +#line 199 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(node_servers.size() == 0) { responseStream << "\n"; + responseStream << "\t\t\t\t\tEdit Node-Servers\n"; + responseStream << "\t\t\t\t"; +#line 201 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t"; +#line 213 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(PAGE_RUN_4_SET_TEST == page && !hedera_topic.isNull() && !node_server.isNull()) { responseStream << "\n"; + responseStream << "\t
    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    1. Create three new accounts and show user public keys for comparisation:

    \n"; + responseStream << "\t\t\t"; +#line 217 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + Profiler time2; + auto group_id = hedera_topic->getModel()->getGroupId(); + auto group_id2 = hedera_topic2->getModel()->getGroupId(); + auto user_group = controller::Group::load(group_id); + auto user_group2 = controller::Group::load(group_id2); + auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; + + std::string password1 = "hsaj(2askaslASlllak3wjjeudsaj"; + auto user_1 = controller::User::create("testEmail@google.de", "Max", "Mustermann", group_id); + auto passphrase_1 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_1 = KeyPairEd25519::create(passphrase_1); + user_1->setGradidoKeyPair(gradido_key_pair_1); + user_1->login(password1); + + std::string password2 = "uweia8saiSale,dsasA"; + auto user_2 = controller::User::create("testEmail2@google.de", "MJax", "Mustrermann", group_id); + auto passphrase_2 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_2 = KeyPairEd25519::create(passphrase_2); + user_2->setGradidoKeyPair(gradido_key_pair_2); + user_2->login(password2); + + std::string password3 = "jaue_skaiellasealaK"; + auto user_3 = controller::User::create("testEmail3@gmail.com", "Morpheus", "Miaufull", group_id2); + auto passphrase_3 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_3 = KeyPairEd25519::create(passphrase_3); + user_3->setGradidoKeyPair(gradido_key_pair_3); + user_3->login(password3); + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t
    "; +#line 246 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( user_group->getModel()->getName() ); + responseStream << "\n"; + responseStream << "\t\t\t\t

    User 1: "; +#line 247 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( user_1->getPublicHex() ); + responseStream << "

    \n"; + responseStream << "\t\t\t\t

    User 2: "; +#line 248 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( user_2->getPublicHex() ); + responseStream << "

    \n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t
    "; +#line 250 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( user_group2->getModel()->getName() ); + responseStream << "\n"; + responseStream << "\t\t\t\t

    User 3: "; +#line 251 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( user_3->getPublicHex() ); + responseStream << "

    \n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t

    Time: "; +#line 253 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "\n"; + responseStream << "\t\t

  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    2. Send a add-member transaction to hedera topic with one signature (first user)

    \n"; + responseStream << "\t\t\t"; +#line 257 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[0]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 261 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto transaction1 = model::gradido::Transaction::createGroupMemberUpdate(user_1, user_group); + transaction1->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1); + transaction1->sign(user_1); + auto transaction1_json = transaction1->getTransactionAsJson(true); + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 267 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction1_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t"; +#line 268 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 269 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "\n"; + responseStream << "\t\t

  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    3. Send a add-member transaction to hedera topic with two signatures (first user and second user)

    \n"; + responseStream << "\t\t\t"; +#line 273 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[1]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 277 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto transaction2 = model::gradido::Transaction::createGroupMemberUpdate(user_2, user_group); + transaction2->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(2); + transaction2->sign(user_2); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction2->sign(user_1); + auto transaction2_json = transaction2->getTransactionAsJson(true); + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 286 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction2_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t"; +#line 287 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 288 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "\n"; + responseStream << "\t\t

  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    4. Send a creation transaction to second user, signed by first user

    \n"; + responseStream << "\t\t\t"; +#line 292 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[2]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 296 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto transaction3 = model::gradido::Transaction::createCreation(user_2, 10000000, Poco::DateTime(), "Test Creation"); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction3->sign(user_1); + auto transaction3_json = transaction3->getTransactionAsJson(true); + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 303 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction3_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t"; +#line 304 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 305 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "

    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    5. Send a transfer transaction from second user to first user signed by second user

    \n"; + responseStream << "\t\t\t"; +#line 309 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[3]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 313 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto user_1_pubkey = user_1->getModel()->getPublicKeyCopy(); + auto transaction4 = model::gradido::Transaction::createTransfer(user_2, user_1_pubkey, user_group, 5000000, "Test Transfer"); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction4[0]->sign(user_2); + auto transaction4_json = transaction4[0]->getTransactionAsJson(true); + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 321 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction4_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t"; +#line 322 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 323 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "

    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    6. Send a add-member transaction to hedera topic 2 with one signature (third user)

    \n"; + responseStream << "\t\t\t"; +#line 327 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[4]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 331 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto transaction5 = model::gradido::Transaction::createGroupMemberUpdate(user_3, user_group2); + transaction5->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1); + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction5->sign(user_3); + auto transaction5_json = transaction5->getTransactionAsJson(true); + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 338 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction5_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t"; +#line 339 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 340 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "

    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    7. Send a cross group transfer from second user to third user signed by second user

    \n"; + responseStream << "\t\t\t"; +#line 344 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + time2.reset(); + if(!steps[5]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 348 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto user_3_pubkey = user_3->getModel()->getPublicKeyCopy(); + auto transaction6 = model::gradido::Transaction::createTransfer(user_2, user_3_pubkey, user_group2, 4000000, "Test Group Transfer", false); + if(!transaction6.size()) { + responseStream << "\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\treport_problem\n"; + responseStream << "\t\t\t\t\tError creating Transaction\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t"; +#line 357 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + } else { + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction6[0]->sign(user_2); + auto transaction6_json = transaction6[0]->getTransactionAsJson(true); + auto paired_transaction = transaction6[0]->getPairedTransaction(); + responseStream << "\n"; + responseStream << "\t\t\t\t\t

    "; +#line 364 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction6_json) ); + responseStream << "

    \t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 365 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(!paired_transaction.isNull()) { + auto transaction6_2_json = paired_transaction->getTransactionAsJson(true); + responseStream << "

    "; +#line 367 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(transaction6_2_json) ); + responseStream << "

    \n"; + responseStream << "\t\t\t\t\t"; +#line 368 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 369 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t"; +#line 370 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << " \n"; + responseStream << "\t\t\t

    Time: "; +#line 371 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "

    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    8. Wait "; +#line 374 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( hedera_timeout ); + responseStream << " seconds to give hedera time to process transactions

    \n"; + responseStream << "\t\t\t"; +#line 375 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + if(!steps[6]) { responseStream << "\n"; + responseStream << "\t\t\t\t

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 377 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + Poco::Thread::sleep(hedera_timeout * 1000); + } responseStream << "\n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t\t\t

    9. Ask choosen node for transaction and print result

    \n"; + responseStream << "\t\t\t"; +#line 383 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + time2.reset(); + if(!steps[7] || node_server.isNull()) { + responseStream << "

    skipped

    \n"; + responseStream << "\t\t\t"; +#line 386 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else { + auto node_server_model = node_server->getModel(); + JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort()); + Poco::JSON::Object params; + params.set("groupAlias", user_group->getModel()->getAlias()); + params.set("lastKnownSequenceNumber", 0); + auto gn_answear = jsonrpc.request("getTransactions", params); + if(!gn_answear.isNull()) { + std::stringstream ss; + Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER); + std::string answear_string = ss.str(); responseStream << "\n"; + responseStream << "\t\t\t\t\t"; +#line 397 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(answear_string) ); +#line 397 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + } + } responseStream << "\n"; + responseStream << "\t\t\t

    Time: "; +#line 400 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time2.string() ); + responseStream << "

    \n"; + responseStream << "\t\t
  • \n"; + responseStream << "\t
\n"; + responseStream << "\t"; +#line 403 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } else if(PAGE_GET_TRANSACTION_RPC_CALL == page && !node_server.isNull()) { + Profiler time3; + auto node_server_model = node_server->getModel(); + auto user_group = controller::Group::load(node_server_model->getGroupId()); + JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort()); + Poco::JSON::Object params; + params.set("groupAlias", user_group->getModel()->getAlias()); + params.set("lastKnownSequenceNumber", 0); + auto gn_answear = jsonrpc.request("getTransactions", params); + if(!gn_answear.isNull()) { + std::stringstream ss; + Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER); + std::string answear_string = ss.str(); responseStream << "\n"; + responseStream << "\t\t\t"; +#line 416 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( DataTypeConverter::replaceNewLineWithBr(answear_string) ); +#line 416 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + + } + responseStream << "\n"; + responseStream << "\t\t

Time: "; +#line 419 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + responseStream << ( time3.string() ); + responseStream << "

\n"; + responseStream << "\t"; +#line 420 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminNodeServerTest.cpsp" + } responseStream << "\n"; + responseStream << "\t\n"; + responseStream << "
\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_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_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 + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.h b/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.h new file mode 100644 index 000000000..12e550efa --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminNodeServerTestPage.h @@ -0,0 +1,18 @@ +#ifndef AdminNodeServerTestPage_INCLUDED +#define AdminNodeServerTestPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "PageRequestMessagedHandler.h" + + +class AdminNodeServerTestPage: public PageRequestMessagedHandler +{ +public: + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminNodeServerTestPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/AdminTopicPage.cpp b/login_server/src/cpp/HTTPInterface/AdminTopicPage.cpp new file mode 100644 index 000000000..afa2f546e --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminTopicPage.cpp @@ -0,0 +1,558 @@ +#include "AdminTopicPage.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_login_server\\src\\cpsp\\adminTopic.cpsp" + + #include "../controller/HederaAccount.h" + #include "../controller/HederaTopic.h" + #include "../controller/Group.h" + #include "../SingletonManager/SessionManager.h" + #include "../ServerConfig.h" + + #include "../lib/DataTypeConverter.h" + #include "../lib/Profiler.h" + #include "../lib/Success.h" + + #include "Poco/Timespan.h" + #include "Poco/URI.h" +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + +#include "../ServerConfig.h" + + +AdminTopicPage::AdminTopicPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void AdminTopicPage::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 21 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + + const char* pageName = "Topic"; + auto user = mSession->getNewUser(); + auto sm = SessionManager::getInstance(); + Profiler hedera_time; + + std::string name = ""; + std::string topic_id_string = ""; + int auto_renew_account = 0; + int auto_renew_period = 7890000; // 3 Monate + + int group_id = 0; + + Poco::URI uri(request.getURI()); + auto uri_query = uri.getQueryParameters(); + std::string action = ""; + Poco::AutoPtr query_hedera_topic; + + // parsing get query params + if(uri_query.size() >= 2) { + if(uri_query[0].first == "action") { + action = uri_query[0].second; + } + if(uri_query[1].first == "topic_id") { + std::string topic_id_from_query; + int topic_id = 0; + topic_id_from_query = uri_query[1].second; + if(DataTypeConverter::strToInt(topic_id_from_query, topic_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting topic_id_from_query to int")); + } else { + auto hedera_topic = controller::HederaTopic::load(topic_id); + if(hedera_topic.isNull()) { + addError(new Error("Action", "hedera topic not found")); + } else { + query_hedera_topic = hedera_topic; + } + } + } + } + // actions + if(!query_hedera_topic.isNull()) + { + if(action == "getTopicInfos") + { + hedera_time.reset(); + if(query_hedera_topic->updateWithGetTopicInfos(user)) { + addNotification(new ParamSuccess("Hedera", "hedera get topic infos success in ", hedera_time.string())); + } else { + addError(new ParamError("Hedera", "hedera get topic infos failed in ", hedera_time.string())); + } + getErrors(query_hedera_topic); + } + } + else if(!form.empty()) + { + name = form.get("topic-name", ""); + topic_id_string = form.get("topic-id", ""); + auto auto_renew_account_string = form.get("topic-auto-renew-account", "0"); + auto auto_renew_period_string = form.get("topic-auto-renew-period", "7890000"); + auto group_id_string = form.get("topic-group", "-1"); + Poco::AutoPtr topic_id; + + if(topic_id_string != "" && sm->isValid(topic_id_string, VALIDATE_HEDERA_ID)) { + topic_id = controller::HederaId::create(topic_id_string); + if(topic_id.isNull()) { + addError(new Error("Hedera Id", "cannot parse hedera id")); + } + + } else { + + if(name != "" && !sm->isValid(name, VALIDATE_NAME)) { + addError(new Error("Topic", "Name not valid, at least 3 Character")); + } + + if(!sm->isValid(auto_renew_account_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew account id not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_account_string, auto_renew_account) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew account id to int")); + } + } + + if(!sm->isValid(auto_renew_period_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew period not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_period_string, auto_renew_period) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew period to int")); + } + } + } + + if(!sm->isValid(group_id_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "group_id not an integer")); + } else { + if(DataTypeConverter::strToInt(group_id_string, group_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting group_id to int")); + } + } + //const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId + + // add or create topic? + // add topic + if(!topic_id.isNull()) { + if(topic_id->getModel()->insertIntoDB(true)) { + auto hedera_topic = controller::HederaTopic::loadFromHedera(topic_id, group_id, user); + if(!hedera_topic.isNull()) { + hedera_topic->getModel()->insertIntoDB(false); + } else { + addError(new Error("Hedera Topic", "error load topic from hedera")); + } + } else { + addError(new Error("Hedera Id", "Error saving hedera id")); + } + // create topic + } else { + auto hedera_topic = controller::HederaTopic::create(name, auto_renew_account, auto_renew_period, group_id); + if(!hedera_topic->getModel()->insertIntoDB(true)) { + addError(new Error("Topic", "error saving into db")); + } else { + auto payer = controller::HederaAccount::load(auto_renew_account); + if(payer.isNull()) { + addError(new Error("Payer", "payer account not found")); + } else { + auto hedera_task = hedera_topic->createTopic(payer, user); + if(hedera_task.isNull()) { + addError(new Error("Create Topic", "Failed")); + getErrors(hedera_topic); + } + } + } + } + + } + + + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + //std::vector> hedera_accounts; + + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } + + auto hedera_topics = controller::HederaTopic::listAll(); + //std::vector> hedera_topics; + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.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_large.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t
  • getGroupBaseUrl() ); + responseStream << "/\">Startseite
  • \n"; + responseStream << "\t\t\t\t\t"; +#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
  • Gruppen
  • \n"; + responseStream << "\t\t\t\t\t
  • Node Server
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Accounts
  • \n"; + responseStream << "\t\t\t\t\t
  • Hedera Topics
  • \n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; + responseStream << "\n"; +#line 180 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t

Topic Admin Page

\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Hedera Topics

\n"; + responseStream << "\t\t
\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
Topic ID
\t\t\t\n"; + responseStream << "\t\t\t\t
Name
\n"; + responseStream << "\t\t\t\t
Network Type
\n"; + responseStream << "\t\t\t\t
Auto Renew Account Balance
\n"; + responseStream << "\t\t\t\t
Auto Renew Period
\n"; + responseStream << "\t\t\t\t
Group ID
\n"; + responseStream << "\t\t\t\t
Current Timeout
\n"; + responseStream << "\t\t\t\t
Sequence Number
\n"; + responseStream << "\t\t\t\t
Last Updated
\n"; + responseStream << "\t\t\t\t
Aktionen
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 202 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) { + auto hedera_topic_model = (*it)->getModel(); + auto updateUrl = ServerConfig::g_serverPath + "/topic?action=getTopicInfos&topic_id=" + std::to_string(hedera_topic_model->getID()); + std::string kabuto_url = "https://explorer.kabuto.sh/";//testnet/id/0.0.132132; + + + auto auto_renew_account = (*it)->getAutoRenewAccount(); + auto renew_account_model = auto_renew_account->getModel(); + + if(renew_account_model->getNetworkType() == ServerConfig::HEDERA_TESTNET) { + kabuto_url += "testnet/"; + } else if(renew_account_model->getNetworkType() == ServerConfig::HEDERA_MAINNET) { + kabuto_url += "mainnet/"; + } + kabuto_url += "id/"; + + std::string timeout_color = "success-color"; + if(hedera_topic_model->getCurrentTimeout() < Poco::DateTime()) { + timeout_color = "alert-color"; + } else if((hedera_topic_model->getCurrentTimeout() - Poco::DateTime()) < Poco::Timespan(2,0,0,0,0)) { + timeout_color = "orange-color"; + } + std::string topic_hedera_id_string = ""; + auto topic_hedera_id = (*it)->getTopicHederaId(); + if(!topic_hedera_id.isNull()) { + topic_hedera_id_string = topic_hedera_id->getModel()->toString(); + kabuto_url += topic_hedera_id_string; + } + + + responseStream << "\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t
"; +#line 235 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getName() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 236 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( model::table::HederaAccount::hederaNetworkTypeToString(renew_account_model->getNetworkType()) ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 237 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( renew_account_model->getBalanceString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 238 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getAutoRenewPeriodString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 239 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getGroupId() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 240 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getCurrentTimeoutString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 241 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getSequenceNumber() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 242 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << ( hedera_topic_model->getUpdatedString() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 243 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + if(!topic_hedera_id.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t\t"; +#line 247 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 250 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + } responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\n"; + responseStream << "\t
\n"; + responseStream << "\t \n"; + responseStream << "\t \n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Ein neues Topic anlegen

\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Ein bestehendes Topic eintragen

\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\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_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_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 + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << ""; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/AdminTopicPage.h b/login_server/src/cpp/HTTPInterface/AdminTopicPage.h new file mode 100644 index 000000000..b02e5856c --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/AdminTopicPage.h @@ -0,0 +1,20 @@ +#ifndef AdminTopicPage_INCLUDED +#define AdminTopicPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class AdminTopicPage: public SessionHTTPRequestHandler +{ +public: + AdminTopicPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminTopicPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp b/login_server/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp index 42778fd45..d26eec225 100644 --- a/login_server/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp +++ b/login_server/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp @@ -10,7 +10,7 @@ // includes #include "../controller/User.h" #include "../controller/EmailVerificationCode.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" enum PageState @@ -43,7 +43,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request PageState state = PAGE_ASK_EMAIL; Poco::AutoPtr user = controller::User::create(); Poco::AutoPtr code; - Poco::AutoPtr userBackup; + Poco::AutoPtr userBackup; bool validUser = false; std::string pageName = "Admin User Passwort Reset"; @@ -69,11 +69,11 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request } } - auto backups = controller::UserBackups::load(userId); + auto backups = controller::UserBackup::load(userId); auto userPubkey = user->getModel()->getPublicKey(); for(auto it = backups.begin(); it != backups.end(); it++) { auto keys = (*it)->getKeyPair(); - if(keys->isPubkeysTheSame(userPubkey)) { + if(keys->isTheSame(userPubkey)) { userBackup = *it; break; } @@ -235,7 +235,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "Bitte schreibe sie dir auf und packe sie gut weg.\n"; responseStream << "\n"; #line 105 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" - responseStream << ( controller::UserBackups::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) ); + responseStream << ( controller::UserBackup::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) ); responseStream << "\n"; responseStream << " \n"; responseStream << "\n"; diff --git a/login_server/src/cpp/HTTPInterface/CheckEmailPage.cpp b/login_server/src/cpp/HTTPInterface/CheckEmailPage.cpp index b140451c6..0fdd4bbe3 100644 --- a/login_server/src/cpp/HTTPInterface/CheckEmailPage.cpp +++ b/login_server/src/cpp/HTTPInterface/CheckEmailPage.cpp @@ -42,6 +42,7 @@ void CheckEmailPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: auto lm = LanguageManager::getInstance(); auto em = EmailManager::getInstance(); + auto user = mSession->getNewUser(); auto lang = chooseLanguage(request); auto langCatalog = lm->getFreeCatalog(lang); unsigned long long verificationCode = 0; @@ -142,7 +143,7 @@ void CheckEmailPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "
"; // end include header.cpsp responseStream << "\n"; -#line 68 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 69 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "
\n"; @@ -176,85 +177,85 @@ void CheckEmailPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\n"; responseStream << "
\n"; responseStream << "

"; -#line 72 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 73 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("E-Mail verifizieren") ); responseStream << "

\n"; responseStream << "
\n"; responseStream << "
\n"; responseStream << "
\n"; responseStream << "\t"; -#line 76 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 77 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" if(EMAIL_ACTIVATED == state) { responseStream << "\n"; responseStream << "\t\t

"; -#line 77 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 78 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("Deine E-Mail wurde erfolgreich bestätigt. Du kannst nun Gradidos versenden.") ); responseStream << "

\n"; responseStream << "\t\t"; -#line 78 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 79 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("Zur Startseite") ); responseStream << "\n"; responseStream << "\t"; -#line 79 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 80 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" } else { responseStream << "\n"; responseStream << " \n"; responseStream << " gettext("Email Verification Code")); responseStream << "\" "; -#line 81 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 82 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" if(verificationCode) { responseStream << "value=\""; -#line 81 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 82 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( verificationCode ); responseStream << "\" "; -#line 81 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 82 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" } responseStream << ">\n"; responseStream << " \n"; responseStream << " \n"; responseStream << " \n"; responseStream << "

\n"; responseStream << "\t\t"; -#line 89 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 90 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("Funktioniert dein E-Mail Verification Code nicht?")); responseStream << "
\n"; responseStream << "\t\t"; -#line 90 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 91 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("Schicke uns eine E-Mail und wir kümmern uns darum: ")); responseStream << "
\n"; responseStream << " getAdminReceiver()); responseStream << "?subject=Invalid E-Mail Verification Code&body=Hallo Dario,%0D%0A%0D%0Amein E-Mail Verification-Code: "; -#line 91 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( verificationCode ); responseStream << " funktioniert nicht,%0D%0Akannst du das prüfen?%0D%0A%0D%0AMit freundlichen Grüßen%0D%0A\">"; -#line 91 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" responseStream << ( langCatalog->gettext("E-Mail an Support schicken")); responseStream << "\n"; responseStream << "\t

\n"; responseStream << " \n"; responseStream << " "; -#line 94 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" +#line 95 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkEmail.cpsp" } responseStream << "\n"; responseStream << "
\n"; responseStream << "
\n"; diff --git a/login_server/src/cpp/HTTPInterface/CheckTransactionPage.cpp b/login_server/src/cpp/HTTPInterface/CheckTransactionPage.cpp index cb060fe07..89aa80aec 100644 --- a/login_server/src/cpp/HTTPInterface/CheckTransactionPage.cpp +++ b/login_server/src/cpp/HTTPInterface/CheckTransactionPage.cpp @@ -10,14 +10,18 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/SingletonTaskObserver.h" #include "../SingletonManager/EmailManager.h" -#include "../model/TransactionCreation.h" -#include "../model/TransactionTransfer.h" +#include "../SingletonManager/PendingTasksManager.h" +#include "../model/gradido/TransactionCreation.h" +#include "../model/gradido/TransactionTransfer.h" + +#include "../lib/DataTypeConverter.h" #include "Poco/Thread.h" enum PageState { PAGE_TRANSACTION_CREATION, PAGE_TRANSACTION_TRANSFER, + PAGE_TRANSACTION_GROUP_ADD_MEMBER, PAGE_NO_TRANSACTIONS, PAGE_USER_DATA_CORRUPTED }; @@ -42,23 +46,43 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, const char* pageName = gettext("Überprüfe Transaktion"); auto account_user = mSession->getNewUser(); + auto user = account_user; auto user_model = account_user->getModel(); auto em = EmailManager::getInstance(); + auto pt = PendingTasksManager::getInstance(); auto userBalance = account_user->getBalance(); std::string memo = ""; bool hasErrors = false; bool enableLogout = true; + bool enableSign = true; + int skip_count = 0; + int pending_task_id = 0; + + std::string community_server_base_path = ServerConfig::g_php_serverPath; + if(user_model->getGroupId() != 0) { + community_server_base_path = user->getGroupBaseUrl(); + } PageState state = PAGE_NO_TRANSACTIONS; - + if(!user_model->isEmailChecked()) { addError(new Error(gettext("E-Mail Aktivierung"), gettext("E-Mail wurde noch nicht aktiviert, du kannst leider noch keine Transaktionen ausführen!"))); hasErrors = true; } - + bool transaction_finalize_run = false; bool transaction_finalize_result = false; + auto transactions_to_sign = pt->getTransactionsUserMustSign(account_user); + //Poco::AutoPtr pending_task; + model::gradido::Transaction* transaction = nullptr; + Poco::AutoPtr transaction_body; + + if(!form.empty()) + { + transaction = dynamic_cast(transactions_to_sign[0].get()); + transaction_body = transaction->getTransactionBody(); + if(!form.empty()) { auto ok = form.get("ok", ""); auto abort = form.get("abort", ""); @@ -116,25 +140,171 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, breakCount++; Poco::Thread::sleep(10); }*/ - auto lastExternReferer = mSession->getLastReferer(); - //lastExternReferer = ""; - if(lastExternReferer != "" && lastExternReferer.find("transaction-send-coins") == std::string::npos) { - //printf("last extern referer: %s\n", lastExternReferer.data()); - response.redirect(lastExternReferer); + auto pending_task_id_string = form.get("pending-task-id", ""); + int pending_task_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(pending_task_id_string, pending_task_id)) + { + // make sure we have the correct transaction + transaction = nullptr; + printf("transaction_body isNull: %d\n", transaction_body.isNull()); + transaction_body.assign(nullptr); + for(auto it = transactions_to_sign.begin(); it != transactions_to_sign.end(); it++) + { + if((*it)->getModel()->getID() == pending_task_id) { + transaction = dynamic_cast(it->get()); + transaction_body = transaction->getTransactionBody(); + printf("set new transaction and transaction_body\n"); + break; + } + } + if(abort != "") + /* + auto ok = form.get("ok", ""); + auto abort = form.get("abort", ""); + auto skip = form.get("skip", ""); + auto skip_count_str = form.get("skip-count", "0"); + auto pending_task_id_string = form.get("pending-task-id", ""); + DataTypeConverter::strToInt(skip_count_str, skip_count); + + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(pending_task_id_string, pending_task_id)) + { + // load transaction from pending task manager + pending_task = pt->getPendingTask(pending_task_id); + if(!pending_task.isNull() && pending_task->getModel()->isGradidoTransaction()) + */ + { + transaction = dynamic_cast(pending_task.get()); + if(transaction->hasSigned(account_user)) { + transaction = nullptr; + } else { + transaction_body = transaction->getTransactionBody(); + } + + if(abort != "") + { + //mSession->finalizeTransaction(false, true); + // + if(transaction && transaction->getModel()->getUserId() == user_model->getID()) + { + transaction->deleteFromDB(); + transaction = nullptr; + } + } + else if(ok != "") + { + if(!account_user->hasPassword()) { + auto pwd = form.get("sign-password", ""); + auto loginResult = account_user->login(pwd); + switch(loginResult) { + case 0: + addError(new Error(gettext("Passwort"), gettext("Das Passwort stimmt nicht. Bitte verwende dein Passwort von der Registrierung"))); + hasErrors = true; + break; + case -1: + case -2: + addError(new Error(gettext("Passwort"), gettext("Gespeicherte Daten sind korrupt!"))); + hasErrors = true; + state = PAGE_USER_DATA_CORRUPTED; + enableSign = false; + break; + case -3: + addError(new Error(gettext("Passwort"), gettext("Passwortprüfung läuft schon, bitte versuche es in 1-2 Minuten erneut."))); + hasErrors = true; + break; + } + } + if(!hasErrors) { + //mSession->finalizeTransaction(true, false); + if(transaction && transaction->sign(account_user)) { + transaction = nullptr; + } + } + } + else if(skip != "") + { + skip_count++; + transaction = nullptr; + } + } else { + addError(new Error(gettext("Input Error"), gettext("Task no found"))); + } } else { - response.redirect(ServerConfig::g_php_serverPath + "state-balances/overview"); + addError(new Error(gettext("Form Error"), gettext("error with field"))); + } + } + + auto transactions_user_must_sign = pt->getTransactionsUserMustSign(account_user); + std::vector> transactions_someone_must_sign; + // TODO: work with community server roles + if(user_model->getRole() == model::table::ROLE_ADMIN) { + transactions_someone_must_sign = pt->getTransactionSomeoneMustSign(account_user); + } + std::vector> transactions_to_sign; + bool transaction_removeable = false; + int transaction_to_sign_index = 0; + if(!transaction) + { + if(transactions_user_must_sign.size() > skip_count) { + transactions_to_sign = transactions_user_must_sign; + transaction_to_sign_index = skip_count; + } else if(transactions_someone_must_sign.size() > (skip_count - transactions_user_must_sign.size())) { + transactions_to_sign = transactions_someone_must_sign; + transaction_to_sign_index = skip_count - transactions_user_must_sign.size(); + } + + if(transactions_to_sign.size() > transaction_to_sign_index) + { + transaction = dynamic_cast(transactions_to_sign[transaction_to_sign_index].get()); + transaction_body = transaction->getTransactionBody(); + // user can only delete there own transactions + // TODO: Auto timeout for community transactions + if(transaction->getModel()->getUserId() == user_model->getID()) { + transaction_removeable = true; + } + } + } + size_t sumTransactions = transactions_user_must_sign.size() + transactions_someone_must_sign.size(); + if(sumTransactions == 0) + { + auto lastExternReferer = mSession->getLastReferer(); + auto callerUri = mSession->getCallerUri(); + //lastExternReferer = ""; + account_user->reload(); + if(callerUri != "") { + response.redirect(callerUri); + } else if(lastExternReferer != "" && lastExternReferer.find("transaction-send-coins") == std::string::npos) { + response.redirect(lastExternReferer); + } else if(!account_user->getModel()->getGroupId()) { + response.redirect(getBaseUrl() + "/userUpdateGroup"); + } else { + response.redirect(account_user->getGroupBaseUrl() + "/state-balances/overview"); } return; } - auto processingTransaction = mSession->getNextReadyTransaction(¬ReadyTransactions); - if(sumTransactions > 0) { + + if(transactions_user_must_sign.size() > 0) + { enableLogout = false; } - if(PAGE_NO_TRANSACTIONS == state && !processingTransaction.isNull()) { - auto transactionType = processingTransaction->getType(); + if(PAGE_NO_TRANSACTIONS == state && transaction && !transaction_body.isNull()) + { + auto transactionType = transaction_body->getType(); + memo = transaction_body->getMemo(); switch(transactionType) { - case TRANSACTION_CREATION: state = PAGE_TRANSACTION_CREATION; break; - case TRANSACTION_TRANSFER: state = PAGE_TRANSACTION_TRANSFER; break; + case model::gradido::TRANSACTION_CREATION: state = PAGE_TRANSACTION_CREATION; break; + case model::gradido::TRANSACTION_TRANSFER: state = PAGE_TRANSACTION_TRANSFER; break; + case model::gradido::TRANSACTION_GROUP_MEMBER_UPDATE: + state = PAGE_TRANSACTION_GROUP_ADD_MEMBER; + //community_server_base_path + break; + } + if(model::gradido::TRANSACTION_GROUP_MEMBER_UPDATE != transactionType) + { + if(!user_model->isEmailChecked()) { + addError(new Error(gettext("E-Mail Aktivierung"), gettext("E-Mail wurde noch nicht aktiviert, du kannst leider noch keine Transaktionen ausführen!"))); + hasErrors = true; + enableSign = false; + } } } @@ -156,6 +326,7 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << ( pageName ); responseStream << "\n"; responseStream << " \n"; @@ -170,7 +341,22 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << " \n"; +*/ +#line 8 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_navi_chr.cpsp" + responseStream << ( community_server_base_path ); + responseStream << "/favicon.ico\" type=\"image/x-icon\" rel=\"icon\" />\n"; + responseStream << " \n"; + responseStream << " \n"; + responseStream << " \n"; responseStream << "\n"; responseStream << "\n"; responseStream << "\n"; @@ -179,6 +365,7 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "
\n"; responseStream << "
\n"; responseStream << " \n"; @@ -194,10 +381,27 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << " \n"; +*/ +#line 19 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_navi_chr.cpsp" + responseStream << ( community_server_base_path ); + responseStream << "\">\n"; + responseStream << " \n"; responseStream << " \n"; responseStream << " \n"; responseStream << "
\n"; @@ -222,10 +437,13 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "
    \n"; responseStream << "
  • account_balance_walletKontoübersicht ( "; #line 38 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\header_navi_chr.cpsp" @@ -233,12 +451,19 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << " GDD )
  • \n"; responseStream << "
  • homehomeStartseite
  • \n"; + //responseStream << "
  • homeStartseite
  • \n"; responseStream << "
  • account_balanceÜberweisung
  • \n"; responseStream << "
  • \n"; responseStream << "
    \n"; responseStream << "
    "; // end include header_navi_chr.cpsp responseStream << "\n"; +/* #line 126 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" if(transaction_finalize_run) { responseStream << "\n"; responseStream << "
    \n"; @@ -339,196 +568,368 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, } responseStream << "\n"; responseStream << " "; #line 154 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +*/ +#line 192 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp"´ + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
    \n"; + responseStream << "\t\n"; + responseStream << "\t"; +#line 212 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(sumTransactions == 0) { responseStream << "\n"; + responseStream << "\t\t"; +#line 213 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Es gibt zurzeit keine Transaktionen zum bestätigen") ); + responseStream << "\n"; + responseStream << " "; +#line 214 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else { responseStream << "\t\n"; + responseStream << "\t\t

    "; +#line 215 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( sumTransactions ); + responseStream << " "; +#line 215 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Transaktionen warten darauf bestätigt zu werden.") ); + responseStream << "

    \n"; + responseStream << "\t\t"; +#line 216 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(skip_count > 0) { responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 217 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( skip_count ); + responseStream << " "; +#line 217 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Transaktionen übersprungen.") ); + responseStream << "

    \n"; + responseStream << "\t\t"; +#line 218 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t"; +#line 219 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; responseStream << "\t
    \n"; responseStream << "
    \n"; responseStream << "
    \n"; responseStream << "\t
    \n"; responseStream << "\t\t

    "; -#line 159 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 224 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Transaktion Unterzeichnen") ); responseStream << "

    \n"; responseStream << "\t\t
    \n"; responseStream << "\t\t"; -#line 161 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 226 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" if(state == PAGE_TRANSACTION_TRANSFER) { - auto transferTransaction = processingTransaction->getTransferTransaction(); - memo = transferTransaction->getMemo(); + auto transferTransaction = transaction_body->getTransferTransaction(); responseStream << "\n"; responseStream << "\t\t\t

    "; -#line 165 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 229 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Überweisung") ); responseStream << "

    \n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t\t"; -#line 168 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 232 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Konto") ); responseStream << "\n"; responseStream << "\t\t\t\t"; -#line 169 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 233 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Gradido") ); responseStream << "\n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t "; -#line 171 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 235 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" for(int i = 0; i < transferTransaction->getKontoTableSize(); i++) { responseStream << "\t\t\t\t\t\n"; responseStream << "\t\t\t\t\t"; -#line 172 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 236 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" if((i+1) % 2 == 0) { responseStream << "\n"; responseStream << "\t\t\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t"; -#line 174 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 238 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } else { responseStream << "\n"; responseStream << "\t\t\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t"; -#line 176 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 240 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; responseStream << "\t\t\t\t\t\t"; -#line 177 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 241 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( transferTransaction->getKontoNameCell(i) ); responseStream << "\n"; responseStream << "\t\t\t\t\t\t"; -#line 178 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 242 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(((i+1) % 2) == 0 && transferTransaction->getTargetGroupAlias() != "") { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t ("; +#line 243 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( transferTransaction->getTargetGroupAlias() ); + responseStream << ")\n"; + responseStream << "\t\t\t\t\t\t"; +#line 244 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\t"; +#line 245 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( transferTransaction->getAmountCell(i) ); responseStream << "\n"; responseStream << "\t\t\t\t\t
    \n"; responseStream << "\t\t\t "; -#line 180 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 247 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t "; -#line 182 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 249 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } else if(PAGE_TRANSACTION_CREATION == state) { - auto creationTransaction = processingTransaction->getCreationTransaction(); + auto creationTransaction = transaction_body->getCreationTransaction(); auto transactionUser = creationTransaction->getUser(); - memo = creationTransaction->getMemo(); responseStream << "\n"; responseStream << "\t\t\t\t

    "; -#line 187 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 253 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Schöpfung") ); responseStream << "

    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t"; -#line 190 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 256 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Konto") ); responseStream << "\n"; responseStream << "\t\t\t\t\t"; -#line 191 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 257 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Zieldatum") ); responseStream << "\n"; responseStream << "\t\t\t\t\t"; -#line 192 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 258 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Gradido") ); responseStream << "\n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t"; -#line 195 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - if(transactionUser) { responseStream << "\n"; +#line 261 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(!transactionUser.isNull()) { + auto user_model = transactionUser->getModel(); + responseStream << "\n"; responseStream << "\t\t\t\t\t\t"; -#line 196 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - responseStream << ( transactionUser->getFirstName() ); +#line 264 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( user_model->getFirstName() ); responseStream << " "; -#line 196 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - responseStream << ( transactionUser->getLastName() ); +#line 264 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( user_model->getLastName() ); responseStream << " <"; -#line 196 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - responseStream << ( transactionUser->getEmail() ); +#line 264 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( user_model->getEmail() ); responseStream << ">\n"; responseStream << "\t\t\t\t\t"; -#line 197 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 265 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } else { responseStream << "\n"; responseStream << "\t\t\t\t\t\t0x"; -#line 198 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 266 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( creationTransaction->getPublicHex() ); responseStream << "\n"; responseStream << "\t\t\t\t\t"; -#line 199 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 267 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; responseStream << "\t\t\t\t\t"; -#line 200 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 268 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( creationTransaction->getTargetDateString() ); responseStream << "\n"; responseStream << "\t\t\t\t\t"; -#line 201 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 269 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( creationTransaction->getAmountString() ); responseStream << " GDD\n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t "; +#line 272 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else if(PAGE_TRANSACTION_GROUP_ADD_MEMBER == state) { + auto groupMemberUpdateTransaction = transaction_body->getGroupMemberUpdate(); + auto groups = controller::Group::load(groupMemberUpdateTransaction->getTargetGroupAlias()); + Poco::AutoPtr group_model; + Poco::AutoPtr user; + if(groups.size() == 1 && !groups[0].isNull()) group_model = groups[0]->getModel(); + auto user_id = transaction->getModel()->getUserId(); + if(user_id == user_model->getID()) { + user = account_user; + } else { + user = controller::User::sload(user_id); + } + responseStream << "\n"; + responseStream << "\t\t\t

    "; +#line 285 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Benutzer zu einer Gruppe hinzufügen") ); + responseStream << "

    \n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t\t

    "; +#line 287 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(!user.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\tBenutzer: "; +#line 288 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( user->getEmailWithNames() ); + responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 289 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t\tAccount public key: "; +#line 290 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( groupMemberUpdateTransaction->getPublicKeyHex() ); + responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 291 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "

    \n"; + responseStream << "\t\t\t\t"; +#line 292 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(!group_model.isNull()) { responseStream << "\n"; + responseStream << "\t\t\t\t\t

    "; +#line 293 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Gruppe") ); + responseStream << ":

    \n"; + responseStream << "\t\t\t\t\t
      \n"; + responseStream << "\t\t\t\t\t\t
    • "; +#line 295 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Name") ); + responseStream << ": "; +#line 295 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( group_model->getName() ); + responseStream << "
    • \n"; + responseStream << "\t\t\t\t\t\t
    • "; +#line 296 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Alias") ); + responseStream << ": "; +#line 296 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( group_model->getAlias() ); + responseStream << "
    • \n"; + responseStream << "\t\t\t\t\t\t
    • "; +#line 297 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Url") ); + responseStream << ": getUrl() ); + responseStream << "/pages/visitor\" target=\"_blank\">"; +#line 297 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( group_model->getUrl() ); + responseStream << "
    • \n"; + responseStream << "\t\t\t\t\t\t
    • "; +#line 298 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( group_model->getDescription() ); + responseStream << "
    • \n"; + responseStream << "\t\t\t\t\t
    \n"; + responseStream << "\t\t\t\t"; +#line 300 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t\t"; +#line 301 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Unbekannte Gruppe") ); + responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 302 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 303 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Es haben bereits ") ); +#line 303 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( std::to_string(transaction->getSignCount()) ); +#line 303 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext(" unterzeichnet") ); + responseStream << "\n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t \n"; responseStream << "\t\t\t "; -#line 204 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 306 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } else if(PAGE_USER_DATA_CORRUPTED == state) { responseStream << "\n"; responseStream << "\t\t\t\t

    "; -#line 205 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 307 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( gettext("Es gibt ein Problem mit deinen gespeicherten Daten, bitte wende dich an den")); responseStream << "getAdminReceiver()); responseStream << "?subject=Corrupt User Data&body=Hallo Dario,%0D%0A%0D%0Ameine Benutzer Daten sind korrupt.%0D%0Akannst du das prüfen?%0D%0A%0D%0AMit freundlichen Grüßen%0D%0A\">"; -#line 205 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 307 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << (gettext("Support") ); responseStream << "

    \n"; responseStream << "\t\t\t "; -#line 206 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 308 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\tAktives Konto\n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\t"; -#line 212 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" + responseStream << "\t\t\t "; +#line 309 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(PAGE_NO_TRANSACTIONS == state) { responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 310 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + responseStream << ( gettext("Zurück") ); + responseStream << "\n"; + responseStream << "\t\t\t "; +#line 311 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\tAktives Konto\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 317 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( user_model->getNameWithEmailHtml() ); responseStream << "\n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\tVerwendungszweck\n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\t"; -#line 220 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\tVerwendungszweck\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 325 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" responseStream << ( memo ); responseStream << "\n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\t"; -#line 224 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 329 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(transaction) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\tgetModel()->getID() ); + responseStream << "\">\n"; + responseStream << "\t\t\t\t\t"; +#line 331 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 333 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" if(!account_user->hasPassword()) { responseStream << "\n"; - responseStream << "\t\t\t\t
    \n"; - responseStream << "\t\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t"; +#line 338 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" } responseStream << "\n"; - responseStream << "\t\t\t\t"; -#line 230 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - if(PAGE_USER_DATA_CORRUPTED != state && user_model->isEmailChecked()) { responseStream << "\n"; - responseStream << "\t\t\t\t\t\n"; - responseStream << "\t\t\t\t"; -#line 235 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - } responseStream << "\n"; - responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\t"; -#line 238 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" +#line 344 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\t"; +#line 345 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + if(transaction_removeable) { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\n"; @@ -541,8 +942,26 @@ void CheckTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "\t\t\t\t\t\t\n"; responseStream << "\t\t\t\t"; #line 245 "F:\\Gradido\\gradido_login_server_production\\src\\cpsp\\checkTransaction.cpsp" - } responseStream << "\n"; + responseStream << "\n"; responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 350 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t\t\t\n"; + responseStream << "\t\t\t\t\t"; +#line 355 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\t\n"; + responseStream << "\t\t\t"; +#line 357 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\checkTransaction.cpsp" + } responseStream << "\n"; responseStream << "\t\t
    \n"; responseStream << "\t
    \n"; responseStream << "
    \n"; diff --git a/login_server/src/cpp/HTTPInterface/DashboardPage.cpp b/login_server/src/cpp/HTTPInterface/DashboardPage.cpp index dcd034d63..d377cd24d 100644 --- a/login_server/src/cpp/HTTPInterface/DashboardPage.cpp +++ b/login_server/src/cpp/HTTPInterface/DashboardPage.cpp @@ -31,13 +31,16 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N #line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" const char* pageName = "Dashboard"; + auto user = mSession->getNewUser(); + auto user_model = user->getModel(); //Poco::Net::NameValueCollection cookies; //request.getCookies(cookies); if(!form.empty()) { //form.get("email-verification-code") } - auto uri_start = ServerConfig::g_serverPath;//request.serverParams().getServerName(); - response.redirect(ServerConfig::g_php_serverPath + "/"); + auto uri_start = getBaseUrl(); + //response.redirect(ServerConfig::g_php_serverPath); + response.redirect(user->getGroupBaseUrl()); return; std::ostream& _responseStream = response.send(); Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); @@ -109,34 +112,34 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N responseStream << "\n"; responseStream << "
    \n"; responseStream << "\t

    Willkommen "; -#line 23 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" - responseStream << ( mSession->getUser()->getFirstName() ); +#line 26 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" + responseStream << ( user_model->getFirstName() ); responseStream << " "; -#line 23 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" - responseStream << ( mSession->getUser()->getLastName() ); +#line 26 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" + responseStream << ( user_model->getLastName() ); responseStream << "

    \n"; responseStream << "\t"; -#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" +#line 27 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" responseStream << ( mSession->getErrorsHtml() ); responseStream << "\n"; responseStream << "\t

    Status

    \n"; responseStream << "\t

    "; -#line 26 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" +#line 29 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" responseStream << ( mSession->getSessionStateString() ); responseStream << "

    \n"; responseStream << "\t"; -#line 27 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" +#line 30 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" if(mSession->getSessionState() == SESSION_STATE_EMAIL_VERIFICATION_SEND) { responseStream << "\n"; responseStream << "\t

    Verification Code E-Mail wurde erfolgreich an dich verschickt, bitte schaue auch in dein Spam-Verzeichnis nach wenn du sie nicht findest und klicke auf den Link den du dort findest oder kopiere den Code hier her:

    \n"; responseStream << "\t
    \n"; responseStream << "\t\t\n"; responseStream << "\t\t\n"; responseStream << "\t\n"; responseStream << "\t"; -#line 33 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" +#line 36 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" } else if(mSession->getSessionState() == SESSION_STATE_EMAIL_VERIFICATION_WRITTEN) { responseStream << "\n"; responseStream << "\t

    Hast du schon eine E-Mail mit einem Verification Code erhalten? Wenn ja kannst du ihn hier hinein kopieren:

    \n"; responseStream << "\t
    \n"; @@ -144,14 +147,14 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N responseStream << "\t\t\n"; responseStream << "\t\n"; responseStream << "\t"; -#line 39 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" +#line 42 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\dashboard.cpsp" } responseStream << "\n"; responseStream << "\tAbmelden\n"; responseStream << "\tAccount löschen\n"; responseStream << "
    \n"; @@ -159,10 +162,13 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N responseStream << "\t
    \n"; responseStream << "\t\t\n"; responseStream << "\t
    \n"; responseStream << "\n"; diff --git a/login_server/src/cpp/HTTPInterface/DebugMnemonicPage.cpp b/login_server/src/cpp/HTTPInterface/DebugMnemonicPage.cpp index 8065c725f..8c9c492d6 100644 --- a/login_server/src/cpp/HTTPInterface/DebugMnemonicPage.cpp +++ b/login_server/src/cpp/HTTPInterface/DebugMnemonicPage.cpp @@ -8,7 +8,7 @@ #line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugMnemonic.cpsp" #include "../ServerConfig.h" -#include "../Crypto/KeyPair.h" +#include "../Crypto/Passphrase.h" struct WordChecked { WordChecked() : index(0), bSet(false) {}; @@ -69,7 +69,7 @@ void DebugMnemonicPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poc { if("" != form.get("check_word", "")) { - auto word = KeyPair::filterPassphrase(form.get("word", "")); + auto word = Passphrase::filter(form.get("word", "")); if("" != word) { checkedWord.bSet = true; checkedWord.word = word; diff --git a/login_server/src/cpp/HTTPInterface/DebugPassphrasePage.cpp b/login_server/src/cpp/HTTPInterface/DebugPassphrasePage.cpp index e5990c1d2..cbfb5bad6 100644 --- a/login_server/src/cpp/HTTPInterface/DebugPassphrasePage.cpp +++ b/login_server/src/cpp/HTTPInterface/DebugPassphrasePage.cpp @@ -7,7 +7,8 @@ #line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" +#include "../controller/User.h" #line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp" #include "../ServerConfig.h" @@ -27,44 +28,34 @@ void DebugPassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, P if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" const char* pageName = "Debug Passphrase"; - auto mm = MemoryManager::getInstance(); - KeyPair keys; - std::string privKeyHex = ""; + + KeyPairEd25519* keys = nullptr; std::string privKeyCryptedHex = ""; - User::passwordHashed pwdHashed = 0; + Poco::UInt64 pwdHashed = 0; Poco::AutoPtr existingUser; if(!form.empty()) { - auto passphrase = KeyPair::filterPassphrase(form.get("passphrase", "")); - Mnemonic* wordSource = nullptr; - if(!User::validatePassphrase(passphrase, &wordSource)) { + auto passphrase_string = form.get("passphrase", ""); + auto wordSource = Passphrase::detectMnemonic(passphrase_string); + if(!wordSource) { addError(new Error("debug Passphrase", "invalid passphrase"), false); } else { - keys.generateFromPassphrase(passphrase.data(), wordSource); + keys = KeyPairEd25519::create(Passphrase::create(passphrase_string, wordSource)); } auto email = form.get("email", ""); - auto newUser = new User(email.data(), "first_name", "last_name"); - if(email != "") { existingUser = controller::User::create(); - existingUser->load(email); - } - newUser->validatePwd(form.get("password", ""), this); - pwdHashed = newUser->getPwdHashed(); - auto privKey = keys.getPrivateKey(); - if(privKey) { - privKeyHex = KeyPair::getHex(privKey); - auto privKeyCrypted = newUser->encrypt(privKey); - if(privKeyCrypted) { - privKeyCryptedHex = KeyPair::getHex(privKeyCrypted); - mm->releaseMemory(privKeyCrypted); + if(1 == existingUser->load(email)) { + auto user_model = existingUser->getModel(); + pwdHashed = user_model->getPasswordHashed(); + if(user_model->hasPrivateKeyEncrypted()) { + privKeyCryptedHex = user_model->getPrivateKeyEncryptedHex(); + } } } - getErrors(newUser); - delete newUser; } @@ -139,7 +130,7 @@ void DebugPassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, P responseStream << "
    \n"; responseStream << "\t

    Debug Passphrase

    \n"; responseStream << "\t"; -#line 53 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" +#line 44 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "\t
    \n"; @@ -148,51 +139,51 @@ void DebugPassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, P responseStream << "\t\t\t

    \n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; responseStream << "\t\t\t\n"; responseStream << "\t\t\n"; responseStream << "\t\t\n"; responseStream << "\t\n"; - responseStream << "\t

    Public key:
    "; -#line 69 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" - responseStream << ( keys.getPubkeyHex() ); + responseStream << "\t"; +#line 56 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + if(keys) { responseStream << "\n"; + responseStream << "\t\t

    Public key:
    "; +#line 57 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + responseStream << ( keys->getPublicKeyHex() ); responseStream << "

    \n"; - responseStream << "\t

    Private Key:
    "; -#line 70 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" - responseStream << ( privKeyHex ); - responseStream << "

    \n"; - responseStream << "\t

    Passwort Hashed:
    "; -#line 71 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" - responseStream << ( std::to_string(pwdHashed) ); - responseStream << "

    \n"; - responseStream << "\t

    Private key crypted:
    "; -#line 72 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + responseStream << "\t\t

    Private key crypted:
    "; +#line 58 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" responseStream << ( privKeyCryptedHex ); responseStream << "

    \n"; - responseStream << "\t"; -#line 73 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" - if(!existingUser.isNull()) { - auto userModel = existingUser->getModel(); - auto dbPubkey = userModel->getPublicKey(); - responseStream << "\n"; - responseStream << "\t\t

    user Public:
    "; -#line 77 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" - responseStream << ( KeyPair::getHex(dbPubkey, ed25519_pubkey_SIZE) ); + responseStream << "\t\t

    Passwort Hashed:
    "; +#line 59 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + responseStream << ( std::to_string(pwdHashed) ); responseStream << "

    \n"; + responseStream << "\t\t"; +#line 60 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + if(!existingUser.isNull()) { + auto userModel = existingUser->getModel(); + auto dbPubkey = userModel->getPublicKey(); + responseStream << "\n"; + responseStream << "\t\t\t

    user Public:
    "; +#line 64 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + responseStream << ( keys->getPublicKeyHex() ); + responseStream << "

    \n"; + responseStream << "\t\t"; +#line 65 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + } responseStream << "\n"; responseStream << "\t"; -#line 78 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" +#line 66 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" } responseStream << "\n"; responseStream << "
    \n"; +#line 68 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\debugPassphrase.cpsp" + if(keys) delete keys; responseStream << "\n"; // begin include footer.cpsp responseStream << "
    \n"; responseStream << "

    Copyright © Gradido 2020

    \n"; diff --git a/login_server/src/cpp/HTTPInterface/DecodeTransactionPage.cpp b/login_server/src/cpp/HTTPInterface/DecodeTransactionPage.cpp index 405ed85a6..1d66e4afd 100644 --- a/login_server/src/cpp/HTTPInterface/DecodeTransactionPage.cpp +++ b/login_server/src/cpp/HTTPInterface/DecodeTransactionPage.cpp @@ -8,10 +8,12 @@ #line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" #include "sodium.h" +#include "../proto/gradido/GradidoTransaction.pb.h" #include "../proto/gradido/TransactionBody.pb.h" #include "../controller/User.h" -#include "../model/TransactionBase.h" -#include "../model/TransactionCreation.h" +#include "../model/gradido/TransactionBase.h" +#include "../model/gradido/TransactionCreation.h" +#include "../lib/DataTypeConverter.h" #line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp" #include "../ServerConfig.h" @@ -31,10 +33,11 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 14 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 16 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" const char* pageName = "Decode Transaction"; - model::messages::gradido::TransactionBody transactionBody; + proto::gradido::TransactionBody transactionBody; + proto::gradido::GradidoTransaction transaction; bool decoded = false; bool adminUser = false; if(mSession && mSession->getNewUser()) { @@ -51,6 +54,7 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, size_t resultingBinSize = 0; size_t base64_size = base64.size(); bool encodingValid = false; + bool encodedTransaction = false; if (!sodium_base642bin( binBuffer, base64_size, base64.data(), base64_size, @@ -63,9 +67,10 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, base64.data(), base64_size, nullptr, &resultingBinSize, nullptr, sodium_base64_VARIANT_URLSAFE_NO_PADDING)) { - //encodingValid = true; + encodingValid = true; //free(binBuffer); - addError(new Error("ProcessingTransaction", "it is maybe a Transaction, but I support only TransactionBodys"), false); + //addError(new Error("ProcessingTransaction", "it is maybe a Transaction, but I support only TransactionBodys"), false); + encodedTransaction = true; } if(false == encodingValid) { free(binBuffer); @@ -73,11 +78,24 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, } else { std::string binString((char*)binBuffer, resultingBinSize); free(binBuffer); - - if (!transactionBody.ParseFromString(binString)) { - addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message"), false); + if(!encodedTransaction) { + + if (!transactionBody.ParseFromString(binString)) { + addError(new Error("ProcessingTransaction", "error creating Transaction Body from binary Message"), false); + } else { + decoded = true; + } } else { - decoded = true; + + if(!transaction.ParseFromString(binString)) { + addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message"), false); + } else { + if(!transactionBody.ParseFromString(transaction.body_bytes())) { + addError(new Error("ProcessingTransaction", "error creating Transaction Body from Transaction body bytes"), false); + } else { + decoded = true; + } + } } } @@ -158,84 +176,79 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "
    \n"; responseStream << "\t

    Transaktion dekodieren

    \n"; responseStream << "\t"; -#line 72 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 90 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "\t
    \n"; responseStream << "\t\t
    \n"; responseStream << "\t\t\tTransaktion dekodieren\n"; responseStream << "\t\t\t\n"; responseStream << "\t\t
    \n"; responseStream << "\t\t\n"; responseStream << "\t\n"; responseStream << "\t"; -#line 80 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 98 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" if(decoded) { responseStream << "\n"; responseStream << "\t\t

    Verwendungszweck:

    \n"; responseStream << "\t\t

    "; -#line 82 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 100 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" responseStream << ( transactionBody.memo() ); responseStream << "

    \n"; responseStream << "\t\t"; -#line 83 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 101 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" if(transactionBody.has_transfer()) { auto transfer = transactionBody.transfer(); + char hex[65]; memset(hex, 0, 65); responseStream << "\n"; - responseStream << "\t\t

    Transfer

    \n"; - responseStream << "\t\tSender\n"; - responseStream << "\t\t"; -#line 88 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - for(int i = 0; i < transfer.senderamounts_size(); i++) { - auto sender = transfer.senderamounts(i); - char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)sender.ed25519_sender_pubkey().data(), sender.ed25519_sender_pubkey().size()); - responseStream << "\n"; - responseStream << "\t\t\t

    pubkey: "; -#line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - responseStream << ( hex ); - responseStream << "

    \n"; - responseStream << "\t\t\t

    amount: "; -#line 94 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - responseStream << ( TransactionBase::amountToString(sender.amount()) ); - responseStream << " GDD

    \n"; - responseStream << "\t\t"; -#line 95 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - } responseStream << "\n"; - responseStream << "\t\tReceiver\n"; - responseStream << "\t\t"; -#line 97 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - for(int i = 0; i < transfer.receiveramounts_size(); i++) { - auto receiver = transfer.receiveramounts(i); - char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)receiver.ed25519_receiver_pubkey().data(), receiver.ed25519_receiver_pubkey().size()); - responseStream << "\n"; - responseStream << "\t\t\t

    pubkey: "; -#line 102 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - responseStream << ( hex ); - responseStream << "

    \n"; - responseStream << "\t\t\t

    amount: "; -#line 103 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - responseStream << ( TransactionBase::amountToString(receiver.amount()) ); - responseStream << " GDD

    \n"; - responseStream << "\t\t"; -#line 104 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - } responseStream << "\n"; - responseStream << "\t\t"; + responseStream << "\t\t\t"; #line 105 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + if(transfer.has_local()) { + auto local_transfer = transfer.local(); + auto sender_pubkey = local_transfer.sender().pubkey(); + auto receiver_pubkey = local_transfer.receiver(); + sodium_bin2hex(hex, 65, (const unsigned char*)sender_pubkey.data(), sender_pubkey.size()); + responseStream << "\n"; + responseStream << "\t\t\t\t

    Local Transfer

    \n"; + responseStream << "\t\t\t\tFrom: "; +#line 112 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( hex ); + responseStream << "\n"; + responseStream << "\t\t\t\t"; +#line 113 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + sodium_bin2hex(hex, 65, (const unsigned char*)receiver_pubkey.data(), receiver_pubkey.size()); responseStream << "\n"; + responseStream << "\t\t\t\tTo: "; +#line 114 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( hex ); + responseStream << "\n"; + responseStream << "\t\t\t\tAmount: "; +#line 115 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( model::gradido::TransactionBase::amountToString(local_transfer.sender().amount()) ); + responseStream << "\n"; + responseStream << "\t\t\t"; +#line 116 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + } else { responseStream << "\n"; + responseStream << "\t\t\t\t

    - Not implemented yet (Group Transfer) -

    \n"; + responseStream << "\t\t\t"; +#line 118 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + } responseStream << "\n"; + responseStream << "\t\t"; +#line 120 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" } else if(transactionBody.has_creation()) { auto creation = transactionBody.creation(); + + // model::gradido::TransactionCreation creationObject("", creation); TransactionCreation creationObject("", creation); - auto receiver = creation.receiveramount(); + auto receiver = creation.receiver(); char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)receiver.ed25519_receiver_pubkey().data(), receiver.ed25519_receiver_pubkey().size()); + sodium_bin2hex(hex, 65, (const unsigned char*)receiver.pubkey().data(), receiver.pubkey().size()); Poco::AutoPtr user = nullptr; if(adminUser) { user = controller::User::create(); - if(!user->load((const unsigned char*)receiver.ed25519_receiver_pubkey().data())) { + if(!user->load((const unsigned char*)receiver.pubkey().data())) { user.assign(nullptr); } } @@ -243,36 +256,60 @@ void DecodeTransactionPage::handleRequest(Poco::Net::HTTPServerRequest& request, responseStream << "\n"; responseStream << "\t\t

    Creation

    \n"; responseStream << "\t\t"; -#line 122 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" if(!adminUser || user.isNull() || !user->getModel()) { responseStream << "\n"; responseStream << "\t\t

    pubkey: "; -#line 123 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 140 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" responseStream << ( hex ); responseStream << "

    \n"; responseStream << "\t\t"; -#line 124 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 141 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" } else { responseStream << "\n"; responseStream << "\t\t

    user:

    \n"; responseStream << "\t\t

    "; -#line 126 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 143 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" responseStream << ( user->getModel()->toHTMLString() ); responseStream << "

    \n"; responseStream << "\t\t"; -#line 127 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" } responseStream << "\n"; responseStream << "\t\t

    amount: "; -#line 128 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" - responseStream << ( TransactionBase::amountToString(receiver.amount()) ); +#line 145 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( model::gradido::TransactionBase::amountToString(receiver.amount()) ); responseStream << " GDD

    \n"; responseStream << "\t\t

    target date: "; -#line 129 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" responseStream << ( creationObject.getTargetDateString() ); responseStream << "

    \n"; responseStream << "\t\t"; -#line 130 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 147 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + } else if(transactionBody.has_group_member_update()) { + auto group_member_update = transactionBody.group_member_update(); + auto paired_transaction_id = group_member_update.paired_transaction_id(); + std::string paired_transaction_string = std::to_string(paired_transaction_id.seconds()) + "." + std::to_string(paired_transaction_id.nanos()); + responseStream << "\n"; + responseStream << "\t\t\t

    Group Member Update

    \n"; + responseStream << "\t\t\t

    Target group alias: "; +#line 153 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( group_member_update.target_group() ); + responseStream << "

    \n"; + responseStream << "\t\t\t

    Paired transaction id: "; +#line 154 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( paired_transaction_string ); + responseStream << "

    \n"; + responseStream << "\t\t\t

    Member Update Type: "; +#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( proto::gradido::GroupMemberUpdate_MemberUpdateType_Name(group_member_update.member_update_type()) ); + responseStream << "

    \n"; + responseStream << "\t\t\t

    User Public Key Hex: "; +#line 156 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" + responseStream << ( DataTypeConverter::pubkeyToHex((const unsigned char*)group_member_update.user_pubkey().data()) ); + responseStream << "

    \n"; + responseStream << "\t\t"; +#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" } responseStream << "\n"; responseStream << "\t"; -#line 131 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" +#line 158 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\decodeTransaction.cpsp" } responseStream << "\n"; responseStream << "
    \n"; // begin include footer.cpsp diff --git a/login_server/src/cpp/HTTPInterface/ElopageWebhook.cpp b/login_server/src/cpp/HTTPInterface/ElopageWebhook.cpp index c29b280a8..6d72fd4dd 100644 --- a/login_server/src/cpp/HTTPInterface/ElopageWebhook.cpp +++ b/login_server/src/cpp/HTTPInterface/ElopageWebhook.cpp @@ -321,7 +321,7 @@ int HandleElopageRequestTask::run() mEmail = mRequestData.get("payer[email]", ""); mFirstName = mRequestData.get("payer[first_name]", ""); mLastName = mRequestData.get("payer[last_name]", ""); - auto newUser = controller::User::create(mEmail, mFirstName, mLastName); + auto newUser = controller::User::create(mEmail, mFirstName, mLastName, 0); /* printf("LastName: %s\n", mLastName.data()); for (int i = 0; i < mLastName.size(); i++) { diff --git a/login_server/src/cpp/HTTPInterface/ElopageWebhook.h b/login_server/src/cpp/HTTPInterface/ElopageWebhook.h index bf8ea4efc..77c60b155 100644 --- a/login_server/src/cpp/HTTPInterface/ElopageWebhook.h +++ b/login_server/src/cpp/HTTPInterface/ElopageWebhook.h @@ -4,7 +4,7 @@ #include "PageRequestMessagedHandler.h" #include "../tasks/CPUTask.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" #include "Poco/Net/NameValueCollection.h" @@ -14,7 +14,7 @@ public: void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); }; -class HandleElopageRequestTask : public UniLib::controller::CPUTask, protected ErrorList +class HandleElopageRequestTask : public UniLib::controller::CPUTask, protected NotificationList { public: HandleElopageRequestTask(Poco::Net::NameValueCollection& requestData); diff --git a/login_server/src/cpp/HTTPInterface/Error500Page.cpp b/login_server/src/cpp/HTTPInterface/Error500Page.cpp index e36e1da31..4d2c6ec0f 100644 --- a/login_server/src/cpp/HTTPInterface/Error500Page.cpp +++ b/login_server/src/cpp/HTTPInterface/Error500Page.cpp @@ -36,9 +36,9 @@ void Error500Page::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne const char* pageName = "Error"; response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - Poco::AutoPtr user; + Poco::AutoPtr user; if(mSession) { - auto user = mSession->getUser(); + auto user = mSession->getNewUser(); } // begin include header_old.cpsp responseStream << "\n"; @@ -111,7 +111,7 @@ void Error500Page::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne if(mSession) { responseStream << "\n"; responseStream << "\t\t"; #line 21 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\Error500.cpsp" - responseStream << ( mSession->getErrorsHtml() ); + responseStream << ( mSession->getErrorsHtmlNewFormat() ); responseStream << "\n"; responseStream << "\t"; #line 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\Error500.cpsp" @@ -121,7 +121,7 @@ void Error500Page::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Ne if(!user.isNull()) { responseStream << "\n"; responseStream << "\t\t"; #line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\Error500.cpsp" - responseStream << ( user->getErrorsHtml() ); + responseStream << ( user->getModel()->getErrorsHtmlNewFormat() ); responseStream << " \n"; responseStream << "\t"; #line 25 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\Error500.cpsp" diff --git a/login_server/src/cpp/HTTPInterface/LoginPage.cpp b/login_server/src/cpp/HTTPInterface/LoginPage.cpp index bdf4ea8b4..1f50e11ba 100644 --- a/login_server/src/cpp/HTTPInterface/LoginPage.cpp +++ b/login_server/src/cpp/HTTPInterface/LoginPage.cpp @@ -1,365 +1,462 @@ -#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_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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->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_login_server_v1\\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_login_server_v1\\src\\cpsp\\header.cpsp" - responseStream << ( pageName ); - responseStream << "\n"; - responseStream << "\n"; -#line 13 "F:\\Gradido\\gradido_login_server_v1\\src\\cpsp\\header.cpsp" - if(withMaterialIcons) { responseStream << "\n"; - responseStream << "\n"; -#line 15 "F:\\Gradido\\gradido_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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_login_server_v1\\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_login_server\\src\\cpsp\\login.cpsp" + +#include "../gettext.h" + +#include "Poco/Net/HTTPCookie.h" +#include "Poco/Net/HTTPServerParams.h" +#include "Poco/URI.h" +#include "Poco/Logger.h" +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/LanguageManager.h" +#include "../SingletonManager/ErrorManager.h" + +#include "../lib/JsonRequest.h" + + +#line 1 "F:\\Gradido\\gradido_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 22 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp" + + const char* pageName = "Login"; + auto sm = SessionManager::getInstance(); + auto lm = LanguageManager::getInstance(); + auto em = ErrorManager::getInstance(); + + auto uri = Poco::URI(request.getURI()); + auto query_parameter = uri.getQueryParameters(); + std::string caller_uri = ""; + + auto lang = chooseLanguage(request); + //printf("choose language return: %d\n", lang); + auto langCatalog = lm->getFreeCatalog(lang); + + std::string presetEmail(""); + if(mSession && mSession->getNewUser()) { + presetEmail = mSession->getNewUser()->getModel()->getEmail(); + } + /* + if(mSession && mSession->getUser()) { + presetEmail = mSession->getUser()->getEmail(); + } + */ + + if(!form.empty()) { + + caller_uri = form.get("caller_uri", ""); + //printf("form.get: caller_uri: %s\n", caller_uri.data()); + + 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_ip.toString(); + Poco::Logger::get("requestLog").information(clientIpString); + // debugging end + auto user_host = request.clientAddress().host(); + mSession->setClientIp(user_host); + response.addCookie(mSession->getLoginCookie()); + } else { + langCatalog = mSession->getLanguageCatalog(); +*/ + + /*if(mSession) { + printf("start with session: %d\n", mSession->getHandle()); + } else { + printf("start without session\n"); + }*/ + + 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); + + // TODO: check for valid url + if(caller_uri != "") { + mSession->setCallerUri(caller_uri); + } + response.addCookie(mSession->getLoginCookie()); + } else { + langCatalog = mSession->getLanguageCatalog(); + if(caller_uri == "") { + caller_uri = mSession->getCallerUri(); + } + } + + //printf("after session: caller_uri: %s\n", caller_uri.data()); + + + if(email != "" && password != "") { + + UserState 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->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 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); + mSession = nullptr; + } + sm->deleteLoginCookies(request, response); + break; + case USER_NO_GROUP: + response.redirect(getBaseUrl() + "/userUpdateGroup"); + return; + case USER_NO_PRIVATE_KEY: + case USER_COMPLETE: + case USER_EMAIL_NOT_ACTIVATED: + for(auto it = query_parameter.begin(); it != query_parameter.end(); it++) { + printf("query parameter: %s: %s\n", it->first.data(), it->second.data()); + if(it->first == "caller_uri") { + std::string redirect_url = it->second; + redirect_url += "?session_id=" + std::to_string(mSession->getHandle()); + response.redirect(redirect_url); + } + } + auto referer = request.find("Referer"); + std::string refererString; + if (referer != request.end()) { + refererString = referer->second; + } + if(caller_uri != "") + { + std::string redirect_url = caller_uri; + redirect_url += "?session_id=" + std::to_string(mSession->getHandle()); + response.redirect(redirect_url); + } + else if(lastExternReferer != "") { + printf("redirect to: %s (last extern referer)\n", lastExternReferer.data()); + response.redirect(lastExternReferer); + } + else if(refererString != "" && refererString != "/" && + refererString.find("login") == std::string::npos && + refererString.find("logout") == std::string::npos && + refererString.find("user_delete") == std::string::npos && + refererString != getBaseUrl() + request.getURI() && + refererString != user->getGroupBaseUrl() + request.getURI()) + { + std::string uri = request.getURI(); + printf("request uri: %s, redirect to: %s\n", uri.data(), refererString.data()); + response.redirect(refererString); + } + else + { + if(user->getModel()->getGroupId() != 0) { + printf("redirect to: %s/\n", user->getGroupBaseUrl().data()); + + auto group = controller::Group::load(user->getModel()->getGroupId()); + + response.redirect(user->getGroupBaseUrl() + "/"); + } else { + response.redirect("https://" + request.getHost() + "/"); + } + } + return; + } + + } else if(!langUpdatedByBtn && caller_uri == "") { + 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); + } + + std::string form_action_url = ServerConfig::g_serverPath + "/"; + if(mSession && !mSession->getNewUser().isNull()) { + form_action_url = mSession->getNewUser()->getGroupBaseUrl() + "/"; + } else { + form_action_url = getBaseUrl() + "/"; + } + +#line 3 "F:\\Gradido\\gradido_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_login_server\\src\\cpsp\\header.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
    \n"; + responseStream << "
    \n"; + responseStream << " "; + // end include header.cpsp + responseStream << "\n"; +#line 234 "F:\\Gradido\\gradido_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 240 "F:\\Gradido\\gradido_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 247 "F:\\Gradido\\gradido_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 249 "F:\\Gradido\\gradido_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_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_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/PageRequestHandlerFactory.cpp b/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp index 454cc930a..23ff4e756 100644 --- a/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp +++ b/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp @@ -7,7 +7,7 @@ #include "ConfigPage.h" #include "LoginPage.h" -#include "RegisterPage.h" +//#include "RegisterPage.h" #include "HandleFileRequest.h" #include "DashboardPage.h" #include "CheckEmailPage.h" @@ -16,6 +16,7 @@ #include "ElopageWebhook.h" #include "ElopageWebhookLight.h" #include "UpdateUserPasswordPage.h" +#include "UserUpdateGroupPage.h" #include "Error500Page.h" #include "CheckTransactionPage.h" #include "ResetPassword.h" @@ -27,6 +28,11 @@ #include "PassphrasedTransaction.h" #include "AdminUserPasswordReset.h" #include "RegisterDirectPage.h" +#include "AdminGroupsPage.h" +#include "AdminTopicPage.h" +#include "AdminHederaAccountPage.h" +#include "AdminNodeServerPage.h" +#include "AdminNodeServerTestPage.h" #include "DecodeTransactionPage.h" #include "RepairDefectPassphrase.h" @@ -46,6 +52,17 @@ PageRequestHandlerFactory::PageRequestHandlerFactory() ServerConfig::g_ServerKeySeed->put(8, DRRandom::r64()); } +Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::basicSetup(PageRequestMessagedHandler* handler, const Poco::Net::HTTPServerRequest& request, Profiler profiler) +{ + handler->setHost(request.getHost()); + handler->setProfiler(profiler); + auto login_server_path = request.find("grd-login-server-path"); + if (login_server_path != request.end()) { + handler->setLoginServerPath("/" + login_server_path->second); + } + return handler; +} + Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) { //printf("request uri: %s\n", request.getURI().data()); @@ -71,17 +88,12 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c if (url_first_part == "/elopage_webhook_261") { mLogging.information(dateTimeString + " call from elopage"); - //printf("call from elopage\n"); - auto pageRequestHandler = new ElopageWebhook; - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new ElopageWebhook, request, timeUsed); } if (url_first_part == "/elopage_webhook_211") { mLogging.information(dateTimeString + " call from elopage light"); - auto pageRequestHandler = new ElopageWebhookLight; - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new ElopageWebhookLight, request, timeUsed); } // check if user has valid session @@ -124,87 +136,76 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c }*/ if (url_first_part.size() >= 9 && url_first_part.substr(0,9) == "/register") { //if (url_first_part == "/register" || url_first_part == "/registerDirect" ) { - auto pageRequestHandler = new RegisterDirectPage; - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new RegisterDirectPage, request, timeUsed); } if (url_first_part == "/resetPassword") { - auto resetPassword = new ResetPassword; - resetPassword->setProfiler(timeUsed); - return resetPassword; + return basicSetup(new ResetPassword, request, timeUsed); } if (url_first_part == "/decode_transaction") { mLogging.information(dateTimeString + " decode"); - auto pageRequestHandler = new DecodeTransactionPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new DecodeTransactionPage(s), request, timeUsed); } if (url_first_part == "/passphrased_transaction") { - auto pageRequestHandler = new PassphrasedTransaction(); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new PassphrasedTransaction, request, timeUsed); + } + if (url_first_part == "/adminNodeServerTest") { + return basicSetup(new AdminNodeServerTestPage, request, timeUsed); } if (s) { if (externReferer != "") { s->setLastReferer(externReferer); } model::table::User* userModel = nullptr; - auto user = s->getUser(); auto newUser = s->getNewUser(); if (newUser) userModel = newUser->getModel(); - if (s->errorCount() || (!user.isNull() && user->errorCount()) || (userModel && userModel->errorCount())) { - if (!user.isNull() && user->errorCount()) { - s->getErrors(user); - } + if (s->errorCount() || (userModel && userModel->errorCount())) { if (userModel && userModel->errorCount()) { s->getErrors(userModel); } s->sendErrorsAsEmail(); - auto pageRequestHandler = new Error500Page(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new Error500Page(s), request, timeUsed); } if (url_first_part == "/error500") { - auto pageRequestHandler = new Error500Page(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new Error500Page(s), request, timeUsed); } + if (url_first_part == "/userUpdateGroup") { + return basicSetup(new UserUpdateGroupPage(s), request, timeUsed); + } + if (url_first_part == "/transform_passphrase") { - auto pageRequestHandler = new TranslatePassphrase(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new TranslatePassphrase(s), request, timeUsed); } if (url_first_part == "/repairPassphrase") { - auto pageRequestHandler = new RepairDefectPassphrase(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new RepairDefectPassphrase(s), request, timeUsed); } if (userModel && userModel->getRole() == model::table::ROLE_ADMIN) { if (url_first_part == "/adminRegister") { - auto pageRequestHandler = new RegisterAdminPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new RegisterAdminPage(s), request, timeUsed); } if (url_first_part == "/debugPassphrase") { - auto pageRequestHandler = new DebugPassphrasePage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new DebugPassphrasePage(s), request, timeUsed); } if (url_first_part == "/debugMnemonic") { - auto pageRequestHandler = new DebugMnemonicPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new DebugMnemonicPage(s), request, timeUsed); } if (url_first_part == "/checkUserBackups") { - auto pageRequestHandler = new AdminCheckUserBackup(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new AdminCheckUserBackup(s), request, timeUsed); } if (url_first_part == "/adminUserPasswordReset") { - auto pageRequestHandler = new AdminUserPasswordReset(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new AdminUserPasswordReset(s), request, timeUsed); + } + if (url_first_part == "/groups") { + return basicSetup(new AdminGroupsPage(s), request, timeUsed); + } + if (url_first_part == "/topic") { + return basicSetup(new AdminTopicPage(s), request, timeUsed); + } + if (url_first_part == "/hedera_account") { + return basicSetup(new AdminHederaAccountPage(s), request, timeUsed); + } + if (url_first_part == "/nodes") { + return basicSetup(new AdminNodeServerPage(s), request, timeUsed); } } @@ -213,36 +214,30 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c // remove cookie(s) //printf("session released\n"); - auto pageRequestHandler = new LoginPage(nullptr); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new LoginPage(nullptr), request, timeUsed); } if(url_first_part == "/user_delete") { if(s->deleteUser()) { sm->releaseSession(s); - auto pageRequestHandler = new LoginPage(nullptr); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + + return basicSetup(new LoginPage(nullptr), request, timeUsed); } } auto sessionState = s->getSessionState(); //printf("session state: %s\n", s->getSessionStateString()); if (url_first_part == "/updateUserPassword") { - auto pageRequestHandler = new UpdateUserPasswordPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new UpdateUserPasswordPage(s), request, timeUsed); } if (url_first_part == "/checkTransactions") { - auto pageRequestHandler = new CheckTransactionPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new CheckTransactionPage(s), request, timeUsed); } if(s && newUser && newUser->hasPassword() && newUser->hasPublicKey()) { //printf("[PageRequestHandlerFactory] go to dashboard page with user\n"); - auto pageRequestHandler = new DashboardPage(s); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new DashboardPage(s), request, timeUsed); + } + if (url_first_part == "/login" || url_first_part == "/") { + return basicSetup(new LoginPage(s), request, timeUsed); } } else { @@ -251,14 +246,10 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c return new ConfigPage; } else if (url_first_part == "/login") { - auto pageRequestHandler = new LoginPage(nullptr); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new LoginPage(nullptr), request, timeUsed); } } - auto pageRequestHandler = new LoginPage(nullptr); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new LoginPage(nullptr), request, timeUsed); //return new HandleFileRequest; //return new PageRequestHandlerFactory; } @@ -287,9 +278,7 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi // if no verification code given or error with given code, show form if (!verificationCode) { - auto pageRequestHandler = new CheckEmailPage(session); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new CheckEmailPage(session), request, timeUsed); } // we have a verification code, now let's check that thing @@ -316,9 +305,7 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi } else { //sm->releaseSession(session); - auto pageRequestHandler = new CheckEmailPage(session); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new CheckEmailPage(session), request, timeUsed); } } // suitable session found or created @@ -328,9 +315,7 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi assert(session->getNewUser()); if (!session->getNewUser()->hasPassword()) { // user has no password, maybe account created from elopage webhook - auto pageRequestHandler = new UpdateUserPasswordPage(session); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new UpdateUserPasswordPage(session), request, timeUsed); } /* //! \return 1 = konto already exist @@ -352,39 +337,29 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi } else { pageRequestHandler = new PassphrasePage(session); } - - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(pageRequestHandler, request, timeUsed); } else if (1 == retUpdateEmailVerification) { //auto user = session->getUser(); //LoginPage* loginPage = new LoginPage(session); //loginPage->setProfiler(timeUsed); - CheckEmailPage* check_email_page = new CheckEmailPage(session); - check_email_page->setProfiler(timeUsed); - return check_email_page; - //return loginPage; + return basicSetup(new CheckEmailPage(session), request, timeUsed); } else if (-1 == retUpdateEmailVerification) { auto checkEmail = new CheckEmailPage(session); - checkEmail->setProfiler(timeUsed); checkEmail->getErrors(session); sm->releaseSession(session); - return checkEmail; + + return basicSetup(checkEmail, request, timeUsed); } else if (-2 == retUpdateEmailVerification) { - auto errorPage = new Error500Page(session); - errorPage->setProfiler(timeUsed); - return errorPage; + return basicSetup(new Error500Page(session), request, timeUsed); } } if (session) { sm->releaseSession(session); } - - auto pageRequestHandler = new CheckEmailPage(nullptr); - pageRequestHandler->setProfiler(timeUsed); - return pageRequestHandler; + return basicSetup(new CheckEmailPage(nullptr), request, timeUsed); } diff --git a/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.h b/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.h index 75744d501..5a18bb99c 100644 --- a/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.h +++ b/login_server/src/cpp/HTTPInterface/PageRequestHandlerFactory.h @@ -6,6 +6,7 @@ #include "Poco/Logger.h" #include "../model/Session.h" #include "../lib/Profiler.h" +#include "PageRequestMessagedHandler.h" #define HTTP_PAGES_COUNT 1 @@ -18,6 +19,8 @@ public: protected: Poco::Net::HTTPRequestHandler* handleCheckEmail(Session* session, const std::string uri, const Poco::Net::HTTPServerRequest& request, Profiler timeUsed); + Poco::Net::HTTPRequestHandler* basicSetup(PageRequestMessagedHandler* handler, const Poco::Net::HTTPServerRequest& request, Profiler profiler); + Poco::RegularExpression mRemoveGETParameters; Poco::Logger& mLogging; }; diff --git a/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.cpp b/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.cpp index 63b933703..3403e06a9 100644 --- a/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.cpp +++ b/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.cpp @@ -8,6 +8,12 @@ // detect also lang field from form get const Poco::RegularExpression PageRequestMessagedHandler::mDetectLanguageGET("^(?:/[a-zA-Z0-9/_-]*)?(?:/(en|de)|\\?.*lang=(en|de))"); +PageRequestMessagedHandler::PageRequestMessagedHandler() + : mLoginServerPath("/account") +{ + +} + Languages PageRequestMessagedHandler::chooseLanguage(Poco::Net::HTTPServerRequest& request, std::string lang_btn /*= ""*/) { @@ -69,4 +75,12 @@ unsigned long long PageRequestMessagedHandler::getLastGetAsU64(const std::string return 0; } return result; +} + +std::string PageRequestMessagedHandler::getBaseUrl() +{ + if (ServerConfig::g_ServerSetupType == ServerConfig::SERVER_TYPE_TEST) { + return "http://" + mHost + mLoginServerPath; + } + return "https://" + mHost + mLoginServerPath; } \ No newline at end of file diff --git a/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.h b/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.h index 2e47b398d..587aad77f 100644 --- a/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.h +++ b/login_server/src/cpp/HTTPInterface/PageRequestMessagedHandler.h @@ -2,7 +2,7 @@ #define PAGE_REQUEST_MESSAGE_HANDLER_INCLUDED #include "../model/Session.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" #include "../lib/Profiler.h" #include "../SingletonManager/LanguageManager.h" @@ -11,12 +11,14 @@ #include "Poco/Net/HTMLForm.h" #include "Poco/RegularExpression.h" -class PageRequestMessagedHandler : public Poco::Net::HTTPRequestHandler, public ErrorList +class PageRequestMessagedHandler : public Poco::Net::HTTPRequestHandler, public NotificationList { public: - PageRequestMessagedHandler() {} + PageRequestMessagedHandler(); inline void setProfiler(Profiler profiler) { mTimeProfiler = profiler; } + inline void setHost(const std::string &host) { mHost = host; } + inline void setLoginServerPath(const std::string& loginServerPath) { mLoginServerPath = loginServerPath; } //Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request); protected: @@ -26,8 +28,11 @@ protected: virtual Languages chooseLanguage(Poco::Net::HTTPServerRequest& request, std::string lang_btn = ""); unsigned long long getLastGetAsU64(const std::string& uri); + std::string getBaseUrl(); Profiler mTimeProfiler; + std::string mHost; + std::string mLoginServerPath; }; diff --git a/login_server/src/cpp/HTTPInterface/PassphrasePage.cpp b/login_server/src/cpp/HTTPInterface/PassphrasePage.cpp index 39a353e4a..bec72a609 100644 --- a/login_server/src/cpp/HTTPInterface/PassphrasePage.cpp +++ b/login_server/src/cpp/HTTPInterface/PassphrasePage.cpp @@ -9,7 +9,7 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/LanguageManager.h" -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" #include "../ServerConfig.h" //#include "Poco/Net/HTTPServerParams.h" @@ -89,13 +89,15 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: auto registerKeyChoice = form.get("passphrase", "no"); std::string oldPassphrase = ""; if (registerKeyChoice == "no") { - auto oldPassphrase = KeyPair::filterPassphrase(form.get("passphrase-existing", "")); + auto oldPassphrase = Passphrase::filter(form.get("passphrase-existing", "")); if(oldPassphrase != "") { - if (User::validatePassphrase(oldPassphrase, &wordSource)) { + auto word_source = Passphrase::detectMnemonic(oldPassphrase); + if (word_source) { // passphrase is valid if(PAGE_FORCE_ASK_PASSPHRASE == state) { - auto compareResult = mSession->comparePassphraseWithSavedKeys(oldPassphrase, wordSource); + + auto compareResult = mSession->comparePassphraseWithSavedKeys(oldPassphrase, word_source); if(-2 == compareResult) { response.redirect(ServerConfig::g_serverPath + "/error500"); return; @@ -117,7 +119,8 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: } } else if (registerKeyChoice == "yes") { - mSession->generatePassphrase(); + auto passphrase = Passphrase::generate(wordSource); + mSession->setPassphrase(passphrase); } } } @@ -125,7 +128,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: // double check passphrase auto passphrase = mSession->getOldPassphrase(); auto langWordSource = wordSource; - if("" != passphrase && !User::validatePassphrase(passphrase, &wordSource)) { + if("" != passphrase && !Passphrase::detectMnemonic(passphrase)) { addError(new Error("PassphrasePage", "Invalid Passphrase after double check")); addError(new ParamError("PassphrasePage", "passphrase", passphrase.data())); if(!mSession->getNewUser().isNull()) { @@ -138,8 +141,8 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: } //printf("wordSource: %d, langWordSource: %d\n", (int)wordSource, (int)langWordSource); if(wordSource != langWordSource) { - mSession->generatePassphrase(); - User::validatePassphrase(passphrase, &wordSource); + //mSession->generatePassphrase(); + mSession->setPassphrase(Passphrase::generate(wordSource)); } if(mSession->getSessionState() == SESSION_STATE_PASSPHRASE_GENERATED && state != PAGE_ASK_ENSURE_PASSPHRASE) { @@ -159,7 +162,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: #line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" bool withMaterialIcons = false; -#line 138 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 141 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" withMaterialIcons = true; std::ostream& _responseStream = response.send(); Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; @@ -251,9 +254,9 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "
    "; // end include login_header.cpsp responseStream << "\n"; -#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 142 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" if(state == PAGE_ASK_ENSURE_PASSPHRASE) { responseStream << "
    "; -#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 142 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" } responseStream << "\n"; responseStream << "\t"; // begin include flags.cpsp @@ -283,93 +286,93 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "
    "; // end include flags.cpsp responseStream << "\n"; -#line 141 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" if(state == PAGE_ASK_ENSURE_PASSPHRASE) { responseStream << "
    "; -#line 141 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" } responseStream << "\n"; responseStream << "
    \n"; responseStream << "\t

    "; -#line 143 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( pageTitle ); responseStream << ": "; -#line 143 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( pageSubtitle ); responseStream << "

    \n"; responseStream << "\t"; -#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 147 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" if(state == PAGE_SHOW_PASSPHRASE) { responseStream << "\n"; responseStream << "\t\t

    "; -#line 145 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 148 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Passphrase abschreiben") ); responseStream << "

    \n"; responseStream << "\t"; -#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 149 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" } responseStream << "\n"; responseStream << "
    \n"; responseStream << "
    \n"; responseStream << "\t
    \n"; responseStream << "\t"; -#line 150 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 153 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" if(state == PAGE_SHOW_PASSPHRASE) { responseStream << "\n"; responseStream << "\t
    \n"; responseStream << "\t\t
    \n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    "; -#line 156 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 159 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Was ist eine Passphrase?") ); responseStream << "
    \n"; responseStream << "\t\t\t\t

    "; -#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 160 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Deine Passphrase besteht aus den im grünen Feld angezeigten Wörtern.") ); responseStream << "

    \n"; responseStream << "\t\t\t\t

    "; -#line 158 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 161 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Sie dient deiner Sicherheit.") ); responseStream << "

    \n"; responseStream << "\t\t\t\t

    "; -#line 159 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 162 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Du brauchst deine Passphrase um dein Konto wiederherzustellen, wenn du mal dein Passwort vergessen haben solltest.") ); responseStream << "

    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    "; -#line 161 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 164 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Deine Passphrase (Groß/Kleinschreibung beachten)") ); responseStream << ":
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t

    "; -#line 163 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" - responseStream << ( mSession->getPassphrase() ); +#line 166 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" + responseStream << ( mSession->getPassphrase()->getString() ); responseStream << "

    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t
    "; -#line 166 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 169 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Was zu tun ist:") ); responseStream << "
    \n"; responseStream << "\t\t\t\t

    "; -#line 167 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 170 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Schreibe dir die obenstehende Passphrase von Hand auf ein Blatt Papier!") ); responseStream << "

    \n"; responseStream << "\t\t\t\t

    "; -#line 168 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 171 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Speichere sie auf keinen Fall auf deinem Rechner oder Mobilgerät!!") ); responseStream << "

    \n"; responseStream << "\t\t\t\t

    "; -#line 169 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 172 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" responseStream << ( gettext("Bewahre sie an einem sicheren Ort auf!") ); responseStream << "

    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t
    \n"; @@ -377,7 +380,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\t\t
    \n"; responseStream << "\t
    \n"; responseStream << "\t "; -#line 176 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" +#line 179 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\passphrase.cpsp" } else if(state == PAGE_ASK_ENSURE_PASSPHRASE) { responseStream << "\n"; responseStream << "\t \n"; - responseStream << "\n"; - responseStream << "\n"; - responseStream << "
    \n"; - responseStream << "\t

    Login Server in Entwicklung

    \n"; - responseStream << "\t

    Alpha "; -#line 53 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp" - responseStream << ( ServerConfig::g_versionString ); - responseStream << "

    \n"; - responseStream << "
    \n"; - // end include header_old.cpsp - responseStream << "\n"; - responseStream << "
    \n"; - responseStream << "\t

    Einen neuen Account anlegen

    \n"; - responseStream << "\t"; -#line 45 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\register.cpsp" - responseStream << ( getErrorsHtml() ); - responseStream << "\n"; - responseStream << "\t"; -#line 46 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\register.cpsp" - if(!form.empty() && userReturned) { responseStream << "\n"; - responseStream << "\t\t
    \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t\t\tDeine Anmeldung wird verarbeitet und es wird dir eine E-Mail zugeschickt. \n"; - responseStream << "\t\t\t\tWenn sie da ist, befolge ihren Anweisungen. \n"; - responseStream << "\t\t\t
    \n"; - responseStream << "\t\t
    \n"; - responseStream << "\t"; -#line 53 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\register.cpsp" - } else { responseStream << "\n"; - responseStream << "\t\n"; - responseStream << "\t\t\n"; - responseStream << "\t\t
    \n"; - responseStream << "\t\t\tAccount anlegen\n"; - responseStream << "\t\t\t

    Bitte gebe deine Daten um einen Account anzulegen

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t

    \n"; - responseStream << "\t\t
    \n"; - responseStream << "\t\t\n"; - responseStream << "\t\t\n"; - responseStream << "\t\n"; - responseStream << "\t"; -#line 83 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\register.cpsp" - } responseStream << "\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_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_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 - responseStream << "\n"; - if (_compressResponse) _gzipStream.close(); -} diff --git a/login_server/src/cpp/HTTPInterface/RegisterPage.h b/login_server/src/cpp/HTTPInterface/RegisterPage.h deleted file mode 100644 index 7dc16970a..000000000 --- a/login_server/src/cpp/HTTPInterface/RegisterPage.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef RegisterPage_INCLUDED -#define RegisterPage_INCLUDED - - -#include "Poco/Net/HTTPRequestHandler.h" - - -#include "PageRequestMessagedHandler.h" - - -class RegisterPage: public PageRequestMessagedHandler -{ -public: - void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); -}; - - -#endif // RegisterPage_INCLUDED diff --git a/login_server/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp b/login_server/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp index 3b8087c0c..5c988ba88 100644 --- a/login_server/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp +++ b/login_server/src/cpp/HTTPInterface/RepairDefectPassphrase.cpp @@ -9,11 +9,10 @@ #include "../SingletonManager/MemoryManager.h" #include "../SingletonManager/EmailManager.h" -#include "../Crypto/KeyPair.h" #include "../Crypto/Passphrase.h" #include "../Crypto/KeyPairEd25519.h" #include "../lib/DataTypeConverter.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "../tasks/SigningTransaction.h" #include "../ServerConfig.h" @@ -53,7 +52,7 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 36 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 35 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" auto mm = MemoryManager::getInstance(); auto em = EmailManager::getInstance(); @@ -85,7 +84,7 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request else { mSession->setPassphrase(passphrase); - auto newPassphraseModel = controller::UserBackups::create( + auto newPassphraseModel = controller::UserBackup::create( user_model->getID(), passphrase->getString(), ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES @@ -161,11 +160,11 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request } else if(stateString == "success") { printf("[repairDefectPassphrase] request success, wait on transaction ready\n"); auto currentActiveTransaction = mSession->getNextReadyTransaction(); - while(currentActiveTransaction.isNull()) { + while(currentActiveTransaction.isNull() || currentActiveTransaction->getTransactionBody().isNull()) { Poco::Thread::sleep(10); currentActiveTransaction = mSession->getNextReadyTransaction(); } - if(!currentActiveTransaction->isTransfer()) { + if(!currentActiveTransaction->getTransactionBody()->isTransfer()) { addError(new Error("Transaction", "Falsche Transaktion, bitte erst alle anderen Transaktionen abschließen und dann Seite neuladen")); } else { auto signing = new SigningTransaction(currentActiveTransaction, new_user); @@ -270,26 +269,26 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "
    \n"; // end include header_old.cpsp responseStream << "\n"; -#line 185 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 184 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" if("" != errorString) { responseStream << "\n"; responseStream << "\t"; -#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 185 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" responseStream << ( errorString ); responseStream << "\n"; -#line 187 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } responseStream << "\n"; responseStream << "
    \n"; responseStream << "\t"; -#line 189 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 188 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "\t

    Konto reparieren

    \n"; responseStream << "\t

    Der Login-Server hat festgestellt das die gespeicherte Passphrase nicht zu deinem Konto passt.

    \n"; responseStream << "\t"; -#line 192 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 191 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" if(GENERATE_PASSPHRASE == state) { responseStream << "\n"; responseStream << "\t\t"; -#line 193 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 192 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" if(new_user->canDecryptPrivateKey()) { responseStream << "\n"; responseStream << "\t\t\t

    Dein Privat Key konnte noch entschlüsselt werden. Es könnte also eine neue Passphrase generiert werden und dein aktueller Kontostand\n"; responseStream << "\t\t\tauf die neue Adresse transferiert werden.

    \n"; @@ -297,27 +296,27 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\n"; responseStream << "\t\t"; -#line 199 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 198 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } else { responseStream << "\n"; responseStream << "\t\t\t

    Dein Privat Key konnte nicht entschlüsselt werden. Bitte wende dich an den Admin: "; -#line 200 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 199 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" responseStream << ( adminEmail ); responseStream << "

    \n"; responseStream << "\t\t"; -#line 201 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 200 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } responseStream << "\n"; responseStream << "\t"; -#line 202 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 201 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } else if(SHOW_PASSPHRASE == state) { responseStream << "\n"; responseStream << "\t\t

    Deine neue Passphrase, bitte schreibe sie dir auf (am besten auf einen Zettel) und hebe sie gut auf. \n"; responseStream << "\t\tDu brauchst sie wenn du dein Passwort vergessen hast oder dein Konto umziehen möchtest:

    \n"; responseStream << "\t\t
    Deine neue Passphrase:\n"; responseStream << "\t\t\t
    \n"; responseStream << "\t\t\t\t"; -#line 207 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 206 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" responseStream << ( mSession->getPassphrase()->getString() ); responseStream << "\n"; responseStream << "\t\t\t
    \n"; @@ -328,15 +327,15 @@ void RepairDefectPassphrase::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "\t\t\t

    \n"; responseStream << "\t\t\n"; responseStream << "\t"; -#line 215 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 214 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } else if(FINISH == state) { responseStream << "\n"; responseStream << "\t\t

    Neue Daten erfolgreich gespeichert, bitte logge dich nun aus. Danach kannst du dich gerne wieder einloggen und müsstest dein Guthaben wieder auf deinem Konto haben.

    \n"; responseStream << "\t\tAusloggen\n"; responseStream << "\t"; -#line 218 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" +#line 217 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\repairDefectPassphrase.cpsp" } responseStream << "\n"; responseStream << "
    \n"; // begin include footer.cpsp diff --git a/login_server/src/cpp/HTTPInterface/ResetPassword.cpp b/login_server/src/cpp/HTTPInterface/ResetPassword.cpp index 23d6b8331..5b5b95721 100644 --- a/login_server/src/cpp/HTTPInterface/ResetPassword.cpp +++ b/login_server/src/cpp/HTTPInterface/ResetPassword.cpp @@ -11,7 +11,7 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/EmailManager.h" #include "../controller/User.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" enum PageState { PAGE_EMAIL_ASK, @@ -95,7 +95,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N // send reset password email int result = 0; if(user_exist) { - result = session->sendResetPasswordEmail(user, sendUserEmail); + result = session->sendResetPasswordEmail(user, sendUserEmail, getBaseUrl()); } if(2 == result) { @@ -187,7 +187,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N responseStream << "
    \n"; responseStream << "\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t
    \n"; responseStream << "\t\t\t\t\t
    \n"; @@ -244,7 +244,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N responseStream << "\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t\t
    \n"; responseStream << "\t
    \n"; diff --git a/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.cpp b/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.cpp new file mode 100644 index 000000000..9517ea185 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.cpp @@ -0,0 +1,303 @@ +#include "UserUpdateGroupPage.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/DeflatingStream.h" + + +#line 6 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + + +#include "../controller/Group.h" +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/PendingTasksManager.h" +#include "../lib/DataTypeConverter.h" +#include "../model/gradido/Transaction.h" + +enum PageState { + PAGE_STATE_OVERVIEW, + PAGE_STATE_REQUEST_IS_RUNNING, + PAGE_STATE_NO_GROUPS +}; + +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + +#include "../ServerConfig.h" + + +UserUpdateGroupPage::UserUpdateGroupPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void UserUpdateGroupPage::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 21 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + + const char* pageName = gettext("Gruppe wählen"); + auto user = mSession->getNewUser(); + auto sm = SessionManager::getInstance(); + auto pt = PendingTasksManager::getInstance(); + PageState state = PAGE_STATE_OVERVIEW; + + auto groups = controller::Group::listAll(); + Poco::AutoPtr choosen_group; + + if(!form.empty()) { + auto group_id_string = form.get("group_id", ""); + if(group_id_string == "") { + addError(new Error(gettext("Fehler"), gettext("HTML Form Fehler"))); + } else { + int group_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(group_id_string, group_id)) { + std::string group_alias = ""; + + for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); + if(group_model->getID() == group_id) { + choosen_group = *it; + } + } + if(choosen_group.isNull()) { + addError(new Error(gettext("Fehler"), gettext("Interner Fehler"))); + } else { + auto addGroupMemberTransaction = + model::gradido::Transaction::createGroupMemberUpdate(user, choosen_group); + response.redirect(ServerConfig::g_serverPath + "/checkTransactions"); + return; + state = PAGE_STATE_REQUEST_IS_RUNNING; + } + } else { + addError(new Error(gettext("Fehler"), gettext("HTML Value Type Fehler"))); + } + } + } else { + if(groups.size() == 0) { + if(user->getModel()->getRole() == model::table::ROLE_ADMIN) { + response.redirect(getBaseUrl() + "/groups"); + return; + } + state = PAGE_STATE_NO_GROUPS; + + } else { + auto referer = request.find("Referer"); + std::string refererString; + if (referer != request.end()) { + refererString = referer->second; + } + + + + pt->lock("userUpdateGroup Page"); + auto has_pending_group_add_member_task = pt->hasPendingTask(user, model::table::TASK_TYPE_GROUP_ADD_MEMBER); + auto referer_was_checkTransaction = refererString.find("checkTransactions") != std::string::npos; + if(has_pending_group_add_member_task) { + state = PAGE_STATE_REQUEST_IS_RUNNING; + std::vector> tasks = pt->getPendingTasks(user, model::table::TASK_TYPE_GROUP_ADD_MEMBER); + // should be only one + Poco::AutoPtr transaction = tasks[0].cast(); + if(transaction->getSignCount() == 0) { + + pt->unlock(); + response.redirect(getBaseUrl() + "/checkTransactions"); + return; + } + } else if(referer_was_checkTransaction && user->getModel()->getGroupId()) { + pt->unlock(); + response.redirect(user->getGroupBaseUrl()); + return; + } + + pt->unlock(); + } + } + + + + +#line 3 "F:\\Gradido\\gradido_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_login_server\\src\\cpsp\\header.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
    \n"; + responseStream << "
    \n"; + responseStream << " "; + // end include header.cpsp + responseStream << "\n"; +#line 104 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
    \n"; + responseStream << "\t"; +#line 106 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + if(PAGE_STATE_OVERVIEW == state ) { responseStream << "\n"; + responseStream << "
    \n"; + responseStream << "

    "; +#line 108 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Gruppe wählen") ); + responseStream << "

    \n"; + responseStream << "
    \n"; + responseStream << "\t

    "; +#line 110 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Bitte wähle die Gruppe/Gemeinschaft aus, zu der du gehörst.") ); + responseStream << "

    \n"; + responseStream << "\t

    "; +#line 111 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Du bekommst eine Bestätigungsmail, nachdem dein Beitritt bestätigt wurde.") ); + responseStream << "

    \n"; + responseStream << "\t
    \n"; + responseStream << "\t\t
    \n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t\t
    "; +#line 115 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Auswahl") ); + responseStream << "
    \n"; + responseStream << "\t\t\t\t
    Name
    \n"; + responseStream << "\t\t\t\t
    Alias
    \n"; + responseStream << "\t\t\t\t
    Url
    \n"; + responseStream << "\t\t\t\t
    "; +#line 119 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Description") ); + responseStream << "
    \n"; + responseStream << "\t\t\t
    \n"; + responseStream << "\t\t\t"; +#line 121 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); responseStream << "\n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t\t\t
    getID()); + responseStream << "\" />
    \n"; + responseStream << "\t\t\t\t\t
    "; +#line 125 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( group_model->getName() ); + responseStream << "
    \n"; + responseStream << "\t\t\t\t\t
    "; +#line 126 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( group_model->getAlias() ); + responseStream << "
    \n"; + responseStream << "\t\t\t\t\t
    "; +#line 127 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( group_model->getUrl() ); + responseStream << "
    \n"; + responseStream << "\t\t\t\t\t
    "; +#line 128 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( group_model->getDescription()); + responseStream << "
    \n"; + responseStream << "\t\t\t\t
    \n"; + responseStream << "\t\t\t"; +#line 130 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + } responseStream << "\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t
    \n"; + responseStream << "\t\n"; + responseStream << "\t"; +#line 134 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + } else if(PAGE_STATE_REQUEST_IS_RUNNING == state) { responseStream << "\n"; + responseStream << "\t\t

    "; +#line 135 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Deine Beitrittsanfrage wird bearbeitet, du bekommst eine E-Mail wenn sie bestätigt oder abgelehnt wurde.") ); + responseStream << "

    \n"; + responseStream << "\t\t

    "; +#line 136 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Abmelden") ); + responseStream << "

    \n"; + responseStream << "\t"; +#line 137 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + } else if(PAGE_STATE_NO_GROUPS == state) { responseStream << "\n"; + responseStream << "\t\t

    "; +#line 138 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + responseStream << ( gettext("Noch keine Gruppen vorhanden, bitte warte bis der Admin welche hinzugefügt hat.") ); + responseStream << "\n"; + responseStream << "\t"; +#line 139 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\userUpdateGroup.cpsp" + } responseStream << "\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_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_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 + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.h b/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.h new file mode 100644 index 000000000..5b1e9a7d1 --- /dev/null +++ b/login_server/src/cpp/HTTPInterface/UserUpdateGroupPage.h @@ -0,0 +1,20 @@ +#ifndef UserUpdateGroupPage_INCLUDED +#define UserUpdateGroupPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class UserUpdateGroupPage: public SessionHTTPRequestHandler +{ +public: + UserUpdateGroupPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // UserUpdateGroupPage_INCLUDED diff --git a/login_server/src/cpp/ImportantTests.cpp b/login_server/src/cpp/ImportantTests.cpp index d321bab5f..33c7d0f26 100644 --- a/login_server/src/cpp/ImportantTests.cpp +++ b/login_server/src/cpp/ImportantTests.cpp @@ -2,7 +2,7 @@ #include #include "ServerConfig.h" -#include "Crypto/KeyPair.h" +//#include "Crypto/KeyPair.h" #include "Crypto/KeyPairEd25519.h" #include "lib/DataTypeConverter.h" @@ -38,27 +38,36 @@ namespace ImportantTests { // test old key pair implementation - KeyPair keys; + //KeyPair keys; bool errorsOccured = false; - std::string filtered_1_de = KeyPair::filterPassphrase(passphrase_1_de); - keys.generateFromPassphrase(filtered_1_de.data(), de_words); - if (keys.getPubkeyHex() != passphrase_1_pubkey_hex) { + std::string filtered_1_de = Passphrase::filter(passphrase_1_de); + KeyPairEd25519* keys = nullptr; + keys = KeyPairEd25519::create(Passphrase::create(filtered_1_de, de_words)); + std::string public_key_hex = keys->getPublicKeyHex(); + + if (std::string(public_key_hex.data(), public_key_hex.size() - 1) != passphrase_1_pubkey_hex) { printf("1 de incorrect\n"); errorsOccured = true; } - keys.generateFromPassphrase(passphrase_1_en.data(), en_words); - if (keys.getPubkeyHex() != passphrase_1_pubkey_hex) { + delete keys; + keys = KeyPairEd25519::create(Passphrase::create(passphrase_1_en, en_words)); + public_key_hex = keys->getPublicKeyHex(); + if (std::string(public_key_hex.data(), public_key_hex.size() - 1) != passphrase_1_pubkey_hex) { printf("1 en incorrect\n"); errorsOccured = true; } - std::string filtered_2_de = KeyPair::filterPassphrase(passphrase_2_de); - keys.generateFromPassphrase(filtered_2_de.data(), de_words); - if (keys.getPubkeyHex() != passphrase_2_pubkey_hex) { + std::string filtered_2_de = Passphrase::filter(passphrase_2_de); + delete keys; + keys = KeyPairEd25519::create(Passphrase::create(filtered_2_de, de_words)); + public_key_hex = keys->getPublicKeyHex(); + if (std::string(public_key_hex.data(), public_key_hex.size() - 1) != passphrase_2_pubkey_hex) { printf("2 de incorrect\n"); errorsOccured = true; } - keys.generateFromPassphrase(passphrase_2_en.data(), en_words); - if (keys.getPubkeyHex() != passphrase_2_pubkey_hex) { + delete keys; + keys = KeyPairEd25519::create(Passphrase::create(passphrase_2_en, en_words)); + public_key_hex = keys->getPublicKeyHex(); + if (std::string(public_key_hex.data(), public_key_hex.size() - 1) != passphrase_2_pubkey_hex) { printf("2 en incorrect\n"); errorsOccured = true; } diff --git a/login_server/src/cpp/JSONInterface/JsonAppLogin.cpp b/login_server/src/cpp/JSONInterface/JsonAppLogin.cpp new file mode 100644 index 000000000..3fe1e7d31 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonAppLogin.cpp @@ -0,0 +1,59 @@ +#include "JsonAppLogin.h" + +#include "Poco/URI.h" + +#include "../lib/DataTypeConverter.h" + +#include "../controller/AppAccessToken.h" +#include "../controller/User.h" + +#include "../SingletonManager/SessionManager.h" + + +Poco::JSON::Object* JsonAppLogin::handle(Poco::Dynamic::Var params) +{ + Poco::UInt64 access_token_code; + if (params.isVector()) { + try { + const Poco::URI::QueryParameters queryParams = params.extract(); + for (auto it = queryParams.begin(); it != queryParams.end(); it++) { + if (it->first == "access_token") { + auto numberParseResult = DataTypeConverter::strToInt(it->second, access_token_code); + if (DataTypeConverter::NUMBER_PARSE_OKAY != numberParseResult) { + return stateError("error parsing access token", DataTypeConverter::numberParseStateToString(numberParseResult)); + } + break; + } + } + //auto var = params[0]; + } + catch (Poco::Exception& ex) { + return stateError("error parsing query params, Poco Error", ex.displayText()); + } + } + auto sm = SessionManager::getInstance(); + auto access_token = controller::AppAccessToken::load(access_token_code); + if (access_token.isNull()) { + return stateError("access token not found"); + } + Poco::Timespan max_age; + max_age.assign(7, 0, 0, 0, 0); + if (access_token->getAge() > max_age) { + access_token->deleteFromDB(); + return stateError("access token to old"); + } + access_token->getModel()->update(); + auto session = sm->getNewSession(); + auto user = controller::User::create(); + if (1 != user->load(access_token->getModel()->getUserId())) { + return stateError("access token invalid"); + } + session->setUser(user); + + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + result->set("session_id", session->getHandle()); + + return result; + +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonAppLogin.h b/login_server/src/cpp/JSONInterface/JsonAppLogin.h new file mode 100644 index 000000000..c587b61e2 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonAppLogin.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_APP_LOGIN_H_ +#define __JSON_INTERFACE_JSON_APP_LOGIN_H_ + +#include "JsonRequestHandler.h" + +class JsonAppLogin : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_APP_LOGIN_H_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.cpp b/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.cpp new file mode 100644 index 000000000..5a6f8c6dc --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.cpp @@ -0,0 +1,46 @@ +#include "JsonAquireAccessToken.h" + +#include "../SingletonManager/SessionManager.h" + +#include "../controller/AppAccessToken.h" +#include "../controller/Group.h" + + +Poco::JSON::Object* JsonAquireAccessToken::handle(Poco::Dynamic::Var params) +{ + if (!mSession || mSession->getNewUser().isNull()) { + auto session_result = checkAndLoadSession(params, true); + if (session_result) { + return session_result; + } + } + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + auto user = mSession->getNewUser(); + auto user_id = user->getModel()->getID(); + auto access_tokens = controller::AppAccessToken::load(user_id); + Poco::AutoPtr access_token; + if (access_tokens.size() > 0) { + access_token = access_tokens[0]; + access_token->getModel()->update(); + } + else { + access_token = controller::AppAccessToken::create(user_id); + // for a bit faster return + UniLib::controller::TaskPtr task = new model::table::ModelInsertTask(access_token->getModel(), false, true); + task->scheduleTask(task); + // default + //access_token->getModel()->insertIntoDB(false); + } + + result->set("access_token", std::to_string(access_token->getModel()->getCode())); + + auto group_base_url = user->getGroupBaseUrl(); + auto group = controller::Group::load(user->getModel()->getGroupId()); + if (!group.isNull()) { + result->set("group_base_url", group->getModel()->getUrl()); + } + + return result; + +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.h b/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.h new file mode 100644 index 000000000..dfacb85d8 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonAquireAccessToken.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_ACQUIRE_ACCESS_TOKEN_ +#define __JSON_INTERFACE_JSON_ACQUIRE_ACCESS_TOKEN_ + +#include "JsonRequestHandler.h" + +class JsonAquireAccessToken : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_ACQUIRE_ACCESS_TOKEN_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp new file mode 100644 index 000000000..99aa1f8b8 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp @@ -0,0 +1,268 @@ +#include "JsonCreateTransaction.h" + +#include "../controller/User.h" + +#include "../lib/DataTypeConverter.h" + +#include "../model/gradido/Transaction.h" + +#include "../SingletonManager/ErrorManager.h" + +Poco::JSON::Object* JsonCreateTransaction::handle(Poco::Dynamic::Var params) +{ + auto sm = SessionManager::getInstance(); + + int session_id = 0; + std::string transaction_type; + + // 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); + paramJsonObject->get("transaction_type").convert(transaction_type); + paramJsonObject->get("memo").convert(mMemo); + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + if (!session_id) { + return stateError("session_id invalid"); + } + + mSession = sm->getSession(session_id); + if (!mSession) { + return stateError("session not found"); + } + auto user = mSession->getNewUser(); + if (user.isNull()) { + auto em = ErrorManager::getInstance(); + em->addError(new Error("JsonCreateTransaction", "session hasn't a user, check code")); + em->sendErrorsAsEmail(); + return customStateError("code error", "user is zero"); + } + + getTargetGroup(params); + if (transaction_type == "transfer") { + return transfer(params); + } + else if (transaction_type == "creation") { + return creation(params); + } + else if (transaction_type == "groupMemberUpdate") { + return groupMemberUpdate(params); + } + + return stateError("transaction_type unknown"); + +} + +Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params) +{ + auto target_pubkey = getTargetPubkey(params); + if (!target_pubkey) { + return customStateError("not found", "receiver not found"); + } + + auto user = mSession->getNewUser(); + Poco::UInt32 amount = 0; + auto mm = MemoryManager::getInstance(); + Poco::JSON::Object* result = nullptr; + + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + try { + paramJsonObject->get("amount").convert(amount); + } + catch (Poco::Exception& ex) { + result = stateError("json exception", ex.displayText()); + } + } + else { + result = stateError("parameter format unknown"); + } + if (result) { + mm->releaseMemory(target_pubkey); + return result; + } + + if (!mReceiverUser.isNull() && mReceiverUser->getModel()) { + auto receiver_user_model = mReceiverUser->getModel(); + if (receiver_user_model->isDisabled()) { + result = customStateError("disabled", "receiver is disabled"); + } + if (!mTargetGroup.isNull() && receiver_user_model->getGroupId() != mTargetGroup->getModel()->getID()) { + result = stateError("user not in group", "receiver user isn't in target group"); + } + } + if (!result) { + model::gradido::Transaction::createTransfer(mSession->getNewUser(), target_pubkey, mTargetGroup, amount, mMemo); + result = stateSuccess(); + } + mm->releaseMemory(target_pubkey); + return result; +} +Poco::JSON::Object* JsonCreateTransaction::creation(Poco::Dynamic::Var params) +{ + auto target_pubkey = getTargetPubkey(params); + if (!target_pubkey) { + return customStateError("not found", "receiver not found"); + } + + Poco::UInt32 amount = 0; + Poco::DateTime target_date; + auto mm = MemoryManager::getInstance(); + Poco::JSON::Object* result = nullptr; + + if (params.type() == typeid(Poco::JSON::Object::Ptr)) + { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + try { + paramJsonObject->get("amount").convert(amount); + paramJsonObject->get("target_date").convert(target_date); + } + catch (Poco::Exception& ex) { + result = stateError("json exception", ex.displayText()); + } + } + else + { + result = stateError("parameter format unknown"); + } + + if (amount <= 0 || amount > 10000000) { + result = customStateError("invalid parameter", "invalid amount", "GDD amount in GDD cent ]0,10000000]"); + } + + if (mReceiverUser.isNull()) { + mReceiverUser = controller::User::create(); + if (1 != mReceiverUser->load(target_pubkey->data())) { + mReceiverUser.assign(nullptr); + result = customStateError("not found", "receiver not found"); + } + } + + if (result) { + mm->releaseMemory(target_pubkey); + return result; + } + + if (!mReceiverUser.isNull() && mReceiverUser->getModel()) { + auto receiver_user_model = mReceiverUser->getModel(); + + if (receiver_user_model->isDisabled()) { + result = customStateError("disabled", "receiver is disabled"); + } + if (!receiver_user_model->getGroupId()) { + result = stateError("receiver user hasn't group"); + } + if (receiver_user_model->getGroupId() != mSession->getNewUser()->getModel()->getGroupId()) { + result = stateError("user not in group", "target user is in another group"); + } + } + + if(!result) { + model::gradido::Transaction::createCreation(mReceiverUser, amount, target_date, mMemo); + result = stateSuccess(); + } + mm->releaseMemory(target_pubkey); + + return result; + +} +Poco::JSON::Object* JsonCreateTransaction::groupMemberUpdate(Poco::Dynamic::Var params) +{ + if (mTargetGroup.isNull()) { + return stateError("target_group not found"); + } + model::gradido::Transaction::createGroupMemberUpdate(mSession->getNewUser(), mTargetGroup); + return stateSuccess(); + +} +MemoryBin* JsonCreateTransaction::getTargetPubkey(Poco::Dynamic::Var params) +{ + std::string email; + std::string target_username; + std::string target_pubkey_hex; + + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + auto fields = paramJsonObject->getNames(); + try { + for (auto it = fields.begin(); it != fields.end(); it++) { + if (*it == "target_email") { + paramJsonObject->get("target_email").convert(email); + break; + } + if (*it == "target_username") { + paramJsonObject->get("target_username").convert(target_username); + break; + } + if (*it == "target_pubkey") { + paramJsonObject->get("target_pubkey").convert(target_pubkey_hex); + break; + } + } + } + catch (Poco::Exception& ex) { + return nullptr; + } + mReceiverUser = controller::User::create(); + int result_count = 0; + + MemoryBin* result = nullptr; + if (email != "") { + result_count = mReceiverUser->load(email); + } + else if (target_username != "") { + int group_id = 0; + if (!mTargetGroup.isNull()) { + group_id = mTargetGroup->getModel()->getID(); + } else { + mSession->getNewUser()->getModel()->getGroupId(); + } + result_count = mReceiverUser->getModel()->loadFromDB({ "username", "group_id" }, target_username, group_id, model::table::MYSQL_CONDITION_AND); + } + else if (target_pubkey_hex != "") { + result = DataTypeConverter::hexToBin(target_pubkey_hex); + } + if (1 == result_count) { + result = mReceiverUser->getModel()->getPublicKeyCopy(); + } + else { + mReceiverUser.assign(nullptr); + } + return result; +} + +bool JsonCreateTransaction::getTargetGroup(Poco::Dynamic::Var params) +{ + std::string target_group_alias; + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + try + { + auto target_group = paramJsonObject->get("target_group"); + if (!target_group.isEmpty()) { + target_group.convert(target_group_alias); + auto groups = controller::Group::load(target_group_alias); + if (groups.size() == 1) { + mTargetGroup = groups[0]; + return true; + } + } + + } + catch (Poco::Exception& ex) { + return false; + } + return false; +} diff --git a/login_server/src/cpp/JSONInterface/JsonCreateTransaction.h b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.h new file mode 100644 index 000000000..356e13fc1 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.h @@ -0,0 +1,27 @@ +#ifndef __JSON_INTERFACE_JSON_CREATE_TRANSACTION_ +#define __JSON_INTERFACE_JSON_CREATE_TRANSACTION_ + +#include "JsonRequestHandler.h" +#include "../SingletonManager/SessionManager.h" +#include "../controller/Group.h" + +class JsonCreateTransaction : public JsonRequestHandler +{ +public: + JsonCreateTransaction() : mSession(nullptr) {} + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + Poco::JSON::Object* transfer(Poco::Dynamic::Var params); + Poco::JSON::Object* creation(Poco::Dynamic::Var params); + Poco::JSON::Object* groupMemberUpdate(Poco::Dynamic::Var params); + MemoryBin* getTargetPubkey(Poco::Dynamic::Var params); + bool getTargetGroup(Poco::Dynamic::Var params); + + Session* mSession; + std::string mMemo; + Poco::AutoPtr mTargetGroup; + Poco::AutoPtr mReceiverUser; +}; + +#endif // __JSON_INTERFACE_JSON_CREATE_TRANSACTION_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp index 6b5ecf33d..f0a6ee7e9 100644 --- a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp +++ b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp @@ -1,108 +1,114 @@ -#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; + int group_id; + + 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); + paramJsonObject->get("group_id").convert(group_id); + + 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) { + /*Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "exist"); + result->set("msg", "user already exist"); + return result;*/ + return customStateError("exist", "user already exist"); + } + + if (password.size()) { + NotificationList 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, group_id); + 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/JsonGetLogin.cpp b/login_server/src/cpp/JSONInterface/JsonGetLogin.cpp index a881ae8a0..92ef5e887 100644 --- a/login_server/src/cpp/JSONInterface/JsonGetLogin.cpp +++ b/login_server/src/cpp/JSONInterface/JsonGetLogin.cpp @@ -4,6 +4,7 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/SingletonTaskObserver.h" #include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/PendingTasksManager.h" #include "../lib/DataTypeConverter.h" @@ -12,52 +13,19 @@ Poco::JSON::Object* JsonGetLogin::handle(Poco::Dynamic::Var params) int session_id = 0; auto sm = SessionManager::getInstance(); + auto pt = PendingTasksManager::getInstance(); auto observer = SingletonTaskObserver::getInstance(); - if (params.isStruct()) { - session_id = params["session_id"]; - //std::string miau = params["miau"]; - } - else if (params.isVector()) { - try { - const Poco::URI::QueryParameters queryParams = params.extract(); - for (auto it = queryParams.begin(); it != queryParams.end(); it++) { - if (it->first == "session_id") { - auto numberParseResult = DataTypeConverter::strToInt(it->second, session_id); - if (DataTypeConverter::NUMBER_PARSE_OKAY != numberParseResult) { - return stateError("error parsing session_id", DataTypeConverter::numberParseStateToString(numberParseResult)); - } - break; - } - } - //auto var = params[0]; - } - catch (Poco::Exception& ex) { - return stateError("error parsing query params, Poco Error", ex.displayText()); - } - } - - if (!session_id) { - return stateError("empty session id"); - } - - auto session = sm->getSession(session_id); - if (!session) { - return customStateError("not found", "session not found"); - } - - auto userNew = session->getNewUser(); - //auto user = session->getUser(); - if (userNew.isNull()) { - return customStateError("not found", "Session didn't contain user"); - } - auto userModel = userNew->getModel(); - if(userModel.isNull()) { - return customStateError("not found", "User is empty"); + //if(!mClientIp.isLoopback()) + auto session_check_result = checkAndLoadSession(params, false); + if (session_check_result) { + return session_check_result; } + Poco::JSON::Object* result = new Poco::JSON::Object; result->set("state", "success"); - result->set("clientIP", session->getClientIp().toString()); + //result->set("clientIP", mSession->getClientIp().toString()); + auto userNew = mSession->getNewUser(); try { result->set("user", userNew->getJson()); } @@ -71,12 +39,20 @@ Poco::JSON::Object* JsonGetLogin::handle(Poco::Dynamic::Var params) em->addError(new Error("JsonGetLogin::handle", "generic exception calling userModel->getJson: ")); em->sendErrorsAsEmail(); } - result->set("Transaction.pending", session->getProcessingTransactionCount()); - auto executing = observer->getTaskCount(userModel->getEmail(), TASK_OBSERVER_SIGN_TRANSACTION); + int pending = 0; + auto user_must_sign = pt->getTransactionsUserMustSign(userNew); + pending = user_must_sign.size(); + result->set("Transactions.pending", pending); + + auto some_must_sign = pt->getTransactionSomeoneMustSign(userNew); + //pending = some_must_sign.size(); + result->set("Transactions.can_signed", some_must_sign.size()); + + auto executing = observer->getTaskCount(userNew->getModel()->getEmail(), TASK_OBSERVER_SIGN_TRANSACTION); if (executing < 0) { executing = 0; } - result->set("Transaction.executing", executing); + result->set("Transactions.executing", executing); //printf("pending: %d\n", session->getProcessingTransactionCount()); //std::string user_string = userModel->toString(); //printf("[JsonGetLogin] %s\n", user_string.data()); diff --git a/login_server/src/cpp/JSONInterface/JsonNetworkInfos.cpp b/login_server/src/cpp/JSONInterface/JsonNetworkInfos.cpp new file mode 100644 index 000000000..58a86db4e --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonNetworkInfos.cpp @@ -0,0 +1,68 @@ +#include "JsonNetworkInfos.h" + +#include "../controller/Group.h" + +Poco::JSON::Object* JsonNetworkInfos::handle(Poco::Dynamic::Var params) +{ + /* + 'ask' => ['groups'] + */ + // incoming + + Poco::JSON::Array::Ptr askArray; + + // 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 { + askArray = paramJsonObject->getArray("ask"); + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + + if (askArray.isNull()) { + return stateError("ask is zero or not an array"); + } + + + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + Poco::JSON::Array jsonErrorsArray; + Poco::JSON::Object json_network_infos; + + for (auto it = askArray->begin(); it != askArray->end(); it++) { + auto parameter = *it; + std::string parameterString; + try { + parameter.convert(parameterString); + if (parameterString == "groups") { + auto groups = controller::Group::listAll(); + Poco::JSON::Array json_groups; + for (auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); + json_groups.add(group_model->getAlias()); + } + json_network_infos.set("groups", json_groups); + } + + } + catch (Poco::Exception& ex) { + jsonErrorsArray.add("ask parameter invalid"); + } + } + result->set("errors", jsonErrorsArray); + result->set("data", json_network_infos); + return result; + +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonNetworkInfos.h b/login_server/src/cpp/JSONInterface/JsonNetworkInfos.h new file mode 100644 index 000000000..fc6f20c10 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonNetworkInfos.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_NETWORK_INFOS_ +#define __JSON_INTERFACE_JSON_NETWORK_INFOS_ + +#include "JsonRequestHandler.h" + +class JsonNetworkInfos : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_GET_USERS_ \ 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..9453434de 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp @@ -1,141 +1,211 @@ -#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" + +#include "../SingletonManager/SessionManager.h" + +JsonRequestHandler::JsonRequestHandler() + : mSession(nullptr) +{ + +} + +JsonRequestHandler::JsonRequestHandler(Session* session) + : mSession(session) +{ + +} + +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; + + mClientIp = request.clientAddress().host(); + + 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) { + NotificationList 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, NotificationList* 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; +} + +Poco::JSON::Object* JsonRequestHandler::checkAndLoadSession(Poco::Dynamic::Var params, bool checkIp/* = false*/) +{ + int session_id = 0; + auto sm = SessionManager::getInstance(); + + if (params.isStruct()) { + session_id = params["session_id"]; + //std::string miau = params["miau"]; + } + else if (params.isVector()) { + try { + const Poco::URI::QueryParameters queryParams = params.extract(); + for (auto it = queryParams.begin(); it != queryParams.end(); it++) { + if (it->first == "session_id") { + auto numberParseResult = DataTypeConverter::strToInt(it->second, session_id); + if (DataTypeConverter::NUMBER_PARSE_OKAY != numberParseResult) { + return stateError("error parsing session_id", DataTypeConverter::numberParseStateToString(numberParseResult)); + } + break; + } + } + //auto var = params[0]; + } + catch (Poco::Exception& ex) { + return stateError("error parsing query params, Poco Error", ex.displayText()); + } + } + + if (!session_id) { + return stateError("empty session id"); + } + + auto session = sm->getSession(session_id); + if (!session) { + return customStateError("not found", "session not found"); + } + if (checkIp) { + if (mClientIp.isLoopback()) { + return stateError("client ip is loop back ip"); + } + if (!session->isIPValid(mClientIp)) { + return stateError("client ip differ from login client ip"); + } + } + auto userNew = session->getNewUser(); + //auto user = session->getUser(); + if (userNew.isNull()) { + return customStateError("not found", "Session didn't contain user"); + } + auto userModel = userNew->getModel(); + if (userModel.isNull()) { + return customStateError("not found", "User is empty"); + } + mSession = session; + return nullptr; + +} diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandler.h b/login_server/src/cpp/JSONInterface/JsonRequestHandler.h index 72230bfe4..93e9e436b 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandler.h +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandler.h @@ -3,22 +3,32 @@ #include "Poco/Net/HTTPRequestHandler.h" #include "Poco/JSON/Object.h" - -#include "../lib/ErrorList.h" +#include "../model/Session.h" +#include "../lib/NotificationList.h" class JsonRequestHandler : public Poco::Net::HTTPRequestHandler { public: + JsonRequestHandler(); + JsonRequestHandler(Session* session); + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); virtual Poco::JSON::Object* handle(Poco::Dynamic::Var params) = 0; - static Poco::Dynamic::Var parseJsonWithErrorPrintFile(std::istream& request_stream, ErrorList* errorHandler = nullptr, const char* functionName = nullptr); + static Poco::Dynamic::Var parseJsonWithErrorPrintFile(std::istream& request_stream, NotificationList* errorHandler = nullptr, const char* functionName = nullptr); + + inline void setSession(Session* session) { mSession = session; } protected: Poco::JSON::Object* mResultJson; + Poco::Net::IPAddress mClientIp; + Session* mSession; + + Poco::JSON::Object* checkAndLoadSession(Poco::Dynamic::Var params, bool checkIp = false); + static Poco::JSON::Object* stateError(const char* msg, std::string details = ""); static Poco::JSON::Object* customStateError(const char* state, const char* msg, std::string details = ""); static Poco::JSON::Object* stateSuccess(); diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp index fc52c3a2c..1ec87d9f5 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -1,74 +1,134 @@ -#include "JsonRequestHandlerFactory.h" - -#include "Poco/Net/HTTPServerRequest.h" - -#include "../SingletonManager/SessionManager.h" - -#include "JsonCreateUser.h" -#include "JsonGetLogin.h" -#include "JsonUnknown.h" -#include "JsonTransaction.h" -#include "JsonGetRunningUserTasks.h" -#include "JsonGetUsers.h" -#include "JsonAdminEmailVerificationResend.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 == "/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 == "/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 "JsonAppLogin.h" +#include "JsonAquireAccessToken.h" +#include "JsonCreateTransaction.h" +#include "JsonCreateUser.h" +#include "JsonGetLogin.h" +#include "JsonUnknown.h" +#include "JsonTransaction.h" +#include "JsonGetRunningUserTasks.h" +#include "JsonGetUsers.h" +#include "JsonLogout.h" +#include "JsonNetworkInfos.h" +#include "JsonGetUserInfos.h" +#include "JsonUnsecureLogin.h" +#include "JsonUpdateUserInfos.h" +#include "JsonUnsecureLogin.h" +#include "JsonLogout.h" +#include "JsonSearch.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); + + // 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()); + } + catch (...) {} + + auto sm = SessionManager::getInstance(); + Session* s = nullptr; + if (!session_id) { + s = sm->getSession(session_id); + } + + 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 == "/checkTransaction") { + return new JsonTransaction; + } + else if (url_first_part == "/createTransaction") { + return new JsonCreateTransaction; + } + else if (url_first_part == "/getRunningUserTasks") { + return new JsonGetRunningUserTasks; + } + else if (url_first_part == "/getUsers") { + return new JsonGetUsers; + } + else if (url_first_part == "/networkInfos") { + return new JsonNetworkInfos; + } + 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 == "/search") { + return new JsonSearch; + } + else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { + return new JsonUnsecureLogin(client_host); + } + else if (url_first_part == "/logout") { + return new JsonLogout(client_host); + } + else if (url_first_part == "/acquireAccessToken") { + auto requestHandler = new JsonAquireAccessToken; + requestHandler->setSession(s); + return requestHandler; + } + else if (url_first_part == "/unsecureLogin" && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS)) { + return new JsonUnsecureLogin(client_host); + } + else if (url_first_part == "/appLogin") { + return new JsonAppLogin; + } + else if (url_first_part == "/appLogout") { + if (s) { + sm->releaseSession(s); + } + } + else if (url_first_part == "/logout") { + return new JsonLogout(client_host); + } + + return new JsonUnknown; +} diff --git a/login_server/src/cpp/JSONInterface/JsonSearch.cpp b/login_server/src/cpp/JSONInterface/JsonSearch.cpp new file mode 100644 index 000000000..4b7d82ec6 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonSearch.cpp @@ -0,0 +1,89 @@ +#include "JsonSearch.h" + +#include "../lib/DataTypeConverter.h" +#include "../controller/User.h" +#include "../SingletonManager/SessionManager.h" + +Poco::JSON::Object* JsonSearch::handle(Poco::Dynamic::Var params) +{ + /* + 'ask' = ['account_publickey' => ''] + */ + // incoming + + Poco::JSON::Object::Ptr ask; + + // 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 { + ask = paramJsonObject->getObject("ask"); + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + else { + return stateError("parameter format unknown"); + } + + + if (ask.isNull()) { + return stateError("ask is zero or not an object"); + } + + + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + Poco::JSON::Array jsonErrorsArray; + Poco::JSON::Object result_fields; + auto sm = SessionManager::getInstance(); + auto mm = MemoryManager::getInstance(); + for (auto it = ask->begin(); it != ask->end(); it++) { + std::string name = it->first; + auto value = it->second; + + + try { + if ("account_publickey" == name) { + if (!value.isString()) { + jsonErrorsArray.add("account_publickey isn't a string"); + } + else { + MemoryBin* email_hash = nullptr; + if (sm->isValid(value, VALIDATE_ONLY_HEX)) { + email_hash = DataTypeConverter::hexToBin(value); + } + if (!email_hash) { + email_hash = DataTypeConverter::base64ToBin(value); + } + if (!email_hash) { + jsonErrorsArray.add("account_publickey isn't valid base64 or hex"); + } + else { + auto user = controller::User::create(); + user->load(email_hash); + mm->releaseMemory(email_hash); + auto user_model = user->getModel(); + auto public_key_base64 = DataTypeConverter::binToBase64(user_model->getPublicKey(), user_model->getPublicKeySize()); + result_fields.set("account_publickey", public_key_base64); + } + } + } + } + catch (Poco::Exception& ex) { + jsonErrorsArray.add("update parameter invalid"); + } + } + + result->set("errors", jsonErrorsArray); + result->set("results", result_fields); + result->set("state", "success"); + + return result; +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonSearch.h b/login_server/src/cpp/JSONInterface/JsonSearch.h new file mode 100644 index 000000000..c6fa683a8 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonSearch.h @@ -0,0 +1,24 @@ +#ifndef __JSON_INTERFACE_JSON_SEARCH_ +#define __JSON_INTERFACE_JSON_SEARCH_ + +#include "JsonRequestHandler.h" + +/*! +* @author Dario Rekowski +* @date 2020-09-28 +* @brief search for public informations (no session_id needed), like account id for email hash +* +* +*/ + +class JsonSearch : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_SEARCH_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonTransaction.cpp b/login_server/src/cpp/JSONInterface/JsonTransaction.cpp index 62f001469..1e7f7844e 100644 --- a/login_server/src/cpp/JSONInterface/JsonTransaction.cpp +++ b/login_server/src/cpp/JSONInterface/JsonTransaction.cpp @@ -1,175 +1,171 @@ -#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 nu = session->getNewUser(); + if (!nu.isNull()) { + nu->setBalance(balance); + } + } + } + + std::string transactionBase64String; + Poco::Dynamic::Var transaction_base64 = paramJsonObject->get("transaction_base64"); + int alreadyEnlisted = 0; + 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("meg", "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/JsonUnsecureLogin.cpp b/login_server/src/cpp/JSONInterface/JsonUnsecureLogin.cpp index 18080cfa6..401f46e41 100644 --- a/login_server/src/cpp/JSONInterface/JsonUnsecureLogin.cpp +++ b/login_server/src/cpp/JSONInterface/JsonUnsecureLogin.cpp @@ -52,7 +52,7 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params) return stateError("user with email not found", email); } - ErrorList pwd_errors; + NotificationList pwd_errors; Poco::JSON::Object* result = new Poco::JSON::Object; if (!password.size() || !sm->checkPwdValidation(password, &pwd_errors)) { @@ -110,5 +110,4 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params) sm->releaseSession(session); return result; - } \ No newline at end of file diff --git a/login_server/src/cpp/MySQL/Connector.cpp b/login_server/src/cpp/MySQL/Connector.cpp index dc170cacb..1d9c8df64 100644 --- a/login_server/src/cpp/MySQL/Connector.cpp +++ b/login_server/src/cpp/MySQL/Connector.cpp @@ -48,18 +48,22 @@ const std::string& Connector::name() const Poco::AutoPtr Connector::createSession(const std::string& connectionString, std::size_t timeout) { - return Poco::AutoPtr(new SessionImpl(connectionString, timeout)); + return Poco::AutoPtr(new SessionImpl(connectionString, timeout)); } void Connector::registerConnector() { - if (mysql_library_init(0, 0, 0) != 0) - { - throw Exception("mysql_library_init error"); - } - ServerConfig::g_ServerKeySeed->put(4, DRRandom::r64()); + try { + if (mysql_library_init(0, nullptr, nullptr) != 0) + { + throw Exception("mysql_library_init error"); + } + } catch(std::exception &ex) { + printf("mysql exception: \n"); + } + ServerConfig::g_ServerKeySeed->put(4, DRRandom::r64()); Poco::Data::SessionFactory::instance().add(new Connector()); } diff --git a/login_server/src/cpp/ServerConfig.cpp b/login_server/src/cpp/ServerConfig.cpp index f319ea460..5aaf65edc 100644 --- a/login_server/src/cpp/ServerConfig.cpp +++ b/login_server/src/cpp/ServerConfig.cpp @@ -1,349 +1,397 @@ -#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" +#include "Poco/Environment.h" + +#include "model/table/HederaAccount.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; + HederaConsensusMessageFormat g_ConsensusMessageFormat = HEDERA_CONSENSUS_FORMAT_BINARY; + HederaNetworkType g_HederaNetworkType = HEDERA_TESTNET; + Poco::Timespan g_HederaDefaultTimeout; + +#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; + } + + HederaConsensusMessageFormat getHederaConsensusMessageFormatFromString(const std::string& hederaConsensusMessageFormatString) + { + if ("json" == hederaConsensusMessageFormatString) { + return HEDERA_CONSENSUS_FORMAT_JSON; + } + if ("binary" == hederaConsensusMessageFormatString || "bin" == hederaConsensusMessageFormatString) { + return HEDERA_CONSENSUS_FORMAT_BINARY; + } + if ("base64" == hederaConsensusMessageFormatString) { + return HEDERA_CONSENSUS_FORMAT_BASE64_URLSAVE_NO_PADDING; + } + return HEDERA_CONSENSUS_FORMAT_BINARY; + } + + + + + 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); + + auto hedera_consensus_message_format_string = cfg.getString("hedera.consensus.message_format", "bin"); + g_ConsensusMessageFormat = getHederaConsensusMessageFormatFromString(hedera_consensus_message_format_string); + + auto hedera_network_type_string = cfg.getString("hedera.nettype", "Testnet"); + g_HederaNetworkType = model::table::HederaAccount::hederaNetworkTypeFromString(hedera_network_type_string); + if (HEDERA_UNKNOWN == g_HederaNetworkType) { + g_HederaNetworkType = HEDERA_TESTNET; + } + + // 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 + + // 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); + } + + g_HederaDefaultTimeout = cfg.getInt("hedera.default_timeout", 5); + + 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..9d48521fa 100644 --- a/login_server/src/cpp/ServerConfig.h +++ b/login_server/src/cpp/ServerConfig.h @@ -1,90 +1,109 @@ -#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 + }; + + enum HederaConsensusMessageFormat { + HEDERA_CONSENSUS_FORMAT_BINARY, + HEDERA_CONSENSUS_FORMAT_JSON, + HEDERA_CONSENSUS_FORMAT_BASE64_URLSAVE_NO_PADDING + }; + + enum HederaNetworkType { + HEDERA_MAINNET, + HEDERA_TESTNET, + HEDERA_NET_COUNT, + HEDERA_UNKNOWN + }; + + + + + 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; + extern HederaConsensusMessageFormat g_ConsensusMessageFormat; + extern HederaNetworkType g_HederaNetworkType; + extern Poco::Timespan g_HederaDefaultTimeout; + + + 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/ConnectionManager.cpp b/login_server/src/cpp/SingletonManager/ConnectionManager.cpp index f844a6aa1..5e5bc4935 100644 --- a/login_server/src/cpp/SingletonManager/ConnectionManager.cpp +++ b/login_server/src/cpp/SingletonManager/ConnectionManager.cpp @@ -73,9 +73,9 @@ Poco::Data::Session ConnectionManager::getConnection(ConnectionType type) throw Poco::NotFoundException("Connection Type unknown", std::to_string(type)); } auto session = mSessionPools.getPool(mSessionPoolNames[type]).get(); - + //return mSessionPoolNames[type]; - /*if (!session.isConnected()) { + if (!session.isConnected()) { printf("reconnect called\n"); try { session.reconnect(); @@ -85,7 +85,8 @@ Poco::Data::Session ConnectionManager::getConnection(ConnectionType type) sendErrorsAsEmail(); return mSessionPools.getPool(mSessionPoolNames[type]).get(); } - }*/ + + }//*/ //std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); //printf("[getConnection] %s impl: %p\n", dateTimeString.data(), session.impl()); return session; diff --git a/login_server/src/cpp/SingletonManager/ConnectionManager.h b/login_server/src/cpp/SingletonManager/ConnectionManager.h index 72c8b02e4..2c0d4968a 100644 --- a/login_server/src/cpp/SingletonManager/ConnectionManager.h +++ b/login_server/src/cpp/SingletonManager/ConnectionManager.h @@ -9,7 +9,7 @@ #include "../MySQL/Poco/Connector.h" #include "Poco/Exception.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" enum ConnectionType { CONNECTION_MYSQL_LOGIN_SERVER, @@ -17,7 +17,7 @@ enum ConnectionType { CONNECTION_MAX }; -class ConnectionManager : public ErrorList +class ConnectionManager : public NotificationList { public: ~ConnectionManager(); diff --git a/login_server/src/cpp/SingletonManager/CronManager.cpp b/login_server/src/cpp/SingletonManager/CronManager.cpp new file mode 100644 index 000000000..893cb7040 --- /dev/null +++ b/login_server/src/cpp/SingletonManager/CronManager.cpp @@ -0,0 +1,200 @@ +#include "CronManager.h" +#include "../lib/JsonRequest.h" + +#include "../ServerConfig.h" + + + +CronManager::CronManager() + : mInitalized(false), mMainTimer(1000, 600000) +{ + +} + +CronManager::~CronManager() +{ + Poco::ScopedLock _lock(mMainWorkMutex); + + mMainTimer.stop(); + mInitalized = false; + +} + +CronManager* CronManager::getInstance() +{ + static CronManager one; + return &one; +} + +bool CronManager::init(long defaultPeriodicIntervallMilliseconds/* = 600000*/) +{ + Poco::ScopedLock _lock(mMainWorkMutex); + mInitalized = true; + controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_COMMUNITY); + + mDefaultIntervalMilliseconds = defaultPeriodicIntervallMilliseconds; + mMainTimer.setPeriodicInterval(defaultPeriodicIntervallMilliseconds); + Poco::TimerCallback callback(*this, &CronManager::runUpdateStep); + mMainTimer.start(callback); + + return true; +} + +void CronManager::stop() +{ + Poco::ScopedLock _lock(mMainWorkMutex); + mInitalized = false; + mMainTimer.stop(); +} + +void CronManager::runUpdateStep(Poco::Timer& timer) +{ + auto current = Poco::DateTime(); + //printf("%s [CronManager::runUpdateStep] \n", Poco::DateTimeFormatter::format(current, "%d.%m.%y %H:%M:%S.%i").data()); + Poco::ScopedLock _lock(mMainWorkMutex); + if (!mInitalized) { + return; + } + mNodeServersToPingMutex.lock(); + for (auto it = mNodeServersToPing.begin(); it != mNodeServersToPing.end(); it++) + { + // TODO: Make sure that task not already running, for example if community server needs more time for processing that between calls + // or with schedule update run to short time between calls + UniLib::controller::TaskPtr ping_node_server_task(new PingServerTask(*it)); + ping_node_server_task->scheduleTask(ping_node_server_task); + } + mNodeServersToPingMutex.unlock(); + + mTimestampsMutex.lock(); + //printf("update timestamp sizes: %d\n", mUpdateTimestamps.size()); + bool timerRestarted = false; + + if (mUpdateTimestamps.size() > 0) + { + Poco::Timestamp now; + // update maximal once per second + now += Poco::Timespan(1, 0); + while (mUpdateTimestamps.size() > 0 && mUpdateTimestamps.front() < now) { + // printf("remove update time in past: %d\n", mUpdateTimestamps.front().epochTime()); + mUpdateTimestamps.pop_front(); + } + if (mUpdateTimestamps.size() > 0) { + Poco::Timespan next_run = mUpdateTimestamps.front() - now; + //printf("timer restart called with: %d\n", next_run.seconds()); + //mMainTimer.setPeriodicInterval(next_run.totalMilliseconds()); + mMainTimer.restart(next_run.totalMilliseconds()); + mUpdateTimestamps.pop_front(); + timerRestarted = true; + } + } + + if (!timerRestarted && mMainTimer.getPeriodicInterval() != mDefaultIntervalMilliseconds) { + //printf("reset to default interval\n"); + mMainTimer.setPeriodicInterval(mDefaultIntervalMilliseconds); + //mMainTimer.restart(mDefaultIntervalMilliseconds); + } + mTimestampsMutex.unlock(); + //printf("[CronManager::runUpdateStep] end\n"); +} + +void CronManager::scheduleUpdateRun(Poco::Timespan timespanInFuture) +{ + Poco::Timestamp timestamp; + timestamp += timespanInFuture; + + mTimestampsMutex.lock(); + //printf("[CronManager::scheduleUpdateRun] push:\n%d\n", timestamp.epochTime()); + mUpdateTimestamps.push_back(timestamp); + mUpdateTimestamps.sort(); + auto frontTimestamp = mUpdateTimestamps.front(); + auto backTimestamp = mUpdateTimestamps.back(); + //printf("[CronManager::scheduleUpdateRun] front timestamp and back timestamp:\n%d\n%d\n", frontTimestamp.epochTime(), backTimestamp.epochTime()); + //printf("current: \n%d\n", Poco::Timestamp().epochTime()); + Poco::Timespan next_run = mUpdateTimestamps.front() - Poco::Timestamp(); + + Poco::DateTime now; + std::string now_string = Poco::DateTimeFormatter::format(now, "%d.%m.%y %H:%M:%S.%i"); + //printf("%s [CronManager::scheduleUpdateRun] next run in %d seconds, %d millis (intervall: %d, default: %d)\n", + //now_string.data(), next_run.seconds(), next_run.milliseconds(), mMainTimer.getPeriodicInterval(), mDefaultIntervalMilliseconds); + if (next_run.seconds() > 0 && mMainTimer.getPeriodicInterval() == mDefaultIntervalMilliseconds) { + if (mMainWorkMutex.tryLock(100)) { + mMainTimer.restart(next_run.totalMilliseconds()); + mUpdateTimestamps.pop_front(); + mMainWorkMutex.unlock(); + } + } + + mTimestampsMutex.unlock(); + //printf("[CronManager::scheduleUpdateRun] end\n"); +} + + +void CronManager::addNodeServerToPing(Poco::AutoPtr nodeServer) +{ + if (nodeServer.isNull() || !nodeServer->getModel()) { + return; + } + if (isNodeServerInList(nodeServer)) { + return; + } + mNodeServersToPingMutex.lock(); + mNodeServersToPing.push_back(nodeServer); + mNodeServersToPingMutex.unlock(); + +} +void CronManager::removeNodeServerToPing(Poco::AutoPtr nodeServer) +{ + if (nodeServer.isNull() || !nodeServer->getModel()) { + return; + } + mNodeServersToPingMutex.lock(); + int node_server_id = nodeServer->getModel()->getID(); + for (auto it = mNodeServersToPing.begin(); it != mNodeServersToPing.end(); it++) { + if ((*it)->getModel()->getID() == node_server_id) { + mNodeServersToPing.erase(it); + break; + } + } + mNodeServersToPingMutex.unlock(); +} + +bool CronManager::isNodeServerInList(Poco::AutoPtr nodeServer) +{ + bool result = false; + mNodeServersToPingMutex.lock(); + int node_server_id = nodeServer->getModel()->getID(); + for (auto it = mNodeServersToPing.begin(); it != mNodeServersToPing.end(); it++) { + if ((*it)->getModel()->getID() == node_server_id) { + result = true; + break; + } + } + mNodeServersToPingMutex.unlock(); + return false; +} + +// *********************************************************************************************************** +PingServerTask::PingServerTask(Poco::AutoPtr nodeServer) + : CPUTask(ServerConfig::g_CPUScheduler), mNodeServer(nodeServer) +{ + +} + +PingServerTask::~PingServerTask() +{ + +} + +int PingServerTask::run() +{ + //return 0; + auto current = Poco::DateTime(); + if (model::table::NODE_SERVER_GRADIDO_COMMUNITY == mNodeServer->getModel()->getNodeServerType()) { + std::string url_port = mNodeServer->getModel()->getUrlWithPort(); + printf("%s [PingServerTask::run] call update for %s\n", Poco::DateTimeFormatter::format(current, "%d.%m.%y %H:%M:%S.%i").data(), url_port.data()); + + auto json_request = mNodeServer->createJsonRequest(); + json_request.request("updateReadNode"); + } + return 0; +} \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/CronManager.h b/login_server/src/cpp/SingletonManager/CronManager.h new file mode 100644 index 000000000..e7ff73114 --- /dev/null +++ b/login_server/src/cpp/SingletonManager/CronManager.h @@ -0,0 +1,66 @@ +#ifndef __GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CRON_MANAGER_H +#define __GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CRON_MANAGER_H + +#include "Poco/Timer.h" +#include "../controller/NodeServer.h" +#include "../tasks/CPUTask.h" + + +/*! + * \author: Dario Rekowski + * + * \date: 2020-11-03 + * + * \brief: Manager for "Cron"-like Tasks. + * + * Ping for example community server to get new blocks from nodes + * or Hedera Tasks to (re)try receiving Transaction Receipts + * + */ +class CronManager +{ +public: + ~CronManager(); + + static CronManager* getInstance(); + + bool init(long defaultPeriodicIntervallMilliseconds = 600000); + void stop(); + + void runUpdateStep(Poco::Timer& timer); + void scheduleUpdateRun(Poco::Timespan timespanInFuture); + + + void addNodeServerToPing(Poco::AutoPtr nodeServer); + void removeNodeServerToPing(Poco::AutoPtr nodeServer); + +protected: + CronManager(); + + bool isNodeServerInList(Poco::AutoPtr nodeServer); + bool mInitalized; + + Poco::Timer mMainTimer; + std::list> mNodeServersToPing; + std::list mUpdateTimestamps; + Poco::FastMutex mNodeServersToPingMutex; + Poco::FastMutex mMainWorkMutex; + Poco::FastMutex mTimestampsMutex; + long mDefaultIntervalMilliseconds; +}; + +class PingServerTask : public UniLib::controller::CPUTask +{ +public: + PingServerTask(Poco::AutoPtr nodeServer); + virtual ~PingServerTask(); + + const char* getResourceType() const { return "PingServerTask"; } + + int run(); + +protected: + Poco::AutoPtr mNodeServer; +}; + +#endif //__GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_CRON_MANAGER_H \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/EmailManager.cpp b/login_server/src/cpp/SingletonManager/EmailManager.cpp index 847887316..41f45b471 100644 --- a/login_server/src/cpp/SingletonManager/EmailManager.cpp +++ b/login_server/src/cpp/SingletonManager/EmailManager.cpp @@ -1,172 +1,173 @@ -#include "EmailManager.h" -#include "../ServerConfig.h" - -#include "../Crypto/Obfus_array.h" -#include "../Crypto/DRRandom.h" - -#include "../SingletonManager/LanguageManager.h" - -#include "Poco/Net/SecureSMTPClientSession.h" -#include "Poco/Net/SSLException.h" - - -EmailManager::EmailManager() - : Thread("emails", false), mEmailLog(Poco::Logger::get("emailLog")), mInitalized(false), mDisableEmail(false) -{ - - -} - -EmailManager::~EmailManager() -{ - exit(); - -} - -EmailManager* EmailManager::getInstance() -{ - static EmailManager theOne; - return &theOne; -} - -bool EmailManager::init(const Poco::Util::LayeredConfiguration& cfg) -{ - try { - mDisableEmail = cfg.getBool("email.disable", false); - if (!mDisableEmail) { - mEmailAccount.sender = cfg.getString("email.sender"); - mEmailAccount.admin_receiver = cfg.getString("email.admin_receiver"); - mEmailAccount.username = cfg.getString("email.username"); - mEmailAccount.password = cfg.getString("email.password"); - mEmailAccount.url = cfg.getString("email.smtp.url"); - mEmailAccount.port = cfg.getInt("email.smtp.port"); - } - } - catch (Poco::Exception& ex) { - printf("email account not set in config: %s\n", ex.displayText().data()); - return false; - } - Thread::init("emails"); - mInitalized = true; - - DISASM_FALSERET; - ServerConfig::g_ServerKeySeed->put(3, DRRandom::r64()); - - return true; -} - -void EmailManager::addEmail(model::Email* email) { - if (mDisableEmail) { - std::string log_message = "Email should be sended to: "; - auto email_user = email->getUser(); - if (email_user && email_user->getModel()) { - log_message += email_user->getModel()->getNameWithEmail(); - } - else { - log_message += ""; - } - log_message += ", type: "; - log_message += model::Email::emailTypeString(email->getType()); - mEmailLog.log(log_message); - delete email; - return; - } - mPendingEmails.push(email); - condSignal(); -} - -void EmailManager::exit() -{ - model::Email* email = nullptr; - while (mPendingEmails.pop(email)) { - delete email; - } - mInitalized = false; -} - -int EmailManager::ThreadFunction() -{ - // prepare connection to email server - if (ServerConfig::g_disableEmail) return 0; - - if (mPendingEmails.empty()) return 0; - - auto lm = LanguageManager::getInstance(); - - Poco::Net::SecureSMTPClientSession mailClientSession(mEmailAccount.url, mEmailAccount.port); - mailClientSession.login(); - try { - mailClientSession.startTLS(ServerConfig::g_SSL_CLient_Context); - mailClientSession.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, mEmailAccount.username, mEmailAccount.password); - } - catch (Poco::Net::SSLException& ex) { - printf("[PrepareEmailTask] ssl certificate error: %s\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n", ex.displayText().data()); - return -1; - } - - model::Email* email = nullptr; - Poco::AutoPtr catalogs[2]; - - // if email list empty, wait 500ms x time before exit thread and closing connection - int timeoutWaits = 20; - - while (mPendingEmails.pop(email) || timeoutWaits > 0) { - if (email) { - Poco::Net::MailMessage mailMessage; - mailMessage.setSender(mEmailAccount.sender); - Languages lang_code = ServerConfig::g_default_locale; - if (email->getUser()) { - Poco::AutoPtr userModel = email->getUser()->getModel(); - - if (!userModel.isNull()) { - userModel->lock("EmailManager::ThreadFunction"); - lang_code = LanguageManager::languageFromString(userModel->getLanguageKey()); - userModel->unlock(); - if (lang_code > LANG_COUNT) lang_code = ServerConfig::g_default_locale; - } - } - if (catalogs[lang_code].isNull()) { - catalogs[lang_code] = lm->getFreeCatalog(lang_code); - } - if (email->draft(&mailMessage, catalogs[lang_code])) { - - mailClientSession.sendMessage(mailMessage); - // add for debugging - if (email->getUser()) { - //printf("send email to %s\n", user_model->getEmail().data()); - auto user_model = email->getUser()->getModel(); - std::string log_message = "Email sended to: "; - auto email_user = email->getUser(); - if (user_model) { - log_message += email_user->getModel()->getNameWithEmail(); - } - else { - log_message += ""; - } - log_message += ", type: "; - log_message += model::Email::emailTypeString(email->getType()); - mEmailLog.log(log_message); - } - } - else { - // error drafting email, shouldn't happend - printf("[EmailManager::ThreadFunction] Error drafting email\n"); - } - delete email; - email = nullptr; - } - if (mPendingEmails.empty()) { - Poco::Thread::sleep(500); - timeoutWaits--; - } - } - - - - - - - mailClientSession.close(); - - return 0; +#include "EmailManager.h" +#include "../ServerConfig.h" + +#include "../Crypto/Obfus_array.h" +#include "../Crypto/DRRandom.h" + +#include "../SingletonManager/LanguageManager.h" + +#include "Poco/Net/SecureSMTPClientSession.h" +#include "Poco/Net/SSLException.h" + + +EmailManager::EmailManager() + : Thread("emails", false), mEmailLog(Poco::Logger::get("emailLog")), mInitalized(false), mDisableEmail(false) +{ + + +} + +EmailManager::~EmailManager() +{ + exit(); + +} + +EmailManager* EmailManager::getInstance() +{ + static EmailManager theOne; + return &theOne; +} + +bool EmailManager::init(const Poco::Util::LayeredConfiguration& cfg) +{ + try { + mDisableEmail = cfg.getBool("email.disable", false); + if (!mDisableEmail) { + mEmailAccount.sender = cfg.getString("email.sender"); + mEmailAccount.admin_receiver = cfg.getString("email.admin_receiver"); + mEmailAccount.username = cfg.getString("email.username"); + mEmailAccount.password = cfg.getString("email.password"); + mEmailAccount.url = cfg.getString("email.smtp.url"); + mEmailAccount.port = cfg.getInt("email.smtp.port"); + } + } + catch (Poco::Exception& ex) { + printf("email account not set in config: %s\n", ex.displayText().data()); + return false; + } + Thread::init("emails"); + mInitalized = true; + + DISASM_FALSERET; + ServerConfig::g_ServerKeySeed->put(3, DRRandom::r64()); + + return true; +} + +void EmailManager::addEmail(model::Email* email) { + if (mDisableEmail) { + std::string log_message = "Email should be sended to: "; + auto email_user = email->getUser(); + Poco::AutoPtr email_model; + if (email_user) { + email_model = email_user->getModel(); + log_message += email_model->getNameWithEmailHtml(); + } + if (email_model.isNull()) { + log_message += ""; + } + log_message += ", type: "; + log_message += model::Email::emailTypeString(email->getType()); + mEmailLog.log(log_message); + + delete email; + return; + } + mPendingEmails.push(email); + condSignal(); +} + +void EmailManager::exit() +{ + model::Email* email = nullptr; + while (mPendingEmails.pop(email)) { + delete email; + } + mInitalized = false; +} + +int EmailManager::ThreadFunction() +{ + // prepare connection to email server + if (ServerConfig::g_disableEmail) return 0; + + if (mPendingEmails.empty()) return 0; + + auto lm = LanguageManager::getInstance(); + + Poco::Net::SecureSMTPClientSession mailClientSession(mEmailAccount.url, mEmailAccount.port); + mailClientSession.login(); + try { + mailClientSession.startTLS(ServerConfig::g_SSL_CLient_Context); + mailClientSession.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, mEmailAccount.username, mEmailAccount.password); + } + catch (Poco::Net::SSLException& ex) { + printf("[PrepareEmailTask] ssl certificate error: %s\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n", ex.displayText().data()); + return -1; + } + + model::Email* email = nullptr; + Poco::AutoPtr catalogs[2]; + + // if email list empty, wait 500ms x time before exit thread and closing connection + int timeoutWaits = 20; + + while (mPendingEmails.pop(email) || timeoutWaits > 0) { + if (email) { + Poco::Net::MailMessage mailMessage; + mailMessage.setSender(mEmailAccount.sender); + Languages lang_code = ServerConfig::g_default_locale; + auto email_user = email->getUser(); + if (email_user) { + Poco::AutoPtr userModel = email_user->getModel(); + + if (!userModel.isNull()) { + lang_code = LanguageManager::languageFromString(userModel->getLanguageKey()); + if (lang_code > LANG_COUNT) lang_code = ServerConfig::g_default_locale; + } + } + if (catalogs[lang_code].isNull()) { + catalogs[lang_code] = lm->getFreeCatalog(lang_code); + } + if (email->draft(&mailMessage, catalogs[lang_code])) { + + mailClientSession.sendMessage(mailMessage); + // add for debugging + if (email_user) { + //printf("send email to %s\n", user_model->getEmail().data()); + auto user_model = email_user->getModel(); + std::string log_message = "Email sended to: "; + if (user_model) { + log_message += email_user->getModel()->getNameWithEmailHtml(); + } + else { + log_message += ""; + } + log_message += ", type: "; + log_message += model::Email::emailTypeString(email->getType()); + mEmailLog.log(log_message); + } + } + else { + // error drafting email, shouldn't happend + printf("[EmailManager::ThreadFunction] Error drafting email\n"); + } + delete email; + email = nullptr; + } + if (mPendingEmails.empty()) { + Poco::Thread::sleep(500); + timeoutWaits--; + } + } + + + + + + + mailClientSession.close(); + + return 0; } \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/ErrorManager.cpp b/login_server/src/cpp/SingletonManager/ErrorManager.cpp index 090a6f9dd..320c34f30 100644 --- a/login_server/src/cpp/SingletonManager/ErrorManager.cpp +++ b/login_server/src/cpp/SingletonManager/ErrorManager.cpp @@ -4,7 +4,7 @@ #include "Poco/Net/SecureSMTPClientSession.h" #include "Poco/Net/StringPartSource.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" #include "../model/email/Email.h" @@ -34,37 +34,37 @@ ErrorManager::~ErrorManager() mErrorsMap.clear(); } -void ErrorManager::addError(Error* error, bool log/* = true*/) +void ErrorManager::addError(Notification* error, bool log/* = true*/) { DHASH id = DRMakeStringHash(error->getFunctionName()); - mWorkingMutex.lock(); + Poco::ScopedLock _lock(mWorkingMutex); + auto it = mErrorsMap.find(id); - std::list* list = nullptr; + std::list* list = nullptr; //printf("[ErrorManager::addError] error with function: %s, %s\n", error->getFunctionName(), error->getMessage()); if(log) mLogging.error("[ErrorManager::addError] %s", error->getString(false)); if (it == mErrorsMap.end()) { - list = new std::list; - mErrorsMap.insert(std::pair*>(id, list)); + list = new std::list; + mErrorsMap.insert(std::pair*>(id, list)); } else { list = it->second; // check if hash collision if (strcmp((*list->begin())->getFunctionName(), error->getFunctionName()) != 0) { - mWorkingMutex.unlock(); + throw "[ErrorManager::addError] hash collision detected"; } } list->push_back(error); - mWorkingMutex.unlock(); } -int ErrorManager::getErrors(ErrorList* send) +int ErrorManager::getErrors(NotificationList* send) { - Error* error = nullptr; + Notification* error = nullptr; int iCount = 0; while (error = send->getLastError()) { addError(error, false); diff --git a/login_server/src/cpp/SingletonManager/ErrorManager.h b/login_server/src/cpp/SingletonManager/ErrorManager.h index e59bd7d35..a0e427d9e 100644 --- a/login_server/src/cpp/SingletonManager/ErrorManager.h +++ b/login_server/src/cpp/SingletonManager/ErrorManager.h @@ -15,7 +15,7 @@ #include #include #include -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" #include "../lib/DRHash.h" #include "../tasks/CPUTask.h" @@ -24,7 +24,7 @@ #include "Poco/Net/MailMessage.h" -class ErrorManager : public IErrorCollection +class ErrorManager : public INotificationCollection { public: ~ErrorManager(); @@ -32,9 +32,9 @@ public: static ErrorManager* getInstance(); // will called delete on error - virtual void addError(Error* error, bool log = true); + virtual void addError(Notification* error, bool log = true); - int getErrors(ErrorList* send); + int getErrors(NotificationList* send); virtual void sendErrorsAsEmail(); @@ -43,7 +43,7 @@ protected: // access mutex Poco::Mutex mWorkingMutex; - std::map*> mErrorsMap; + std::map*> mErrorsMap; // how many errors should be stored // poco logging diff --git a/login_server/src/cpp/SingletonManager/HederaTaskManager.cpp b/login_server/src/cpp/SingletonManager/HederaTaskManager.cpp new file mode 100644 index 000000000..f54ca58f3 --- /dev/null +++ b/login_server/src/cpp/SingletonManager/HederaTaskManager.cpp @@ -0,0 +1,17 @@ +#include "HederaTaskManager.h" + +HederaTaskManager* HederaTaskManager::getInstance() +{ + static HederaTaskManager one; + return &one; +} + +HederaTaskManager::HederaTaskManager() +{ + +} + +HederaTaskManager::~HederaTaskManager() +{ + +} \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/HederaTaskManager.h b/login_server/src/cpp/SingletonManager/HederaTaskManager.h new file mode 100644 index 000000000..361ace551 --- /dev/null +++ b/login_server/src/cpp/SingletonManager/HederaTaskManager.h @@ -0,0 +1,23 @@ +#ifndef __GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H +#define __GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H + +/*! + * @author: Dario Rekowski + * + * @date: 11.09.2020 + * + * @brief: Manage Hedera Task, waiting on Consensus for Hedera Transactions + * +*/ + +class HederaTaskManager +{ +public: + ~HederaTaskManager(); + + static HederaTaskManager* getInstance(); +protected: + HederaTaskManager(); +}; + +#endif //__GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H \ No newline at end of file diff --git a/login_server/src/cpp/SingletonManager/MemoryManager.cpp b/login_server/src/cpp/SingletonManager/MemoryManager.cpp index 2c6e98ca7..2ef51fc19 100644 --- a/login_server/src/cpp/SingletonManager/MemoryManager.cpp +++ b/login_server/src/cpp/SingletonManager/MemoryManager.cpp @@ -52,6 +52,14 @@ int MemoryBin::convertFromHex(const std::string& hex) return 0; } +bool MemoryBin::isSame(const MemoryBin* b) const +{ + if (b->size() != size()) { + return false; + } + return 0 == memcmp(data(), b->data(), size()); +} + // ************************************************************* @@ -76,30 +84,29 @@ MemoryPageStack::~MemoryPageStack() MemoryBin* MemoryPageStack::getFreeMemory() { - lock(); + Poco::ScopedLock _lock(mWorkMutex); + if (!mSize) { - unlock(); return nullptr; } if (mMemoryBinStack.size() == 0) { - unlock(); return new MemoryBin(mSize); } MemoryBin* memoryBin = mMemoryBinStack.top(); mMemoryBinStack.pop(); - unlock(); + return memoryBin; } void MemoryPageStack::releaseMemory(MemoryBin* memory) { if (!memory) return; - lock(); + Poco::ScopedLock _lock(mWorkMutex); + if (memory->size() != mSize) { - unlock(); throw new Poco::Exception("MemoryPageStack::releaseMemory wron memory page stack"); } mMemoryBinStack.push(memory); - unlock(); + } // *********************************************************************************** diff --git a/login_server/src/cpp/SingletonManager/MemoryManager.h b/login_server/src/cpp/SingletonManager/MemoryManager.h index 7cb9233f7..fc723f392 100644 --- a/login_server/src/cpp/SingletonManager/MemoryManager.h +++ b/login_server/src/cpp/SingletonManager/MemoryManager.h @@ -18,6 +18,7 @@ #include #include +#include #define MEMORY_MANAGER_PAGE_SIZE 10 @@ -41,12 +42,16 @@ public: inline unsigned char* data() { return mData; } inline const unsigned char* data() const { return mData; } + inline unsigned char* data(size_t startIndex) { assert(startIndex < mSize); return &mData[startIndex]; } + inline const unsigned char* data(size_t startIndex) const { assert(startIndex < mSize); return &mData[startIndex]; } std::string convertToHex(); //! \return 0 if ok //! -1 if bin is to small //! -2 if hex is invalid int convertFromHex(const std::string& hex); + bool isSame(const MemoryBin* b) const; + protected: MemoryBin(Poco::UInt32 size); ~MemoryBin(); diff --git a/login_server/src/cpp/SingletonManager/PendingTasksManager.cpp b/login_server/src/cpp/SingletonManager/PendingTasksManager.cpp new file mode 100644 index 000000000..1f8071908 --- /dev/null +++ b/login_server/src/cpp/SingletonManager/PendingTasksManager.cpp @@ -0,0 +1,251 @@ +#include "PendingTasksManager.h" +#include "../lib/JsonRequest.h" +#include "ErrorManager.h" + + +PendingTasksManager::PendingTasksManager() + : mCheckForFinishedTimer(2000, 2000) +{ + //mCheckForFinishedTimer +} + +PendingTasksManager::~PendingTasksManager() +{ + + Poco::ScopedLock _lock(mWorkMutex); + mCheckForFinishedTimer.stop(); + + for (auto it = mPendingTasks.begin(); it != mPendingTasks.end(); it++) { + delete it->second; + } + mPendingTasks.clear(); +} + +PendingTasksManager* PendingTasksManager::getInstance() +{ + static PendingTasksManager theOne; + return &theOne; +} + +int PendingTasksManager::load() +{ + // they add them self to Pending Task Manager + auto pending_tasks = controller::PendingTask::loadAll(); + Poco::TimerCallback callback(*this, &PendingTasksManager::checkForFinishedTasks); + mCheckForFinishedTimer.start(callback); + + return 0; +} + +int PendingTasksManager::addTask(Poco::AutoPtr task) +{ + if (task.isNull() || !task->getModel()) { + return -1; + } + auto model = task->getModel(); + Poco::ScopedLock _lock(mWorkMutex); + auto pending_task_list = getTaskListForUser(model->getUserId()); + pending_task_list->push_back(task); + return 0; + +} + +bool PendingTasksManager::removeTask(Poco::AutoPtr task) +{ + if (task.isNull() || !task->getModel()) { + return false; + } + auto model = task->getModel(); + Poco::ScopedLock _lock(mWorkMutex); + auto pending_task_list = getTaskListForUser(model->getUserId()); + bool removed = false; + for (auto it = pending_task_list->begin(); it != pending_task_list->end(); it++) { + if (task.get() == it->get()) { + pending_task_list->erase(it); + removed = true; + break; + } + } + // keep list for user in memory + return removed; +} + +PendingTasksManager::PendingTaskList* PendingTasksManager::getTaskListForUser(int userId) +{ + Poco::ScopedLock _lock(mWorkMutex); + auto it = mPendingTasks.find(userId); + if (it == mPendingTasks.end()) { + auto pending_list = new PendingTaskList; + mPendingTasks.insert(std::pair(userId, pending_list)); + return pending_list; + } + else { + return it->second; + } + +} +const PendingTasksManager::PendingTaskList* PendingTasksManager::getTaskListForUser(int userId) const +{ + Poco::ScopedLock _lock(mWorkMutex); + auto it = mPendingTasks.find(userId); + if (it != mPendingTasks.end()) { + return it->second; + } + return nullptr; +} + +bool PendingTasksManager::hasPendingTask(Poco::AutoPtr user, model::table::TaskType type) +{ + auto model = user->getModel(); + int user_id = model->getID(); + Poco::ScopedLock _lock(mWorkMutex); + auto it = mPendingTasks.find(user_id); + if (it != mPendingTasks.end()) { + auto task_list = it->second; + for (auto task = task_list->begin(); task != task_list->end(); it++) { + auto task_model = (*task)->getModel(); + if (type == task_model->getTaskType()) { + return true; + } + } + } + return false; + +} + +std::vector> PendingTasksManager::getPendingTasks(Poco::AutoPtr user, model::table::TaskType type) +{ + auto model = user->getModel(); + int user_id = model->getID(); + Poco::ScopedLock _lock(mWorkMutex); + std::vector> results; + + auto it = mPendingTasks.find(user_id); + if (it != mPendingTasks.end()) { + auto task_list = it->second; + results.reserve(task_list->size()); + for (auto taskIt = task_list->begin(); taskIt != task_list->end(); taskIt++) { + auto task_model = (*taskIt)->getModel(); + if (type == task_model->getTaskType()) { + results.push_back(*taskIt); + } + } + } + return results; +} + +std::vector> PendingTasksManager::getTransactionsUserMustSign(Poco::AutoPtr user) +{ + // TODO: don't use cast here, because can lead to errors + Poco::ScopedLock _lock(mWorkMutex); + std::vector> transactions_to_sign; + + for (auto map_it = mPendingTasks.begin(); map_it != mPendingTasks.end(); map_it++) + { + auto list = map_it->second; + for (auto list_it = list->begin(); list_it != list->end(); list_it++) + { + if ((*list_it)->getModel()->isGradidoTransaction()) { + auto transaction = dynamic_cast(list_it->get()); + if (transaction->mustSign(user)) { + transactions_to_sign.push_back(*list_it); + } + } + } + } + return transactions_to_sign; +} + +std::vector> PendingTasksManager::getTransactionSomeoneMustSign(Poco::AutoPtr user) +{ + // TODO: don't use cast here, because can lead to errors + Poco::ScopedLock _lock(mWorkMutex); + std::vector> transactions_to_sign; + + for (auto map_it = mPendingTasks.begin(); map_it != mPendingTasks.end(); map_it++) + { + auto list = map_it->second; + for (auto list_it = list->begin(); list_it != list->end(); list_it++) + { + if ((*list_it)->getModel()->isGradidoTransaction()) { + auto transaction = dynamic_cast(list_it->get()); + if (transaction->needSomeoneToSign(user)) { + transactions_to_sign.push_back(*list_it); + } + } + } + } + return transactions_to_sign; +} + +void PendingTasksManager::checkForFinishedTasks(Poco::Timer& timer) +{ + Poco::ScopedLock _lock(mWorkMutex); + + for (auto map_it = mPendingTasks.begin(); map_it != mPendingTasks.end(); map_it++) + { + auto list = map_it->second; + for (auto list_it = list->begin(); list_it != list->end(); list_it++) + { + if ((*list_it)->getModel()->isGradidoTransaction()) { + auto transaction = dynamic_cast(list_it->get()); + auto json = transaction->getModel()->getResultJson(); + bool removeIt = false; + if (!json.isNull()) { + if (json->get("state").toString() == "success") { + removeIt = true; + } + } + if (removeIt) { + transaction->deleteFromDB(); + list_it = list->erase(list_it); + if (!list->size()) break; + } + } + } + } +} + +Poco::AutoPtr PendingTasksManager::getPendingTask(int pendingTaskId) +{ + Poco::ScopedLock _lock(mWorkMutex); + for (auto map_it = mPendingTasks.begin(); map_it != mPendingTasks.end(); map_it++) + { + auto list = map_it->second; + for (auto list_it = list->begin(); list_it != list->end(); list_it++) + { + if ((*list_it)->getModel()->getID() == pendingTaskId) { + return *list_it; + } + } + } + return nullptr; +} + + +void PendingTasksManager::reportErrorToCommunityServer(Poco::AutoPtr task, std::string error, std::string errorDetails) +{ + // TODO: choose user specific server + JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, ServerConfig::g_phpServerPort); + //Poco::Net::NameValueCollection payload; + Poco::JSON::Object payload; + + auto task_model = task->getModel(); + auto user_model = task->getUser()->getModel(); + + payload.set("created", task_model->getCreated()); + payload.set("id", task_model->getID()); + payload.set("type", task_model->getTaskTypeString()); + payload.set("public_key", user_model->getPublicKeyHex()); + payload.set("error", error); + payload.set("errorMessage", errorDetails); + + auto ret = phpServerRequest.request("errorInTransaction", payload); + if (ret == JSON_REQUEST_RETURN_ERROR) + { + auto em = ErrorManager::getInstance(); + em->addError(new Error("PendingTasksManager::reportErrorToCommunityServer", "php server error")); + em->getErrors(&phpServerRequest); + em->sendErrorsAsEmail(); + } +} diff --git a/login_server/src/cpp/SingletonManager/PendingTasksManager.h b/login_server/src/cpp/SingletonManager/PendingTasksManager.h new file mode 100644 index 000000000..8444f32ea --- /dev/null +++ b/login_server/src/cpp/SingletonManager/PendingTasksManager.h @@ -0,0 +1,68 @@ +/*! +* +* \author: einhornimmond +* +* \date: 13.10.20 +* +* \brief: manage tasks which need to wait on extern work + +* like hedera tasks waiting on hedera network processing transactions +* like gradido transactions which are signed from additional people like ManageGroup Tasks +*/ + +#ifndef GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_PENDING_TASKS_MANAGER +#define GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_PENDING_TASKS_MANAGER + +#include "../controller/PendingTask.h" +#include "../controller/User.h" +#include "../model/gradido/Transaction.h" + +class UserUpdateGroupPage; + +class PendingTasksManager: protected UniLib::lib::MultithreadContainer +{ + friend UserUpdateGroupPage; +public: + typedef std::list> PendingTaskList; + + ~PendingTasksManager(); + + static PendingTasksManager* getInstance(); + + //! \brief load pending tasks from db at server start + int load(); + + //! \return -1 task is zero + //! \return 0 if added + int addTask(Poco::AutoPtr task); + bool removeTask(Poco::AutoPtr task); + + //! check if tasks can be removed + void checkForFinishedTasks(Poco::Timer& timer); + + //! by calling this, important is to call lock to prevent vanishing the list while working with it, + //! and unlock afterwards + //! \return list or nullptr if no list for user exist + const PendingTaskList* getTaskListForUser(int userId) const; + bool hasPendingTask(Poco::AutoPtr user, model::table::TaskType type); + std::vector> getPendingTasks(Poco::AutoPtr user, model::table::TaskType type); + Poco::AutoPtr getPendingTask(int pendingTaskId); + std::vector> getTransactionsUserMustSign(Poco::AutoPtr user); + std::vector> getTransactionSomeoneMustSign(Poco::AutoPtr user); + + void reportErrorToCommunityServer(Poco::AutoPtr task, std::string error, std::string errorDetails); + +protected: + PendingTasksManager(); + + Poco::Timer mCheckForFinishedTimer; + + + std::map mPendingTasks; + //! \return list for user, creating new list and map entry if not exist + PendingTaskList* getTaskListForUser(int userId); +}; + + + +#endif //GRADIDO_LOGIN_SERVER_SINGLETON_MANAGER_PENDING_TASKS_MANAGER \ 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..01df87d3a 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.cpp +++ b/login_server/src/cpp/SingletonManager/SessionManager.cpp @@ -1,626 +1,635 @@ -#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_GROUP_ALIAS: mValidations[i] = new Poco::RegularExpression("^[a-z0-9-]{3,120}"); break; + case VALIDATE_HEDERA_ID: mValidations[i] = new Poco::RegularExpression("^[0-9]*\.[0-9]*\.[0-9]\.$"); break; + case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break; + case VALIDATE_ONLY_INTEGER: mValidations[i] = new Poco::RegularExpression("^[0-9]*$"); break; + case VALIDATE_ONLY_DECIMAL: mValidations[i] = new Poco::RegularExpression("^[0-9]*(\.|,)[0-9]*$"); break; + case VALIDATE_ONLY_HEX: mValidations[i] = new Poco::RegularExpression("^(0x)?[a-fA-F0-9]*$"); break; + //case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break; + case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); 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 { + NotificationList 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 { + NotificationList 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()) { + //printf("[SessionManager::getSession] found existing session, try if active...\n"); + 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, NotificationList* 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/SingletonManager/SessionManager.h b/login_server/src/cpp/SingletonManager/SessionManager.h index 2f720b82b..e20002856 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.h +++ b/login_server/src/cpp/SingletonManager/SessionManager.h @@ -27,7 +27,13 @@ enum SessionValidationTypes { VALIDATE_EMAIL, VALIDATE_PASSWORD, VALIDATE_PASSPHRASE, + VALIDATE_GROUP_ALIAS, + VALIDATE_HEDERA_ID, VALIDATE_HAS_NUMBER, + VALIDATE_ONLY_INTEGER, + VALIDATE_ONLY_DECIMAL, + VALIDATE_ONLY_HEX, + VALIDATE_ONLY_URL, VALIDATE_HAS_SPECIAL_CHARACTER, VALIDATE_HAS_UPPERCASE_LETTER, VALIDATE_HAS_LOWERCASE_LETTER, @@ -66,7 +72,7 @@ public: bool isValid(const std::string& subject, SessionValidationTypes validationType); //! \return true if password is valid - bool checkPwdValidation(const std::string& pwd, ErrorList* errorReciver); + bool checkPwdValidation(const std::string& pwd, NotificationList* errorReciver); void checkTimeoutSession(); diff --git a/login_server/src/cpp/controller/AppAccessToken.cpp b/login_server/src/cpp/controller/AppAccessToken.cpp new file mode 100644 index 000000000..1da6ddd0b --- /dev/null +++ b/login_server/src/cpp/controller/AppAccessToken.cpp @@ -0,0 +1,65 @@ +#include "AppAccessToken.h" + +#include "sodium.h" + +namespace controller +{ + AppAccessToken::AppAccessToken(model::table::AppAccessToken* dbModel) + { + mDBModel = dbModel; + } + + AppAccessToken::~AppAccessToken() + { + + } + + Poco::AutoPtr AppAccessToken::create(int user_id) + { + auto code = createAppAccessCode(); + auto db = new model::table::AppAccessToken(code, user_id); + return Poco::AutoPtr(new AppAccessToken(db)); + } + + Poco::AutoPtr AppAccessToken::load(const Poco::UInt64& code) + { + auto db = new model::table::AppAccessToken(); + if (db->loadFromDB("app_access_tokens", code) == 1) { + return Poco::AutoPtr(new AppAccessToken(db)); + } + db->release(); + return nullptr; + } + + std::vector> AppAccessToken::load(int user_id) + { + auto db = new model::table::AppAccessToken(); + auto results = db->loadFromDB("user_id", user_id, 2); + + std::vector> resultObjects; + if (db->errorCount()) { + db->sendErrorsAsEmail(); + db->release(); + return resultObjects; + } + db->release(); + if (results.size() == 0) { + return resultObjects; + } + for (auto it = results.begin(); it != results.end(); it++) { + resultObjects.push_back(new AppAccessToken(new model::table::AppAccessToken(*it))); + } + + return resultObjects; + } + + Poco::UInt64 AppAccessToken::createAppAccessCode() + { + Poco::UInt64 resultCode; + uint32_t* code_p = (uint32_t*)&resultCode; + for (int i = 0; i < sizeof(resultCode) / 4; i++) { + code_p[i] = randombytes_random(); + } + return resultCode; + } +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/AppAccessToken.h b/login_server/src/cpp/controller/AppAccessToken.h new file mode 100644 index 000000000..35093c442 --- /dev/null +++ b/login_server/src/cpp/controller/AppAccessToken.h @@ -0,0 +1,34 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE + +#include "../model/table/AppAccessToken.h" + +#include "TableControllerBase.h" + +namespace controller { + class AppAccessToken : public TableControllerBase + { + public: + + ~AppAccessToken(); + + static Poco::AutoPtr create(int user_id); + + static Poco::AutoPtr load(const Poco::UInt64& code); + static std::vector> load(int user_id); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + + inline Poco::Timespan getAge() { return Poco::DateTime() - getModel()->getCreated(); } + + protected: + AppAccessToken(model::table::AppAccessToken* dbModel); + static Poco::UInt64 createAppAccessCode(); + + //table::EmailOptIn* mDBModel; + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/CryptoKey.cpp b/login_server/src/cpp/controller/CryptoKey.cpp new file mode 100644 index 000000000..338ad05a4 --- /dev/null +++ b/login_server/src/cpp/controller/CryptoKey.cpp @@ -0,0 +1,150 @@ + +#include "CryptoKey.h" +#include "../SingletonManager/ErrorManager.h" +#include "../lib/DataTypeConverter.h" + +namespace controller { + + CryptoKey::CryptoKey(model::table::CryptoKey* dbModel) + { + mDBModel = dbModel; + } + + CryptoKey::~CryptoKey() + { + + } + + Poco::AutoPtr CryptoKey::create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user, bool saveEncrypted/* = true*/) + { + auto mm = MemoryManager::getInstance(); + + MemoryBin* private_key = nullptr; + auto public_key = hederaKeyPair->getPublicKeyCopy(); + + model::table::KeyType key_type; + if (saveEncrypted) { + key_type = model::table::KEY_TYPE_ED25519_HEDERA_ENCRYPTED; + private_key = hederaKeyPair->getCryptedPrivKey(user->getPassword()); + } + else { + key_type = model::table::KEY_TYPE_ED25519_HEDERA_CLEAR; + private_key = hederaKeyPair->getPrivateKeyCopy(); + } + auto db = new model::table::CryptoKey(private_key, public_key, key_type); + + mm->releaseMemory(private_key); + mm->releaseMemory(public_key); + + auto cryptoKey = new CryptoKey(db); + return Poco::AutoPtr(cryptoKey); + } + + Poco::AutoPtr CryptoKey::load(int id) + { + auto db = new model::table::CryptoKey(); + if (1 == db->loadFromDB("id", id)) { + auto cryptoKey = new CryptoKey(db); + return Poco::AutoPtr(cryptoKey); + } + return nullptr; + } + + Poco::AutoPtr CryptoKey::load(MemoryBin* publicKey) + { + return load(*publicKey, publicKey->size()); + } + + Poco::AutoPtr CryptoKey::load(const unsigned char* publicKey, size_t size) + { + assert(publicKey); + assert(size); + + Poco::Data::BLOB public_key_blob(publicKey, size); + auto db = new model::table::CryptoKey(); + auto count = db->loadFromDB("public_key", public_key_blob); + if (!count) return nullptr; + if (1 == count) return new CryptoKey(db); + + auto em = ErrorManager::getInstance(); + em->addError(new Error("CryptoKey::load", "found more than one crypto key with same public key")); + em->sendErrorsAsEmail(); + return nullptr; + } + + std::unique_ptr CryptoKey::getKeyPair(Poco::AutoPtr user) const + { + auto model = getModel(); + assert(model); + + if (!model->isEncrypted()) { + return getKeyPair(); + } + + if (!model->hasPrivateKey()) { + printf("[CryptoKey::getKeyPair] return null, no private key\n"); + return nullptr; + } + + auto password = user->getPassword(); + auto mm = MemoryManager::getInstance(); + if (!password) { + printf("[CryptoKey::getKeyPair] return null, password empty\n"); + } + MemoryBin* clearPrivateKey = nullptr; + auto encrypted_private_key = model->getPrivateKey(); + //auto encrypted_private_key_hex_string = DataTypeConverter::binToHex(encrypted_private_key); + //printf("[CryptoKey::getKeyPair] encrypted private key hex: %s\n", encrypted_private_key_hex_string.data()); + if (password->decrypt(model->getPrivateKey(), &clearPrivateKey) != SecretKeyCryptography::AUTH_DECRYPT_OK) { + printf("[CryptoKey::getKeyPair] return null, error decrypting\n"); + return nullptr; + } + auto key_pair = std::make_unique(clearPrivateKey->data(), clearPrivateKey->size(), model->getPublicKey(), model->getPublicKeySize()); + mm->releaseMemory(clearPrivateKey); + return key_pair; + } + + std::unique_ptr CryptoKey::getKeyPair() const + { + auto model = getModel(); + assert(model); + if (!model->hasPrivateKey() || model->isEncrypted()) { + printf("[CryptoKey::getKeyPair] no private key or encrypted\n"); + return nullptr; + } + + + return std::make_unique(model->getPrivateKey(), model->getPublicKey(), model->getPublicKeySize()); + } + + bool CryptoKey::changeEncryption(Poco::AutoPtr user) + { + auto key_pair = getKeyPair(user); + if (!key_pair || !key_pair->hasPrivateKey()) { + addError(new Error("Crypto Key", "key pair or private key was null")); + return false; + } + auto model = getModel(); + auto mm = MemoryManager::getInstance(); + // update key type + model->changeKeyTypeToggleEncrypted(); + MemoryBin* private_key = nullptr; + if (model->isEncrypted()) { + private_key = key_pair->getCryptedPrivKey(user->getPassword()); + } + else { + private_key = key_pair->getPrivateKeyCopy(); + } + if (!private_key) { + addError(new Error("Crypto Key", " private_key not get")); + return false; + } + model->setPrivateKey(private_key); + // save changes into db + model->updatePrivkeyAndKeyType(); + + mm->releaseMemory(private_key); + return true; + } +} + diff --git a/login_server/src/cpp/controller/CryptoKey.h b/login_server/src/cpp/controller/CryptoKey.h new file mode 100644 index 000000000..ddd2a7435 --- /dev/null +++ b/login_server/src/cpp/controller/CryptoKey.h @@ -0,0 +1,50 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_CRYPTO_KEY_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_CRYPTO_KEY_INCLUDE + +#include "../model/table/CryptoKey.h" +#include "../Crypto/KeyPairHedera.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" +#include "User.h" + + + +namespace controller { + + class HederaAccount; + + class CryptoKey : public TableControllerBase, public NotificationList + { + friend HederaAccount; + public: + + ~CryptoKey(); + + static Poco::AutoPtr create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user, bool saveEncrypted = true); + + //! if returned ptr is NULL, dataset not found + static Poco::AutoPtr load(int id); + static Poco::AutoPtr load(MemoryBin* publicKey); + static Poco::AutoPtr load(const unsigned char* publicKey, size_t size); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + inline const model::table::CryptoKey* getModel() const { return _getModel(); } + + std::unique_ptr getKeyPair(Poco::AutoPtr user) const; + std::unique_ptr getKeyPair() const; + + + + protected: + + bool changeEncryption(Poco::AutoPtr user); + CryptoKey(model::table::CryptoKey* dbModel); + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_CRYPTO_KEY_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/EmailVerificationCode.cpp b/login_server/src/cpp/controller/EmailVerificationCode.cpp index 57022b191..310108f42 100644 --- a/login_server/src/cpp/controller/EmailVerificationCode.cpp +++ b/login_server/src/cpp/controller/EmailVerificationCode.cpp @@ -6,6 +6,7 @@ namespace controller { EmailVerificationCode::EmailVerificationCode(model::table::EmailOptIn* dbModel) + : mBaseUrl(ServerConfig::g_serverPath) { mDBModel = dbModel; } @@ -96,7 +97,7 @@ namespace controller { std::string EmailVerificationCode::getLink() { - std::string link = ServerConfig::g_serverPath; + std::string link = mBaseUrl; link += "/checkEmail/"; link += std::to_string(getModel()->getCode()); return link; diff --git a/login_server/src/cpp/controller/EmailVerificationCode.h b/login_server/src/cpp/controller/EmailVerificationCode.h index 77d607de3..4e6ac4f03 100644 --- a/login_server/src/cpp/controller/EmailVerificationCode.h +++ b/login_server/src/cpp/controller/EmailVerificationCode.h @@ -26,10 +26,14 @@ namespace controller { std::string getLink(); inline Poco::Timespan getAge() { return Poco::DateTime() - getModel()->getCreated(); } + inline void setBaseUrl(const std::string& baseUrl) { mBaseUrl = baseUrl; } + protected: EmailVerificationCode(model::table::EmailOptIn* dbModel); static Poco::UInt64 createEmailVerificationCode(); + std::string mBaseUrl; + //table::EmailOptIn* mDBModel; }; } diff --git a/login_server/src/cpp/controller/Group.cpp b/login_server/src/cpp/controller/Group.cpp new file mode 100644 index 000000000..d033d37f1 --- /dev/null +++ b/login_server/src/cpp/controller/Group.cpp @@ -0,0 +1,82 @@ + +#include "Group.h" + +namespace controller { + + Group::Group(model::table::Group* dbModel) + { + mDBModel = dbModel; + } + + Group::~Group() + { + + } + + Poco::AutoPtr Group::create(const std::string& alias, const std::string& name, const std::string& url, const std::string& home, const std::string& description) + { + auto db = new model::table::Group(alias, name, url, home, description); + auto group = new Group(db); + return Poco::AutoPtr(group); + } + + std::vector> Group::load(const std::string& alias) + { + auto db = new model::table::Group(); + auto group_list = db->loadFromDB("alias", alias, 1); + + std::vector> resultVector; + resultVector.reserve(group_list.size()); + for (auto it = group_list.begin(); it != group_list.end(); it++) { + resultVector.push_back(new Group(new model::table::Group(*it))); + } + return resultVector; + } + + Poco::AutoPtr Group::load(int id) + { + auto db = new model::table::Group(); + if (1 == db->loadFromDB("id", id)) { + return new Group(db); + } + else { + return nullptr; + } + } + + + std::vector> Group::listAll() + { + auto db = new model::table::Group(); + std::vector group_list; + // throw an unresolved external symbol error + //group_list = db->loadAllFromDB(); + + // work around for not working call to loadAllFromDB + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + + select << "SELECT id, alias, name, url, home, description FROM " << db->getTableName() + , Poco::Data::Keywords::into(group_list); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + printf("[Group::listAll] poco exception: %s\n", ex.displayText().data()); + } + // work around end + std::vector> resultVector; + + resultVector.reserve(group_list.size()); + for (auto it = group_list.begin(); it != group_list.end(); it++) { + Poco::AutoPtr group_ptr(new Group(new model::table::Group(*it))); + resultVector.push_back(group_ptr); + } + return resultVector; + } + +} + diff --git a/login_server/src/cpp/controller/Group.h b/login_server/src/cpp/controller/Group.h new file mode 100644 index 000000000..a9b3ca55d --- /dev/null +++ b/login_server/src/cpp/controller/Group.h @@ -0,0 +1,34 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE + +#include "../model/table/Group.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" + +namespace controller { + class Group : public TableControllerBase + { + public: + + ~Group(); + + static Poco::AutoPtr create(const std::string& alias, const std::string& name, const std::string& url, const std::string& home, const std::string& description); + + static std::vector> load(const std::string& alias); + static Poco::AutoPtr load(int id); + static std::vector> listAll(); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + + + protected: + Group(model::table::Group* dbModel); + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaAccount.cpp b/login_server/src/cpp/controller/HederaAccount.cpp new file mode 100644 index 000000000..e6e4e490e --- /dev/null +++ b/login_server/src/cpp/controller/HederaAccount.cpp @@ -0,0 +1,294 @@ + +#include "HederaAccount.h" +#include "NodeServer.h" +#include "CryptoKey.h" +#include "../model/hedera/Query.h" +//#include "../model/hedera/Tr" +#include "HederaRequest.h" + +#include "../SingletonManager/ErrorManager.h" + +using namespace Poco::Data::Keywords; + +namespace controller { + + HederaAccount::HederaAccount(model::table::HederaAccount* dbModel) + { + mDBModel = dbModel; + } + + HederaAccount::~HederaAccount() + { + } + + Poco::AutoPtr HederaAccount::create(int user_id, int account_hedera_id, int account_key_id, Poco::UInt64 balance/* = 0*/, ServerConfig::HederaNetworkType type/* = HEDERA_MAINNET*/) + { + auto db = new model::table::HederaAccount(user_id, account_hedera_id, account_key_id, balance, type); + auto group = new HederaAccount(db); + return Poco::AutoPtr(group); + } + + std::vector> HederaAccount::load(const std::string& fieldName, int fieldValue) + { + auto db = new model::table::HederaAccount(); + auto hedera_account_list = db->loadFromDB(fieldName, fieldValue, 2); + std::vector> resultVector; + resultVector.reserve(hedera_account_list.size()); + for (auto it = hedera_account_list.begin(); it != hedera_account_list.end(); it++) { + //mHederaID + auto db = new model::table::HederaAccount(*it); + auto hedera_account = new HederaAccount(db); + resultVector.push_back(hedera_account); + } + return resultVector; + } + + Poco::AutoPtr HederaAccount::load(int id) + { + auto db = new model::table::HederaAccount(); + if (1 == db->loadFromDB("id", id)) { + return new HederaAccount(db); + } + db->release(); + return nullptr; + } + + Poco::AutoPtr HederaAccount::getHederaId() + { + if (mHederaID.isNull()) { + mHederaID = HederaId::load(getModel()->getAccountHederaId()); + } + return mHederaID; + } + + Poco::AutoPtr HederaAccount::load(Poco::AutoPtr hederaId) + { + if (!hederaId->isExistInDB()) return nullptr; + + auto db = new model::table::HederaAccount(); + auto result_count = db->loadFromDB("account_hedera_id", hederaId->getModel()->getID()); + if (1 == result_count) { + return new HederaAccount(db); + } + // maybe change later to using error manager and send email + printf("[HederaAccount::load] result_count not expected: %d\n", result_count); + return nullptr; + } + + Poco::AutoPtr HederaAccount::pick(ServerConfig::HederaNetworkType networkType, bool encrypted/* = false*/, int user_id/* = 0*/) + { + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + + Poco::Tuple result_tuple; + int crypto_key_type = encrypted ? model::table::KEY_TYPE_ED25519_HEDERA_ENCRYPTED : model::table::KEY_TYPE_ED25519_HEDERA_CLEAR; + int network_type_int = (int)networkType; + + select + << "SELECT account.id, account.user_id, account.account_hedera_id, account.account_key_id, account.balance, i.shardNum, i.realmNum, i.num " + << "FROM hedera_accounts as account " + << "JOIN hedera_ids as i ON(i.id = account_hedera_id) " + << "JOIN crypto_keys as k ON(k.id = account.account_key_id) " + << "WHERE account.network_type = ? " + << "AND k.crypto_key_type_id = ? "; + + if (user_id > 0) { + select << " AND account.user_id = ? "; + } + select << "ORDER BY RAND() LIMIT 1 " + , into(result_tuple), use(network_type_int) , use(crypto_key_type); + + if (user_id > 0) { + select, use(user_id); + } + + try { + select.executeAsync(); + select.wait(); + auto result_count = select.rowsExtracted(); + if (1 == result_count) { + auto db = new model::table::HederaAccount( + result_tuple.get<1>(), result_tuple.get<2>(), result_tuple.get<3>(), + result_tuple.get<4>(), networkType + ); + db->setID(result_tuple.get<0>()); + Poco::AutoPtr hedera_account(new HederaAccount(db)); + auto hedera_id_db = new model::table::HederaId(result_tuple.get<5>(), result_tuple.get<6>(), result_tuple.get<7>()); + Poco::AutoPtr hedera_id(new HederaId(hedera_id_db)); + hedera_account->setHederaId(hedera_id); + return hedera_account; + } + else if(result_count > 1) { + printf("[HederaAccount::pick] extracted rows not like expected\n"); + } + } + catch (Poco::Exception& ex) { + auto em = ErrorManager::getInstance(); + static const char* function_name = "HederaAccount::pick"; + printf("exception: %s\n", ex.displayText().data()); + em->addError(new ParamError(function_name, "mysql error: ", ex.displayText())); + em->addError(new ParamError(function_name, "network type: ", networkType)); + em->addError(new ParamError(function_name, "encrypted: ", (int)encrypted)); + em->sendErrorsAsEmail(); + } + + return nullptr; + + } + + std::vector> HederaAccount::listAll() + { + auto db = new model::table::HederaAccount(); + std::vector group_list; + // throw an unresolved external symbol error + group_list = db->loadAllFromDB(); + + // work around for not working call to loadAllFromDB + /*auto cm = ConnectionManager::getInstance(); + + Poco::Data::Statement select(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); + + select << "SELECT id, alias, name, url, description FROM " << db->getTableName() + , Poco::Data::Keywords::into(group_list); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + printf("[Group::listAll] poco exception: %s\n", ex.displayText().data()); + } + //*/ //work around end + std::vector> resultVector; + + resultVector.reserve(group_list.size()); + for (auto it = group_list.begin(); it != group_list.end(); it++) { + Poco::AutoPtr group_ptr(new HederaAccount(new model::table::HederaAccount(*it))); + resultVector.push_back(group_ptr); + } + return resultVector; + } + + Poco::AutoPtr HederaAccount::getCryptoKey() const + { + auto model = getModel(); + return controller::CryptoKey::load(model->getCryptoKeyId()); + } + + bool HederaAccount::hederaAccountGetBalance(Poco::AutoPtr user) + { + static const char* functionName = "HederaAccount::updateBalanceFromHedera"; + + if (user.isNull() || !user->getModel()) { + printf("[%s] invalid user\n", functionName); + return false; + } + + auto account_model = getModel(); + auto hedera_node = NodeServer::pick(account_model->networkTypeToNodeServerType(account_model->getNetworkType())); + if (hedera_node.url == "") { + addError(new Error("Hedera Node", "no hedera node found")); + return false; + } + auto crypto_key = controller::CryptoKey::load(account_model->getCryptoKeyId()); + if (crypto_key.isNull()) { + addError(new Error("Keys", "could not found crypto key for account")); + printf("[%s] error, crypto key with id: %d not found\n", functionName, account_model->getCryptoKeyId()); + return false; + } + auto hedera_key_pair = crypto_key->getKeyPair(user); + if (!hedera_key_pair) { + addError(new Error("Keys", "error decrypting private key")); + printf("[%s] error decrypting private key with id: %d, with user: %d\n", functionName, account_model->getCryptoKeyId(), user->getModel()->getID()); + return false; + } + + auto query = model::hedera::Query::getBalance(getHederaId(), hedera_node); + + if (!query) { + printf("[%s] error creating query\n", functionName); + } + query->sign(std::move(hedera_key_pair)); + + HederaRequest request; + model::hedera::Response response; + try { + if (HEDERA_REQUEST_RETURN_OK == request.request(query, &response) && proto::OK == response.getResponseCode()) { + account_model->updateIntoDB("balance", response.getAccountBalance()); + } + else { + addError(new Error("Hedera", "Hedera request failed")); + addError(new ParamError("Hedera", "Hedera Response Code", proto::ResponseCodeEnum_Name(response.getResponseCode()))); + } + //request.requestViaPHPRelay(query); + } + catch (Poco::Exception& ex) { + printf("[HederaAccount::updateBalanceFromHedera] exception calling hedera request: %s\n", ex.displayText().data()); + } + + if (0 == errorCount() && 0 == request.errorCount()) { + return true; + } + getErrors(&request); + + return false; + } + + bool HederaAccount::hederaAccountCreate(int autoRenewPeriodSeconds, double initialBalance) + { + auto account_model = getModel(); + auto new_key_pair = KeyPairHedera::create(); + auto transaction_body = createTransactionBody(); + //CryptoCreateTransaction(const unsigned char* publicKey, Poco::UInt64 initialBalance, int autoRenewPeriod); + model::hedera::CryptoCreateTransaction create_transaction(new_key_pair->getPublicKey(), initialBalance, autoRenewPeriodSeconds); + transaction_body->setCryptoCreate(create_transaction); + + + return false; + } + + bool HederaAccount::changeEncryption(Poco::AutoPtr user) + { + assert(!user.isNull() && user->getModel()); + auto model = getModel(); + assert(!model.isNull()); + + if (user->getModel()->getID() != model->getUserId()) { + addError(new Error("Hedera Account", "wrong user")); + return false; + } + auto crypto_key = controller::CryptoKey::load(model->getCryptoKeyId()); + if (crypto_key.isNull()) { + addError(new Error("Hedera Account", "couldn't find crypto key")); + return false; + } + bool result = crypto_key->changeEncryption(user); + getErrors(crypto_key); + return result; + + } + + std::unique_ptr HederaAccount::createTransactionBody() + { + auto account_model = getModel(); + auto hedera_node = NodeServer::pick(account_model->networkTypeToNodeServerType(account_model->getNetworkType())); + auto hedera_id = getHederaId(); + if (hedera_id.isNull()) { + return nullptr; + } + return std::make_unique(mHederaID, hedera_node); + } + + + std::string HederaAccount::toShortSelectOptionName() + { + std::stringstream ss; + auto model = getModel(); + ss << model::table::HederaAccount::hederaNetworkTypeToString((ServerConfig::HederaNetworkType)model->getNetworkType()) << " "; + ss << getHederaId()->getModel()->toString() << " " << ((double)model->getBalance() / 100000000.0) << " Hbar"; + return ss.str(); + } + +} + diff --git a/login_server/src/cpp/controller/HederaAccount.h b/login_server/src/cpp/controller/HederaAccount.h new file mode 100644 index 000000000..9490b4bfb --- /dev/null +++ b/login_server/src/cpp/controller/HederaAccount.h @@ -0,0 +1,56 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ACCOUNT_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ACCOUNT_INCLUDE + +#include "HederaId.h" +#include "User.h" +#include "../model/table/HederaAccount.h" + +#include "../model/hedera/TransactionBody.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" +#include "CryptoKey.h" + +namespace controller { + class HederaAccount : public TableControllerBase, public NotificationList + { + public: + ~HederaAccount(); + + static Poco::AutoPtr create(int user_id, int account_hedera_id, int account_key_id, Poco::UInt64 balance = 0, ServerConfig::HederaNetworkType type = ServerConfig::HEDERA_MAINNET); + + static std::vector> load(const std::string& fieldName, int fieldValue); + static Poco::AutoPtr load(int id); + static Poco::AutoPtr load(Poco::AutoPtr hederaId); + static std::vector> listAll(); + //! \brief for picking a account for paying transaction, mostly consensusSendMessage + static Poco::AutoPtr pick(ServerConfig::HederaNetworkType networkType, bool encrypted = false, int user_id = 0); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + std::string toShortSelectOptionName(); + + inline Poco::AutoPtr getModel() { return _getModel(); } + inline const model::table::HederaAccount* getModel() const { return _getModel(); } + + inline void setHederaId(Poco::AutoPtr hederaId) { mHederaID = hederaId; } + Poco::AutoPtr getHederaId(); + + Poco::AutoPtr getCryptoKey() const; + + bool hederaAccountGetBalance(Poco::AutoPtr user); + bool hederaAccountCreate(int autoRenewPeriodSeconds, double initialBalance); + bool changeEncryption(Poco::AutoPtr user); + + //! \brief create Transaction body with this hedera account as operator + std::unique_ptr createTransactionBody(); + + protected: + + HederaAccount(model::table::HederaAccount* dbModel); + Poco::AutoPtr mHederaID; + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ACCOUNT_INCLUDE diff --git a/login_server/src/cpp/controller/HederaId.cpp b/login_server/src/cpp/controller/HederaId.cpp new file mode 100644 index 000000000..3e7da7319 --- /dev/null +++ b/login_server/src/cpp/controller/HederaId.cpp @@ -0,0 +1,127 @@ +#include "HederaId.h" +#include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/SessionManager.h" + +#include "../lib/DataTypeConverter.h" + +using namespace Poco::Data::Keywords; + +namespace controller { + + HederaId::HederaId(model::table::HederaId* dbModel) + { + mDBModel = dbModel; + } + + HederaId::~HederaId() + { + + } + + Poco::AutoPtr HederaId::create(Poco::UInt64 shardNum, Poco::UInt64 realmNum, Poco::UInt64 num) + { + auto db = new model::table::HederaId(shardNum, realmNum, num); + + auto hedera_id = new HederaId(db); + return Poco::AutoPtr(hedera_id); + } + + Poco::AutoPtr HederaId::create(std::string hederaIdString) + { + auto sm = SessionManager::getInstance(); + if (!sm->isValid(hederaIdString, VALIDATE_HEDERA_ID)) { + return nullptr; + } + std::vector number_strings; + std::istringstream f(hederaIdString); + std::string s; + while (getline(f, s, '.')) { + std::cout << s << std::endl; + number_strings.push_back(s); + } + Poco::UInt64 numbers[3]; + for (int i = 0; i < 3; i++) { + unsigned long long temp_number; + if (DataTypeConverter::NUMBER_PARSE_OKAY != DataTypeConverter::strToInt(number_strings[i], temp_number)) { + return nullptr; + } + numbers[i] = temp_number; + } + auto db = new model::table::HederaId(numbers[0], numbers[1], numbers[2]); + + auto hedera_id = new HederaId(db); + return Poco::AutoPtr(hedera_id); + } + + Poco::AutoPtr HederaId::load(int id) + { + auto db = new model::table::HederaId(); + if (1 == db->loadFromDB("id", id)) { + auto cryptoKey = new HederaId(db); + return Poco::AutoPtr(cryptoKey); + } + return nullptr; + } + + Poco::AutoPtr HederaId::find(int groupId, ServerConfig::HederaNetworkType networkType) + { + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + model::table::HederaIdTuple result_tuple; + int network_type_int = (int)networkType; + + Poco::Data::Statement select(session); + select << "SELECT h.id, h.shardNum, h.realmNum, h.num FROM hedera_ids as h " + << "JOIN hedera_topics as topic ON(topic.topic_hedera_id = h.id) " + << "JOIN hedera_accounts as account ON(account.id = topic.auto_renew_account_hedera_id) " + << "WHERE topic.group_id = ? AND account.network_type = ?" + , into(result_tuple), use(groupId), use(network_type_int); + + try { + select.executeAsync(); + select.wait(); + auto result_count = select.rowsExtracted(); + if (1 == result_count) { + return new HederaId(new model::table::HederaId(result_tuple)); + } + else if(result_count > 1) { + printf("[HederaId::find] result_count other as expected: %d\n", result_count); + } + } + catch (Poco::Exception& ex) { + auto em = ErrorManager::getInstance(); + static const char* function_name = "HederaId::find"; + em->addError(new ParamError(function_name, "mysql error: ", ex.displayText())); + em->addError(new ParamError(function_name, "group id: ", groupId)); + em->addError(new ParamError(function_name, "network type: ", (int)networkType)); + em->sendErrorsAsEmail(); + } + return nullptr; + } + + void HederaId::copyToProtoAccountId(proto::AccountID* protoAccountId) const + { + auto model = getModel(); + protoAccountId->set_shardnum(model->getShardNum()); + protoAccountId->set_realmnum(model->getRealmNum()); + protoAccountId->set_accountnum(model->getNum()); + } + + void HederaId::copyToProtoTopicId(proto::TopicID* protoTopicId) const + { + auto model = getModel(); + protoTopicId->set_shardnum(model->getShardNum()); + protoTopicId->set_realmnum(model->getRealmNum()); + protoTopicId->set_topicnum(model->getNum()); + } + + bool HederaId::isExistInDB() + { + auto model = getModel(); + if (model->getID() > 0) return true; + //std::vector loadFromDB(const std::vector& fieldNames, const std::vector& fieldValues, MysqlConditionType conditionType = MYSQL_CONDITION_AND, int expectedResults = 0); + model->isExistInDB(); + return model->getID() != 0; + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaId.h b/login_server/src/cpp/controller/HederaId.h new file mode 100644 index 000000000..5ec8dffdf --- /dev/null +++ b/login_server/src/cpp/controller/HederaId.h @@ -0,0 +1,46 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ID_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ID_INCLUDE + +#include "../model/table/HederaId.h" +#include "../model/table/HederaAccount.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" + +#include "../proto/hedera/BasicTypes.pb.h" + +namespace controller { + class HederaAccount; + class HederaId : public TableControllerBase + { + friend HederaAccount; + public: + + ~HederaId(); + + static Poco::AutoPtr create(Poco::UInt64 shardNum, Poco::UInt64 realmNum, Poco::UInt64 num); + static Poco::AutoPtr create(std::string hederaIdString); + + static Poco::AutoPtr load(int id); + //! \return hedera topic id for group and network type (should exist only one) + static Poco::AutoPtr find(int groupId, ServerConfig::HederaNetworkType networkType); + + bool isExistInDB(); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + inline const model::table::HederaId* getModel() const { return _getModel(); } + + void copyToProtoAccountId(proto::AccountID* protoAccountId) const; + void copyToProtoTopicId(proto::TopicID* protoTopicId) const; + + + protected: + HederaId(model::table::HederaId* dbModel); + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_ID_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaRequest.cpp b/login_server/src/cpp/controller/HederaRequest.cpp new file mode 100644 index 000000000..9a01d3bc1 --- /dev/null +++ b/login_server/src/cpp/controller/HederaRequest.cpp @@ -0,0 +1,174 @@ +#include "HederaRequest.h" +#include "../proto/hedera/CryptoService.grpc.pb.h" +#include "../proto/hedera/ConsensusService.grpc.pb.h" + +#include "../lib/DataTypeConverter.h" + +#include +#include +#include +#include +#include + + +HederaRequest::HederaRequest() +{ + +} + +HederaRequest::~HederaRequest() +{ + +} + +HederaRequestReturn HederaRequest::request(model::hedera::Query* query, model::hedera::Response* response, Poco::UInt64 fee/* = 0*/) +{ + auto channel = grpc::CreateChannel(query->getConnectionString(), grpc::InsecureChannelCredentials()); + + grpc::ClientContext context; + std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + + std::chrono::milliseconds(5000); + context.set_deadline(deadline); + //grpc::CompletionQueue cq; + + auto proto_query = query->getProtoQuery(); + + auto proto_query_serialized = proto_query->SerializeAsString(); + //auto query_hex_string = DataTypeConverter::binToHex((unsigned char*)proto_query_serialized.data(), proto_query_serialized.size()); + //printf("[HederaRequest::request] query as hex: %s\n", query_hex_string.data()); + + auto proto_response = response->getResponsePtr(); + auto connect_string = query->getConnectionString(); + + grpc::Status status; + std::string queryName; + + if (proto_query->has_cryptogetaccountbalance()) + { + auto stub = proto::CryptoService::NewStub(channel); + // crypto account get balance currently hasn't fees + query->setResponseType(proto::ANSWER_ONLY); + + queryName = "crypte get balance"; + status = stub->cryptoGetBalance(&context, *proto_query, proto_response); + + } + else if (proto_query->has_consensusgettopicinfo()) + { + auto stub = proto::ConsensusService::NewStub(channel); + + queryName = "consensus topic get info"; + status = stub->getTopicInfo(&context, *proto_query, proto_response); + + } + else if (proto_query->has_transactiongetreceipt()) { + auto stub = proto::CryptoService::NewStub(channel); + + queryName = "crypto transaction get receipt"; + status = stub->getTransactionReceipts(&context, *proto_query, proto_response); + } + else if (proto_query->has_transactiongetrecord()) { + auto stub = proto::CryptoService::NewStub(channel); + + queryName = "crypto transaction get record"; + status = stub->getTxRecordByTxID(&context, *proto_query, proto_response); + + } + else { + addError(new Error("Hedera Request", "unknown or empty query")); + return HEDERA_REQUEST_UNKNOWN_QUERY; + } + if (status.ok()) + { + auto response_code = response->getResponseCode(); + if (response_code) { + addError(new ParamError("Hedera Request", "precheck code: ", proto::ResponseCodeEnum_Name(response_code))); + return HEDERA_REQUEST_PRECHECK_ERROR; + } + else { + return HEDERA_REQUEST_RETURN_OK; + } + + } + else if("" != queryName) + { + addError(new ParamError("Hedera Request", "query name: ", queryName)); + addError(new ParamError("Hedera Request", "error message: ", status.error_message())); + addError(new ParamError("Hedera Request", "details: ", status.error_details())); + return HEDERA_REQUEST_RETURN_ERROR; + } + return HEDERA_REQUEST_UNKNOWN_QUERY; +} + + +HederaRequestReturn HederaRequest::request(model::hedera::Transaction* transaction, model::hedera::Response* response) +{ + auto channel = grpc::CreateChannel(transaction->getConnectionString(), grpc::InsecureChannelCredentials()); + + grpc::ClientContext context; + std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + + std::chrono::milliseconds(5000); + context.set_deadline(deadline); + + return HEDERA_REQUEST_RETURN_OK; +} + +HederaRequestReturn HederaRequest::request(model::hedera::Transaction* transaction, HederaTask* task) +{ + assert(transaction && task); + auto channel = grpc::CreateChannel(transaction->getConnectionString(), grpc::InsecureChannelCredentials()); + + grpc::ClientContext context; + std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + + std::chrono::milliseconds(5000); + context.set_deadline(deadline); + auto transaction_type = transaction->getType(); + task->setTransactionId(transaction->getTransactionId()); + if (model::hedera::TRANSACTION_CONSENSUS_SUBMIT_MESSAGE == transaction_type || + model::hedera::TRANSACTION_CONSENSUS_CREATE_TOPIC == transaction_type) { + auto stub = proto::ConsensusService::NewStub(channel); + grpc::Status status; + std::string service_name; + if (model::hedera::TRANSACTION_CONSENSUS_SUBMIT_MESSAGE == transaction_type) { + status = stub->submitMessage(&context, *transaction->getTransaction(), task->getTransactionResponse()->getProtoResponse()); + service_name = "submitMessage"; + } + else if (model::hedera::TRANSACTION_CONSENSUS_CREATE_TOPIC == transaction_type) { + status = stub->createTopic(&context, *transaction->getTransaction(), task->getTransactionResponse()->getProtoResponse()); + service_name = "createTopic"; + } + if (status.ok()) { + return HEDERA_REQUEST_RETURN_OK; + } + else { + addError(new ParamError("Hedera Request", "consensus service error message:", status.error_message())); + addError(new ParamError("Hedera Request", "service name", service_name)); + addError(new ParamError("Hedera Request", "details: ", status.error_details())); + return HEDERA_REQUEST_RETURN_ERROR; + } + } + + addError(new ParamError("Hedera Request", "not implementet or unknown transaction type", transaction_type)); + return HEDERA_REQUEST_UNKNOWN_TRANSACTION; +} + +#include "Poco/JSON/Object.h" +#include "../lib/JsonRequest.h" + +HederaRequestReturn HederaRequest::requestViaPHPRelay(model::hedera::Query* query) +{ + JsonRequest phpRelay("***REMOVED***", 88); + Poco::Net::NameValueCollection parameters; + std::string query_string = query->getProtoQuery()->SerializeAsString(); + //auto query_base64 = DataTypeConverter::binToBase64((const unsigned char*)query_string.data(), query_string.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING); + //auto findPos = query_string.find_first_of("\u"); + auto query_hex = DataTypeConverter::binToHex((const unsigned char*)query_string.data(), query_string.size()); + parameters.set("content", query_hex.substr(0, query_hex.size()-1)); + parameters.set("server", query->getConnectionString()); + parameters.set("method", "getBalance"); + parameters.set("service", "crypto"); + phpRelay.requestGRPCRelay(parameters); + //phpRelay.request("") + + return HEDERA_REQUEST_RETURN_OK; +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaRequest.h b/login_server/src/cpp/controller/HederaRequest.h new file mode 100644 index 000000000..51606f2b0 --- /dev/null +++ b/login_server/src/cpp/controller/HederaRequest.h @@ -0,0 +1,53 @@ +#ifndef __GRADIDO_LOGIN_SERVER_LIB_HEDERA_REQUEST_ +#define __GRADIDO_LOGIN_SERVER_LIB_HEDERA_REQUEST_ +/*! +* +* \author: Dario Rekowski +* +* \date: 31.08.2020 +* +* \brief: Class for Hedera Requests +* +*/ + +#include "../controller/NodeServer.h" +#include "../model/hedera/Query.h" +#include "../model/hedera/TransactionGetReceiptQuery.h" +#include "../model/hedera/Transaction.h" +#include "../model/hedera/Response.h" +#include "../model/hedera/TransactionResponse.h" +#include "../tasks/HederaTask.h" + +enum HederaRequestReturn +{ + HEDERA_REQUEST_RETURN_OK, + HEDERA_REQUEST_RETURN_PARSE_ERROR, + HEDERA_REQUEST_PRECHECK_ERROR, + HEDERA_REQUEST_RETURN_ERROR, + HEDERA_REQUEST_UNKNOWN_TRANSACTION, + HEDERA_REQUEST_UNKNOWN_QUERY, + HEDERA_REQUEST_CONNECT_ERROR +}; + +// NodeServerConnection +class HederaRequest : public NotificationList +{ +public: + HederaRequest(); + ~HederaRequest(); + + HederaRequestReturn request(model::hedera::Query* query, model::hedera::Response* response, Poco::UInt64 fee = 0); + HederaRequestReturn request(model::hedera::Transaction* transaction, model::hedera::Response* response); + //! + //! \param task goes into HederaTaskManager and will be run after transaction + HederaRequestReturn request(model::hedera::Transaction* transaction, HederaTask* task); + //! for testing, didn't work server say invalid json :/ + HederaRequestReturn requestViaPHPRelay(model::hedera::Query* query); + +protected: + +}; + + +#endif //__GRADIDO_LOGIN_SERVER_LIB_HEDERA_REQUEST_ +// \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaTopic.cpp b/login_server/src/cpp/controller/HederaTopic.cpp new file mode 100644 index 000000000..36793a732 --- /dev/null +++ b/login_server/src/cpp/controller/HederaTopic.cpp @@ -0,0 +1,235 @@ +#include "HederaTopic.h" +//#include "../model/hedera/Transaction.h" +#include "HederaRequest.h" +#include "../lib/Success.h" + +#include "../model/hedera/ConsensusCreateTopic.h" +#include "../model/hedera/Transaction.h" + +#include "../SingletonManager/PendingTasksManager.h" + +namespace controller { + HederaTopic::HederaTopic(model::table::HederaTopic* dbModel) + { + mDBModel = dbModel; + } + HederaTopic::~HederaTopic() + { + + } + + Poco::AutoPtr HederaTopic::create(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId) + { + auto db = new model::table::HederaTopic(name, autoRenewAccountId, autoRenewPeriod, groupId); + + auto hedera_topic = new HederaTopic(db); + return Poco::AutoPtr(hedera_topic); + } + + std::vector> HederaTopic::listAll() + { + auto db = new model::table::HederaTopic(); + std::vector topic_list; + // throw an unresolved external symbol error + topic_list = db->loadAllFromDB(); + + std::vector> resultVector; + + resultVector.reserve(topic_list.size()); + for (auto it = topic_list.begin(); it != topic_list.end(); it++) { + Poco::AutoPtr topic_ptr(new HederaTopic(new model::table::HederaTopic(*it))); + resultVector.push_back(topic_ptr); + } + + return resultVector; + } + + Poco::AutoPtr HederaTopic::load(int id) + { + auto db = new model::table::HederaTopic; + if (1 == db->loadFromDB("id", id)) { + return new HederaTopic(db); + } + return nullptr; + } + + Poco::AutoPtr HederaTopic::getTopicHederaId() + { + if (mTopicHederaId.isNull()) { + mTopicHederaId = HederaId::load(getModel()->getTopicHederaId()); + } + return mTopicHederaId; + } + + Poco::AutoPtr HederaTopic::getAutoRenewAccount() + { + if (mAutoRenewAccount.isNull()) { + mAutoRenewAccount = HederaAccount::load(getModel()->getAutoRenewAccountId()); + } + return mAutoRenewAccount; + } + + bool HederaTopic::getTopicInfosFromHedera(Poco::AutoPtr topicHederaId, Poco::AutoPtr user, model::hedera::Response& response) + { + auto payer_account = controller::HederaAccount::pick(ServerConfig::g_HederaNetworkType); + auto node_server = NodeServer::pick(payer_account->getModel()->getNetworkType(), getModel()->getGroupId()); + + if (topicHederaId.isNull()) { + addError(new Error("Hedera Topic", "no hedera topic id exist")); + return false; + } + auto query = model::hedera::Query::getTopicInfo(topicHederaId, payer_account->getHederaId(), node_server); + query->setResponseType(proto::COST_ANSWER); + HederaRequest request; + query->sign(payer_account->getCryptoKey()->getKeyPair(user)); + if (HEDERA_REQUEST_RETURN_OK == request.request(query, &response)) { + auto queryCost = response.getQueryCost(); + printf("query cost: %d\n", queryCost); + + query->setTransactionFee(queryCost); + query->setResponseType(proto::ANSWER_ONLY); + query->sign(payer_account->getCryptoKey()->getKeyPair(user)); + + + if (HEDERA_REQUEST_RETURN_OK == request.request(query, &response)) { + return true; + } + else { + addError(new Error("Hedera Query", "Error by query for consensus get topic info")); + } + + } + else { + addError(new Error("Hedera Query", "Error by getting costs for consensus get topic info")); + } + getErrors(&request); + return false; + + } + + bool HederaTopic::updateWithGetTopicInfos(Poco::AutoPtr user) + { + + model::hedera::Response response; + if (!getTopicInfosFromHedera(getTopicHederaId(), user, response)) { + return false; + } + + auto consensus_topic_info = response.getConsensusTopicInfo(); + //addNotification(new ParamSuccess("consensus get topic info", "memo: ", consensus_topic_info->getMemo())); + //addNotification(new ParamSuccess("consensus get topic info", "string: ", consensus_topic_info->toStringHtml())); + auto model = getModel(); + model->setAutoRenewPeriod(consensus_topic_info->getAutoRenewPeriod().seconds()); + model->setCurrentTimeout(consensus_topic_info->getExpirationTime()); + model->setSequeceNumber(consensus_topic_info->getSequenceNumber()); + + + std::string fieldNames[] = { "auto_renew_period", "current_timeout", "sequence_number" }; + if (model->updateIntoDB( + fieldNames, + model->getAutoRenewPeriod(), + model->getCurrentTimeout(), + model->getSequenceNumber() + ) > 1) { + addError(new Error("DB", "error saving changes in DB")); + getErrors(model); + return false; + } + return true; + + } + + Poco::AutoPtr HederaTopic::loadFromHedera(Poco::AutoPtr hederaId, Poco::UInt32 groupId, Poco::AutoPtr user) + { + auto db = new model::table::HederaTopic(); + auto hedera_topic = new HederaTopic(db); + + model::hedera::Response response; + if (!hedera_topic->getTopicInfosFromHedera(hederaId, user, response)) { + delete hedera_topic; + return nullptr; + } + + auto consensus_topic_info = response.getConsensusTopicInfo(); + //addNotification(new ParamSuccess("consensus get topic info", "memo: ", consensus_topic_info->getMemo())); + //addNotification(new ParamSuccess("consensus get topic info", "string: ", consensus_topic_info->toStringHtml())); + auto group_name = consensus_topic_info->getMemo(); + auto groups = controller::Group::load(group_name); + db->setTopicHederaID(hederaId->getModel()->getID()); + db->setName(group_name); + if (1 == groups.size()) { + db->setGroupId(groups[0]->getModel()->getID()); + } + else if (groupId > 0) { + db->setGroupId(groupId); + } + db->setAutoRenewPeriod(consensus_topic_info->getAutoRenewPeriod().seconds()); + db->setCurrentTimeout(consensus_topic_info->getExpirationTime()); + db->setSequeceNumber(consensus_topic_info->getSequenceNumber()); + + return Poco::AutoPtr(hedera_topic); + } + + Poco::AutoPtr HederaTopic::createTopic(Poco::AutoPtr operatorAccount, Poco::AutoPtr user) + { + static const char* function_name = "HederaTopic::createTopic"; + printf("[HederaTopic::createTopic]\n"); + auto model = getModel(); + if (!model->getID()) { + addError(new Error(function_name, "no db entry for topic created, id is missing")); + return nullptr; + } + Poco::AutoPtr autoRenewAccountId(nullptr); + if (model->getAutoRenewAccountId()) { + //autoRenewAccountId = controller::HederaId::load(model->getAutoRenewAccountId()); + } + model::hedera::ConsensusCreateTopic hederaCreateTopic(autoRenewAccountId, model->getAutoRenewPeriod()); + auto hederaTransactionBody = operatorAccount->createTransactionBody(); + if (model->getName() != "") { + hederaCreateTopic.setMemo(model->getName()); + } + if (!hederaTransactionBody->setCreateTopic(hederaCreateTopic)) { + addError(new Error(function_name, "error validating create topic transaction")); + return nullptr; + } + model::hedera::Transaction hederaTransaction; + if (!hederaTransaction.sign(operatorAccount->getCryptoKey()->getKeyPair(user), std::move(hederaTransactionBody))) { + addError(new Error(function_name, "error signing hedera transaction")); + return nullptr; + } + + auto proto_transaction = hederaTransaction.getTransaction(); + + + Poco::AutoPtr receiptTask(new HederaTask(&hederaTransaction)); + auto receipt_task_model = receiptTask->getModel(); + receipt_task_model->setParentPendingTaskId(model->getID()); + receipt_task_model->setUserId(user->getModel()->getID()); + + HederaRequest request; + printf("[HederaTopic::createTopic] before calling request\n"); + auto result = request.request(&hederaTransaction, receiptTask.get()); + if (HEDERA_REQUEST_RETURN_OK == result) { + if (proto::OK == receiptTask->getTransactionResponse()->getPrecheckCode()) { + auto pt = PendingTasksManager::getInstance(); + printf("[HederaTopic::createTopic] before add task\n"); + pt->addTask(receiptTask); + printf("[HederaTopic::createTopic] before start timer\n"); + receiptTask->startTimer(); + return receiptTask; + } + else { + addError(new ParamError(function_name, "precheck code error", receiptTask->getTransactionResponse()->getPrecheckCodeString())); + + return nullptr; + } + } + else { + addError(new Error(function_name, "error in hedera request")); + return nullptr; + } + + } + + +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/HederaTopic.h b/login_server/src/cpp/controller/HederaTopic.h new file mode 100644 index 000000000..2808794ee --- /dev/null +++ b/login_server/src/cpp/controller/HederaTopic.h @@ -0,0 +1,58 @@ +#ifndef __GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H +#define __GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H + +/*! +* +* \author: Dario Rekowski +* +* \date: 03.09.2020 +* +* \brief: Class for Hedera Topic, connct db table with hedera object +* +*/ +#include "TableControllerBase.h" +#include "../model/table/HederaTopic.h" +#include "../model/hedera/Response.h" +#include "HederaId.h" +#include "HederaAccount.h" + +#include "../tasks/HederaTask.h" + +namespace controller { + class HederaTopic : public TableControllerBase, public NotificationList + { + public: + + ~HederaTopic(); + + static Poco::AutoPtr create(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId); + static Poco::AutoPtr loadFromHedera(Poco::AutoPtr hederaId, Poco::UInt32 groupId, Poco::AutoPtr user); + static std::vector> listAll(); + static Poco::AutoPtr load(int id); + + + bool updateWithGetTopicInfos(Poco::AutoPtr user); + + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + Poco::AutoPtr getTopicHederaId(); + Poco::AutoPtr getAutoRenewAccount(); + + //! \brief hedera call to create a hedera topic + Poco::AutoPtr createTopic(Poco::AutoPtr operatorAccount, Poco::AutoPtr user); + + inline Poco::AutoPtr getModel() { return _getModel(); } + + + protected: + HederaTopic(model::table::HederaTopic* dbModel); + + bool getTopicInfosFromHedera(Poco::AutoPtr topicHederaId, Poco::AutoPtr user, model::hedera::Response& response); + + Poco::AutoPtr mTopicHederaId; + Poco::AutoPtr mAutoRenewAccount; + + }; +} + +#endif //__GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H diff --git a/login_server/src/cpp/controller/NodeServer.cpp b/login_server/src/cpp/controller/NodeServer.cpp new file mode 100644 index 000000000..9ae570e66 --- /dev/null +++ b/login_server/src/cpp/controller/NodeServer.cpp @@ -0,0 +1,208 @@ +#include "NodeServer.h" +#include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/ConnectionManager.h" +#include "../SingletonManager/CronManager.h" +#include "Poco/RegularExpression.h" + +namespace controller { + + Poco::RegularExpression g_filterHttp("^https?://"); + + std::string NodeServerConnection::getUriWithPort() const + { + std::string protocol; + g_filterHttp.extract(url, protocol); + return url.substr(protocol.size()) + ":" + std::to_string(port); + } + + std::string NodeServerConnection::getUri() const + { + std::string protocol; + g_filterHttp.extract(url, protocol); + return url.substr(protocol.size()); + } + + + + + NodeServer::NodeServer(model::table::NodeServer* dbModel) + { + mDBModel = dbModel; + if (model::table::NODE_SERVER_GRADIDO_COMMUNITY == dbModel->getNodeServerType()) { + CronManager::getInstance()->addNodeServerToPing(Poco::AutoPtr(this, true)); + } + } + + NodeServer::~NodeServer() + { + + } + + bool NodeServer::deleteFromDB() + { + auto result = mDBModel->deleteFromDB(); + if (result && model::table::NODE_SERVER_GRADIDO_COMMUNITY == getModel()->getNodeServerType()) { + CronManager::getInstance()->removeNodeServerToPing(Poco::AutoPtr(this, true)); + } + return result; + } + + Poco::AutoPtr NodeServer::create(const std::string& url, int port, int groupId, model::table::NodeServerType type, int nodeHederaId) + { + auto db = new model::table::NodeServer(url, port, groupId, type, nodeHederaId); + auto group = new NodeServer(db); + return Poco::AutoPtr(group); + } + + Poco::AutoPtr NodeServer::load(int id) + { + auto db = new model::table::NodeServer(); + if (1 == db->loadFromDB("id", id)) { + return new NodeServer(db); + } + return nullptr; + } + + std::vector> NodeServer::load(model::table::NodeServerType type, int group_id/* = 0*/) + { + auto db = new model::table::NodeServer(); + std::vector node_server_list; + + if (type == model::table::NODE_SERVER_HEDERA_MAINNET_NODE || type == model::table::NODE_SERVER_HEDERA_TESTNET_NODE) + { + node_server_list = db->loadFromDB("server_type", type, 4); + } + else if (type == model::table::NODE_SERVER_GRADIDO_NODE || type == model::table::NODE_SERVER_GRADIDO_COMMUNITY) + { + if (group_id) + { + node_server_list = db->loadFromDB( + { "server_type", "group_id" }, + { type, group_id }, + model::table::MYSQL_CONDITION_AND + ); + } + else + { + node_server_list = db->loadFromDB("server_type", type, 4); + } + } + //auto node_server_list = db->loadFromDB("alias", alias, 0); + + std::vector> resultVector; + resultVector.reserve(node_server_list.size()); + for (auto it = node_server_list.begin(); it != node_server_list.end(); it++) { + resultVector.push_back(new NodeServer(new model::table::NodeServer(*it))); + } + return resultVector; + } + + /* + SELECT * FROM table_name + ORDER BY RAND() + LIMIT 1; + */ + NodeServerConnection NodeServer::pick(ServerConfig::HederaNetworkType type, int group_id /*= 0*/) + { + model::table::NodeServerType node_server_type = model::table::NODE_SERVER_NONE; + if (ServerConfig::HEDERA_MAINNET) node_server_type = model::table::NODE_SERVER_HEDERA_MAINNET_NODE; + else if (ServerConfig::HEDERA_TESTNET) node_server_type = model::table::NODE_SERVER_HEDERA_TESTNET_NODE; + return pick(node_server_type, group_id); + } + NodeServerConnection NodeServer::pick(model::table::NodeServerType type, int group_id/* = 0*/) + { + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + NodeServerConnection result; + int hedera_node_id = 0; + + Poco::Data::Statement select(session); + select << "SELECT url, port"; + + if (model::table::NodeServerIsHederaNode(type)) { + select << ", node_hedera_id"; + } + select << " from node_servers where server_type = ? ORDER BY RAND() LIMIT 1" + , Poco::Data::Keywords::into(result.url) + , Poco::Data::Keywords::into(result.port); + if (model::table::NodeServerIsHederaNode(type)) { + select, Poco::Data::Keywords::into(hedera_node_id); + } + select , Poco::Data::Keywords::bind((int)type); + try { + if (1 == select.execute()) { + if (model::table::NodeServerIsHederaNode(type)) { + result.hederaId = controller::HederaId::load(hedera_node_id); + } + return result; + } + } + catch (Poco::Exception& ex) { + auto em = ErrorManager::getInstance(); + const char* functionName = "NodeServer::pick"; + em->addError(new ParamError(functionName, "mysql error by pick: ", ex.message())); + em->addError(new ParamError(functionName, "server type: ", model::table::NodeServer::nodeServerTypeToString(type))); + em->addError(new ParamError(functionName, "group id", group_id)); + em->sendErrorsAsEmail(); + } + return result; + + } + + std::vector> NodeServer::listAll() + { + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + std::vector rows; + // typedef Poco::Tuple NodeServerFullTuple; + select << "SELECT n.id, n.url, n.port, n.group_id, n.server_type, n.node_hedera_id, h.shardNum, h.realmNum, h.num, n.last_live_sign " + << "FROM node_servers as n " + << "LEFT JOIN hedera_ids as h ON h.id = n.node_hedera_id" + , Poco::Data::Keywords::into(rows); + + try { + select.executeAsync(); + select.wait(); + } + catch (Poco::Exception& ex) { + auto em = ErrorManager::getInstance(); + const char* functionName = "NodeServer::listAll"; + em->addError(new ParamError(functionName, "mysql error by list all: ", ex.message())); + em->sendErrorsAsEmail(); + } + std::vector> results; + for (auto it = rows.begin(); it != rows.end(); it++) { + //NodeServer(const std::string& url, int port, int groupId, NodeServerType type, int nodeHederaId); + auto row = *it; + model::table::NodeServer* db = new model::table::NodeServer( + row.get<1>(), row.get<2>(), row.get<3>(), (model::table::NodeServerType)row.get<4>(), row.get<5>() + ); + db->setLastLiveSign(row.get<9>()); + db->setID(row.get<0>()); + Poco::AutoPtr node_server(new NodeServer(db)); + node_server->setHederaId(controller::HederaId::create( + row.get<6>(), row.get<7>(), row.get<8>() + )); + results.push_back(node_server); + + } + return results; + + } + + JsonRequest NodeServer::createJsonRequest() + { + auto model = getModel(); + NodeServerConnection connection(model->getUrl(), model->getPort()); + return JsonRequest(connection.getUri(), model->getPort()); + } + + std::string NodeServer::getBaseUri() + { + auto model = getModel(); + NodeServerConnection connection(model->getUrl(), model->getPort()); + return connection.getUri(); + } + +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/NodeServer.h b/login_server/src/cpp/controller/NodeServer.h new file mode 100644 index 000000000..d91cc3612 --- /dev/null +++ b/login_server/src/cpp/controller/NodeServer.h @@ -0,0 +1,66 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_NODE_SERVER_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_NODE_SERVER_INCLUDE + +#include "../model/table/NodeServer.h" +#include "../controller/HederaId.h" +#include "../lib/JsonRequest.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" + +namespace controller { + + struct NodeServerConnection + { + NodeServerConnection(const std::string& _url, int _port) : url(_url), port(_port) {} + NodeServerConnection() :port(0) {}; + + // with http:// or https:// + inline std::string getUrlWithPort() const { return url + ":" + std::to_string(port); } + + // without http:// or https:// + std::string getUriWithPort() const; + std::string getUri() const; + + bool isValid() { return url != "" && port; } + std::string url; + int port; + + Poco::AutoPtr hederaId; + }; + + typedef Poco::Tuple NodeServerFullTuple; + + class NodeServer : public TableControllerBase + { + public: + + ~NodeServer(); + + static Poco::AutoPtr create(const std::string& url, int port, int groupId, model::table::NodeServerType type, int nodeHederaId); + + //! \param group_id is zero take everyone + static std::vector> load(model::table::NodeServerType type, int group_id = 0); + static Poco::AutoPtr load(int id); + static std::vector> listAll(); + // pick server randomly + static NodeServerConnection pick(ServerConfig::HederaNetworkType type, int group_id = 0); + static NodeServerConnection pick(model::table::NodeServerType type, int group_id = 0); + bool deleteFromDB(); + + inline Poco::AutoPtr getModel() { return _getModel(); } + + inline void setHederaId(Poco::AutoPtr hederaId) { mHederaID = hederaId; } + inline Poco::AutoPtr getHederaId() { return mHederaID; } + + std::string getBaseUri(); + JsonRequest createJsonRequest(); + protected: + NodeServer(model::table::NodeServer* dbModel); + Poco::AutoPtr mHederaID; + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_NODE_SERVER_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/PendingTask.cpp b/login_server/src/cpp/controller/PendingTask.cpp new file mode 100644 index 000000000..2b991b580 --- /dev/null +++ b/login_server/src/cpp/controller/PendingTask.cpp @@ -0,0 +1,160 @@ +#include "PendingTask.h" + +#include "../tasks/GradidoGroupAddMemberTask.h" +#include "../model/gradido/Transaction.h" +#include "../tasks/HederaTask.h" + +#include "../SingletonManager/PendingTasksManager.h" +#include "../SingletonManager/ErrorManager.h" + +namespace controller { + + PendingTask::PendingTask(model::table::PendingTask* dbModel) + { + mDBModel = dbModel; + } + + PendingTask::~PendingTask() + { + + } + + Poco::AutoPtr PendingTask::create(int userId, std::string serializedProtoRequest, model::table::TaskType type) + { + auto db = new model::table::PendingTask(userId, serializedProtoRequest, type); + //auto pending_task = new PendingTask(db); + auto pending_task = loadCorrectDerivedClass(db); + return Poco::AutoPtr(pending_task); + } + + std::vector> PendingTask::load(int userId) + { + auto db = new model::table::PendingTask(); + auto pending_task_list = db->loadFromDB("user_id", userId, 3); + std::vector> resultVector; + resultVector.reserve(pending_task_list.size()); + for (auto it = pending_task_list.begin(); it != pending_task_list.end(); it++) { + //resultVector.push_back(new PendingTask(new model::table::PendingTask(*it))); + resultVector.push_back(loadCorrectDerivedClass(new model::table::PendingTask(*it))); + } + return resultVector; + + + } + + /*Poco::AutoPtr PendingTask::loadCorrectDerivedClass(model::table::PendingTask* dbModel) + { + if (dbModel->isGradidoTransaction()) { + return model::gradido::Transaction::load(dbModel); + } + }*/ + Poco::AutoPtr PendingTask::loadCorrectDerivedClass(model::table::PendingTask* dbModel) + { + /*if (!dbModel) return nullptr; + auto type = dbModel->getTaskType(); + switch (type) { + case model::table::TASK_TYPE_GROUP_ADD_MEMBER: return new GradidoGroupAddMemberTask(dbModel); + default: return nullptr;*/ + if (dbModel->isGradidoTransaction()) { + return model::gradido::Transaction::load(dbModel); + } + else if (dbModel->isGradidoTransaction()) { + return HederaTask::load(dbModel); + } + return nullptr; + } + + std::vector> PendingTask::loadAll() + { + auto db = new model::table::PendingTask(); + std::vector task_list; + // throw an unresolved external symbol error + task_list = db->loadAllFromDB(); + + + //*/ //work around end + std::vector> resultVector; + + resultVector.reserve(task_list.size()); + for (auto it = task_list.begin(); it != task_list.end(); it++) { + auto group_ptr = loadCorrectDerivedClass(new model::table::PendingTask(*it)); + resultVector.push_back(group_ptr); + } + return resultVector; + } + + bool PendingTask::deleteFromDB() + { + Poco::ScopedLock _lock(mWorkMutex); + auto result = mDBModel->deleteFromDB(); + return result; + } + + Poco::AutoPtr PendingTask::getUser() + { + if (!mUser.isNull()) { + return mUser; + } + auto user_id = getModel()->getUserId(); + if (!user_id) { + return nullptr; + } + mUser = controller::User::create(); + mUser->load(user_id); + return mUser; + + } + + void PendingTask::startTimer() + { + Poco::ScopedLock _lock(mWorkMutex); + static const char* function_name = "PendingTask::startTimer"; + auto em = ErrorManager::getInstance(); + + if (isTimeoutTask()) { + auto next_run_time = getNextRunTime(); + if (next_run_time >= Poco::DateTime()) { + auto result = run(); + if (result != 1 && result != -1) { + return; + } + next_run_time = getNextRunTime(); + } + if (next_run_time >= Poco::DateTime()) { + em->addError(new Error(function_name, "get next runtime doesn't seem to work correctly")); + em->addError(new ParamError(function_name, "task type", getModel()->getTaskTypeString())); + em->sendErrorsAsEmail(); + } + next_run_time = getNextRunTime(); + auto interval = next_run_time - Poco::DateTime(); + printf("interval: %d\n", interval.milliseconds()); + if (interval.milliseconds() > 0) { + mTimer.setStartInterval(interval.milliseconds()); + } + else { + mTimer.setStartInterval(100); + } + Poco::TimerCallback callback(*this, &PendingTask::calledFromTimer); + mTimer.start(callback); + } + + } + void PendingTask::calledFromTimer(Poco::Timer& timer) + { + Poco::DateTime now; + std::string now_string = Poco::DateTimeFormatter::format(now, "%f.%m.%Y %H:%M:%S"); + printf("[PendingTask::calledFromTimer] now: %s\n", now_string.data()); + Poco::ScopedLock _lock(mWorkMutex); + auto result = run(); + printf("run result: %d\n", result); + if (result != 1 && result != -1) { + timer.restart(0); + return; + } + auto interval = Poco::Timespan(getNextRunTime() - Poco::DateTime()).milliseconds(); + if (interval <= 0) { + interval = 100; + } + timer.restart(interval); + } +} \ No newline at end of file diff --git a/login_server/src/cpp/controller/PendingTask.h b/login_server/src/cpp/controller/PendingTask.h new file mode 100644 index 000000000..1de4dd22e --- /dev/null +++ b/login_server/src/cpp/controller/PendingTask.h @@ -0,0 +1,57 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_PENDING_TASK_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_PENDING_TASK_INCLUDE + +#include "../model/table/PendingTask.h" + +#include "Poco/SharedPtr.h" +#include "Poco/Timer.h" + +#include "TableControllerBase.h" +#include "User.h" + +namespace controller { + + + typedef Poco::Tuple NodeServerFullTuple; + + class PendingTask : public TableControllerBase + { + public: + + ~PendingTask(); + + static Poco::AutoPtr create(int userId, std::string serializedProtoRequest, model::table::TaskType type); + + static std::vector> load(int userId); + static std::vector> loadAll(); + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + inline const model::table::PendingTask* getModel() const { return _getModel(); } + //! \brief delete from db and remove from Pending Task Manager + bool deleteFromDB(); + + virtual bool isTimeoutTask() = 0; + virtual Poco::DateTime getNextRunTime() { return Poco::DateTime(); }; + //! \return 1 run finished, more runs needed + //! \return 0 run finished, no more runs needed + //! \return -1 error, more runs needed + //! \return -2 critical error, abort, remove + virtual int run() { return false; }; + + void startTimer(); + void calledFromTimer(Poco::Timer& timer); + + Poco::AutoPtr getUser(); + + protected: + static Poco::AutoPtr loadCorrectDerivedClass(model::table::PendingTask* dbModel); + PendingTask(model::table::PendingTask* dbModel); + + Poco::AutoPtr mUser; + Poco::Timer mTimer; + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_PENDING_TASK_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/controller/User.cpp b/login_server/src/cpp/controller/User.cpp index 7aedbb701..a2c081b03 100644 --- a/login_server/src/cpp/controller/User.cpp +++ b/login_server/src/cpp/controller/User.cpp @@ -1,5 +1,5 @@ #include "User.h" -#include "UserBackups.h" +#include "UserBackup.h" #include "sodium.h" @@ -7,6 +7,9 @@ #include "../SingletonManager/ErrorManager.h" #include "../SingletonManager/SingletonTaskObserver.h" +#include "NodeServer.h" +#include "Group.h" + #include "../lib/DataTypeConverter.h" #include "../tasks/VerificationEmailResendTask.h" @@ -21,6 +24,7 @@ namespace controller { : mPassword(nullptr), mGradidoKeyPair(nullptr), mCanDecryptPrivateKey(false), mGradidoCurrentBalance(0) { mDBModel = dbModel; + } User::~User() @@ -39,9 +43,9 @@ namespace controller { return Poco::AutoPtr(user); } - Poco::AutoPtr User::create(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) + Poco::AutoPtr User::create(const std::string& email, const std::string& first_name, const std::string& last_name, int group_id, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) { - auto db = new model::table::User(email, first_name, last_name, passwordHashed, languageKey); + auto db = new model::table::User(email, first_name, last_name, group_id, passwordHashed, languageKey); auto user = new User(db); return Poco::AutoPtr(user); } @@ -83,6 +87,28 @@ namespace controller { return getModel()->loadFromDB("pubkey", pubkey); } + int User::load(MemoryBin* emailHash) + { + Poco::Data::BLOB email_hash(*emailHash, crypto_generichash_BYTES); + return getModel()->loadFromDB("email_hash", email_hash); + } + Poco::AutoPtr User::sload(int user_id) + { + auto db = new model::table::User(); + if (0 == db->loadFromDB("id", user_id)) { + delete db; + return nullptr; + } + auto user = new User(db); + return Poco::AutoPtr(user); + } + + void User::reload() + { + getModel()->loadFromDB("id", getModel()->getID()); + } + + const std::string& User::getPublicHex() { if (mPublicHex != "") { @@ -144,7 +170,7 @@ namespace controller { return -3; } observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); - Poco::AutoPtr authenticated_encryption(new AuthenticatedEncryption); + Poco::AutoPtr authenticated_encryption(new SecretKeyCryptography); assert(!authenticated_encryption.isNull() && model); authenticated_encryption->createKey(model->getEmail(), password); @@ -163,7 +189,7 @@ namespace controller { } else { - if (AuthenticatedEncryption::AUTH_DECRYPT_OK == authenticated_encryption->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) { + if (SecretKeyCryptography::AUTH_DECRYPT_OK == authenticated_encryption->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) { if (mGradidoKeyPair) { if (mGradidoKeyPair->isTheSame(clear_private_key) == 0) { mCanDecryptPrivateKey = true; @@ -225,7 +251,7 @@ namespace controller { auto email_hash = observer->makeHash(model->getEmail()); observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); - Poco::AutoPtr authenticated_encryption(new AuthenticatedEncryption); + Poco::AutoPtr authenticated_encryption(new SecretKeyCryptography); assert(!authenticated_encryption.isNull() && model); authenticated_encryption->createKey(model->getEmail(), password); @@ -234,7 +260,7 @@ namespace controller { } - int User::setNewPassword(Poco::AutoPtr passwd) + int User::setNewPassword(Poco::AutoPtr passwd) { std::unique_lock _lock(mSharedMutex); auto model = getModel(); @@ -249,7 +275,7 @@ namespace controller { if ((!mGradidoKeyPair || !mGradidoKeyPair->hasPrivateKey()) && model->hasPrivateKeyEncrypted()) { //if (!mGradidoKeyPair) mGradidoKeyPair = new KeyPairEd25519; MemoryBin* clear_private_key = nullptr; - if (AuthenticatedEncryption::AUTH_DECRYPT_OK == mPassword->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) { + if (SecretKeyCryptography::AUTH_DECRYPT_OK == mPassword->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) { if (mGradidoKeyPair && mGradidoKeyPair->isTheSame(clear_private_key) != 0) { delete mGradidoKeyPair; @@ -299,7 +325,7 @@ namespace controller { auto user_model = getModel(); if (user_model->getID() <= 0) return -2; - auto backups = UserBackups::load(user_model->getID()); + auto backups = UserBackup::load(user_model->getID()); if (backups.size() == 0) return -1; for (auto it = backups.begin(); it != backups.end(); it++) { auto user_backup = *it; @@ -322,6 +348,41 @@ namespace controller { return -1; } + /* + USER_EMPTY, + USER_LOADED_FROM_DB, + USER_PASSWORD_INCORRECT, + USER_PASSWORD_ENCRYPTION_IN_PROCESS, + USER_EMAIL_NOT_ACTIVATED, + USER_NO_KEYS, + USER_NO_PRIVATE_KEY, + USER_NO_GROUP, + USER_KEYS_DONT_MATCH, + USER_COMPLETE, + USER_DISABLED + */ + UserState User::getUserState() + { + std::unique_lock _lock(mSharedMutex); + auto model = getModel(); + if (!model->getID() && model->getEmail() == "") { + return USER_EMPTY; + } + if (!model->hasPrivateKeyEncrypted() && !model->hasPublicKey()) { + return USER_NO_KEYS; + } + if (!model->hasPrivateKeyEncrypted()) { + return USER_NO_PRIVATE_KEY; + } + if (!model->getGroupId()) { + return USER_NO_GROUP; + } + if (!model->isEmailChecked()) { + return USER_EMAIL_NOT_ACTIVATED; + } + return USER_COMPLETE; + } + int User::checkIfVerificationEmailsShouldBeResend(const Poco::Util::Timer& timer) { @@ -404,4 +465,105 @@ namespace controller { return 0; } + int User::addMissingEmailHashes() + { + auto cm = ConnectionManager::getInstance(); + auto em = ErrorManager::getInstance(); + static const char* function_name = "User::addMissingEmailHashes"; + + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + std::vector> results; + + select << "select id, email from users " + << "where email_hash IS NULL " + , Poco::Data::Keywords::into(results) + ; + int result_count = 0; + try { + result_count = select.execute(); + } + catch (Poco::Exception& ex) { + em->addError(new ParamError(function_name, "mysql error by select", ex.displayText().data())); + em->sendErrorsAsEmail(); + //return -1; + } + if (0 == result_count) return 0; + std::vector> updates; + // calculate hashes + updates.reserve(results.size()); + unsigned char email_hash[crypto_generichash_BYTES]; + for (auto it = results.begin(); it != results.end(); it++) { + memset(email_hash, 0, crypto_generichash_BYTES); + auto id = it->get<0>(); + auto email = it->get<1>(); + crypto_generichash(email_hash, crypto_generichash_BYTES, + (const unsigned char*)email.data(), email.size(), + NULL, 0); + updates.push_back(Poco::Tuple(Poco::Data::BLOB(email_hash, crypto_generichash_BYTES), id)); + } + + // update db + // reuse connection, I hope it's working + Poco::Data::Statement update(session); + update << "UPDATE users set email_hash = ? where id = ?" + , Poco::Data::Keywords::use(updates); + int updated_count = 0; + try { + updated_count = update.execute(); + } + catch (Poco::Exception& ex) { + em->addError(new ParamError(function_name, "mysql error by update", ex.displayText().data())); + em->sendErrorsAsEmail(); + } + return updated_count; + } + + + std::string User::getGroupBaseUrl() + { + UNIQUE_LOCK; + static const char* function_name = "User::getGroupBaseUrl"; + if (mGroupBaseUrl != "") { + printf("[%s] return saved group base Url: %s\n", function_name, mGroupBaseUrl.data()); + return mGroupBaseUrl; + } + + auto model = getModel(); + if (!model->getGroupId()) { + printf("[%s] return ServerConfig::g_php_serverPath because no group id\n", function_name); + return ServerConfig::g_php_serverPath; + } + auto servers = controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_COMMUNITY, model->getGroupId()); + if (!servers.size()) { + auto group = controller::Group::load(model->getGroupId()); + if (!group.isNull()) { + auto group_model = group->getModel(); + if (ServerConfig::g_ServerSetupType == ServerConfig::SERVER_TYPE_TEST) { + mGroupBaseUrl = "http://" + group_model->getUrl() + group_model->getHome(); + } + else { + mGroupBaseUrl = "https://" + group_model->getUrl() + group_model->getHome(); + } + printf("[%s] return group base Url: %s from Group\n", function_name, mGroupBaseUrl.data()); + return mGroupBaseUrl; + } + return ServerConfig::g_php_serverPath; + } + if (servers.size() > 1) { + auto em = ErrorManager::getInstance(); + em->addError(new ParamError(function_name, "error, more than one community server found for group", model->getGroupId())); + em->sendErrorsAsEmail(); + return ServerConfig::g_php_serverPath; + } + if (ServerConfig::g_ServerSetupType == ServerConfig::SERVER_TYPE_TEST) { + mGroupBaseUrl = "http://" + servers[0]->getBaseUri(); + } + else { + mGroupBaseUrl = "https://" + servers[0]->getBaseUri(); + } + printf("[%s] return group base Url: %s from NodeServer\n", function_name, mGroupBaseUrl.data()); + return mGroupBaseUrl; + } + } diff --git a/login_server/src/cpp/controller/User.h b/login_server/src/cpp/controller/User.h index 33daa9eda..3a62f6fcf 100644 --- a/login_server/src/cpp/controller/User.h +++ b/login_server/src/cpp/controller/User.h @@ -9,6 +9,21 @@ #include "TableControllerBase.h" +enum UserState +{ + USER_EMPTY, + USER_LOADED_FROM_DB, + USER_PASSWORD_INCORRECT, + USER_PASSWORD_ENCRYPTION_IN_PROCESS, + USER_EMAIL_NOT_ACTIVATED, + USER_NO_KEYS, + USER_NO_PRIVATE_KEY, + USER_NO_GROUP, + USER_KEYS_DONT_MATCH, + USER_COMPLETE, + USER_DISABLED +}; + namespace controller { @@ -26,7 +41,7 @@ namespace controller { ~User(); static Poco::AutoPtr create(); - static Poco::AutoPtr create(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); + static Poco::AutoPtr create(const std::string& email, const std::string& first_name, const std::string& last_name, int group_id, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); static std::vector search(const std::string& searchString); @@ -37,6 +52,9 @@ namespace controller { // TODO: instead scheduling all, scheduling only for next day and run this function every day (own task for that) static int checkIfVerificationEmailsShouldBeResend(const Poco::Util::Timer& timer); + //! \brief go through whole db and search for user without email hash and set this in db + static int addMissingEmailHashes(); + //! \brief try to find correct passphrase for this user from db //! //! select entries from user_backups db table belonging to user @@ -52,7 +70,10 @@ namespace controller { //! \brief try to load user from db via user_id //! \return count of found rows, should be 1 or 0 inline size_t load(int user_id) { return getModel()->loadFromDB("id", user_id); } + void reload(); + static Poco::AutoPtr sload(int user_id); int load(const unsigned char* pubkey_array); + int load(MemoryBin* emailHash); Poco::JSON::Object getJson(); inline Poco::AutoPtr getModel() { return _getModel(); } @@ -80,7 +101,7 @@ namespace controller { //! \return 1 = password changed, private key re-encrypted and saved into db //! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption //! \return -1 = stored pubkey and private key didn't match - int setNewPassword(Poco::AutoPtr passwd); + int setNewPassword(Poco::AutoPtr passwd); //! \brief set authenticated encryption and save hash in db, also re encrypt private key if exist @@ -91,8 +112,11 @@ namespace controller { //! \return -1 = stored pubkey and private key didn't match int setNewPassword(const std::string& password); + //! \brief calculate user state + UserState getUserState(); + //! \brief return AuthenticatedEncryption Auto Pointer - inline const Poco::AutoPtr getPassword() { + inline const Poco::AutoPtr getPassword() { std::shared_lock _lock(mSharedMutex); return mPassword; } @@ -121,6 +145,11 @@ namespace controller { inline void setBalance(int gradidoBalance) { std::unique_lock _lock(mSharedMutex); mGradidoCurrentBalance = gradidoBalance; } inline int getBalance() { std::shared_lock _lock(mSharedMutex); return mGradidoCurrentBalance; } + + std::string getGroupBaseUrl(); + + // connection to other tables + protected: @@ -128,7 +157,7 @@ namespace controller { std::string mPublicHex; - Poco::AutoPtr mPassword; + Poco::AutoPtr mPassword; KeyPairEd25519* mGradidoKeyPair; bool mCanDecryptPrivateKey; @@ -137,6 +166,8 @@ namespace controller { //! use it for showing balance in menu in check transaction int mGradidoCurrentBalance; + std::string mGroupBaseUrl; + mutable std::shared_mutex mSharedMutex; }; } diff --git a/login_server/src/cpp/controller/UserBackups.cpp b/login_server/src/cpp/controller/UserBackup.cpp similarity index 51% rename from login_server/src/cpp/controller/UserBackups.cpp rename to login_server/src/cpp/controller/UserBackup.cpp index bf7096442..9899fc58a 100644 --- a/login_server/src/cpp/controller/UserBackups.cpp +++ b/login_server/src/cpp/controller/UserBackup.cpp @@ -1,14 +1,14 @@ -#include "UserBackups.h" +#include "UserBackup.h" #include "../Crypto/Passphrase.h" namespace controller { - UserBackups::UserBackups(model::table::UserBackups* dbModel) + UserBackup::UserBackup(model::table::UserBackup* dbModel) { mDBModel = dbModel; } - UserBackups::~UserBackups() + UserBackup::~UserBackup() { } @@ -17,20 +17,20 @@ namespace controller { // --------------- static members ----------------------------- - Poco::AutoPtr UserBackups::create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) + Poco::AutoPtr UserBackup::create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) { - auto db = new model::table::UserBackups(user_id, passphrase, type); - return Poco::AutoPtr(new UserBackups(db)); + auto db = new model::table::UserBackup(user_id, passphrase, type); + return Poco::AutoPtr(new UserBackup(db)); } - std::vector> UserBackups::load(int user_id) + std::vector> UserBackup::load(int user_id) { - auto db = new model::table::UserBackups(); + auto db = new model::table::UserBackup(); auto results = db->loadFromDB("user_id", user_id, 1); - std::vector> resultObjects; + std::vector> resultObjects; if (db->errorCount()) { db->sendErrorsAsEmail(); db->release(); @@ -41,27 +41,23 @@ namespace controller { return resultObjects; } for (auto it = results.begin(); it != results.end(); it++) { - resultObjects.push_back(new UserBackups(new model::table::UserBackups(*it))); + resultObjects.push_back(new UserBackup(new model::table::UserBackup(*it))); } return resultObjects; } - Poco::SharedPtr UserBackups::getKeyPair() + Poco::SharedPtr UserBackup::getKeyPair() { if (!mKeyPair.isNull()) { return mKeyPair; } - mKeyPair = new KeyPair; - auto model = getModel(); - auto passphrase = model->getPassphrase(); - - mKeyPair->generateFromPassphrase(passphrase); + mKeyPair = createGradidoKeyPair(); return mKeyPair; } - KeyPairEd25519* UserBackups::createGradidoKeyPair() + KeyPairEd25519* UserBackup::createGradidoKeyPair() { auto model = getModel(); auto mnemonicType = model->getMnemonicType(); @@ -71,23 +67,23 @@ namespace controller { return KeyPairEd25519::create(passphrase); } - std::string UserBackups::getPassphrase(ServerConfig::Mnemonic_Types type) + std::string UserBackup::getPassphrase(ServerConfig::Mnemonic_Types type) { if ((int)type < 0 || (int)type >= ServerConfig::Mnemonic_Types::MNEMONIC_MAX) { return ""; } auto passphrase = getModel()->getPassphrase(); - Mnemonic* wordSource = nullptr; - if (KeyPair::validatePassphrase(passphrase, &wordSource)) { - for (int i = 0; i < ServerConfig::Mnemonic_Types::MNEMONIC_MAX; i++) { - Mnemonic* m = &ServerConfig::g_Mnemonic_WordLists[i]; - if (m == wordSource) { - if (type == i) { - return passphrase; - } - else { - return KeyPair::passphraseTransform(passphrase, m, &ServerConfig::g_Mnemonic_WordLists[type]); - } + auto wordSource = Passphrase::detectMnemonic(passphrase); + for (int i = 0; i < ServerConfig::Mnemonic_Types::MNEMONIC_MAX; i++) { + Mnemonic* m = &ServerConfig::g_Mnemonic_WordLists[i]; + if (m == wordSource) { + if (type == i) { + return passphrase; + } + else { + //return KeyPair::passphraseTransform(passphrase, m, &ServerConfig::g_Mnemonic_WordLists[type]); + auto passphrase_obj = Passphrase::create(passphrase, wordSource); + return passphrase_obj->transform(&ServerConfig::g_Mnemonic_WordLists[type])->getString(); } } } @@ -96,7 +92,7 @@ namespace controller { } - std::string UserBackups::formatPassphrase(std::string passphrase, int targetLinesCount/* = 5*/) + std::string UserBackup::formatPassphrase(std::string passphrase, int targetLinesCount/* = 5*/) { int count = passphrase.size(); int charPerLine = count / (targetLinesCount); diff --git a/login_server/src/cpp/controller/UserBackups.h b/login_server/src/cpp/controller/UserBackup.h similarity index 60% rename from login_server/src/cpp/controller/UserBackups.h rename to login_server/src/cpp/controller/UserBackup.h index c1cb08047..f1ab2f95a 100644 --- a/login_server/src/cpp/controller/UserBackups.h +++ b/login_server/src/cpp/controller/UserBackup.h @@ -1,8 +1,7 @@ #ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_USER_BACKUPS_INCLUDE #define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_BACKUPS_INCLUDE -#include "../model/table/UserBackups.h" -#include "../Crypto/KeyPair.h" +#include "../model/table/UserBackup.h" #include "../Crypto/KeyPairEd25519.h" #include "Poco/SharedPtr.h" @@ -10,23 +9,23 @@ #include "TableControllerBase.h" namespace controller { - class UserBackups : public TableControllerBase + class UserBackup : public TableControllerBase { public: - ~UserBackups(); + ~UserBackup(); - static Poco::AutoPtr create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); + static Poco::AutoPtr create(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); - static std::vector> load(int user_id); + static std::vector> load(int user_id); inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } - inline Poco::AutoPtr getModel() { return _getModel(); } + inline Poco::AutoPtr getModel() { return _getModel(); } //! depracted //! \return create keyPair from passphrase if not exist, else return existing pointer - Poco::SharedPtr getKeyPair(); + Poco::SharedPtr getKeyPair(); //! \return newly created key pair from passphrase or nullptr if not possible, caller becomes owner of pointer KeyPairEd25519* createGradidoKeyPair(); @@ -37,8 +36,8 @@ namespace controller { std::string getPassphrase(ServerConfig::Mnemonic_Types type); protected: - UserBackups(model::table::UserBackups* dbModel); - Poco::SharedPtr mKeyPair; + UserBackup(model::table::UserBackup* dbModel); + Poco::SharedPtr mKeyPair; }; } diff --git a/login_server/src/cpp/lib/DataTypeConverter.cpp b/login_server/src/cpp/lib/DataTypeConverter.cpp index c3275ba49..62417f638 100644 --- a/login_server/src/cpp/lib/DataTypeConverter.cpp +++ b/login_server/src/cpp/lib/DataTypeConverter.cpp @@ -1,5 +1,7 @@ #include "DataTypeConverter.h" +#include "Poco/RegularExpression.h" + #include #include "sodium.h" #include @@ -9,6 +11,8 @@ namespace DataTypeConverter { + Poco::RegularExpression g_rexExpBase64("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"); + NumberParseState strToInt(const std::string& input, int& result) { try { @@ -31,7 +35,7 @@ namespace DataTypeConverter return NUMBER_PARSE_LOGIC_ERROR; } } - +#ifdef __linux__ NumberParseState strToInt(const std::string& input, unsigned long long& result) { try { @@ -54,6 +58,57 @@ namespace DataTypeConverter return NUMBER_PARSE_LOGIC_ERROR; } } +#endif + NumberParseState strToInt(const std::string& input, Poco::UInt64& result) + { + try { + result = stoull(input); + return NUMBER_PARSE_OKAY; + } + catch (const std::invalid_argument& ia) + { + printf("[strToInt] exception: invalid argument: %s\n", ia.what()); + return NUMBER_PARSE_INVALID_ARGUMENT; + } + catch (const std::out_of_range& oor) + { + printf("[strToInt] exception: out or range: %s\n", oor.what()); + return NUMBER_PARSE_OUT_OF_RANGE; + } + catch (const std::logic_error & ler) + { + printf("[strToInt] exception: logical error: %s\n", ler.what()); + return NUMBER_PARSE_LOGIC_ERROR; + } + } + + NumberParseState strToDouble(const std::string& input, double& result) + { + auto comma_position = input.find(','); + std::string input_filtered = input; + if (comma_position > 0 && comma_position != input.npos) { + input_filtered = input_filtered.replace(comma_position, 0, 1, '.'); + } + try { + result = stod(input_filtered); + return NUMBER_PARSE_OKAY; + } + catch (const std::invalid_argument& ia) + { + printf("[strToDouble] exception: invalid argument: %s\n", ia.what()); + return NUMBER_PARSE_INVALID_ARGUMENT; + } + catch (const std::out_of_range& oor) + { + printf("[strToDouble] exception: out or range: %s\n", oor.what()); + return NUMBER_PARSE_OUT_OF_RANGE; + } + catch (const std::logic_error & ler) + { + printf("[strToDouble] exception: logical error: %s\n", ler.what()); + return NUMBER_PARSE_LOGIC_ERROR; + } + } const char* numberParseStateToString(NumberParseState state) { @@ -111,7 +166,7 @@ namespace DataTypeConverter } - MemoryBin* base64ToBin(const std::string& base64String) + MemoryBin* base64ToBin(const std::string& base64String, int variant /*= sodium_base64_VARIANT_ORIGINAL*/) { /* int sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, @@ -133,23 +188,30 @@ namespace DataTypeConverter mm->releaseMemory(bin); return nullptr; } + if (resultBinSize < binSize) { + auto bin_real = mm->getFreeMemory(resultBinSize); + memcpy(*bin_real, *bin, resultBinSize); + mm->releaseMemory(bin); + return bin_real; + } return bin; } + - std::string binToBase64(const MemoryBin* data) + + std::string binToBase64(const unsigned char* data, size_t size, int variant /*= sodium_base64_VARIANT_ORIGINAL*/) { auto mm = MemoryManager::getInstance(); - size_t binSize = data->size(); - size_t encodedSize = sodium_base64_encoded_len(binSize, sodium_base64_VARIANT_ORIGINAL); - + + size_t encodedSize = sodium_base64_encoded_len(size, variant); auto base64 = mm->getFreeMemory(encodedSize); memset(*base64, 0, encodedSize); size_t resultBinSize = 0; - if (0 != sodium_bin2base64(*base64, encodedSize, *data, binSize, sodium_base64_VARIANT_ORIGINAL)) { + if (nullptr == sodium_bin2base64(*base64, encodedSize, data, size, variant)) { mm->releaseMemory(base64); return ""; } @@ -176,6 +238,16 @@ namespace DataTypeConverter return hexString; } + std::string binToHex(const Poco::Nullable& nullableBin) + { + if (nullableBin.isNull()) { + return "0x0"; + } + else { + return binToHex(nullableBin.value().content().data(), nullableBin.value().content().size()); + } + } + std::string pubkeyToHex(const unsigned char* pubkey) { auto mm = MemoryManager::getInstance(); @@ -224,4 +296,138 @@ namespace DataTypeConverter return result; } + + Poco::Timestamp convertFromProtoTimestamp(const proto::Timestamp& timestamp) + { + // microseconds + google::protobuf::int64 microseconds = timestamp.seconds() * (google::protobuf::int64)10e5 + (google::protobuf::int64)(timestamp.nanos()) / (google::protobuf::int64)10e2; + return microseconds; + } + + Poco::Timestamp convertFromProtoTimestamp(const proto::gradido::Timestamp& timestamp) + { + // microseconds + google::protobuf::int64 microseconds = timestamp.seconds() * (google::protobuf::int64)10e5 + (google::protobuf::int64)(timestamp.nanos()) / (google::protobuf::int64)10e2; + return microseconds; + } + + void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::Timestamp* protoTimestamp) + { + auto microsecondsTotal = pocoTimestamp.epochMicroseconds(); + auto secondsTotal = pocoTimestamp.epochTime(); + protoTimestamp->set_seconds(secondsTotal); + protoTimestamp->set_nanos((microsecondsTotal - secondsTotal * pocoTimestamp.resolution()) * 1000); + } + + void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::gradido::Timestamp* protoTimestamp) + { + auto microsecondsTotal = pocoTimestamp.epochMicroseconds(); + auto secondsTotal = pocoTimestamp.epochTime(); + protoTimestamp->set_seconds(secondsTotal); + protoTimestamp->set_nanos((microsecondsTotal - secondsTotal * pocoTimestamp.resolution()) * 1000); + } + + Poco::Timestamp convertFromProtoTimestampSeconds(const proto::gradido::TimestampSeconds& timestampSeconds) + { + google::protobuf::int64 microseconds = timestampSeconds.seconds() * (google::protobuf::int64)10e5; + + return microseconds; + } + + Poco::Timespan convertFromProtoDuration(const proto::Duration& duration) + { + return Poco::Timespan(duration.seconds(), 0); + } + + int replaceBase64WithHex(Poco::JSON::Object::Ptr json) + { + //g_rexExpBase64 + auto mm = MemoryManager::getInstance(); + int count_replacements = 0; + + for (Poco::JSON::Object::ConstIterator it = json->begin(); it != json->end(); it++) + { + if (json->isObject(it)) { + auto local_json = it->second.extract(); + count_replacements += replaceBase64WithHex(local_json); + json->set(it->first, local_json); + } + else if (json->isArray(it)) { + auto local_json = it->second.extract(); + count_replacements += replaceBase64WithHex(local_json); + json->set(it->first, local_json); + } + else if (it->second.isString()) + { + if (it->first == "amount") continue; + auto field_value = it->second.extract(); + if(!g_rexExpBase64.match(field_value)) continue; + + auto bin = base64ToBin(field_value); + if(!bin) continue; + + auto hex = binToHex(bin); + mm->releaseMemory(bin); + json->set(it->first, hex.substr(0, hex.size()-1)); + count_replacements++; + } + } + + return count_replacements; + } + + int replaceBase64WithHex(Poco::JSON::Array::Ptr json) + { + auto mm = MemoryManager::getInstance(); + int count_replacements = 0; + int count = 0; + for (Poco::JSON::Array::ValueVec::const_iterator it = json->begin(); it != json->end(); it++) + { + if (json->isObject(it)) { + + auto local_json = it->extract(); + count_replacements += replaceBase64WithHex(local_json); + json->set(count, local_json); + } + else if (json->isArray(it)) { + auto local_json = it->extract(); + count_replacements += replaceBase64WithHex(local_json); + json->set(count, local_json); + } + else if (it->isString()) + { + auto field_value = it->extract(); + if (!g_rexExpBase64.match(field_value)) continue; + + auto bin = base64ToBin(field_value); + if (!bin) continue; + + auto hex = binToHex(bin); + mm->releaseMemory(bin); + json->set(count, hex.substr(0, hex.size()-1)); + count_replacements++; + } + count++; + } + + return count_replacements; + } + + std::string replaceNewLineWithBr(std::string& in) + { + + std::string::size_type pos = 0; // Must initialize + while ((pos = in.find("\r\n", pos)) != std::string::npos) { + in.replace(pos, 2, "
    "); + } + pos = 0; + while ((pos = in.find("\n", pos)) != std::string::npos) { + in.replace(pos, 1, "
    "); + } + pos = 0; + while ((pos = in.find(" ", pos)) != std::string::npos) { + in.replace(pos, 1, " "); + } + return in; + } } \ No newline at end of file diff --git a/login_server/src/cpp/lib/DataTypeConverter.h b/login_server/src/cpp/lib/DataTypeConverter.h index e1a419a93..38249f740 100644 --- a/login_server/src/cpp/lib/DataTypeConverter.h +++ b/login_server/src/cpp/lib/DataTypeConverter.h @@ -5,8 +5,17 @@ #include "../SingletonManager/MemoryManager.h" #include "Poco/Timespan.h" +#include "Poco/Nullable.h" +#include "Poco/Data/LOB.h" +#include "Poco/JSON/Object.h" +#include "Poco/JSON/Array.h" #include "../SingletonManager/LanguageManager.h" +#include "../proto/hedera/Timestamp.pb.h" +#include "../proto/hedera/Duration.pb.h" +#include "../proto/gradido/BasicTypes.pb.h" + +#include "sodium.h" namespace DataTypeConverter { @@ -19,15 +28,23 @@ namespace DataTypeConverter { }; NumberParseState strToInt(const std::string& input, int& result); +#ifdef __linux__ NumberParseState strToInt(const std::string& input, unsigned long long& result); +#endif + NumberParseState strToInt(const std::string& input, Poco::UInt64& result); + NumberParseState strToDouble(const std::string& input, double& result); MemoryBin* hexToBin(const std::string& hexString); - MemoryBin* base64ToBin(const std::string& base64String); + MemoryBin* base64ToBin(const std::string& base64String, int variant = sodium_base64_VARIANT_ORIGINAL); - std::string binToBase64(const MemoryBin* data); + + std::string binToBase64(const unsigned char* data, size_t size, int variant = sodium_base64_VARIANT_ORIGINAL); + inline std::string binToBase64(const MemoryBin* data, int variant = sodium_base64_VARIANT_ORIGINAL) { return binToBase64(data->data(), data->size(), variant); } std::string binToHex(const unsigned char* data, size_t size); + std::string binToHex(const Poco::Nullable& nullableBin); inline std::string binToHex(const MemoryBin* data) { return binToHex(data->data(), data->size());} + inline std::string binToHex(const std::vector& data) { return binToHex(data.data(), data.size()); } //! \param pubkey pointer to array with crypto_sign_PUBLICKEYBYTES size std::string pubkeyToHex(const unsigned char* pubkey); @@ -37,6 +54,19 @@ namespace DataTypeConverter { //! \brief convert duration in string showing seconds, minutes, hours or days std::string convertTimespanToLocalizedString(Poco::Timespan duration, LanguageCatalog* lang); + + Poco::Timestamp convertFromProtoTimestamp(const proto::Timestamp& timestamp); + Poco::Timestamp convertFromProtoTimestamp(const proto::gradido::Timestamp& timestamp); + void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::Timestamp* protoTimestamp); + void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::gradido::Timestamp* protoTimestamp); + Poco::Timestamp convertFromProtoTimestampSeconds(const proto::gradido::TimestampSeconds& timestampSeconds); + Poco::Timespan convertFromProtoDuration(const proto::Duration& duration); + + //! \brief go through json object and replace every string entry in base64 format into hex format + //! \return count of replaced strings + int replaceBase64WithHex(Poco::JSON::Object::Ptr json); + int replaceBase64WithHex(Poco::JSON::Array::Ptr json); + std::string replaceNewLineWithBr(std::string& in); }; #endif // __GRADIDO_LOGIN_SERVER_LIB_DATA_TYPE_CONVERTER_H diff --git a/login_server/src/cpp/lib/Error.cpp b/login_server/src/cpp/lib/Error.cpp index c44f48711..9897d7930 100644 --- a/login_server/src/cpp/lib/Error.cpp +++ b/login_server/src/cpp/lib/Error.cpp @@ -2,7 +2,7 @@ Error::Error(const char* functionName, const char* message) - : mFunctionName(functionName), mMessage(message) + : Notification(functionName, message) { } @@ -12,7 +12,7 @@ Error::~Error() } -std::string Error::getString(bool withNewline/* = true*/) +std::string Error::getString(bool withNewline/* = true*/) const { std::stringstream ss; ss << mFunctionName << ": " << mMessage; @@ -20,7 +20,7 @@ std::string Error::getString(bool withNewline/* = true*/) return ss.str(); } -std::string Error::getHtmlString() +std::string Error::getHtmlString() const { std::stringstream ss; ss << mFunctionName << ": " << mMessage; @@ -28,7 +28,7 @@ std::string Error::getHtmlString() return ss.str(); } -std::string ParamError::getString(bool withNewline/* = true*/) +std::string ParamError::getString(bool withNewline/* = true*/) const { std::stringstream ss; ss << mFunctionName << ": " << mMessage << " " << mParam; @@ -36,7 +36,7 @@ std::string ParamError::getString(bool withNewline/* = true*/) return ss.str(); } -std::string ParamError::getHtmlString() +std::string ParamError::getHtmlString() const { std::stringstream ss; ss << mFunctionName << ": " << mMessage << " " << mParam << std::endl; diff --git a/login_server/src/cpp/lib/Error.h b/login_server/src/cpp/lib/Error.h index 2a4d79e85..34199034f 100644 --- a/login_server/src/cpp/lib/Error.h +++ b/login_server/src/cpp/lib/Error.h @@ -1,63 +1,64 @@ -/*! -* -* \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 "Notification.h" +#include +#include + + +class Error : public Notification +{ +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) const; + virtual std::string getHtmlString() const; + + virtual bool isError() { return true; } + +protected: + +}; + +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) const; + virtual std::string getHtmlString() const; +protected: + std::string mParam; +}; + + + +class INotificationCollection +{ +public: + virtual void addError(Notification*, bool log = true) = 0; +}; + +#endif // DR_LUA_WEB_MODULE_ERROR_ERROR_H diff --git a/login_server/src/cpp/lib/JsonRPCRequest.cpp b/login_server/src/cpp/lib/JsonRPCRequest.cpp new file mode 100644 index 000000000..1d4637fea --- /dev/null +++ b/login_server/src/cpp/lib/JsonRPCRequest.cpp @@ -0,0 +1,145 @@ +#include "JsonRPCRequest.h" + +#include "Profiler.h" + + +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" +#include "Poco/JSON/Parser.h" + +#include "sodium.h" +#include "../SingletonManager/MemoryManager.h" +#include "DataTypeConverter.h" + + +JsonRPCRequest::JsonRPCRequest(const std::string& serverHost, int serverPort) + : JsonRequest(serverHost, serverPort) +{ + + if (serverHost.find("http://") != serverHost.npos) { + mServerHost = serverHost.substr(7); + } + else if (serverHost.find("https://") != serverHost.npos) { + mServerHost = serverHost.substr(8); + } +} + +JsonRPCRequest::~JsonRPCRequest() +{ + +} + +Poco::JSON::Object::Ptr JsonRPCRequest::request(const char* methodName, const Poco::JSON::Object& params) +{ + static const char* functionName = "JsonRequest::request"; + + //requestJson.set("user", std::string(mSessionUser->getPublicKeyHex())); + + // send post request via https + // 443 = HTTPS Default + // TODO: adding port into ServerConfig + try { + Profiler phpRequestTime; + + Poco::SharedPtr clientSession; + if (mServerPort == 443) { + clientSession = new Poco::Net::HTTPSClientSession(mServerHost, mServerPort); + } + else { + clientSession = new Poco::Net::HTTPClientSession(mServerHost, mServerPort); + } + //Poco::Net::HTTPSClientSession httpsClientSession(mServerHost, mServerPort); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/", "HTTP/1.1"); + //request.setContentType("application/json"); + + Poco::JSON::Object requestJson; + + requestJson.set("jsonrpc", "2.0"); + requestJson.set("id", rand()); + requestJson.set("method", methodName); + requestJson.set("params", params); + + request.setChunkedTransferEncoding(true); + std::ostream& request_stream = clientSession->sendRequest(request); + requestJson.stringify(request_stream); + + Poco::Net::HTTPResponse response; + std::istream& response_stream = clientSession->receiveResponse(response); + + // debugging answer + + std::stringstream responseStringStream; + for (std::string line; std::getline(response_stream, line); ) { + responseStringStream << line << std::endl; + } + Poco::Logger& speedLog = Poco::Logger::get("SpeedLog"); + std::string method_name(methodName); + speedLog.information("[%s] node server time: %s", method_name, phpRequestTime.string()); + + if (responseStringStream.str().size() == 0) { + addError(new Error(functionName, "empty request answer")); + addError(new ParamError(functionName, "server host: ", mServerHost)); + addError(new ParamError(functionName, "server port", mServerPort)); + addError(new ParamError(functionName, "method: ", methodName)); + sendErrorsAsEmail(); + return nullptr; + } + + // extract parameter from request + Poco::JSON::Parser jsonParser; + Poco::Dynamic::Var parsedJson; + try { + parsedJson = jsonParser.parse(responseStringStream.str()); + } + catch (Poco::Exception& ex) { + addError(new ParamError(functionName, "error parsing request answer", ex.displayText().data())); + + std::string fileName = "node_response_"; + fileName += methodName; + fileName += ".html"; + + FILE* f = fopen(fileName.data(), "wt"); + if (f) { + std::string responseString = responseStringStream.str(); + fwrite(responseString.data(), 1, responseString.size(), f); + fclose(f); + } + // */ + sendErrorsAsEmail(responseStringStream.str()); + return nullptr; + } + + auto object = parsedJson.extract(); + auto result = object->getObject("result"); + auto state = result->get("state"); + + std::string stateString = state.convert(); + if (stateString == "error") { + addError(new Error(functionName, "node server return error")); + if (!result->isNull("msg")) { + addError(new ParamError(functionName, "msg:", result->get("msg").convert().data())); + } + if (!result->isNull("details")) { + addError(new ParamError(functionName, "details:", result->get("details").convert().data())); + } + sendErrorsAsEmail(); + return nullptr; + } + else if (stateString == "success") { + /*for (auto it = result->begin(); it != result->end(); it++) { + std::string index = it->first; + std::string value = it->second.toString(); + printf("[JsonRequest] %s: %s\n", index.data(), value.data()); + }*/ + return object; + } + } + catch (Poco::Exception& e) { + addError(new ParamError(functionName, "connect error to node server", e.displayText().data())); + sendErrorsAsEmail(); + return nullptr; + } + + return nullptr; +} \ No newline at end of file diff --git a/login_server/src/cpp/lib/JsonRPCRequest.h b/login_server/src/cpp/lib/JsonRPCRequest.h new file mode 100644 index 000000000..a69e8e07d --- /dev/null +++ b/login_server/src/cpp/lib/JsonRPCRequest.h @@ -0,0 +1,30 @@ +/*! + * + * \author: Dario Rekowski + * + * \date: 13.01.2021 + * + * \brief: Class for Json Requests to php server + * +*/ + +#include "JsonRequest.h" + +#ifndef __GRADIDO_LOGIN_SERVER_LIB_JSON_RPC_REQUEST_ +#define __GRADIDO_LOGIN_SERVER_LIB_JSON_RPC_REQUEST_ + + +class JsonRPCRequest : public JsonRequest +{ +public: + JsonRPCRequest(const std::string& serverHost, int serverPort); + ~JsonRPCRequest(); + + Poco::JSON::Object::Ptr request(const char* methodName, const Poco::JSON::Object& params); + +protected: + +}; + + +#endif //__GRADIDO_LOGIN_SERVER_LIB_JSON_RPC_REQUEST_ \ No newline at end of file diff --git a/login_server/src/cpp/lib/JsonRequest.cpp b/login_server/src/cpp/lib/JsonRequest.cpp index 3e05fa85a..ed3448b31 100644 --- a/login_server/src/cpp/lib/JsonRequest.cpp +++ b/login_server/src/cpp/lib/JsonRequest.cpp @@ -2,15 +2,22 @@ #include "JsonRequest.h" #include "Profiler.h" -#include "Poco/JSON/Object.h" + #include "Poco/Net/HTTPSClientSession.h" #include "Poco/Net/HTTPRequest.h" #include "Poco/Net/HTTPResponse.h" #include "Poco/JSON/Parser.h" +#include "sodium.h" +#include "../SingletonManager/MemoryManager.h" +#include "DataTypeConverter.h" + JsonRequest::JsonRequest(const std::string& serverHost, int serverPort) : mServerHost(serverHost), mServerPort(serverPort) { + if (mServerHost.data()[mServerHost.size() - 1] == '/') { + mServerHost = mServerHost.substr(0, mServerHost.size() - 1); + } } @@ -19,16 +26,10 @@ JsonRequest::~JsonRequest() } - -JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net::NameValueCollection& payload) +JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::JSON::Object& requestJson) { static const char* functionName = "JsonRequest::request"; - Poco::JSON::Object requestJson; - requestJson.set("method", methodName); - for(auto it = payload.begin(); it != payload.end(); it++) { - requestJson.set(it->first, it->second); - } //requestJson.set("user", std::string(mSessionUser->getPublicKeyHex())); // send post request via https @@ -36,25 +37,26 @@ JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net:: // TODO: adding port into ServerConfig try { Profiler phpRequestTime; + Poco::Net::HTTPSClientSession httpsClientSession(mServerHost, mServerPort); - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/JsonRequestHandler"); request.setChunkedTransferEncoding(true); - std::ostream& requestStream = httpsClientSession.sendRequest(request); - requestJson.stringify(requestStream); + std::ostream& request_stream = httpsClientSession.sendRequest(request); + requestJson.stringify(request_stream); Poco::Net::HTTPResponse response; - std::istream& request_stream = httpsClientSession.receiveResponse(response); + std::istream& response_stream = httpsClientSession.receiveResponse(response); // debugging answer std::stringstream responseStringStream; - for (std::string line; std::getline(request_stream, line); ) { + for (std::string line; std::getline(response_stream, line); ) { responseStringStream << line << std::endl; } Poco::Logger& speedLog = Poco::Logger::get("SpeedLog"); - speedLog.information("[%s] php server time: %s", methodName, phpRequestTime.string()); + std::string method_name(methodName); + speedLog.information("[%s] php server time: %s", method_name, phpRequestTime.string()); // extract parameter from request Poco::JSON::Parser jsonParser; @@ -80,6 +82,138 @@ JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net:: return JSON_REQUEST_RETURN_PARSE_ERROR; } + Poco::JSON::Object object = *parsedJson.extract(); + auto state = object.get("state"); + auto message = object.get("message"); + if (state.isEmpty() && !message.isEmpty()) { + // than we have maybe get an cakephp exception as result + + addError(new ParamError(functionName, "cakePHP Exception: ", message.toString())); + addError(new ParamError(functionName, "calling: ", methodName)); + addError(new ParamError(functionName, "for server host: ", mServerHost)); + std::string fields[] = { "url", "code", "file", "line" }; + for (int i = 0; i < 4; i++) { + auto field = fields[i]; + std::string field_name = field + ": "; + addError(new ParamError(functionName, field_name.data(), object.get(field).toString())); + } + sendErrorsAsEmail(); + return JSON_REQUEST_RETURN_ERROR; + } + else { + std::string stateString = state.convert(); + if (stateString == "error") { + addError(new Error(functionName, "php server return error")); + if (!object.isNull("msg")) { + addError(new ParamError(functionName, "msg:", object.get("msg").convert().data())); + } + if (!object.isNull("details")) { + addError(new ParamError(functionName, "details:", object.get("details").convert().data())); + } + sendErrorsAsEmail(); + return JSON_REQUEST_RETURN_ERROR; + } + else if (stateString == "success") { + for (auto it = object.begin(); it != object.end(); it++) { + if (it->first == "state") continue; + std::string index = it->first; + std::string value = it->second.toString(); + printf("[JsonRequest] %s: %s\n", index.data(), value.data()); + } + } + } + } + catch (Poco::Exception& e) { + addError(new ParamError(functionName, "connect error to php server", e.displayText().data())); + sendErrorsAsEmail(); + return JSON_REQUEST_CONNECT_ERROR; + } + + return JSON_REQUEST_RETURN_OK; +} + + + +JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net::NameValueCollection& payload) +{ + Poco::JSON::Object requestJson; + requestJson.set("method", methodName); + + for (auto it = payload.begin(); it != payload.end(); it++) { + requestJson.set(it->first, it->second); + } + return request(methodName, requestJson); +} + +JsonRequestReturn JsonRequest::request(const char* methodName) +{ + Poco::JSON::Object requestJson; + requestJson.set("method", methodName); + return request(methodName, requestJson); +} + +#include "Poco/JSON/Stringifier.h" +JsonRequestReturn JsonRequest::requestGRPCRelay(const Poco::Net::NameValueCollection& payload) +{ + static const char* functionName = "JsonRequest::requestGRPCRelay"; + Poco::JSON::Object requestJson; + + for (auto it = payload.begin(); it != payload.end(); it++) { + requestJson.set(it->first, it->second); + } + + // send post request via https + // 443 = HTTPS Default + // TODO: adding port into ServerConfig + try { + Profiler phpRequestTime; + Poco::Net::HTTPClientSession httpClientSession(mServerHost, mServerPort); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/hedera_rpc_relay/gRPCProxy.php"); + + request.setChunkedTransferEncoding(false); + std::ostream& requestStream = httpClientSession.sendRequest(request); + requestJson.stringify(requestStream); + + std::stringstream ss; + requestJson.stringify(ss); + auto f = fopen("grpc.txt", "wt"); + std::string grpc = ss.str(); + fwrite(grpc.data(), grpc.size(), 1, f); + fclose(f); + + Poco::Net::HTTPResponse response; + std::istream& request_stream = httpClientSession.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("[gRPC relay] 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) { + addError(new ParamError(functionName, "error parsing request answer grpc relay", ex.displayText().data())); + + std::string fileName = "response_grpc_"; + fileName += ".html"; + + FILE* f = fopen(fileName.data(), "wt"); + std::string responseString = responseStringStream.str(); + fwrite(responseString.data(), 1, responseString.size(), f); + fclose(f); + // */ + sendErrorsAsEmail(responseStringStream.str()); + return JSON_REQUEST_RETURN_PARSE_ERROR; + } + Poco::JSON::Object object = *parsedJson.extract(); auto state = object.get("state"); std::string stateString = state.convert(); @@ -94,6 +228,9 @@ JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net:: sendErrorsAsEmail(); return JSON_REQUEST_RETURN_ERROR; } + ss.clear(); + Poco::JSON::Stringifier::stringify(object, ss); + printf("json request result: %s\n", ss.str().data()); } catch (Poco::Exception& e) { addError(new ParamError(functionName, "connect error to php server", e.displayText().data())); @@ -101,5 +238,8 @@ JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::Net:: return JSON_REQUEST_CONNECT_ERROR; } + + return JSON_REQUEST_RETURN_OK; -} \ No newline at end of file +} + diff --git a/login_server/src/cpp/lib/JsonRequest.h b/login_server/src/cpp/lib/JsonRequest.h index 87350c002..0def2465d 100644 --- a/login_server/src/cpp/lib/JsonRequest.h +++ b/login_server/src/cpp/lib/JsonRequest.h @@ -8,8 +8,9 @@ * */ -#include "ErrorList.h" +#include "NotificationList.h" #include "Poco/Net/NameValueCollection.h" +#include "Poco/JSON/Object.h" #ifndef __GRADIDO_LOGIN_SERVER_LIB_JSON_REQUEST_ #define __GRADIDO_LOGIN_SERVER_LIB_JSON_REQUEST_ @@ -22,17 +23,21 @@ enum JsonRequestReturn JSON_REQUEST_CONNECT_ERROR }; -class JsonRequest : public ErrorList +class JsonRequest : public NotificationList { public: JsonRequest(const std::string& serverHost, int serverPort); ~JsonRequest(); JsonRequestReturn request(const char* methodName, const Poco::Net::NameValueCollection& payload); + JsonRequestReturn request(const char* methodName, const Poco::JSON::Object& payload); + JsonRequestReturn request(const char* methodName); + JsonRequestReturn requestGRPCRelay(const Poco::Net::NameValueCollection& payload); protected: int mServerPort; std::string mServerHost; + }; diff --git a/login_server/src/cpp/lib/MultithreadContainer.cpp b/login_server/src/cpp/lib/MultithreadContainer.cpp index fc72593a1..d73a6a882 100644 --- a/login_server/src/cpp/lib/MultithreadContainer.cpp +++ b/login_server/src/cpp/lib/MultithreadContainer.cpp @@ -1,5 +1,5 @@ #include "MultithreadContainer.h" -#include "ErrorList.h" +#include "NotificationList.h" namespace UniLib { namespace lib { @@ -14,7 +14,7 @@ namespace UniLib { } } catch (Poco::TimeoutException& ex) { - ErrorList errors; + NotificationList errors; errors.addError(new ParamError(functionName, "lock timeout", ex.displayText())); if (mLastSucceededLock != "") { errors.addError(new ParamError(functionName, "last succeed lock by ", mLastSucceededLock.data())); diff --git a/login_server/src/cpp/lib/Notification.cpp b/login_server/src/cpp/lib/Notification.cpp new file mode 100644 index 000000000..15d622923 --- /dev/null +++ b/login_server/src/cpp/lib/Notification.cpp @@ -0,0 +1,7 @@ +#include "Notification.h" + +Notification::Notification(const char* functionName, const char* message) + : mFunctionName(functionName), mMessage(message) +{ + +} \ No newline at end of file diff --git a/login_server/src/cpp/lib/Notification.h b/login_server/src/cpp/lib/Notification.h new file mode 100644 index 000000000..419b861bc --- /dev/null +++ b/login_server/src/cpp/lib/Notification.h @@ -0,0 +1,24 @@ +#ifndef GRADIDO_LOGIN_SERVER_LIB_NOTIFICATION_H +#define GRADIDO_LOGIN_SERVER_LIB_NOTIFICATION_H + +#include + +class Notification +{ +public: + Notification(const char* functionName, const char* message); + + const char* getFunctionName() { return mFunctionName.data(); } + const char* getMessage() { return mMessage.data(); } + virtual std::string getString(bool withNewline = true) const = 0; + virtual std::string getHtmlString() const = 0; + + virtual bool isError() { return false; } + virtual bool isSuccess() { return false; } + +protected: + std::string mFunctionName; + std::string mMessage; +}; + +#endif //GRADIDO_LOGIN_SERVER_LIB_NOTIFICATION_H \ No newline at end of file diff --git a/login_server/src/cpp/lib/ErrorList.cpp b/login_server/src/cpp/lib/NotificationList.cpp similarity index 74% rename from login_server/src/cpp/lib/ErrorList.cpp rename to login_server/src/cpp/lib/NotificationList.cpp index a663b67b2..e355d1597 100644 --- a/login_server/src/cpp/lib/ErrorList.cpp +++ b/login_server/src/cpp/lib/NotificationList.cpp @@ -1,201 +1,215 @@ -#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 "NotificationList.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; +} + +// ------------------------------------------------------------------------------------ + + +NotificationList::NotificationList() + : mLogging(Poco::Logger::get("errorLog")) +{ + +} + +NotificationList::~NotificationList() +{ + while (mErrorStack.size() > 0) { + delete mErrorStack.top(); + mErrorStack.pop(); + } +} + +void NotificationList::addError(Notification* 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); +} + +void NotificationList::addNotification(Notification* notification) +{ + mErrorStack.push(notification); +} + +Notification* NotificationList::getLastError() +{ + if (mErrorStack.size() == 0) { + return nullptr; + } + + Notification* error = mErrorStack.top(); + if (error) { + mErrorStack.pop(); + } + + return error; +} + +void NotificationList::clearErrors() +{ + while (mErrorStack.size()) { + auto error = mErrorStack.top(); + if (error) { + delete error; + } + mErrorStack.pop(); + } +} + + +int NotificationList::getErrors(NotificationList* send) +{ + Notification* error = nullptr; + int iCount = 0; + while (error = send->getLastError()) { + addError(error, false); + iCount++; + } + return iCount; +} + +void NotificationList::printErrors() +{ + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + printf(error->getString().data()); + delete error; + } +} + +std::vector NotificationList::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 NotificationList::getErrorsHtml() +{ + std::string res; + res = "
      "; + while (mErrorStack.size() > 0) { + auto error = mErrorStack.top(); + mErrorStack.pop(); + if (error->isError()) { + res += "
    • "; + } + else if (error->isSuccess()) { + res += "
    • "; + } + res += error->getHtmlString(); + res += "
    • "; + delete error; + } + res += "
    "; + return res; +} + +std::string NotificationList::getErrorsHtmlNewFormat() +{ + std::string html; + + while (mErrorStack.size() > 0) { + auto error = std::unique_ptr(mErrorStack.top()); + mErrorStack.pop(); + if (error->isError()) { + html += "
    "; + html += "report_problem"; + } + else if (error->isSuccess()) { + html += "
    "; + } + html += ""; + html += error->getHtmlString(); + html += ""; + html += "
    "; + } + return html; +} +/* + +*/ + + +void NotificationList::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/NotificationList.h similarity index 76% rename from login_server/src/cpp/lib/ErrorList.h rename to login_server/src/cpp/lib/NotificationList.h index d2913a241..e343218bb 100644 --- a/login_server/src/cpp/lib/ErrorList.h +++ b/login_server/src/cpp/lib/NotificationList.h @@ -1,76 +1,75 @@ -/*! -* -* \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" + +class NotificationList : public INotificationCollection +{ +public: + NotificationList(); + ~NotificationList(); + + // push error, error will be deleted in deconstructor + virtual void addError(Notification* error, bool log = true); + void addNotification(Notification* notification); + + // return error on top of stack, please delete after using + Notification* getLastError(); + + inline size_t errorCount() { return mErrorStack.size(); } + + // delete all errors + void clearErrors(); + + static int moveErrors(NotificationList* recv, NotificationList* send) { + return recv->getErrors(send); + } + int getErrors(NotificationList* 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/lib/Success.cpp b/login_server/src/cpp/lib/Success.cpp new file mode 100644 index 000000000..5cf23f3b8 --- /dev/null +++ b/login_server/src/cpp/lib/Success.cpp @@ -0,0 +1,52 @@ +#include "Success.h" +#include + +Success::Success(const char* functionName, const char* message) + : Notification(functionName, message) +{ + +} + +std::string Success::getString(bool withNewline/* = true*/) const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage; + if (withNewline) ss << std::endl; + + return ss.str(); +} +std::string Success::getHtmlString() const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage; + + return ss.str(); +} + +ParamSuccess::ParamSuccess(const char* functionName, const char* message, std::string param) + : Success(functionName, message), mParam(param) +{ + +} + +ParamSuccess::ParamSuccess(const char* functionName, const char* message, int param) + : Success(functionName, message), mParam(std::to_string(param)) +{ + +} + +std::string ParamSuccess::getString(bool withNewline/* = true*/) const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage << " " << mParam; + if (withNewline) ss << std::endl; + + return ss.str(); +} +std::string ParamSuccess::getHtmlString() const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage << " " << mParam; + + return ss.str(); +} \ No newline at end of file diff --git a/login_server/src/cpp/lib/Success.h b/login_server/src/cpp/lib/Success.h new file mode 100644 index 000000000..4fc4b4fcf --- /dev/null +++ b/login_server/src/cpp/lib/Success.h @@ -0,0 +1,30 @@ +#ifndef GRADIDO_LOGIN_SERVER_LIB_SUCCESS_H +#define GRADIDO_LOGIN_SERVER_LIB_SUCCESS_H + +#include "Notification.h" + +class Success : public Notification +{ +public: + Success(const char* functionName, const char* message); + + std::string getString(bool withNewline = true) const; + std::string getHtmlString() const; + + virtual bool isSuccess() { return true; } +}; + +class ParamSuccess : public Success +{ +public: + ParamSuccess(const char* functionName, const char* message, std::string param); + ParamSuccess(const char* functionName, const char* message, int param); + + std::string getString(bool withNewline = true) const; + std::string getHtmlString() const; + +protected: + std::string mParam; +}; + +#endif //GRADIDO_LOGIN_SERVER_LIB_SUCCESS_H \ No newline at end of file diff --git a/login_server/src/cpp/main.cpp b/login_server/src/cpp/main.cpp index be08da820..24b6f15cf 100644 --- a/login_server/src/cpp/main.cpp +++ b/login_server/src/cpp/main.cpp @@ -1,57 +1,69 @@ -#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/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" +#include + +#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", (int)sizeof(controller::User), (int)sizeof(Session)); + printf("model sizes: User: %d Bytes, EmailOptIn: %d Bytes\n", (int)sizeof(model::table::User), (int)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; + } + printf("[Gradido_LoginServer::main] mnemonic word lists loaded!\n"); + + if (!ImportantTests::passphraseGenerationAndTransformation()) { + printf("test passphrase generation and transformation failed\n"); + return -3; + } + printf("[Gradido_LoginServer::main] passed important tests\n"); + grpc_init(); + + Gradido_LoginServer app; + try { + auto result = app.run(argc, argv); + grpc_shutdown(); + return result; + } + catch (Poco::Exception& ex) { + printf("[Gradido_LoginServer::main] exception by starting server: %s\n", ex.displayText().data()); + } + return -1; + +} #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..0aa1ae08b 100644 --- a/login_server/src/cpp/model/Session.cpp +++ b/login_server/src/cpp/model/Session.cpp @@ -1,1323 +1,1241 @@ -#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/UserBackup.h" +#include "../controller/EmailVerificationCode.h" + +#include "table/UserRole.h" + +#include "table/ModelBase.h" + + +#include "sodium.h" + +using namespace Poco::Data::Keywords; + + + +// -------------------------------------------------------------------------------------------------------------- + +Session::Session(int handle) + : mHandleId(handle), 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); + 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, int group_id, const std::string &baseUrl) +{ + Profiler usedTime; + auto user_model = mNewUser->getModel(); + if (user_model->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 (user_model->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, group_id); + 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); + email_verification_code->setBaseUrl(baseUrl); + 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, const std::string &baseUrl) +{ + 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, 0); + 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; + } + } + + + // if it gets id 1, it's the first user, so we should give him the admin role + if (user_id == 1) { + Poco::AutoPtr user_role(new model::table::UserRole(user_id, model::table::ROLE_ADMIN)); + user_role->insertIntoDB(false); + mNewUser->reload(); + } + + + 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->setBaseUrl(baseUrl); + 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) + { + // 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()) { + 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; + + } + 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, const std::string& baseUrl) +{ + mNewUser = 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) { + mEmailVerificationCodeObject->setBaseUrl(baseUrl); + 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, const Mnemonic* wordSource) +{ + + static const char* functionName = "Session::comparePassphraseWithSavedKeys"; + if (!wordSource) { + addError(new Error(functionName, "wordSource is empty")); + sendErrorsAsEmail(); + return -2; + } + auto passphrase = Passphrase::create(inputPassphrase, wordSource); + // if (!keys.generateFromPassphrase(inputPassphrase.data(), wordSource)) { + if (passphrase.isNull() || !passphrase->checkIfValid()) { + 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; + } + } + auto keys = KeyPairEd25519::create(passphrase); + if (keys) { + auto cmp_result = memcmp(userModel->getPublicKey(), keys->getPublicKey(), crypto_sign_PUBLICKEYBYTES); + delete keys; + keys = nullptr; + if (0 == cmp_result) { + 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; + } + } + + Languages lang = LANG_DE; + if (!mNewUser.isNull()) { + lang = LanguageManager::languageFromString(mNewUser->getModel()->getLanguageKey()); + } + + Poco::AutoPtr processorTask( + new ProcessingTransaction( + proto_message_base64, + DRMakeStringHash(mSessionUser->getEmail().data()), + lang + ) + ); + 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; +} + +UserState Session::loadUser(const std::string& email, const std::string& password) +{ + static const char* functionName = "Session::loadUser"; + auto observer = SingletonTaskObserver::getInstance(); + auto sm = SessionManager::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); + Poco::ScopedLock _lock(mWorkMutex); + + //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; + } + if (mNewUser->getUserState() >= USER_LOADED_FROM_DB) { + + NotificationList pwd_errors; + if (!sm->checkPwdValidation(password, &pwd_errors)) + { + Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime); + return USER_PASSWORD_INCORRECT; + } + + int loginResult = mNewUser->login(password); + int exitCount = 0; + if (loginResult == -3) + { + do + { + Poco::Thread::sleep(100); + loginResult = mNewUser->login(password); + 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; + } + } + + 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) + { + 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::UserBackup::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; + } + } + } + + } + else { + Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime); + } + + detectSessionState(); + unlock(); + if (0 == mNewUser->getModel()->getGroupId()) { + return USER_NO_GROUP; + } + + return mNewUser->getUserState(); +} + +bool Session::deleteUser() +{ + lock("Session::deleteUser"); + bool bResult = false; + if(!mNewUser.isNull()) { + JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, 443); + Poco::Net::NameValueCollection payload; + auto user_model = mNewUser->getModel(); + payload.add("user", user_model->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 = user_model->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 (mNewUser.isNull() || !mNewUser->getModel() || mNewUser->getPassword().isNull()) { + return; + } + UserState userState = mNewUser->getUserState(); + + int checkEmail = -1, resetPasswd = -1; + try { + auto emailVerificationCodeObjects = controller::EmailVerificationCode::load(mNewUser->getModel()->getID()); + + 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 = mNewUser->getModel()->getID(); + auto userBackups = controller::UserBackup::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++) { + auto passphrase = (*it)->getModel()->getPassphrase(); + Mnemonic* wordSource = nullptr; + auto passphrase_obj = Passphrase::create(passphrase, wordSource); + if (!passphrase_obj.isNull() && passphrase_obj->checkIfValid()) { + auto key_pair = KeyPairEd25519::create(passphrase_obj); + if (key_pair && key_pair->isTheSame(mNewUser->getModel()->getPublicKey())) { + correctPassphraseFound = true; + //break; + } + if (key_pair) { + delete key_pair; + } + if (correctPassphraseFound) { + 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; + } + // TODO: Maybe update language key by user, is session has another, or update only with options-menu + + 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::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::UserBackup::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..aaa6dc7c4 100644 --- a/login_server/src/cpp/model/Session.h +++ b/login_server/src/cpp/model/Session.h @@ -1,282 +1,236 @@ -/*! -* -* \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/NotificationList.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 NotificationList, 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 ---------------------------- + + //! \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, const std::string &baseUrl); + + + // adminRegister without passwort + bool adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email, int group_id, const std::string &baseUrl); + + // TODO: check if email exist and if not, fake waiting on password hashing with profiled times of real password hashing + UserState loadUser(const std::string& email, const std::string& password); + bool ifUserExist(const std::string& email); + + bool deleteUser(); + + + // ------------------------- 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, const std::string &baseUrl); + // + //! \return 0 = not the same + //! \return 1 = same + //! \return -1 = error + //! \return -2 = critical error + int comparePassphraseWithSavedKeys(const std::string& inputPassphrase, const 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 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; } + 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; } + + inline void setCallerUri(const std::string& callerUri) { mCallerUri = callerUri; } + inline const std::string& getCallerUri() { return mCallerUri; } + +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 mNewUser; + std::string mPassphrase; + Poco::AutoPtr mNewPassphrase; + Poco::DateTime mLastActivity; + Poco::Net::IPAddress mClientLoginIP; + std::string mLastExternReferer; + //! should be used by vue-client and similar clients + std::string mCallerUri; + Poco::AutoPtr mEmailVerificationCodeObject; + std::shared_mutex mSharedMutex; + + + SessionStates mState; + + bool mActive; + std::list> mProcessingTransactions; + Poco::AutoPtr mCurrentActiveProcessingTransaction; + + Poco::AutoPtr mLanguageCatalog; +}; + + +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/TransactionBase.cpp b/login_server/src/cpp/model/TransactionBase.cpp deleted file mode 100644 index 820cfcd6f..000000000 --- a/login_server/src/cpp/model/TransactionBase.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "TransactionBase.h" -#include - - -TransactionBase::TransactionBase(const std::string& memo) - : mMemo(memo) -{ - -} - -std::string TransactionBase::amountToString(google::protobuf::int64 amount) -{ - std::stringstream ss; - double dAmount = amount / 10000.0; - ss << std::fixed << std::setprecision(2) << dAmount; - std::string amountString = ss.str(); - if (amountString.find('.') != amountString.npos) { - int pointPlace = amountString.find('.'); - if (amountString.substr(pointPlace+1) == "00") { - amountString = amountString.substr(0, pointPlace); - } - } - return amountString; - //return ss.str(); -} diff --git a/login_server/src/cpp/model/TransactionBase.h b/login_server/src/cpp/model/TransactionBase.h deleted file mode 100644 index 84406fddb..000000000 --- a/login_server/src/cpp/model/TransactionBase.h +++ /dev/null @@ -1,31 +0,0 @@ -/*! -* -* \author: einhornimmond -* -* \date: 25.10.19 -* -* \brief: Interface for Transaction Objects -*/ -#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE -#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE - -#pragma warning(disable:4800) - -#include "../lib/ErrorList.h" -#include "../proto/gradido/BasicTypes.pb.h" -#include "../SingletonManager/MemoryManager.h" - -class TransactionBase : public ErrorList, public UniLib::lib::MultithreadContainer -{ -public: - TransactionBase(const std::string& memo); - virtual int prepare() = 0; - - static std::string amountToString(google::protobuf::int64 amount); - inline const std::string& getMemo() const { return mMemo; } - -protected: - std::string mMemo; -}; - -#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/TransactionCreation.cpp b/login_server/src/cpp/model/TransactionCreation.cpp index a04c424c7..2cc139f59 100644 --- a/login_server/src/cpp/model/TransactionCreation.cpp +++ b/login_server/src/cpp/model/TransactionCreation.cpp @@ -1,72 +1,71 @@ -#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) +TransactionCreation::TransactionCreation(const std::string& memo, const proto::gradido::GradidoCreation& protoCreation) + : TransactionBase(memo), mProtoCreation(protoCreation) +{ + memset(mReceiverPublicHex, 0, 65); +} + +TransactionCreation::~TransactionCreation() +{ + +} + +int TransactionCreation::prepare() +{ + const static char functionName[] = { "TransactionCreation::prepare" }; + if (!mProtoCreation.has_receiver()) { + addError(new Error(functionName, "hasn't receiver amount")); + return -1; + } + auto receiver_amount = mProtoCreation.receiver(); + + 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 = controller::User::create(); + //mReceiverUser = new User((const unsigned char*)receiverPublic.data()); + mReceiverUser->load((const unsigned char*)receiverPublic.data()); + getErrors(mReceiverUser->getModel()); + if (mReceiverUser->getUserState() == USER_EMPTY) { + sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); + mReceiverUser.assign(nullptr); + } + else { + memcpy(mReceiverPublicHex, mReceiverUser->getModel()->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/TransactionCreation.h b/login_server/src/cpp/model/TransactionCreation.h deleted file mode 100644 index a696ff962..000000000 --- a/login_server/src/cpp/model/TransactionCreation.h +++ /dev/null @@ -1,39 +0,0 @@ -/*! -* -* \author: einhornimmond -* -* \date: 25.10.19 -* -* \brief: Creation Transaction -*/ -#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE -#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE - -#pragma warning(disable:4800) - -#include "TransactionBase.h" -#include "../proto/gradido/TransactionCreation.pb.h" -#include "User.h" - -class TransactionCreation : public TransactionBase -{ -public: - TransactionCreation(const std::string& memo, const model::messages::gradido::TransactionCreation& protoCreation); - ~TransactionCreation(); - - int prepare(); - - inline User* getUser() { return mReceiverUser; } - inline google::protobuf::int64 getAmount() { return mProtoCreation.receiveramount().amount(); } - inline char* getPublicHex() { return mReceiverPublicHex; } - - inline std::string getAmountString() { return amountToString(getAmount()); } - std::string getTargetDateString(); - -protected: - const model::messages::gradido::TransactionCreation& mProtoCreation; - char mReceiverPublicHex[65]; - User* mReceiverUser; -}; - -#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/TransactionTransfer.cpp b/login_server/src/cpp/model/TransactionTransfer.cpp index 136258816..014b4b80d 100644 --- a/login_server/src/cpp/model/TransactionTransfer.cpp +++ b/login_server/src/cpp/model/TransactionTransfer.cpp @@ -1,172 +1,180 @@ -#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 = ""; - kontoNameCell += user->getNameWithEmailHtml(); - kontoNameCell += ""; -} - -TransactionTransfer::KontoTableEntry::KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount/* = false*/) -{ - composeAmountCellString(amount, negativeAmount); - //kontoNameCell = ""; - 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 = ""; + kontoNameCell += user->getNameWithEmailHtml(); + kontoNameCell += ""; +} + +TransactionTransfer::KontoTableEntry::KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount/* = false*/) +{ + composeAmountCellString(amount, negativeAmount); + //kontoNameCell = ""; + 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) +TransactionTransfer::TransactionTransfer(const std::string& memo, const proto::gradido::GradidoTransfer& protoTransfer) + : TransactionBase(memo), mProtoTransfer(protoTransfer) +{ + +} + +TransactionTransfer::~TransactionTransfer() +{ + mKontoTable.clear(); +} + +int TransactionTransfer::prepare() +{ + lock(); + const static char functionName[] = { "TransactionTransfer::prepare" }; + + mKontoTable.reserve(2); + + //auto receiverAmount = mProtoTransfer.receiveramount(); + //auto senderAmount + + char pubkeyHexTemp[65]; + + /* + if (mProtoTransfer.has_local()) + { + auto local_transfer = mProtoTransfer.local(); + auto sender = local_transfer.sender(); + auto sender_pubkey = sender.pubkey(); + auto receiver_pubkey = local_transfer.receiver(); + auto amount = sender.amount(); + auto sender_user = controller::User::create(); + auto receiver_user = controller::User::create(); + + if (!sender_user->load((const unsigned char*)sender_pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)sender_pubkey.data(), sender_pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, -amount, true)); + } + else { + mKontoTable.push_back(KontoTableEntry(sender_user->getModel(), -amount, true)); + } + + if (!receiver_user->load((const unsigned char*)receiver_pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)receiver_pubkey.data(), receiver_pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, amount, true)); + } + else { + mKontoTable.push_back(KontoTableEntry(sender_user->getModel(), amount, true)); + } + } + */ + 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(sender_user->getModel(), -amount, true)); + } + + if (!receiver_user->load((const unsigned char*)receiver_pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)receiver_pubkey.data(), receiver_pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, amount, true)); + } + else { + mKontoTable.push_back(KontoTableEntry(sender_user->getModel(), amount, true)); + } + } + 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/TransactionTransfer.h b/login_server/src/cpp/model/TransactionTransfer.h deleted file mode 100644 index b57abd6b3..000000000 --- a/login_server/src/cpp/model/TransactionTransfer.h +++ /dev/null @@ -1,51 +0,0 @@ -/*! -* -* \author: einhornimmond -* -* \date: 25.10.19 -* -* \brief: Creation Transaction -*/ -#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE -#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE - -#pragma warning(disable:4800) - -#include "TransactionBase.h" -#include "../proto/gradido/Transfer.pb.h" - -#include "../controller/User.h" - -class TransactionTransfer : public TransactionBase -{ -public: - TransactionTransfer(const std::string& memo, const model::messages::gradido::Transfer& protoTransfer); - ~TransactionTransfer(); - - int prepare(); - - inline size_t getKontoTableSize() { lock(); size_t s = mKontoTable.size(); unlock(); return s; } - const std::string& getKontoNameCell(int index); - const std::string& getAmountCell(int index); - -protected: - const static std::string mInvalidIndexMessage; - - struct KontoTableEntry - { - public: - KontoTableEntry(model::table::User* user, google::protobuf::int64 amount, bool negativeAmount = false); - KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount = false); - // first name, last name and email or pubkey hex if no user in db found - std::string kontoNameCell; - std::string amountCell; - - protected: - void composeAmountCellString(google::protobuf::int64 amount, bool negativeAmount); - }; - - const model::messages::gradido::Transfer& mProtoTransfer; - std::vector mKontoTable; -}; - -#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/User.cpp b/login_server/src/cpp/model/User.cpp deleted file mode 100644 index 27539ecf1..000000000 --- a/login_server/src/cpp/model/User.cpp +++ /dev/null @@ -1,1323 +0,0 @@ -#include "User.h" -#include "Session.h" -#include -#include "ed25519/ed25519.h" -#include "Poco/Util/Application.h" -#include "Poco/RegularExpression.h" -#include "../ServerConfig.h" - -#include "../SingletonManager/ConnectionManager.h" -#include "../SingletonManager/ErrorManager.h" -#include "../SingletonManager/SessionManager.h" -#include "../SingletonManager/LanguageManager.h" -#include "../SingletonManager/SingletonTaskObserver.h" - -#include "../controller/UserBackups.h" - - -#include "Poco/Data/Binding.h" - -using namespace Poco::Data::Keywords; - -//#define DEBUG_USER_DELETE_ENV - - -// ------------------------------------------------------------------------------------------------- - -UserCreateCryptoKey::UserCreateCryptoKey(Poco::AutoPtr user, Poco::AutoPtr newUser, const std::string& password, UniLib::controller::CPUSheduler* cpuScheduler) - : UniLib::controller::CPUTask(cpuScheduler), mUser(user), mNewUser(newUser), mPassword(password) { -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif - -} - -int UserCreateCryptoKey::run() -{ - auto cryptoKey = mUser->createCryptoKey(mPassword); - mUser->setCryptoKey(cryptoKey); - - if (sizeof(User::passwordHashed) != crypto_shorthash_BYTES) { - printf("[UserCreateCryptoKey] crypto_shorthash_BYTES != sizeof(mPasswordHashed)\n"); - throw Poco::Exception("crypto_shorthash_BYTES != sizeof(mPasswordHashed)"); - } - - auto pwdHashed = mUser->createPasswordHashed(cryptoKey); - mUser->setPwdHashed(pwdHashed); - mNewUser->getModel()->setPasswordHashed(pwdHashed); - - //printf("crypto key created\n"); - setTaskFinished(); - // must poke cpu scheduler manually because another task is waiting for this task, but in the other scheduler - ServerConfig::g_CPUScheduler->checkPendingTasks(); - return 0; -} - -// ------------------------------------------------------------------------------------------------------------- - -int UserGenerateKeys::run() -{ - - Mnemonic* wordList = nullptr; - if (!User::validatePassphrase(mPassphrase, &wordList)) { - mUser->addError(new Error(mUser->gettext("User generate Keys"), mUser->gettext("invalid passphrase, please notice the server admin coin@gradido.net"))); - return -2; - } - - // always return true, cannot fail (only if low on memory) - // !!! update: now can fail, if passphrase is invalid, for example if memory is corrupted - if (!mKeys.generateFromPassphrase(mPassphrase.data(), wordList)) { - mUser->addError(new Error(mUser->gettext("User generate Keys"), mUser->gettext("invalid passphrase2, please notice the server admin coin@gradido.net"))); - return -1; - } - - mUser->setPublicKeyHex(mKeys.getPubkeyHex()); - mUser->setPublicKey(mKeys.getPublicKey()); - - auto newUserModel = mNewUser->getModel(); - - newUserModel->setPublicKey(mKeys.getPublicKey()); - if (mUser->hasCryptoKey()) { - mUser->setPrivKey(mKeys.getPrivateKey()); - newUserModel->setPrivateKey(mUser->getPrivKey()); - } - - //printf("[UserGenerateKeys::run] controller::User: %d\n", (int)mNewUser.get()); - - return 0; -} - -// ----------------------------------------------------------------------------------------------------- - -int UserWriteIntoDB::run() -{ - auto cm = ConnectionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement insert = mUser->insertIntoDB(session); - try { - if (1 != insert.execute()) { - mUser->addError(new Error("User::insertIntoDB", "error by inserting data tuple to db")); - return -1; - } - } catch (Poco::Exception& ex) { - em->addError(new ParamError("[UserWriteIntoDB]", "error writing into db", ex.displayText().data())); - em->sendErrorsAsEmail(); - return -3; - } - if (!mUser->loadEntryDBId(session)) { - return -2; - } - return 0; -} - -// -------------------------------------------------------------------------------------------------------- - -UserWriteKeysIntoDB::UserWriteKeysIntoDB(std::vector parents, Poco::AutoPtr user, bool savePrivKey) - : UniLib::controller::CPUTask(parents.size()), mUser(user), mSavePrivKey(savePrivKey) -{ -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif - if (parents.size() < 1 || strcmp(parents[0]->getResourceType(), "UserGenerateKeys") != 0) { - throw Poco::Exception("given TaskPtr isn't UserGenerateKeys"); - } - for (int i = 0; i < parents.size(); i++) { - setParentTaskPtrInArray(parents[i], i); - } - //setParentTaskPtrInArray(parents[0], 0); - -} - -int UserWriteKeysIntoDB::run() -{ - auto cm = ConnectionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - auto keyPairs = getParent(0).cast()->getKeyPairs(); - auto pubKey = keyPairs->getPublicKey(); - static const char* functionName = "UserWritePrivKeyIntoDB::run"; - - //printf("[UserWriteKeysIntoDB] after init\n"); - - Poco::Data::BLOB pubkey_blob(pubKey, crypto_sign_PUBLICKEYBYTES); - Poco::Data::Statement update(session); - Poco::Data::BLOB* pprivkey_blob = nullptr; - if (mSavePrivKey) { - //printf("[UserWriteKeysIntoDB] save privkey\n"); - // TODO: encrypt privkey - auto privKey = keyPairs->getPrivateKey(); - //printf("[UserWriteKeysIntoDB] privKey hex: %s\n", KeyPair::getHex(*privKey, privKey->size()).data()); - auto encryptedPrivKey = mUser->encrypt(privKey); - //pprivkey_blob = mUser->encrypt(privKey); - if (!encryptedPrivKey) { - em->addError(new Error(functionName, "no privkey found")); - em->sendErrorsAsEmail(); - return -1; - } - pprivkey_blob = new Poco::Data::BLOB(*encryptedPrivKey, encryptedPrivKey->size()); - //printf("[UserWriteKeysIntoDB] privkey encrypted\n"); - //Poco::Data::BLOB privkey_blob(*privKey, privKey->size()); - - update << "UPDATE users SET pubkey=?, privkey=? where id=?", - use(pubkey_blob), use(*pprivkey_blob), bind(mUser->getDBId()); - } - else { - update << "UPDATE users SET pubkey=? where id=?", - use(pubkey_blob), bind(mUser->getDBId()); - } - - try { - if (update.execute() != 1) { - em->addError(new ParamError(functionName, "error writing keys into db for user", std::to_string(mUser->getDBId()))); - em->sendErrorsAsEmail(); - if (pprivkey_blob) { - delete pprivkey_blob; - } - return -1; - } - } - catch (Poco::Exception& ex) { - em->addError(new ParamError(functionName, "mysql error updating", ex.displayText().data())); - em->sendErrorsAsEmail(); - if (pprivkey_blob) { - delete pprivkey_blob; - } - return -1; - } - - //printf("[UserWriteKeysIntoDB] after saving into db\n"); - if (pprivkey_blob) { - delete pprivkey_blob; - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------- - -UserWriteCryptoKeyHashIntoDB::UserWriteCryptoKeyHashIntoDB(Poco::AutoPtr user, int dependencieCount/* = 0*/) - : UniLib::controller::CPUTask(ServerConfig::g_CPUScheduler, dependencieCount), mUser(user) -{ -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif -} - -int UserWriteCryptoKeyHashIntoDB::run() -{ - mUser->updateIntoDB(USER_FIELDS_PASSWORD); - return 0; -} - -// ******************************************************************************* -// new user -User::User(const char* email, const char* first_name, const char* last_name) - : mState(USER_EMPTY), mDBId(0), mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), - mLanguage(LANG_DE), mGradidoCurrentBalance(0), mCryptoKey(nullptr), mReferenceCount(1) -{ - memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); -} -// load from db -User::User(const char* email) - : mState(USER_EMPTY), mDBId(0), mEmail(email), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), - mLanguage(LANG_DE), mGradidoCurrentBalance(0), mCryptoKey(nullptr), mReferenceCount(1) -{ - //crypto_shorthash(mPasswordHashed, (const unsigned char*)password, strlen(password), *ServerConfig::g_ServerCryptoKey); - //memset(mPasswordHashed, 0, crypto_shorthash_BYTES); - auto cm = ConnectionManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - - memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); - - Poco::Nullable pubkey; - Poco::Nullable privkey; - - Poco::Data::Statement select(session); - int email_checked = 0; - std::string language_key; - select << "SELECT id, first_name, last_name, password, pubkey, privkey, email_checked, language from users where email = ?", - into(mDBId), into(mFirstName), into(mLastName), into(mPasswordHashed), into(pubkey), into(privkey), into(email_checked), into(language_key), - use(mEmail); - try { - auto result = select.execute(); - if (result == 1) { - mState = USER_LOADED_FROM_DB; - mLanguage = LanguageManager::languageFromString(language_key); - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); - - if (email_checked == 0) { mState = USER_EMAIL_NOT_ACTIVATED;} - else if (pubkey.isNull()) { mState = USER_NO_KEYS;} - else if (privkey.isNull()) { mState = USER_NO_PRIVATE_KEY; } - else { mState = USER_COMPLETE;} - - mEmailChecked = email_checked == 1; - - if (!pubkey.isNull()) { - auto pubkey_value = pubkey.value(); - if (pubkey_value.size() == crypto_sign_PUBLICKEYBYTES) { - memcpy(mPublicKey, pubkey_value.content().data(), crypto_sign_PUBLICKEYBYTES); - } - else { - addError(new Error("User", "pubkey from db has other size as expected")); - } - size_t hexSize = pubkey_value.size() * 2 + 1; - char* hexString = (char*)malloc(hexSize); - memset(hexString, 0, hexSize); - sodium_bin2hex(hexString, hexSize, pubkey_value.content().data(), pubkey_value.size()); - mPublicHex = hexString; - free(hexString); - } - if (!privkey.isNull()) { - auto privkey_value = privkey.value(); - auto privkey_size = privkey_value.size(); - //mPrivateKey = new ObfusArray(privkey_value.size(), privkey_value.content().data()); - mPrivateKey = MemoryManager::getInstance()->getFreeMemory(privkey_size); - memcpy(*mPrivateKey, privkey_value.content().data(), privkey_size); - } - - } - } catch(Poco::Exception& ex) { - addError(new ParamError("User::User", "mysql error", ex.displayText().data())); - } -} - -User::User(int user_id) - : mState(USER_EMPTY), mDBId(user_id), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), - mLanguage(LANG_DE), mGradidoCurrentBalance(0), mCryptoKey(nullptr), mReferenceCount(1) -{ - auto cm = ConnectionManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - - memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); - - Poco::Nullable pubkey; - Poco::Nullable privkey; - - Poco::Data::Statement select(session); - int email_checked = 0; - std::string language_key; - select << "SELECT email, first_name, last_name, password, pubkey, privkey, email_checked, language from users where id = ?", - into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), into(pubkey), into(privkey), into(email_checked), into(language_key), - use(user_id); - try { - auto result = select.execute(); - if (result == 1) { - mState = USER_LOADED_FROM_DB; - mLanguage = LanguageManager::languageFromString(language_key); - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); - - if (email_checked == 0) { mState = USER_EMAIL_NOT_ACTIVATED; } - else if (pubkey.isNull()) { mState = USER_NO_KEYS; } - else if (privkey.isNull()) { mState = USER_NO_PRIVATE_KEY; } - else { mState = USER_COMPLETE; } - - mEmailChecked = email_checked == 1; - - if (!pubkey.isNull()) { - auto pubkey_value = pubkey.value(); - if (pubkey_value.size() == crypto_sign_PUBLICKEYBYTES) { - memcpy(mPublicKey, pubkey_value.content().data(), crypto_sign_PUBLICKEYBYTES); - } - else { - addError(new Error("User", "pubkey from db has other size as expected")); - } - size_t hexSize = pubkey_value.size() * 2 + 1; - char* hexString = (char*)malloc(hexSize); - memset(hexString, 0, hexSize); - sodium_bin2hex(hexString, hexSize, pubkey_value.content().data(), pubkey_value.size()); - mPublicHex = hexString; - free(hexString); - } - if (!privkey.isNull()) { - auto privkey_value = privkey.value(); - auto privkey_size = privkey_value.size(); - //mPrivateKey = new ObfusArray(privkey_value.size(), privkey_value.content().data()); - mPrivateKey = MemoryManager::getInstance()->getFreeMemory(privkey_size); - memcpy(*mPrivateKey, privkey_value.content().data(), privkey_size); - } - } - } - catch (Poco::Exception& ex) { - addError(new ParamError("User::User", "mysql error", ex.displayText().data())); - } -} - -User::User(const unsigned char* pubkey_array) - : mState(USER_EMPTY), mDBId(0), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), - mLanguage(LANG_DE), mGradidoCurrentBalance(0), mCryptoKey(nullptr), mReferenceCount(1) -{ - //crypto_shorthash(mPasswordHashed, (const unsigned char*)password, strlen(password), *ServerConfig::g_ServerCryptoKey); - //memset(mPasswordHashed, 0, crypto_shorthash_BYTES); - auto cm = ConnectionManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - - memcpy(mPublicKey, pubkey_array, crypto_sign_PUBLICKEYBYTES); - - Poco::Data::BLOB pubkey(pubkey_array, 32); - Poco::Nullable privkey; - - Poco::Data::Statement select(session); - int email_checked = 0; - std::string language_key; - select << "SELECT id, email, first_name, last_name, password, privkey, email_checked, language from users where pubkey = ?", - into(mDBId), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), into(privkey), into(email_checked), into(language_key), - use(pubkey); - try { - auto result = select.execute(); - if (result == 1) { - mState = USER_LOADED_FROM_DB; - mLanguage = LanguageManager::languageFromString(language_key); - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); - - if (email_checked == 0) { mState = USER_EMAIL_NOT_ACTIVATED; } - else if (privkey.isNull()) { mState = USER_NO_PRIVATE_KEY; } - else { mState = USER_COMPLETE; } - - mEmailChecked = email_checked == 1; - - size_t hexSize = pubkey.size() * 2 + 1; - char* hexString = (char*)malloc(hexSize); - memset(hexString, 0, hexSize); - sodium_bin2hex(hexString, hexSize, pubkey.content().data(), pubkey.size()); - mPublicHex = hexString; - free(hexString); - - if (!privkey.isNull()) { - auto privkey_value = privkey.value(); - auto privkey_size = privkey_value.size(); - //mPrivateKey = new ObfusArray(privkey_value.size(), privkey_value.content().data()); - mPrivateKey = MemoryManager::getInstance()->getFreeMemory(privkey_size); - memcpy(*mPrivateKey, privkey_value.content().data(), privkey_size); - } - - } - - } - catch (Poco::Exception& ex) { - addError(new ParamError("User::User", "mysql error", ex.displayText().data())); - } -} - -User::User(Poco::AutoPtr ctrl_user) - : mUserCtrl(ctrl_user), mState(USER_EMPTY), mDBId(0), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), - mLanguage(LANG_DE), mGradidoCurrentBalance(0), mCryptoKey(nullptr), mReferenceCount(1) -{ - assert(!ctrl_user.isNull()); - auto model = ctrl_user->getModel(); - assert(model); - - auto mm = MemoryManager::getInstance(); - mDBId = model->getID(); - mEmail = model->getEmail(); - mFirstName = model->getFirstName(); - mLastName = model->getLastName(); - mPasswordHashed = model->getPasswordHashed(); - auto pubkey = model->getPublicKey(); - if (pubkey) { - memcpy(mPublicKey, pubkey, crypto_sign_PUBLICKEYBYTES); - - size_t hexSize = crypto_sign_PUBLICKEYBYTES * 2 + 1; - auto hexStringTemp = mm->getFreeMemory(hexSize); - //char* hexString = (char*)malloc(hexSize); - memset(*hexStringTemp, 0, hexSize); - sodium_bin2hex((char*)(*hexStringTemp), hexSize, pubkey, crypto_sign_PUBLICKEYBYTES); - mPublicHex = std::string((char*)(*hexStringTemp)); - mm->releaseMemory(hexStringTemp); - } - if (model->hasPrivateKeyEncrypted()) { - auto privKeyVetor = model->getPrivateKeyEncrypted(); - mPrivateKey = mm->getFreeMemory(privKeyVetor.size()); - memcpy(*mPrivateKey, privKeyVetor.data(), privKeyVetor.size()); - } - mEmailChecked = model->isEmailChecked(); - mLanguage = LanguageManager::languageFromString(model->getLanguageKey()); - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); - - /* - USER_EMPTY, - USER_LOADED_FROM_DB, - USER_PASSWORD_INCORRECT, - USER_PASSWORD_ENCRYPTION_IN_PROCESS, - USER_EMAIL_NOT_ACTIVATED, - USER_NO_KEYS, - USER_NO_PRIVATE_KEY, - USER_COMPLETE - */ - - if (mEmail != "") { - mState = USER_LOADED_FROM_DB; - - if (!mEmailChecked) { mState = USER_EMAIL_NOT_ACTIVATED; } - else if (!pubkey) { mState = USER_NO_KEYS; } - else if (!mPrivateKey) { mState = USER_NO_PRIVATE_KEY; } - else { mState = USER_COMPLETE; } - } -} - - -User::~User() -{ -#ifdef DEBUG_USER_DELETE_ENV - printf("[User::~User]\n"); -#endif - auto mm = MemoryManager::getInstance(); - if (mCryptoKey) { - //delete mCryptoKey; - mm->releaseMemory(mCryptoKey); - mCryptoKey = nullptr; - } - if (mPrivateKey) { - //delete mPrivateKey; - mm->releaseMemory(mPrivateKey); - mPrivateKey = nullptr; - } -} - -void User::setLanguage(Languages lang) -{ - lock("User::setLanguage"); - if (mLanguage != lang) { - mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(lang); - } - mLanguage = lang; - unlock(); -} - - -std::string User::generateNewPassphrase(Mnemonic* word_source) -{ - auto em = ErrorManager::getInstance(); - static const char* errorMessageForUser = "Ein Fehler, bitte wende dich an den Server-Admin (coin@gradido.net). | An error occured, please ask the server admin (coin@gradido.net)."; - unsigned int random_indices[PHRASE_WORD_COUNT]; - unsigned int str_sizes[PHRASE_WORD_COUNT]; - unsigned int phrase_buffer_size = 0; - bool errorReloadingMnemonicWordList = false; - int loopTrys = 0; - Poco::RegularExpression checkValidWord("^[a-zA-ZÄÖÜäöüß&;]*$"); - - // TODO: make sure words didn't double - for (int i = 0; i < PHRASE_WORD_COUNT; i++) { - random_indices[i] = randombytes_random() % 2048; - auto word = word_source->getWord(random_indices[i]); - if (loopTrys > 10 || errorReloadingMnemonicWordList) { - return errorMessageForUser; - } - if (!word) { - em->addError(new ParamError("User::generateNewPassphrase", "empty word get for index", random_indices[i])); - em->sendErrorsAsEmail(); - - random_indices[i] = randombytes_random() % 2048; - word = word_source->getWord(random_indices[i]); - if (!word) return errorMessageForUser; - - } - else { - if (!checkValidWord.match(word, 0, Poco::RegularExpression::RE_NOTEMPTY)) { - em->addError(new ParamError("User::generateNewPassphrase", "invalid word", word)); - em->addError(new Error("User::generateNewPassphrase", "try to reload mnemonic word list, but this error is maybe evidence for a serious memory problem!!!")); - if (!ServerConfig::loadMnemonicWordLists()) { - em->addError(new Error("User::generateNewPassphrase", "error reloading mnemonic word lists")); - errorReloadingMnemonicWordList = true; - } - else { - i = 0; - loopTrys++; - } - em->sendErrorsAsEmail(); - //return "Server Fehler, bitte frage den Admin coin@gradido.net | Server error, please ask the admin coin@gradido.net"; - } - } - str_sizes[i] = strlen(word); - phrase_buffer_size += str_sizes[i]; - } - phrase_buffer_size += PHRASE_WORD_COUNT + 1; - - std::string phrase_buffer(phrase_buffer_size, '\0'); - int phrase_buffer_cursor = 0; - - for (int i = 0; i < PHRASE_WORD_COUNT; i++) { - memcpy(&phrase_buffer[phrase_buffer_cursor], word_source->getWord(random_indices[i]), str_sizes[i]); - - phrase_buffer_cursor += str_sizes[i]; - phrase_buffer[phrase_buffer_cursor++] = ' '; - } - - - return phrase_buffer; -} - -bool User::validatePassphrase(const std::string& passphrase, Mnemonic** wordSource/* = nullptr*/) -{ - return KeyPair::validatePassphrase(passphrase, wordSource); - -} - -bool User::isEmptyPassword() -{ - bool bRet = false; - lock("User::isEmptyPassword"); - //printf("[User::isEmptyPassword] pwd hashed: %d, running: %d, this: %d\n", -// mPasswordHashed, !mCreateCryptoKeyTask.isNull(), this); - bRet = mPasswordHashed == 0 && (mCreateCryptoKeyTask.isNull() || mCreateCryptoKeyTask->isTaskFinished()); - unlock(); - return bRet; -} - -UserStates User::getUserState() -{ - UserStates state; - lock("User::getUserState"); - state = mState; - unlock(); - return state; -} - -Poco::JSON::Object User::getJson() -{ - lock("User::getJson"); - Poco::JSON::Object userObj; - - userObj.set("first_name", mFirstName); - userObj.set("last_name", mLastName); - userObj.set("email", mEmail); - userObj.set("public_hex", mPublicHex); - userObj.set("state", userStateToString(mState)); - userObj.set("email_checked", mEmailChecked); - userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); - unlock(); - return userObj; -} - -/* -// TODO: if a password and privkey already exist, load current private key and re encrypt with new crypto key -bool User::setNewPassword(const std::string& newPassword) -{ - //Profiler timeUsed; - if (newPassword == "") { - lock("User::setNewPassword"); - addError(new Error("Passwort", "Ist leer.")); - unlock(); - return false; - } - if (!mCreateCryptoKeyTask.isNull() && !mCreateCryptoKeyTask->isTaskFinished()) { - lock("User::setNewPassword"); - addError(new Error("Passwort", "Wird bereits erstellt, bitte in ca. 1 minute neuladen.")); - unlock(); - return false; - } - duplicate(); - lock("User::setNewPassword"); - //printf("[User::setNewPassword] start create crypto key task with this: %d\n", this); - mCreateCryptoKeyTask = new UserCreateCryptoKey(this, newPassword, ServerConfig::g_CPUScheduler); - mCreateCryptoKeyTask->scheduleTask(mCreateCryptoKeyTask); - unlock(); - - duplicate(); - - UniLib::controller::TaskPtr savePassword(new UserWriteCryptoKeyHashIntoDB(this, 1)); - savePassword->setParentTaskPtrInArray(mCreateCryptoKeyTask, 0); - savePassword->scheduleTask(savePassword); - - - //printf("[User::setNewPassword] timeUsed: %s\n", timeUsed.string().data()); - return true; -} -*/ -bool User::updatePassword(const std::string& newPassword, const std::string& passphrase, Poco::AutoPtr newUser) -{ - static const char* functionName("User::updatePassword"); - if (newPassword == "") { - lock(functionName); - addError(new Error(gettext("Passwort"), gettext("Ist leer."))); - unlock(); - return false; - } - if (!mCreateCryptoKeyTask.isNull() && !mCreateCryptoKeyTask->isTaskFinished()) { - lock(functionName); - addError(new Error(gettext("Passwort"), gettext("Wird bereits erstellt, bitte in ca. 1 minute neuladen."))); - unlock(); - return false; - } - //duplicate(); - //lock("User::setNewPassword"); - //printf("[User::setNewPassword] start create crypto key task with this: %d\n", this); - //mCreateCryptoKeyTask = new UserCreateCryptoKey(this, newPassword, ServerConfig::g_CPUScheduler); - //mCreateCryptoKeyTask->scheduleTask(mCreateCryptoKeyTask); - //unlock(); - - auto mm = MemoryManager::getInstance(); - - bool passwordHashedCalculated = false; - - // no previous password set - - //if (!mPasswordHashed) { - duplicate(); - lock(functionName); - //printf("[User::setNewPassword] start create crypto key task with this: %d\n", this); - mCreateCryptoKeyTask = new UserCreateCryptoKey(this, newUser, newPassword, ServerConfig::g_CPUScheduler); - mCreateCryptoKeyTask->scheduleTask(mCreateCryptoKeyTask); - unlock(); - //} - /*else { - // compare with previous password - auto cryptoKey = createCryptoKey(newPassword); - auto passwordHash = createPasswordHashed(cryptoKey); - lock(functionName); - if (mPasswordHashed == passwordHash) { - addError(new Error(gettext("Passwort"), gettext("Du hast dasselbe Passwort gewählt, bitte wähle ein anderes."))); - unlock(); - mm->releaseMemory(cryptoKey); - return false; - } - mPasswordHashed = passwordHash; - passwordHashedCalculated = true; - if (mCryptoKey) { - mm->releaseMemory(mCryptoKey); - } - mCryptoKey = cryptoKey; - unlock(); - }*/ - - duplicate(); - UniLib::controller::TaskPtr savePassword(nullptr); - UserWriteCryptoKeyHashIntoDB* writePWDHashedIntoDB = nullptr; - if (passwordHashedCalculated) { - savePassword = new UserWriteCryptoKeyHashIntoDB(this, 0); - } - else { - savePassword = new UserWriteCryptoKeyHashIntoDB(this, 1); - savePassword->setParentTaskPtrInArray(mCreateCryptoKeyTask, 0); - } - savePassword->scheduleTask(savePassword); - - if (passphrase != "") { - duplicate(); - UniLib::controller::TaskPtr genKeys(new UserGenerateKeys(this, newUser, passphrase)); - genKeys->scheduleTask(genKeys); - - - std::vector saveKeysParents; - saveKeysParents.reserve(2); // to prevent allocating more memory as ever needed - saveKeysParents.push_back(genKeys); - if (!passwordHashedCalculated) { - saveKeysParents.push_back(mCreateCryptoKeyTask); - } - duplicate(); - UniLib::controller::TaskPtr saveKeys(new UserWriteKeysIntoDB(saveKeysParents, this, true)); - saveKeys->scheduleTask(saveKeys); - } - - //printf("[User::setNewPassword] timeUsed: %s\n", timeUsed.string().data()); - return true; -} - -void User::setEmailChecked() -{ - lock("User::setEmailChecked"); - mEmailChecked = true; - if (mState <= USER_EMAIL_NOT_ACTIVATED) { - if (mPublicHex == "") { - mState = USER_NO_KEYS; - } - else if (!mPrivateKey) { - mState = USER_NO_PRIVATE_KEY; - } - else { - mState = USER_COMPLETE; - } - } - unlock(); -} - -bool User::validatePwd(const std::string& pwd, ErrorList* validationErrorsToPrint) -{ - auto mm = MemoryManager::getInstance(); - auto cmpCryptoKey = createCryptoKey(pwd); - if (sizeof(User::passwordHashed) != crypto_shorthash_BYTES) { - throw Poco::Exception("crypto_shorthash_BYTES != sizeof(User::passwordHashed)"); - } - if (nullptr == cmpCryptoKey) { - if (validationErrorsToPrint) { - validationErrorsToPrint->addError(new Error("User::validatePwd", "couldn't create crypto key")); - return false; - } - } - User::passwordHashed pwdHashed; - if (!ServerConfig::g_ServerCryptoKey) { - if (validationErrorsToPrint) { - validationErrorsToPrint->addError(new Error("User::validatePwd", "server crypto key not set")); - } - mm->releaseMemory(cmpCryptoKey); - return false; - } - crypto_shorthash((unsigned char*)&pwdHashed, *cmpCryptoKey, crypto_box_SEEDBYTES, *ServerConfig::g_ServerCryptoKey); - lock("User::validatePwd"); - if (pwdHashed == mPasswordHashed) { - if (!mCryptoKey) { - mCryptoKey = cmpCryptoKey; - } - else { - //delete cmpCryptoKey; - mm->releaseMemory(cmpCryptoKey); - } - unlock(); - return true; - } - //delete cmpCryptoKey; - mm->releaseMemory(cmpCryptoKey); - - unlock(); - return false; -} - -void User::login(Poco::AutoPtr newUser) -{ - assert(!newUser.isNull()); - assert(newUser->getModel()); - - lock("User::validatePwd"); - mPasswordHashed = newUser->getModel()->getPasswordHashed(); - auto mm = MemoryManager::getInstance(); - if (mCryptoKey) { - mm->releaseMemory(mCryptoKey); - mCryptoKey = nullptr; - } - auto keyPair = newUser->getGradidoKeyPair(); - if (keyPair) { - mCryptoKey = keyPair->getCryptedPrivKey(newUser->getPassword()); - } - unlock(); -} - -bool User::validateIdentHash(HASH hash) -{ - lock("User::validateIdentHash"); - HASH local_hash = DRMakeStringHash(mEmail.data(), mEmail.size()); - unlock(); - return local_hash == hash; -} - -bool User::deleteFromDB() -{ - auto cm = ConnectionManager::getInstance(); - auto em = ErrorManager::getInstance(); - auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - - Poco::Data::Statement deleteFromDB(session); - //DELETE FROM `table_name` [WHERE condition]; - - std::string tables[] = { "users", "email_opt_in", "user_backups" }; - - /*deleteFromDB - << "DELETE from users where id = ?;" - "DELETE from email_opt_in where user_id = ?;" - "DELETE from user_backups where user_id = ?", - use(mDBId), use(mDBId), use(mDBId); - */ - for (int i = 0; i < 3; i++) { - if (i > 0) { - deleteFromDB.reset(session); - deleteFromDB << "DELETE from " << tables[i] << " where user_id = ?", use(mDBId); - } - else { - deleteFromDB << "DELETE from " << tables[i] << " where id = ?", use(mDBId); - } - - try { - lock("User::deleteFromDB"); - auto result = deleteFromDB.execute(); - unlock(); - //printf("[User::deleteFromDB] %s deleted: %d\n", tables[i].data(), result); - } - catch (Poco::Exception& ex) { - unlock(); - em->addError(new ParamError("[User::deleteFromDB]", "error deleting user tables", ex.displayText().data())); - em->sendErrorsAsEmail(); - //return false; - } - } - - - return true; -} - -void User::duplicate() -{ - Poco::Mutex::ScopedLock _lock(mReferenceMutex); - //mReferenceMutex.lock(); - mReferenceCount++; -#ifdef DEBUG_USER_DELETE_ENV - printf("[User::duplicate] new value: %d\n", mReferenceCount); -#endif - //mReferenceMutex.unlock(); -} - -void User::release() -{ - - Poco::Mutex::ScopedLock _lock(mReferenceMutex); - //mReferenceMutex.lock(); - mReferenceCount--; -#ifdef DEBUG_USER_DELETE_ENV - printf("[User::release] new value: %d, this: %d\n", mReferenceCount, this); -#endif - if (0 == mReferenceCount) { - //mReferenceMutex.unlock(); - delete this; - return; - } - //mReferenceMutex.unlock(); - -} - -MemoryBin* User::createCryptoKey(const std::string& password) -{ - - //Profiler timeUsed; - auto mm = MemoryManager::getInstance(); - auto observer = SingletonTaskObserver::getInstance(); - static const char* funcName = "User::createCryptoKey"; - if (mEmail == "") { - lock(funcName); - addError(new Error(funcName, "email is empty")); - unlock(); - return nullptr; - } - - - - // TODO: put it in secure location, or use value from server config - static const unsigned char app_secret[] = { 0x21, 0xff, 0xbb, 0xc6, 0x16, 0xfe }; - - sha_context context_sha512; - //unsigned char* hash512 = (unsigned char*)malloc(SHA_512_SIZE); - if (SHA_512_SIZE < crypto_pwhash_SALTBYTES) { - lock(funcName); - addError(new Error(funcName, "sha512 is to small for libsodium pwhash saltbytes")); - unlock(); - return nullptr; - } - - observer->addTask(mEmail, TASK_OBSERVER_PASSWORD_CREATION); - - unsigned char hash512_salt[SHA_512_SIZE]; // need at least crypto_pwhash_SALTBYTES 16U - sha512_init(&context_sha512); - sha512_update(&context_sha512, (const unsigned char*)mEmail.data(), mEmail.size()); - sha512_update(&context_sha512, app_secret, 6); - sha512_final(&context_sha512, hash512_salt); - - - //unsigned char* key = (unsigned char *)malloc(crypto_box_SEEDBYTES); // 32U - //ObfusArray* key = new ObfusArray(crypto_box_SEEDBYTES); - auto key = mm->getFreeMemory(crypto_box_SEEDBYTES); - //Bin32Bytes* key = mm->get32Bytes(); - if (crypto_pwhash(*key, key->size(), password.data(), password.size(), hash512_salt, 10U, 33554432, 2) != 0) { - lock(funcName); - addError(new ParamError(funcName, " error creating pwd hash, maybe to much memory requestet? error:", strerror(errno))); - unlock(); - observer->removeTask(mEmail, TASK_OBSERVER_PASSWORD_CREATION); - //printf("[User::%s] error creating pwd hash, maybe to much memory requestet? error: %s\n", __FUNCTION__, strerror(errno)); - //printf("pwd: %s\n", pwd); - return nullptr; - } - observer->removeTask(mEmail, TASK_OBSERVER_PASSWORD_CREATION); - -// lock(); -// auto cryptoKey = new ObfusArray(crypto_box_SEEDBYTES, key); -// unlock(); -// free(key); - - // mCryptoKey - //printf("[User::createCryptoKey] time used: %s\n", timeUsed.string().data()); - return key; -} - -User::passwordHashed User::createPasswordHashed(MemoryBin* cryptoKey, ErrorList* errorReceiver/* = nullptr*/) -{ - if (sizeof(User::passwordHashed) != crypto_shorthash_BYTES) { - throw Poco::Exception("crypto_shorthash_BYTES != sizeof(User::passwordHashed)"); - } - User::passwordHashed pwdHashed = 0; - if (!ServerConfig::g_ServerCryptoKey) { - if (errorReceiver) { - errorReceiver->addError(new Error("User::validatePwd", "server crypto key not set")); - } - return pwdHashed; - } - crypto_shorthash((unsigned char*)&pwdHashed, *cryptoKey, crypto_box_SEEDBYTES, *ServerConfig::g_ServerCryptoKey); - - return pwdHashed; -} - -void User::fakeCreateCryptoKey() -{ - Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime); -} - -bool User::generateKeys(bool savePrivkey, const std::string& passphrase, Session* session) -{ - //Profiler timeUsed; - - duplicate(); - UniLib::controller::TaskPtr generateKeysTask(new UserGenerateKeys(this, session->getNewUser(), passphrase)); - //generateKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_GENERATED, session)); - //generateKeysTask->scheduleTask(generateKeysTask); - // run directly because we like to show pubkey on interface, shouldn't last to long - generateKeysTask->run(); - session->updateState(SESSION_STATE_KEY_PAIR_GENERATED); - - if (mDBId == 0) { - //printf("[User::generateKeys] dbid is zero, load from db\n"); - loadEntryDBId(ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); - if (mDBId == 0) { - auto em = ErrorManager::getInstance(); - em->addError(new ParamError("User::generateKeys", "user not found in db with email", mEmail.data())); - em->sendErrorsAsEmail(); - } - return false; - } - - duplicate(); - std::vector parentsForWriteKeys; - parentsForWriteKeys.reserve(2); - parentsForWriteKeys.push_back(generateKeysTask); - if (!mCreateCryptoKeyTask.isNull() && !mCreateCryptoKeyTask->isTaskFinished()) { - parentsForWriteKeys.push_back(mCreateCryptoKeyTask); - } - - UniLib::controller::TaskPtr saveKeysTask(new UserWriteKeysIntoDB(parentsForWriteKeys, this, savePrivkey)); - saveKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_WRITTEN, session)); - saveKeysTask->scheduleTask(saveKeysTask); - - -// printf("[User::generateKeys] call two tasks, time used: %s\n", timeUsed.string().data()); - return true; - -} - -MemoryBin* User::encrypt(const MemoryBin* data) -{ - if (!hasCryptoKey()) { - addError(new Error("User::encrypt", "hasn't crypto key")); - return nullptr; - } - if (!data) { - addError(new Error("User::encrypt", "data is zero")); - return nullptr; - } - size_t message_len = data->size(); - size_t ciphertext_len = crypto_secretbox_MACBYTES + message_len; - - unsigned char nonce[crypto_secretbox_NONCEBYTES]; - // we use a hardcoded value for nonce - memset(nonce, 31, crypto_secretbox_NONCEBYTES); - - //unsigned char* ciphertext = (unsigned char*)malloc(ciphertext_len); - //ObfusArray* ciphertext = new ObfusArray(ciphertext_len); - auto mm = MemoryManager::getInstance(); - auto ciphertext = mm->getFreeMemory(ciphertext_len); - memset(*ciphertext, 0, ciphertext_len); - - if (0 != crypto_secretbox_easy(*ciphertext, *data, message_len, nonce, *mCryptoKey)) { - //printf("[%s] error encrypting message \n", __FUNCTION__); - addError(new Error("User::encrypt", "encrypting message failed")); - //free(ciphertext); - mm->releaseMemory(ciphertext); - - return nullptr; - } - - //printf("[User::encrypt] encrypted: %s, ciphertext len: %u\n", KeyPair::getHex(ciphertext, ciphertext_len).data(), ciphertext_len); - - //auto resultObfus = new ObfusArray(ciphertext_len, ciphertext); - //free(ciphertext); - - return ciphertext; -} - -MemoryBin* User::decrypt(const MemoryBin* encryptedData) -{ - if (!hasCryptoKey()) { - addError(new Error("User::decrypt", "hasn't crypto key")); - return nullptr; - } - //printf("[User::decrypt] decrypt: %s, ciphertext len: %u\n", KeyPair::getHex(*encryptedData, encryptedData->size()).data(), encryptedData->size()); - //ObfusArray* decrypetData = new ObfusArray(encryptedData->size() - crypto_secretbox_MACBYTES); - - size_t decryptSize = encryptedData->size() - crypto_secretbox_MACBYTES; - //unsigned char* decryptBuffer = (unsigned char*)malloc(decryptSize); - auto mm = MemoryManager::getInstance(); - //ObfusArray* decryptedData = new ObfusArray(decryptSize); - auto decryptedData = mm->getFreeMemory(decryptSize); - unsigned char nonce[crypto_secretbox_NONCEBYTES]; - // we use a hardcoded value for nonce - memset(nonce, 31, crypto_secretbox_NONCEBYTES); - - if (crypto_secretbox_open_easy(*decryptedData, *encryptedData, encryptedData->size(), nonce, *mCryptoKey)) { - mm->releaseMemory(decryptedData); - addError(new Error("User::decrypt", "error decrypting")); - return nullptr; - } - /*int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k);*/ - - return decryptedData; -} - -MemoryBin* User::sign(const unsigned char* message, size_t messageSize) -{ - - if (!message || !messageSize) return nullptr; - if (!hasCryptoKey()) { - addError(new Error("User::sign", "hasn't crypto key")); - return nullptr; - } - if (!mPrivateKey) { - addError(new Error("User::sign", "hasn't privkey")); - return nullptr; - } - - //binArrayObj = new BinaryArray(crypto_sign_BYTES); - auto mm = MemoryManager::getInstance(); - //auto signBinBuffer = (unsigned char*)malloc(crypto_sign_BYTES); - auto privKey = getPrivKey(); - - if (!privKey) { - //addError(new Error("User::sign", "decrypt privkey failed")); - - - auto userBackups = controller::UserBackups::load(mDBId); - - // get privkey, only possible while passphrase isn't crypted in db - bool correctPassphraseFound = false; - KeyPair keys; - for (auto it = userBackups.begin(); it != userBackups.end(); it++) { - - auto passphrase = (*it)->getModel()->getPassphrase(); - Mnemonic* wordSource = nullptr; - if (User::validatePassphrase(passphrase, &wordSource)) { - if (keys.generateFromPassphrase((*it)->getModel()->getPassphrase().data(), wordSource)) { - if(keys.isPubkeysTheSame(getPublicKey())) - { - correctPassphraseFound = true; - break; - } - } - } - } - if (correctPassphraseFound) { - - // save corrected key into db - auto encyrptedPrivKey = encrypt(keys.getPrivateKey()); - auto newUser = controller::User::create(); - if (1 == newUser->load(mDBId)) { - auto userModel = newUser->getModel(); - if (encyrptedPrivKey) { - userModel->setPrivateKey(encyrptedPrivKey); - userModel->updatePrivkey(); - // remove unencrypt error from priv key to prevent error 404 forwarding - delete getLastError(); - } - - mm->releaseMemory(encyrptedPrivKey); - - } - - // sign with received key - auto const_privKey = keys.getPrivateKey(); - auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); - unsigned long long actualSignLength = 0; - - if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *const_privKey)) { - addError(new Error("User::sign 2", "sign failed")); - mm->releaseMemory(signBinBuffer); - return nullptr; - } - - if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mPublicKey) != 0) { - // Incorrect signature! - //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); - addError(new Error("User::sign 2", "sign verify failed")); - mm->releaseMemory(privKey); - mm->releaseMemory(signBinBuffer); - return nullptr; - } - - return signBinBuffer; - } - - return nullptr; - } - - auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); - - unsigned long long actualSignLength = 0; - - if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *privKey)) { - addError(new Error("User::sign", "sign failed")); - mm->releaseMemory(privKey); - mm->releaseMemory(signBinBuffer); - return nullptr; - } - - if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mPublicKey) != 0) { - // Incorrect signature! - //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); - addError(new Error("User::sign", "sign verify failed")); - mm->releaseMemory(privKey); - mm->releaseMemory(signBinBuffer); - return nullptr; - } - - // debug - const size_t hex_sig_size = crypto_sign_BYTES * 2 + 1; - char sig_hex[hex_sig_size]; - sodium_bin2hex(sig_hex, hex_sig_size, *signBinBuffer, crypto_sign_BYTES); - printf("[User::sign] signature hex: %s\n", sig_hex); - - mm->releaseMemory(privKey); - - return signBinBuffer; -} - -Poco::Data::Statement User::insertIntoDB(Poco::Data::Session session) -{ - - Poco::Data::Statement insert(session); - - //Poco::Data::BLOB pwd(&mPasswordHashed[0], crypto_shorthash_BYTES); - - //printf("[User::insertIntoDB] password hashed: %llu\n", mPasswordHashed); - std::string languageKey = LanguageManager::keyForLanguage(mLanguage); - if (mPasswordHashed) { - insert << "INSERT INTO users (email, first_name, last_name, password, language) VALUES(?, ?, ?, ?, ?);", - use(mEmail), use(mFirstName), use(mLastName), bind(mPasswordHashed), bind(languageKey); - } - else { - insert << "INSERT INTO users (email, first_name, last_name, language) VALUES(?, ?, ?, ?);", - use(mEmail), use(mFirstName), use(mLastName), bind(languageKey); - } - - - return insert; -} - -bool User::updateIntoDB(UserFields fieldType) -{ - - if (mDBId == 0) { - addError(new Error("User::updateIntoDB", "user id is zero")); - return false; - } - if (USER_FIELDS_PASSWORD == fieldType || USER_FIELDS_EMAIL_CHECKED == fieldType) { - auto session = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); - Poco::Data::Statement update(session); - if (USER_FIELDS_PASSWORD == fieldType) { - update << "UPDATE users SET password = ? where id = ?", - use(mPasswordHashed), use(mDBId); - } - else if (USER_FIELDS_EMAIL_CHECKED == fieldType) { - update << "UPDATE users SET email_checked = ? where id = ?", - use(mEmailChecked), use(mDBId); - } - else if (USER_FIELDS_LANGUAGE == fieldType) { - std::string languageKey = LanguageManager::keyForLanguage(mLanguage); - update << "UPDATE users SET language = ? where id = ?", - bind(languageKey), use(mDBId); - } - try { - if (update.execute() == 1) return true; - addError(new ParamError("User::updateIntoDB", "update not affected 1 rows", fieldType)); - } - catch (Poco::Exception& ex) { - auto em = ErrorManager::getInstance(); - em->addError(new ParamError("User::updateIntoDB", "mysql error", ex.displayText().data())); - em->sendErrorsAsEmail(); - } - } - - return false; - -} - -bool User::loadEntryDBId(Poco::Data::Session session) -{ - auto em = ErrorManager::getInstance(); - Poco::Data::Statement select(session); - - select << "SELECT id from users where email = ?;", - into(mDBId), use(mEmail); - try { - if (select.execute() != 1) { - addError(new Error("User::loadEntryDBId", "didn't get expectet row count (1)")); - return false; - } - } catch(Poco::Exception& ex) { - em->addError(new ParamError("[User::loadEntryDBId]", "error selecting from db", ex.displayText().data())); - em->sendErrorsAsEmail(); - } - - return true; -} - -const char* User::userStateToString(UserStates state) -{ - switch (state) { - case USER_EMPTY: return "empty"; - case USER_LOADED_FROM_DB: return "loaded from db"; - case USER_PASSWORD_INCORRECT: return "password incorrect"; - case USER_EMAIL_NOT_ACTIVATED: return "email not activated"; - case USER_NO_KEYS: return "no keys"; - case USER_NO_PRIVATE_KEY: return "no private key"; - case USER_COMPLETE: return "complete"; - } - return "- unknown -"; -} - -MemoryBin* User::getPrivKey() -{ - if (!mPrivateKey) { - addError(new Error("User::getPrivKey", "no private key saved")); - return nullptr; - } - if (!hasCryptoKey()) { - addError(new Error("User::getPrivKey", "no crypto key set for decrypting priv key")); - return nullptr; - } - return decrypt(mPrivateKey); -} - -bool User::setPrivKey(const MemoryBin* privKey) -{ - if (!hasCryptoKey()) { - lock("User::setPrivKey"); - addError(new Error("User::getPrivKey", "no crypto key set for encrypting priv key")); - unlock(); - return false; - } - auto encyrptedPrivKey = encrypt(privKey); - lock("User::setPrivKey"); - mState = USER_COMPLETE; - mPrivateKey = encyrptedPrivKey;// encrypt(privKey); - unlock(); - - return true; -} - -void User::lock(const char* stateInfos/* = nullptr*/) -{ - try { - mWorkingMutex.lock(500); - } - catch (Poco::TimeoutException& ex) { - addError(new ParamError("User::lock", "timeout exception", ex.displayText())); - if (stateInfos) { - addError(new ParamError("User::lock", "stateInfos", stateInfos)); - } - sendErrorsAsEmail(); - } -} \ No newline at end of file diff --git a/login_server/src/cpp/model/User.h b/login_server/src/cpp/model/User.h deleted file mode 100644 index c041cea7d..000000000 --- a/login_server/src/cpp/model/User.h +++ /dev/null @@ -1,272 +0,0 @@ -#ifndef GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE -#define GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE - -#include "../Crypto/KeyPair.h" -#include -//#include "ModelBase.h" -#include "../lib/ErrorList.h" - -#include "Poco/Thread.h" -#include "Poco/Types.h" -#include "Poco/Data/Session.h" -#include "Poco/JSON/Object.h" -#include "../tasks/CPUTask.h" - -#include "../SingletonManager/MemoryManager.h" -#include "../SingletonManager/LanguageManager.h" - -#include "../controller/User.h" - -class UserCreateCryptoKey; -class UserWriteIntoDB; -class Session; -class UserWriteCryptoKeyHashIntoDB; -class SigningTransaction; -class UserGenerateKeys; -class DebugPassphrasePage; -class RepairDefectPassphrase; - -enum UserStates -{ - USER_EMPTY, - USER_LOADED_FROM_DB, - USER_PASSWORD_INCORRECT, - USER_PASSWORD_ENCRYPTION_IN_PROCESS, - USER_EMAIL_NOT_ACTIVATED, - USER_NO_KEYS, - USER_NO_PRIVATE_KEY, - USER_KEYS_DONT_MATCH, - USER_COMPLETE, - USER_DISABLED -}; - -enum UserFields -{ - USER_FIELDS_ID, - USER_FIELDS_FIRST_NAME, - USER_FIELDS_LAST_NAME, - USER_FIELDS_PASSWORD, - USER_FIELDS_EMAIL_CHECKED, - USER_FIELDS_LANGUAGE -}; - -class User : public ErrorList -{ - friend UserCreateCryptoKey; - friend UserWriteIntoDB; - friend UserWriteCryptoKeyHashIntoDB; - friend SigningTransaction; - friend UserGenerateKeys; - friend DebugPassphrasePage; - friend RepairDefectPassphrase; -public: - // new user - User(const char* email, const char* first_name, const char* last_name); - // existing user - User(const char* email); - - // existing user by public key - User(const unsigned char* pubkey_array); - - User(int user_id); - - // load from controller user - User(Poco::AutoPtr ctrl_user); - - // login - //User(const std::string& email, const std::string& password); - - ~User(); - - void login(Poco::AutoPtr newUser); - - static std::string generateNewPassphrase(Mnemonic* word_source); - static bool validatePassphrase(const std::string& passphrase, Mnemonic** wordSource = nullptr); - static const char* userStateToString(UserStates state); - //static User* login(const std::string& email, const std::string& password, ErrorList* errorContainer = nullptr); - - bool generateKeys(bool savePrivkey, const std::string& passphrase, Session* session); - - bool loadEntryDBId(Poco::Data::Session session); - - bool deleteFromDB(); - - inline bool hasCryptoKey() { lock(); bool bRet = mCryptoKey != nullptr; unlock(); return bRet; } - - inline const char* getEmail() const { return mEmail.data(); } - inline const char* getFirstName() const { return mFirstName.data(); } - inline const char* getLastName() const { return mLastName.data(); } - inline int getDBId() const { return mDBId; } - inline int getBalance() { lock(); int balance = mGradidoCurrentBalance; unlock(); return balance; } - inline std::string getPublicKeyHex() { lock(); std::string pubkeyHex = mPublicHex; unlock(); return pubkeyHex; } - inline const unsigned char* getPublicKey() { return mPublicKey; } - inline Languages getLanguage() { lock(); Languages lang = mLanguage; unlock(); return lang; } - - inline void setPublicKeyHex(const std::string& publicKeyHex) { lock(); mPublicHex = publicKeyHex; unlock(); } - inline void setPublicKey(const unsigned char* key) { lock(); memcpy(mPublicKey, key, crypto_sign_PUBLICKEYBYTES); unlock();} - - inline const char* gettext(const char* text) { if (mLanguageCatalog.isNull()) return text; return mLanguageCatalog->gettext(text); } - - UserStates getUserState(); - - void setLanguage(Languages lang); - inline void setBalance(int balance) { lock(); mGradidoCurrentBalance = balance; unlock(); } - void setEmailChecked(); - bool isEmptyPassword(); - //bool setNewPassword(const std::string& newPassword); - bool updatePassword(const std::string& newPassword, const std::string& passphrase, Poco::AutoPtr newUser); - bool validatePwd(const std::string& pwd, ErrorList* validationErrorsToPrint); - bool validateIdentHash(HASH hash); - - MemoryBin* encrypt(const MemoryBin* data); - MemoryBin* decrypt(const MemoryBin* encryptedData); - MemoryBin* sign(const unsigned char* message, size_t messageSize); - - Poco::JSON::Object getJson(); - - // for poco auto ptr - void duplicate(); - void release(); - - //! \brief wait time create crypto key is normally running - static void fakeCreateCryptoKey(); -protected: - typedef Poco::UInt64 passwordHashed; - - MemoryBin* createCryptoKey(const std::string& password); - static passwordHashed createPasswordHashed(MemoryBin* cryptoKey, ErrorList* errorReceiver = nullptr); - inline void setCryptoKey(MemoryBin* cryptoKey) { lock(); mCryptoKey = cryptoKey; unlock(); } - - //void detectState(); - - Poco::Data::Statement insertIntoDB(Poco::Data::Session session); - bool updateIntoDB(UserFields fieldType); - inline passwordHashed getPwdHashed() { lock(); auto ret = mPasswordHashed; unlock(); return ret; } - inline void setPwdHashed(passwordHashed pwdHashed) { lock(); mPasswordHashed = pwdHashed; unlock(); } - - void lock(const char* stateInfos = nullptr); - inline void unlock() { mWorkingMutex.unlock(); } - - MemoryBin* getPrivKey(); - inline bool hasPrivKey() { lock(); bool result = false; if (mPrivateKey && mCryptoKey) result = true; unlock(); return result; } - bool setPrivKey(const MemoryBin* privKey); - -private: - Poco::AutoPtr mUserCtrl; - UserStates mState; - - // ************************* DB FIELDS ****************************** - int mDBId; - std::string mEmail; - std::string mFirstName; - std::string mLastName; - - passwordHashed mPasswordHashed; - - std::string mPublicHex; - unsigned char mPublicKey[crypto_sign_PUBLICKEYBYTES]; - //! crypted private key - MemoryBin* mPrivateKey; - // TODO: insert created if necessary - - bool mEmailChecked; - Languages mLanguage; - - // ************************ DB FIELDS END ****************************** - - int mGradidoCurrentBalance; - Poco::AutoPtr mLanguageCatalog; - - // crypto key as obfus array - // only in memory, if user has typed in password - MemoryBin* mCryptoKey; - - Poco::Mutex mWorkingMutex; - Poco::Mutex mReferenceMutex; - - // for poco auto ptr - int mReferenceCount; - - UniLib::controller::TaskPtr mCreateCryptoKeyTask; -}; - -class UserCreateCryptoKey : public UniLib::controller::CPUTask -{ -public: - UserCreateCryptoKey(Poco::AutoPtr user, Poco::AutoPtr newUser, const std::string& password, UniLib::controller::CPUSheduler* cpuScheduler); - - virtual int run(); - virtual const char* getResourceType() const { return "UserCreateCryptoKey"; }; - -private: - Poco::AutoPtr mUser; - Poco::AutoPtr mNewUser; - std::string mPassword; -}; - -class UserGenerateKeys : public UniLib::controller::CPUTask -{ -public: - UserGenerateKeys(Poco::AutoPtr user, Poco::AutoPtr newUser, const std::string& passphrase) - : mUser(user), mNewUser(newUser), mPassphrase(passphrase) { -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif - } - - ~UserGenerateKeys() { - - } - virtual int run(); - inline KeyPair* getKeyPairs() { return &mKeys; } - - virtual const char* getResourceType() const { return "UserGenerateKeys"; }; -protected: - Poco::AutoPtr mUser; - Poco::AutoPtr mNewUser; - std::string mPassphrase; - KeyPair mKeys; -}; - -class UserWriteIntoDB : public UniLib::controller::CPUTask -{ -public: - UserWriteIntoDB(Poco::AutoPtr user, UniLib::controller::CPUSheduler* cpuScheduler, size_t taskDependenceCount = 0) - : UniLib::controller::CPUTask(cpuScheduler, taskDependenceCount), mUser(user) { -#ifdef _UNI_LIB_DEBUG - setName(user->getEmail()); -#endif - } - - virtual int run(); - virtual const char* getResourceType() const { return "UserWriteIntoDB"; }; -private: - Poco::AutoPtr mUser; -}; - -class UserWriteKeysIntoDB : public UniLib::controller::CPUTask -{ -public: - UserWriteKeysIntoDB(std::vector parents, Poco::AutoPtr user, bool savePrivKey); - - virtual int run(); - - virtual const char* getResourceType() const { return "UserWriteKeysIntoDB"; }; -protected: - Poco::AutoPtr mUser; - bool mSavePrivKey; -}; - -class UserWriteCryptoKeyHashIntoDB : public UniLib::controller::CPUTask -{ -public: - UserWriteCryptoKeyHashIntoDB(Poco::AutoPtr user, int dependencieCount = 0); - - int run(); - const char* getResourceType() const { return "UserWriteCryptoKeyHashIntoDB"; }; - -protected: - Poco::AutoPtr mUser; -}; - -#endif //GRADIDO_LOGIN_SERVER_MODEL_USER_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/email/Email.cpp b/login_server/src/cpp/model/email/Email.cpp index 2efa473e4..e4c6763d3 100644 --- a/login_server/src/cpp/model/email/Email.cpp +++ b/login_server/src/cpp/model/email/Email.cpp @@ -3,7 +3,7 @@ #include "Poco/Net/MediaType.h" -#include "../TransactionBase.h" +#include "../gradido/TransactionBase.h" #include "../lib/DataTypeConverter.h" @@ -320,7 +320,7 @@ Gradido Login-Server\n\ static const char* functionName = "Email::replaceAmount"; int findPos = result.find("[amount]"); if (findPos != result.npos) { - result.replace(findPos, 8, TransactionBase::amountToString(gradido_cent)); + result.replace(findPos, 8, model::gradido::TransactionBase::amountToString(gradido_cent)); } else { addError(new Error(functionName, "no amount placeholder found")); diff --git a/login_server/src/cpp/model/email/Email.h b/login_server/src/cpp/model/email/Email.h index d2887a26c..0fc52cac0 100644 --- a/login_server/src/cpp/model/email/Email.h +++ b/login_server/src/cpp/model/email/Email.h @@ -17,7 +17,7 @@ #include "../../SingletonManager/LanguageManager.h" -#include "../../lib/ErrorList.h" +#include "../../lib/NotificationList.h" namespace model { using namespace Poco; @@ -39,7 +39,7 @@ namespace model { EMAIL_MAX }; - class Email: public ErrorList + class Email: public NotificationList { public: Email(AutoPtr emailVerification, AutoPtr user, EmailType type); diff --git a/login_server/src/cpp/model/gradido/GroupMemberUpdate.cpp b/login_server/src/cpp/model/gradido/GroupMemberUpdate.cpp new file mode 100644 index 000000000..145e1e97a --- /dev/null +++ b/login_server/src/cpp/model/gradido/GroupMemberUpdate.cpp @@ -0,0 +1,142 @@ +#include "GroupMemberUpdate.h" +#include "../../Crypto/KeyPairEd25519.h" +#include "../../controller/Group.h" +#include "../../SingletonManager/SessionManager.h" +#include "../../lib/JsonRequest.h" + +namespace model { + namespace gradido { + GroupMemberUpdate::GroupMemberUpdate(const std::string& memo, const proto::gradido::GroupMemberUpdate &protoGroupMemberUpdate) + : TransactionBase(memo), mProtoMemberUpdate(protoGroupMemberUpdate) + { + + } + + GroupMemberUpdate::~GroupMemberUpdate() + { + + } + + int GroupMemberUpdate::prepare() + { + auto target_group = mProtoMemberUpdate.target_group(); + auto sm = SessionManager::getInstance(); + auto mm = MemoryManager::getInstance(); + + if (mProtoMemberUpdate.user_pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + return -1; + } + + auto pubkey_copy = mm->getFreeMemory(KeyPairEd25519::getPublicKeySize()); + memcpy(*pubkey_copy, mProtoMemberUpdate.user_pubkey().data(), KeyPairEd25519::getPublicKeySize()); + mRequiredSignPublicKeys.push_back(pubkey_copy); + + if (sm->isValid(target_group, VALIDATE_GROUP_ALIAS)) { + auto groups = controller::Group::load(mProtoMemberUpdate.target_group()); + if (groups.size() > 0 && !groups[0].isNull() && groups[0]->getModel()) { + auto user_db = controller::User::create(); + auto count = user_db->getModel()->countColumns("group_id", groups[0]->getModel()->getID()); + if (!count) + { + // no current user in group, at least login server known, so we need only one signature for transaction + // TODO: maybe check with node server, but maybe it isn't necessary + // check sequence number in topic db entry, should be <= 1 + mMinSignatureCount = 1; + + } + else + { + // at least one more user is in group + // now we need the voting system to decide how many and which signatures are needed + + // for current version we need only one another + mMinSignatureCount = 2; + } + } + /*if (groups.size() != 1) { + addError(new ParamError(functionName, "target group not known or not unambiguous: ", target_group)); + return TRANSACTION_VALID_INVALID_GROUP_ALIAS; + }*/ + } + mIsPrepared = true; + return 0; + } + + TransactionValidation GroupMemberUpdate::validate() + { + const static char functionName[] = { "GroupMemberUpdate::validate" }; + if (mProtoMemberUpdate.user_pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(functionName, "pubkey not set or wrong size")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + + if (mProtoMemberUpdate.member_update_type() != proto::gradido::GroupMemberUpdate::ADD_USER) { + addError(new Error(functionName, "user move not implemented yet!")); + return TRANSACTION_VALID_CODE_ERROR; + } + auto target_group = mProtoMemberUpdate.target_group(); + auto sm = SessionManager::getInstance(); + if (sm->isValid(target_group, VALIDATE_GROUP_ALIAS)) { + auto groups = controller::Group::load(mProtoMemberUpdate.target_group()); + if (groups.size() != 1) { + addError(new ParamError(functionName, "target group not known or not unambiguous: ", target_group)); + return TRANSACTION_VALID_INVALID_GROUP_ALIAS; + } + } + else { + addError(new Error(functionName, "target group isn't valid group alias string ")); + return TRANSACTION_VALID_INVALID_GROUP_ALIAS; + } + + return TRANSACTION_VALID_OK; + } + /* + GroupMemberUpdate::GroupMemberUpdate(const std::string& memo, Poco::AutoPtr user, Poco::AutoPtr group) + { + + } + */ + + std::string GroupMemberUpdate::getPublicKeyHex() + { + auto user_pubkey = mProtoMemberUpdate.user_pubkey(); + return DataTypeConverter::binToHex((const unsigned char*)user_pubkey.data(), user_pubkey.size()); + } + + void GroupMemberUpdate::transactionAccepted(Poco::AutoPtr user) + { + static const char* function_name = "GroupMemberUpdate::transactionAccepted"; + auto sm = SessionManager::getInstance(); + if (user.isNull()) { + printf("[%s] user is zero, was transaction created from test call, without saving user into db?\n", function_name); + return; + } + + auto target_group = mProtoMemberUpdate.target_group(); + + if (sm->isValid(target_group, VALIDATE_GROUP_ALIAS)) { + auto groups = controller::Group::load(mProtoMemberUpdate.target_group()); + if (groups.size() != 1) { + addError(new ParamError(function_name, "target group not known or not unambiguous: ", target_group)); + sendErrorsAsEmail(); + } + else { + auto user_model = user->getModel(); + auto group_model = groups[0]->getModel(); + // write new group_id in user table + user_model->setGroupId(group_model->getID()); + user_model->updateIntoDB("group_id", group_model->getID()); + + JsonRequest request(group_model->getUrl(), 443); + request.request("addUser", user->getJson()); + + printf("[GroupMemberUpdate::transactionAccepted] finished\n"); + } + } + else { + addError(new ParamError(function_name, "invalid group alias, after transaction was successfully sended: ", target_group)); + sendErrorsAsEmail(); + } + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/GroupMemberUpdate.h b/login_server/src/cpp/model/gradido/GroupMemberUpdate.h new file mode 100644 index 000000000..7bd146cfd --- /dev/null +++ b/login_server/src/cpp/model/gradido/GroupMemberUpdate.h @@ -0,0 +1,29 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_GROUP_MEMBER_UPDATE_H +#define __GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_GROUP_MEMBER_UPDATE_H + +#include "TransactionBase.h" +#include "../../proto/gradido/GroupMemberUpdate.pb.h" + + +namespace model { + namespace gradido { + class GroupMemberUpdate : public TransactionBase + { + public: + GroupMemberUpdate(const std::string& memo, const proto::gradido::GroupMemberUpdate &protoGroupMemberUpdate); + ~GroupMemberUpdate(); + int prepare(); + TransactionValidation validate(); + + std::string getTargetGroupAlias() { return mProtoMemberUpdate.target_group(); } + std::string getPublicKeyHex(); + + void transactionAccepted(Poco::AutoPtr); + + protected: + const proto::gradido::GroupMemberUpdate& mProtoMemberUpdate; + }; + } +} + +#endif \ No newline at end of file diff --git a/login_server/src/cpp/model/UserPassphrase.cpp b/login_server/src/cpp/model/gradido/ManageNodeBody.cpp similarity index 100% rename from login_server/src/cpp/model/UserPassphrase.cpp rename to login_server/src/cpp/model/gradido/ManageNodeBody.cpp diff --git a/login_server/src/cpp/model/gradido/ManageNodeBody.h b/login_server/src/cpp/model/gradido/ManageNodeBody.h new file mode 100644 index 000000000..8e757f935 --- /dev/null +++ b/login_server/src/cpp/model/gradido/ManageNodeBody.h @@ -0,0 +1,10 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_MANAGE_NODE_BODY_H +#define __GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_MANAGE_NODE_BODY_H + +namespace model { + namespace gradido { + + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_MANAGE_NODE_BODY_H \ No newline at end of file diff --git a/login_server/src/cpp/model/UserPassphrase.h b/login_server/src/cpp/model/gradido/ManageNodeGroupAdd.cpp similarity index 100% rename from login_server/src/cpp/model/UserPassphrase.h rename to login_server/src/cpp/model/gradido/ManageNodeGroupAdd.cpp diff --git a/login_server/src/cpp/model/gradido/ManageNodeGroupAdd.h b/login_server/src/cpp/model/gradido/ManageNodeGroupAdd.h new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/gradido/Transaction.cpp b/login_server/src/cpp/model/gradido/Transaction.cpp new file mode 100644 index 000000000..0bbaf0ec1 --- /dev/null +++ b/login_server/src/cpp/model/gradido/Transaction.cpp @@ -0,0 +1,827 @@ +#include "Transaction.h" +#include "../../SingletonManager/ErrorManager.h" +#include "../../SingletonManager/PendingTasksManager.h" +#include "../../SingletonManager/LanguageManager.h" +#include "../../SingletonManager/CronManager.h" +#include "../../ServerConfig.h" + +#include "../../controller/HederaId.h" +#include "../../controller/HederaAccount.h" +#include "../../controller/HederaRequest.h" + +#include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" + +#include "../hedera/Transaction.h" +#include "../hedera/TransactionId.h" + +#include "../../tasks/HederaTask.h" + +#include + +#include "Poco/JSON/Parser.h" + +#include + + +namespace model { + namespace gradido { + Transaction::Transaction(Poco::AutoPtr body) + : mTransactionBody(body), mBodyBytesHash(0) + { + + auto body_bytes = mTransactionBody->getBodyBytes(); + mBodyBytesHash = DRMakeStringHash(body_bytes.data(), body_bytes.size()); + mProtoTransaction.set_body_bytes(body_bytes); + } + + Transaction::Transaction(const std::string& protoMessageBin, model::table::PendingTask* dbModel) + : GradidoTask(dbModel) + { + if (!mProtoTransaction.ParseFromString(protoMessageBin)) { + throw new Poco::Exception("error parse from string"); + } + mTransactionBody = TransactionBody::load(mProtoTransaction.body_bytes()); + auto body_bytes = mTransactionBody->getBodyBytes(); + mBodyBytesHash = DRMakeStringHash(body_bytes.data(), body_bytes.size()); + } + + Transaction::~Transaction() + { + Poco::ScopedLock _lock(mWorkMutex); + } + + Poco::AutoPtr Transaction::createGroupMemberUpdate(Poco::AutoPtr user, Poco::AutoPtr group) + { + auto em = ErrorManager::getInstance(); + static const char* function_name = "Transaction::create group member update"; + + if (user.isNull() || !user->getModel() || group.isNull() || !group->getModel()) { + return nullptr; + } + auto group_model = group->getModel(); + auto network_type = ServerConfig::g_HederaNetworkType; + auto topic_id = controller::HederaId::find(group_model->getID(), network_type); + + if (topic_id.isNull()) { + em->addError(new ParamError(function_name, "could'n find topic for group: ", group_model->getID())); + em->addError(new ParamError(function_name, "network type: ", network_type)); + em->sendErrorsAsEmail(); + return nullptr; + } + + auto body = TransactionBody::create("", user, proto::gradido::GroupMemberUpdate_MemberUpdateType_ADD_USER, group_model->getAlias()); + + Poco::AutoPtr result = new Transaction(body); + auto model = result->getModel(); + model->setHederaId(topic_id->getModel()->getID()); + result->insertPendingTaskIntoDB(user, model::table::TASK_TYPE_GROUP_ADD_MEMBER); + PendingTasksManager::getInstance()->addTask(result); + return result; + } + + Poco::AutoPtr Transaction::createCreation(Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::DateTime targetDate, const std::string& memo) + { + auto em = ErrorManager::getInstance(); + static const char* function_name = "Transaction::create creation"; + + if (receiver.isNull() || !receiver->getModel()) { + return nullptr; + } + auto network_type = ServerConfig::g_HederaNetworkType; + auto receiver_model = receiver->getModel(); + auto topic_id = controller::HederaId::find(receiver_model->getGroupId(), network_type); + + if (topic_id.isNull()) { + em->addError(new ParamError(function_name, "could'n find topic for group: ", receiver_model->getGroupId())); + em->addError(new ParamError(function_name, "network type: ", network_type)); + em->sendErrorsAsEmail(); + return nullptr; + } + auto body = TransactionBody::create(memo, receiver, amount, targetDate); + Poco::AutoPtr result = new Transaction(body); + auto model = result->getModel(); + model->setHederaId(topic_id->getModel()->getID()); + result->insertPendingTaskIntoDB(receiver, model::table::TASK_TYPE_CREATION); + PendingTasksManager::getInstance()->addTask(result); + return result; + } + + std::vector> Transaction::createTransfer(Poco::AutoPtr sender, const MemoryBin* receiverPubkey, Poco::AutoPtr receiverGroup, Poco::UInt32 amount, const std::string& memo, bool inbound/* = true*/) + { + std::vector> results; + auto em = ErrorManager::getInstance(); + static const char* function_name = "Transaction::create transfer"; + + if (sender.isNull() || !sender->getModel() || !receiverPubkey || !amount) { + return results; + } + + //std::vector> bodys; + auto sender_model = sender->getModel(); + auto network_type = ServerConfig::g_HederaNetworkType; + // LOCAL Transfer + if (receiverGroup.isNull() || sender_model->getGroupId() == receiverGroup->getModel()->getID()) + { + auto body = TransactionBody::create(memo, sender, receiverPubkey, amount); + Poco::AutoPtr transaction = new Transaction(body); + auto topic_id = controller::HederaId::find(sender_model->getGroupId(), network_type); + if (topic_id.isNull()) { + em->addError(new ParamError(function_name, "could'n find topic for group: ", sender_model->getGroupId())); + em->addError(new ParamError(function_name, "network type: ", network_type)); + em->sendErrorsAsEmail(); + return results; + } + transaction->getModel()->setHederaId(topic_id->getModel()->getID()); + results.push_back(transaction); + } + else + { + auto sender_group = controller::Group::load(sender_model->getGroupId()); + if (sender_group.isNull()) + { + em->addError(new ParamError(function_name, "couldn't find group with id: ", sender_model->getGroupId())); + em->sendErrorsAsEmail(); + return results; + } + Poco::AutoPtr transaction_group; + Poco::AutoPtr topic_group; + // default constructor set it to now + Poco::Timestamp pairedTransactionId; + // create only inbound transaction, and outbound before sending to hedera + //for (int i = 0; i < 1; i++) { + if (!inbound) { + transaction_group = receiverGroup; + topic_group = sender_group; + } + // transaction send to receiver blockchain + else if(inbound) { + transaction_group = sender_group; + topic_group = receiverGroup; + } + auto topic_id = controller::HederaId::find(topic_group->getModel()->getID(), network_type); + if (topic_id.isNull()) { + em->addError(new ParamError(function_name, "could'n find topic for group: ", sender_model->getGroupId())); + em->addError(new ParamError(function_name, "network type: ", network_type)); + em->sendErrorsAsEmail(); + return results; + } + if (transaction_group.isNull()) { + em->addError(new ParamError(function_name, "transaction group is zero, inbound", inbound)); + em->sendErrorsAsEmail(); + return results; + } + + auto body = TransactionBody::create(memo, sender, receiverPubkey, amount, pairedTransactionId, transaction_group); + Poco::AutoPtr transaction = new Transaction(body); + transaction->getModel()->setHederaId(topic_id->getModel()->getID()); + auto transfer_transaction = transaction->getTransactionBody()->getTransferTransaction(); + transfer_transaction->setOwnGroupAlias(sender_group->getModel()->getAlias()); + transfer_transaction->setTargetGroupAlias(receiverGroup->getModel()->getAlias()); + + results.push_back(transaction); + // } + } + + + for (auto it = results.begin(); it != results.end(); it++) { + if (!(*it)->getTransactionBody()->getTransferTransaction()->isInbound()) { + (*it)->insertPendingTaskIntoDB(sender, model::table::TASK_TYPE_TRANSFER); + PendingTasksManager::getInstance()->addTask(*it); + } + } + + + return results; + + } + + bool Transaction::setTopicIdByGroup(const std::string& alias) + { + static const char* function_name = "Transaction::setTopicIdByGroup"; + auto topic_groups = controller::Group::load(alias); + if (topic_groups.size() != 1) { + addError(new ParamError(function_name, "not one group found for alias: ", alias)); + sendErrorsAsEmail(); + return false; + } + auto topic = controller::HederaId::find(topic_groups[0]->getModel()->getID(), ServerConfig::g_HederaNetworkType); + if (topic.isNull()) { + addError(new ParamError(function_name, "no topic found for group id", topic_groups[0]->getModel()->getID())); + addError(new ParamError(function_name, "and network type: ", ServerConfig::g_HederaNetworkType)); + sendErrorsAsEmail(); + return false; + } + getModel()->setHederaId(topic->getModel()->getID()); + return true; + } + + Poco::AutoPtr Transaction::createTransfer(const MemoryBin* senderPubkey, Poco::AutoPtr receiver, std::string senderGroupAlias, Poco::UInt32 amount, const std::string& memo) + { + Poco::AutoPtr result; + auto em = ErrorManager::getInstance(); + static const char* function_name = "Transaction::create transfer 2"; + + if (receiver.isNull() || !receiver->getModel() || !senderPubkey || !amount) { + return result; + } + + //std::vector> bodys; + auto receiver_model = receiver->getModel(); + auto network_type = ServerConfig::g_HederaNetworkType; + + auto sender_groups = controller::Group::load(senderGroupAlias); + if (!sender_groups.size()) { + em->addError(new ParamError(function_name, "couldn't find group", senderGroupAlias)); + em->sendErrorsAsEmail(); + return result; + } + Poco::AutoPtr transaction_group; + Poco::AutoPtr topic_group = controller::Group::load(receiver_model->getGroupId()); + if (topic_group.isNull()) { + em->addError(new ParamError(function_name, "topic group not found", receiver_model->getGroupId())); + em->sendErrorsAsEmail(); + return result; + } + // default constructor set it to now + Poco::Timestamp pairedTransactionId; + // create only inbound transaction, and outbound before sending to hedera + //for (int i = 0; i < 1; i++) { + + //transaction_group = receiverGroup; + //topic_group = sender_group; + + auto topic_id = controller::HederaId::find(topic_group->getModel()->getID(), network_type); + if (topic_id.isNull()) { + em->addError(new ParamError(function_name, "could'n find topic for group: ", receiver_model->getGroupId())); + em->addError(new ParamError(function_name, "network type: ", network_type)); + em->sendErrorsAsEmail(); + return result; + } + if (transaction_group.isNull()) { + em->addError(new Error(function_name, "transaction group is zero, inbound")); + em->sendErrorsAsEmail(); + return result; + } + + auto body = TransactionBody::create(memo, senderPubkey, receiver, amount, pairedTransactionId, transaction_group); + result = new Transaction(body); + result->getModel()->setHederaId(topic_id->getModel()->getID()); + + // } + + //result->insertPendingTaskIntoDB(receiver, model::table::TASK_TYPE_TRANSFER); + //PendingTasksManager::getInstance()->addTask(result); + + return result; + } + + + Poco::AutoPtr Transaction::load(model::table::PendingTask* dbModel) + { + proto::gradido::GradidoTransaction transaction_temp; + + Poco::AutoPtr transaction = new Transaction(dbModel->getRequestCopy(), dbModel); + PendingTasksManager::getInstance()->addTask(transaction); + return transaction; + } + + bool Transaction::insertPendingTaskIntoDB(Poco::AutoPtr user, model::table::TaskType type) + { + static const char* function_name = "Transaction::insertPendingTaskIntoDB"; + auto model = getModel(); + if (model->getID()) { + addError(new Error("Transaction::insertPendingTaskIntoDB", "pending task already inserted into db")); + return false; + } + if (user.isNull() || !user->getModel()) { + addError(new Error(function_name, "invalid user")); + return false; + } + model->setUserId(user->getModel()->getID()); + model->setTaskType(type); + model->setRequest(mProtoTransaction.SerializeAsString()); + if (!model->insertIntoDB(true)) { + + return false; + } + return true; + } + + bool Transaction::sign(Poco::AutoPtr user) + { + static const char function_name[] = "Transaction::addSign"; + Poco::ScopedLock _lock(mWorkMutex); + + if (user.isNull() || !user->getModel()) + { + addError(new Error(function_name, "error user is invalid")); + return false; + } + std::string bodyBytes; + try { + bodyBytes = mTransactionBody->getBodyBytes(); + } + catch (Poco::Exception& ex) { + addError(new Error(function_name, "error getting body bytes")); + return false; + } + auto hash = DRMakeStringHash(bodyBytes.data(), bodyBytes.size()); + + + auto sigMap = mProtoTransaction.mutable_sig_map(); + if (sigMap->sigpair_size() > 0 && mBodyBytesHash && mBodyBytesHash != hash) + { + addError(new Error(function_name, "body bytes hash has changed and signature(s) exist already!")); + return false; + } + if (mBodyBytesHash != hash) { + mProtoTransaction.set_body_bytes(bodyBytes.data(), bodyBytes.size()); + } + mBodyBytesHash = hash; + + auto pubkeyBin = user->getModel()->getPublicKey(); + + // check if pubkey already exist + for (auto it = sigMap->sigpair().begin(); it != sigMap->sigpair().end(); it++) + { + if (it->pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "error signature pubkey hasn't expected size!")); + return false; + } + if (0 == memcmp(pubkeyBin, it->pubkey().data(), KeyPairEd25519::getPublicKeySize())) { + addError(new ParamError(function_name, "error, pubkey has signed already from user: ", user->getModel()->getEmail())); + return false; + } + } + + + auto mm = MemoryManager::getInstance(); + auto gradido_key_pair = user->getGradidoKeyPair(); + KeyPairEd25519* recovered_gradido_key_pair = nullptr; + + if (!gradido_key_pair || !gradido_key_pair->hasPrivateKey()) + { + if (!user->tryLoadPassphraseUserBackup(&recovered_gradido_key_pair)) + { + if (user->setGradidoKeyPair(recovered_gradido_key_pair)) + { + user->getModel()->updatePrivkey(); + } + } + else + { + addError(new Error(function_name, "user cannot decrypt private key")); + return false; + } + } + + + 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(); + addError(new Error(function_name, "error by calculate signature")); + mm->releaseMemory(sign); + return false; + } + auto sigPair = sigMap->add_sigpair(); + auto pubkeyBytes = sigPair->mutable_pubkey(); + *pubkeyBytes = std::string((const char*)pubkeyBin, crypto_sign_PUBLICKEYBYTES); + + auto sigBytes = sigPair->mutable_ed25519(); + *sigBytes = std::string((char*)*sign, crypto_sign_BYTES); + auto sign_hex_string = DataTypeConverter::binToHex(sign); + //printf("sign hex: %s\n", sign_hex_string.data()); + mm->releaseMemory(sign); + + updateRequestInDB(); + // check if enough signatures exist for next step + if (getSignCount() >= mTransactionBody->getTransactionBase()->getMinSignatureCount()) + { + if (getTransactionBody()->isTransfer()) { + auto transfer = getTransactionBody()->getTransferTransaction(); + if (transfer->isOutbound()) { + auto transaction = transfer->createInbound(getTransactionBody()->getMemo()); + if (!transaction.isNull()) { + transaction->sign(user); + // dirty hack because gn crashes if its get transactions out of order + mPairedTransaction = transaction; + // removed because now using only one hedera node + //Poco::Thread::sleep(1000); + } + else { + addError(new Error(function_name, "Error creating outbound transaction")); + return false; + } + + } + } + UniLib::controller::TaskPtr transaction_send_task(new SendTransactionTask(Poco::AutoPtr(this, true))); + transaction_send_task->scheduleTask(transaction_send_task); + } + + //getModel()->updateIntoDB("request", ) + //printf("[Transaction::sign] reference-count: %d\n", mReferenceCount); + return true; + } + + bool Transaction::updateRequestInDB() + { + Poco::ScopedLock _lock(mWorkMutex); + auto size = mProtoTransaction.ByteSize(); + std::string transaction_serialized = std::string(size, 0); + mProtoTransaction.SerializeToString(&transaction_serialized); + auto model = getModel(); + model->setRequest(transaction_serialized); + return model->updateRequest(); + } + + TransactionValidation Transaction::validate() + { + Poco::ScopedLock _lock(mWorkMutex); + auto sig_map = mProtoTransaction.sig_map(); + + // check if all signatures belong to current body bytes + auto body_bytes = mProtoTransaction.body_bytes(); + for (auto it = sig_map.sigpair().begin(); it != sig_map.sigpair().end(); it++) + { + KeyPairEd25519 key_pair((const unsigned char*)it->pubkey().data()); + if (!key_pair.verify(body_bytes, it->ed25519())) { + return TRANSACTION_VALID_INVALID_SIGN; + } + } + + auto transaction_base = mTransactionBody->getTransactionBase(); + auto result = transaction_base->checkRequiredSignatures(&sig_map); + + if (result == TRANSACTION_VALID_OK) { + return transaction_base->validate(); + } + return result; + + } + bool Transaction::hasSigned(Poco::AutoPtr user) + { + static const char* function_name = "Transaction::hasSigned"; + Poco::ScopedLock _lock(mWorkMutex); + auto sig_pairs = mProtoTransaction.sig_map().sigpair(); + auto pubkey = user->getModel()->getPublicKey(); + auto pubkey_size = user->getModel()->getPublicKeySize(); + if (KeyPairEd25519::getPublicKeySize() != pubkey_size) { + addError(new ParamError(function_name, "user public key has invalid size: ", pubkey_size)); + return false; + } + for (auto it = sig_pairs.begin(); it != sig_pairs.end(); it++) + { + if (it->pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new ParamError(function_name, "signed public key has invalid length: ", it->pubkey().size())); + return false; + } + if (memcmp(pubkey, it->pubkey().data(), pubkey_size) == 0) { + return true; + } + } + return false; + } + + //! return true if user must sign it and hasn't yet + bool Transaction::mustSign(Poco::AutoPtr user) + { + if (hasSigned(user)) return false; + Poco::ScopedLock _lock(mWorkMutex); + auto transaction_base = mTransactionBody->getTransactionBase(); + return transaction_base->isPublicKeyRequired(user->getModel()->getPublicKey()); + } + + //! return true if user can sign transaction and hasn't yet + bool Transaction::canSign(Poco::AutoPtr user) + { + if (hasSigned(user)) return false; + Poco::ScopedLock _lock(mWorkMutex); + auto transaction_base = mTransactionBody->getTransactionBase(); + return !transaction_base->isPublicKeyForbidden(user->getModel()->getPublicKey()); + } + + bool Transaction::needSomeoneToSign(Poco::AutoPtr user) + { + if (!canSign(user)) return false; + Poco::ScopedLock _lock(mWorkMutex); + auto transaction_base = mTransactionBody->getTransactionBase(); + if (transaction_base->isPublicKeyRequired(user->getModel()->getPublicKey())) { + return false; + } + if (transaction_base->getMinSignatureCount() > getSignCount()) { + return true; + } + return false; + + } + + int Transaction::runSendTransaction() + { + Poco::ScopedLock _lock(mWorkMutex); + static const char* function_name = "Transaction::runSendTransaction"; + auto result = validate(); + if (TRANSACTION_VALID_OK != result) { + if ( TRANSACTION_VALID_MISSING_SIGN == result || TRANSACTION_VALID_CODE_ERROR == result + || TRANSACTION_VALID_MISSING_PARAM == result || TRANSCATION_VALID_INVALID_PUBKEY == result + || TRANSACTION_VALID_INVALID_SIGN == result) { + addError(new ParamError(function_name, "code error", TransactionValidationToString(result))); + //sendErrorsAsEmail(); + + } else if (mTransactionBody->isGroupMemberUpdate()) { + addError(new ParamError(function_name, "validation return: ", TransactionValidationToString(result))); + //sendErrorsAsEmail(); + } + else + { + + std::string error_name; + std::string error_description; + auto lm = LanguageManager::getInstance(); + auto user_model = getUser()->getModel(); + auto t = lm->getFreeCatalog(lm->languageFromString(user_model->getLanguageKey())); + switch (result) { + case TRANSACTION_VALID_FORBIDDEN_SIGN: + error_name = t->gettext_str("Signature Error"); + error_description = t->gettext_str("Invalid signature!"); + break; + case TRANSACTION_VALID_INVALID_TARGET_DATE: + error_name = t->gettext_str("Creation Error"); + error_description = t->gettext_str("Invalid target date! No future and only 3 month in the past."); + break; + case TRANSACTION_VALID_CREATION_OUT_OF_BORDER: + error_name = t->gettext_str("Creation Error"); + error_description = t->gettext_str("Maximal 1000 GDD per month allowed!"); + break; + case TRANSACTION_VALID_INVALID_AMOUNT: + error_name = t->gettext_str("Transfer Error"); + error_description = t->gettext_str("Invalid GDD amount! Amount must be greater than 0 and maximal your balance."); + break; + case TRANSACTION_VALID_INVALID_GROUP_ALIAS: + error_name = t->gettext_str("Group Error"); + error_description = t->gettext_str("Invalid Group Alias! I didn't know group, please check alias and try again."); + break; + default: + error_name = t->gettext_str("Unknown Error"); + error_description = t->gettext_str("Admin gets an E-Mail"); + addError(new ParamError(function_name, "unknown error", TransactionValidationToString(result))); + //sendErrorsAsEmail(); + } + + auto pt = PendingTasksManager::getInstance(); + pt->reportErrorToCommunityServer(Poco::AutoPtr(this, true), error_name, error_description); + } + return -1; + } + else + { + // send transaction via hedera + auto network_type = ServerConfig::g_HederaNetworkType; + // TODO: get correct topic id for user group + //int user_group_id = 1; + //auto topic_id = controller::HederaId::find(user_group_id, network_type); + auto topic_id = controller::HederaId::load(getModel()->getHederaId()); + auto hedera_operator_account = controller::HederaAccount::pick(network_type, false); + + if (!topic_id.isNull() && !hedera_operator_account.isNull()) + { + auto crypto_key = hedera_operator_account->getCryptoKey(); + if (!crypto_key.isNull()) + { + model::hedera::ConsensusSubmitMessage consensus_submit_message(topic_id); + std::string raw_message = mProtoTransaction.SerializeAsString(); + + if (ServerConfig::HEDERA_CONSENSUS_FORMAT_BINARY == ServerConfig::g_ConsensusMessageFormat) { + consensus_submit_message.setMessage(raw_message); + + // print to txt for debugging gradido node + static Poco::FastMutex _file_mutex; + Poco::ScopedLock _lock_file(_file_mutex); + std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S") + "\n"; + + std::string json_message = getTransactionAsJson(); + std::string base64_message = DataTypeConverter::binToBase64((const unsigned char*)raw_message.data(), raw_message.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING); + if (json_message != "") + { + FILE* f = fopen("transactions_log.txt", "at"); + if (f) { + fwrite(dateTimeString.data(), sizeof(char), dateTimeString.size(), f); + fwrite(json_message.data(), sizeof(char), json_message.size(), f); + fclose(f); + } + else { + printf("[%s] cannot open transactions_log.txt\n", function_name); + } + } + if (base64_message != "") + { + FILE* f2 = fopen("transaction_log_base64.txt", "at"); + if (f2) { + fwrite(dateTimeString.data(), sizeof(char), dateTimeString.size(), f2); + fwrite(base64_message.data(), sizeof(char), base64_message.size(), f2); + fclose(f2); + } + else { + printf("[%s] cannot open transaction_log_base64.txt\n", function_name); + } + } + } + else if (ServerConfig::HEDERA_CONSENSUS_FORMAT_BASE64_URLSAVE_NO_PADDING == ServerConfig::g_ConsensusMessageFormat) { + consensus_submit_message.setMessage(DataTypeConverter::binToBase64((const unsigned char*)raw_message.data(), raw_message.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING)); + } + else if (ServerConfig::HEDERA_CONSENSUS_FORMAT_JSON == ServerConfig::g_ConsensusMessageFormat) { + std::string json_message = getTransactionAsJson(); + if (json_message != "") { + consensus_submit_message.setMessage(json_message); + } + else { + //sendErrorsAsEmail(); + return -7; + } + + } + // if using testnet, transfer message base64 encoded to check messages in hedera block explorer + //if (network_type == table::HEDERA_TESTNET) { + //consensus_submit_message.setMessage(DataTypeConverter::binToBase64((const unsigned char*)raw_message.data(), raw_message.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING)); + //} + //else { + + //} + auto hedera_transaction_body = hedera_operator_account->createTransactionBody(); + hedera_transaction_body->setConsensusSubmitMessage(consensus_submit_message); + model::hedera::Transaction hedera_transaction; + + hedera_transaction.sign(crypto_key->getKeyPair(), std::move(hedera_transaction_body)); + + HederaRequest hedera_request; + Poco::AutoPtr hedera_task(new HederaTask(this)); + + if (HEDERA_REQUEST_RETURN_OK != hedera_request.request(&hedera_transaction, hedera_task)) + { + addError(new Error(function_name, "error send transaction to hedera")); + getErrors(&hedera_request); + //sendErrorsAsEmail(); + return -2; + } + else { + auto hedera_transaction_response = hedera_task->getTransactionResponse(); + auto hedera_precheck_code_string = hedera_transaction_response->getPrecheckCodeString(); + auto precheck_code = hedera_transaction_response->getPrecheckCode(); + auto cost = hedera_transaction_response->getCost(); + + printf("hedera response: %s, cost: %" PRIu64 ", type: %s\n", + hedera_precheck_code_string.data(), cost, + TransactionBody::transactionTypeToString(mTransactionBody->getType())); + if (precheck_code == proto::INVALID_TRANSACTION_START) { + int zahl = 0; + return -5; + } + else if (precheck_code == proto::OK) { + // simply assume if transaction was sended to hedera without error, it was also accepted from gradido node + // TODO: later check, but now I haven't any way to communicate with the gradido node + mTransactionBody->getTransactionBase()->transactionAccepted(getUser()); + auto transaction_model = getModel(); + transaction_model->setFinished(Poco::DateTime()); + Poco::JSON::Object::Ptr result = new Poco::JSON::Object; + model::hedera::TransactionId transaction_id(hedera_task->getTransactionId()); + result->set("state", "success"); + result->set("transactionId", transaction_id.convertToJSON()); + + transaction_model->setResultJson(result); + Profiler timer; + transaction_model->updateFinishedAndResult(); + printf("time for update 2 fields in db: %s\n", timer.string().data()); + + // trigger community server update in 5 seconds + CronManager::getInstance()->scheduleUpdateRun(Poco::Timespan(5, 0)); + return 1; + } + + } + //model::hedera::TransactionBody hedera_transaction_body() + } + else + { + addError(new ParamError(function_name, "hedera crypto key not found for paying for consensus submit message! NetworkType: ", network_type)); + //sendErrorsAsEmail(); + return -3; + } + } + else + { + addError(new Error(function_name, "hedera topic id or operator account not found!")); + addError(new ParamError(function_name, "topic id: ", topic_id->getModel()->toString())); + addError(new ParamError(function_name, "network type: ", network_type)); + //sendErrorsAsEmail(); + return -4; + } + return 0; + } + + } + + std::string Transaction::getTransactionAsJson(bool replaceBase64WithHex/* = false*/) + { + static const char* function_name = "Transaction::getTransactionAsJson"; + std::string json_message = ""; + std::string json_message_body = ""; + google::protobuf::util::JsonPrintOptions options; + options.add_whitespace = true; + options.always_print_primitive_fields = true; + + auto status = google::protobuf::util::MessageToJsonString(mProtoTransaction, &json_message, options); + if (!status.ok()) { + addError(new ParamError(function_name, "error by parsing transaction message to json", status.ToString())); + addError(new ParamError(function_name, "pending task id: ", getModel()->getID())); + return ""; + } + + status = google::protobuf::util::MessageToJsonString(*mTransactionBody->getBody(), &json_message_body, options); + if (!status.ok()) { + addError(new ParamError(function_name, "error by parsing transaction body message to json", status.ToString())); + addError(new ParamError(function_name, "pending task id: ", getModel()->getID())); + return ""; + } + //\"bodyBytes\": \"MigKIC7Sihz14RbYNhVAa8V3FSIhwvd0pWVvZqDnVA91dtcbIgRnZGQx\" + int startBodyBytes = json_message.find("bodyBytes") + std::string("\"bodyBytes\": \"").size() - 2; + int endCur = json_message.find_first_of('\"', startBodyBytes + 2) + 1; + json_message.replace(startBodyBytes, endCur - startBodyBytes, json_message_body); + //printf("json: %s\n", json_message.data()); + + if (replaceBase64WithHex) { + Poco::JSON::Parser json_parser; + try { + auto json = json_parser.parse(json_message); + Poco::JSON::Object::Ptr object = json.extract(); + if (DataTypeConverter::replaceBase64WithHex(object)) { + std::ostringstream oss; + Poco::JSON::Stringifier::stringify(json, oss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER); + json_message = oss.str(); + } + } + catch (Poco::Exception& ex) { + addError(new ParamError(function_name, "exception by parsing or printing json", ex.message())); + addError(new ParamError(function_name, "pending task id: ", getModel()->getID())); + } + } + + return json_message; + + } + + + /// TASK //////////////////////// + SendTransactionTask::SendTransactionTask(Poco::AutoPtr transaction) + : UniLib::controller::CPUTask(ServerConfig::g_CPUScheduler), mTransaction(transaction) + { + + } + + int SendTransactionTask::run() + { + int result = 1; + // if transfer inbound, create also transfer outbound + /*if (mTransaction->getTransactionBody()->isTransfer()) { + auto transfer = mTransaction->getTransactionBody()->getTransferTransaction(); + if (transfer->isInbound()) { + auto outbound = transfer->createOutbound(mTransaction->getTransactionBody()->getMemo()); + if (outbound.isNull()) { result = -1;} + + result = outbound->runSendTransaction(); + } + } + if (result != 1) { + mTransaction->deleteFromDB(); + return 0; + }*/ + result = mTransaction->runSendTransaction(); + //printf("[SendTransactionTask::run] result: %d\n", result); + // delete because of error + if (-1 == result) { + //mTransaction->deleteFromDB(); + Poco::JSON::Object::Ptr errors = new Poco::JSON::Object; + errors->set("errors", mTransaction->getErrorsArray()); + errors->set("state", "error"); + auto model = mTransaction->getModel(); + model->setResultJson(errors); + model->updateFinishedAndResult(); + } + // delete because succeed, maybe change later + if (1 == result) { + //mTransaction->deleteFromDB(); + } + return 0; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/Transaction.h b/login_server/src/cpp/model/gradido/Transaction.h new file mode 100644 index 000000000..109f34e48 --- /dev/null +++ b/login_server/src/cpp/model/gradido/Transaction.h @@ -0,0 +1,90 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_H +#define GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_H + +/* + * @author: Dario Rekowski + * + * @date: 12.10.2020 + * + * @brief: mainly for signing gradido transaction +*/ + +#include "../../proto/gradido/GradidoTransaction.pb.h" +#include "TransactionBody.h" +#include "../../tasks/GradidoTask.h" +#include "../../controller/User.h" + +#include "../tasks/CPUTask.h" + +namespace model { + namespace gradido { + class Transaction : public GradidoTask + { + public: + Transaction(Poco::AutoPtr body); + Transaction(const std::string& protoMessageBin, model::table::PendingTask* dbModel); + ~Transaction(); + + // create group add member transaction + // groupMemberUpdate + static Poco::AutoPtr createGroupMemberUpdate(Poco::AutoPtr user, Poco::AutoPtr group); + //! \brief transfer + //! \return for cross group transaction return two transactions + static std::vector> createTransfer(Poco::AutoPtr sender, const MemoryBin* receiverPubkey, Poco::AutoPtr receiverGroup, Poco::UInt32 amount, const std::string& memo, bool inbound = true); + Poco::AutoPtr createTransfer(const MemoryBin* senderPubkey, Poco::AutoPtr receiver, std::string senderGroupAlias, Poco::UInt32 amount, const std::string& memo); + //! \brief creation transaction + static Poco::AutoPtr createCreation(Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::DateTime targetDate, const std::string& memo); + static Poco::AutoPtr load(model::table::PendingTask* dbModel); + + bool sign(Poco::AutoPtr user); + int getSignCount() { return mProtoTransaction.sig_map().sigpair_size(); } + TransactionValidation validate(); + + //! \brief validate and if valid send transaction via Hedera Consensus Service to node server + int runSendTransaction(); + + inline Poco::AutoPtr getTransactionBody() { Poco::ScopedLock _lock(mWorkMutex); return mTransactionBody; } + + //! \brief get current body bytes from proto transaction and save it into db + bool updateRequestInDB(); + bool insertPendingTaskIntoDB(Poco::AutoPtr user, model::table::TaskType type); + + //! \return true if user must sign it and hasn't yet + bool mustSign(Poco::AutoPtr user); + //! return true if user can sign transaction and hasn't yet + bool canSign(Poco::AutoPtr user); + + //! \return true if user has already signed transaction + bool hasSigned(Poco::AutoPtr user); + //! \return true if at least one sign is missing and user isn't forbidden and isn't required + bool needSomeoneToSign(Poco::AutoPtr user); + + std::string getTransactionAsJson(bool replaceBase64WithHex = false); + inline Poco::AutoPtr getPairedTransaction() { return mPairedTransaction; } + + bool setTopicIdByGroup(const std::string& alias); + + + protected: + Poco::AutoPtr mPairedTransaction; + + Poco::AutoPtr mTransactionBody; + proto::gradido::GradidoTransaction mProtoTransaction; + HASH mBodyBytesHash; + }; + + class SendTransactionTask : public UniLib::controller::CPUTask + { + public: + SendTransactionTask(Poco::AutoPtr transaction); + + const char* getResourceType() const { return "SendTransactionTask"; }; + int run(); + protected: + Poco::AutoPtr mTransaction; + }; + + } +} + +#endif //GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_H diff --git a/login_server/src/cpp/model/gradido/TransactionBase.cpp b/login_server/src/cpp/model/gradido/TransactionBase.cpp new file mode 100644 index 000000000..823a4c5ea --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionBase.cpp @@ -0,0 +1,161 @@ +#include "TransactionBase.h" +#include "../../Crypto/KeyPairEd25519.h" +#include + +namespace model { + namespace gradido { + + + const char* TransactionValidationToString(TransactionValidation result) + { + switch (result) { + case TRANSACTION_VALID_OK: return "ok"; + case TRANSACTION_VALID_MISSING_SIGN: return "missing sign"; + case TRANSACTION_VALID_FORBIDDEN_SIGN: return "forbidden sign"; + case TRANSACTION_VALID_MISSING_PARAM: return "missing param"; + case TRANSACTION_VALID_CODE_ERROR: return "code error"; + case TRANSACTION_VALID_INVALID_TARGET_DATE: return "invalid target date"; + case TRANSACTION_VALID_CREATION_OUT_OF_BORDER: return "creation out of border"; + case TRANSACTION_VALID_INVALID_AMOUNT: return "invalid amount"; + case TRANSCATION_VALID_INVALID_PUBKEY: return "invalid pubkey"; + case TRANSACTION_VALID_INVALID_GROUP_ALIAS: return "invalid group alias"; + case TRANSACTION_VALID_INVALID_SIGN: return "invalid sign"; + } + return ""; + } + + + + TransactionBase::TransactionBase(const std::string& memo) + : mMemo(memo), mMinSignatureCount(0), mIsPrepared(false) + { + + } + + TransactionBase::~TransactionBase() + { + auto mm = MemoryManager::getInstance(); + for (auto it = mRequiredSignPublicKeys.begin(); it != mRequiredSignPublicKeys.end(); it++) + { + mm->releaseMemory(*it); + } + mRequiredSignPublicKeys.clear(); + for (auto it = mForbiddenSignPublicKeys.begin(); it != mForbiddenSignPublicKeys.end(); it++) + { + mm->releaseMemory(*it); + } + mForbiddenSignPublicKeys.clear(); + } + + + std::string TransactionBase::amountToString(google::protobuf::int64 amount) + { + std::stringstream ss; + double dAmount = amount / 10000.0; + ss << std::fixed << std::setprecision(2) << dAmount; + std::string amountString = ss.str(); + if (amountString.find('.') != amountString.npos) { + int pointPlace = amountString.find('.'); + if (amountString.substr(pointPlace + 1) == "00") { + amountString = amountString.substr(0, pointPlace); + } + } + return amountString; + //return ss.str(); + } + + TransactionValidation TransactionBase::checkRequiredSignatures(const proto::gradido::SignatureMap* sig_map) + { + if (!mMinSignatureCount) { + addError(new Error("TransactionBase::checkRequiredSignatures", "mMinSignatureCount is zero")); + return TRANSACTION_VALID_CODE_ERROR; + } + // not enough + if (mMinSignatureCount > sig_map->sigpair_size()) { + return TRANSACTION_VALID_MISSING_SIGN; + } + // enough + if (!mRequiredSignPublicKeys.size() && !mForbiddenSignPublicKeys.size()) { + return TRANSACTION_VALID_OK; + } + // check if specific signatures can be found + static const char function_name[] = "TransactionBase::checkRequiredSignatures"; + // prepare + std::vector required_keys = mRequiredSignPublicKeys; + + bool forbidden_key_found = false; + for (auto it = sig_map->sigpair().begin(); it != sig_map->sigpair().end(); it++) + { + auto pubkey_size = it->pubkey().size(); + if (pubkey_size != KeyPairEd25519::getPublicKeySize()) + { + addError(new ParamError(function_name, "signature pubkey size is not as expected: ", pubkey_size)); + return TRANSACTION_VALID_CODE_ERROR; + } + // check for forbidden key + if (!forbidden_key_found && mForbiddenSignPublicKeys.size()) + { + for (auto it2 = mForbiddenSignPublicKeys.begin(); it2 != mForbiddenSignPublicKeys.end(); it2++) { + if ((*it2)->size() != KeyPairEd25519::getPublicKeySize()) + { + addError(new ParamError(function_name, "forbidden sign public key size is not as expected: ", (*it2)->size())); + return TRANSACTION_VALID_CODE_ERROR; + } + if (0 == memcmp((*it2)->data(), it->pubkey().data(), pubkey_size)) + { + forbidden_key_found = true; + break; + } + } + } + if (forbidden_key_found) break; + + // compare with required keys + for (auto it3 = required_keys.begin(); it3 != required_keys.end(); it3++) + { + if ((*it3)->size() != KeyPairEd25519::getPublicKeySize()) + { + addError(new ParamError(function_name, "required sign public key size is not as expected: ", (*it3)->size())); + return TRANSACTION_VALID_CODE_ERROR; + } + if (0 == memcmp((*it3)->data(), it->pubkey().data(), pubkey_size)) + { + it3 = required_keys.erase(it3); + break; + } + } + } + + if (forbidden_key_found) return TRANSACTION_VALID_FORBIDDEN_SIGN; + if (!required_keys.size()) return TRANSACTION_VALID_OK; + + // TODO: check that given pubkeys are registered for same group + + return TRANSACTION_VALID_MISSING_SIGN; + + } + + bool TransactionBase::isPublicKeyRequired(const unsigned char* pubkey) + { + Poco::ScopedLock _lock(mWorkMutex); + for (auto it = mRequiredSignPublicKeys.begin(); it != mRequiredSignPublicKeys.end(); it++) { + if (memcmp((*it)->data(), pubkey, KeyPairEd25519::getPublicKeySize()) == 0) { + return true; + } + } + return false; + } + + bool TransactionBase::isPublicKeyForbidden(const unsigned char* pubkey) + { + Poco::ScopedLock _lock(mWorkMutex); + for (auto it = mForbiddenSignPublicKeys.begin(); it != mForbiddenSignPublicKeys.end(); it++) { + if (memcmp((*it)->data(), pubkey, KeyPairEd25519::getPublicKeySize()) == 0) { + return true; + } + } + return false; + } + } +} + diff --git a/login_server/src/cpp/model/gradido/TransactionBase.h b/login_server/src/cpp/model/gradido/TransactionBase.h new file mode 100644 index 000000000..bea79c971 --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionBase.h @@ -0,0 +1,75 @@ +/*! +* +* \author: einhornimmond +* +* \date: 25.10.19 +* +* \brief: Interface for Transaction Objects +*/ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE + +#pragma warning(disable:4800) + +#include "../lib/NotificationList.h" +#include "../proto/gradido/BasicTypes.pb.h" +#include "../SingletonManager/MemoryManager.h" + +#include "../controller/User.h" + +namespace model { + namespace gradido { + + enum TransactionValidation { + TRANSACTION_VALID_OK, + TRANSACTION_VALID_MISSING_SIGN, + TRANSACTION_VALID_FORBIDDEN_SIGN, + TRANSACTION_VALID_MISSING_PARAM, + TRANSACTION_VALID_CODE_ERROR, + TRANSACTION_VALID_INVALID_TARGET_DATE, + TRANSACTION_VALID_CREATION_OUT_OF_BORDER, + TRANSACTION_VALID_INVALID_AMOUNT, + TRANSCATION_VALID_INVALID_PUBKEY, + TRANSACTION_VALID_INVALID_GROUP_ALIAS, + TRANSACTION_VALID_INVALID_SIGN + }; + const char* TransactionValidationToString(TransactionValidation result); + + class TransactionBase : public NotificationList, public UniLib::lib::MultithreadContainer + { + public: + TransactionBase(const std::string& memo); + virtual ~TransactionBase(); + //! \return 0 if ok, < 0 if error, > 0 if not implemented + virtual int prepare() = 0; + virtual TransactionValidation validate() = 0; + + static std::string amountToString(google::protobuf::int64 amount); + inline const std::string& getMemo() const { return mMemo; } + + //! \return TRANSACTION_VALID_OK if all required signatures are found in signature pairs + TransactionValidation checkRequiredSignatures(const proto::gradido::SignatureMap* sig_map); + //! \param pubkey pointer must point to valid unsigned char[KeyPairEd25519::getPublicKeySize()] array + bool isPublicKeyRequired(const unsigned char* pubkey); + //! \param pubkey pointer must point to valid unsigned char[KeyPairEd25519::getPublicKeySize()] array + bool isPublicKeyForbidden(const unsigned char* pubkey); + + inline Poco::UInt32 getMinSignatureCount() { return mMinSignatureCount; } + void setMinSignatureCount(Poco::UInt32 minSignatureCount) { mMinSignatureCount = minSignatureCount; } + + // called after sending transaction over hedera and after they was accepted from gradido node (at least one) + virtual void transactionAccepted(Poco::AutoPtr user) = 0; + + protected: + std::string mMemo; + Poco::UInt32 mMinSignatureCount; + bool mIsPrepared; + std::vector mRequiredSignPublicKeys; + std::vector mForbiddenSignPublicKeys; + }; + } +} + + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/TransactionBody.cpp b/login_server/src/cpp/model/gradido/TransactionBody.cpp new file mode 100644 index 000000000..2e69085e0 --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionBody.cpp @@ -0,0 +1,298 @@ +#include "TransactionBody.h" + + +namespace model { + namespace gradido { + + TransactionBody::TransactionBody() + : mTransactionSpecific(nullptr), mType(TRANSACTION_NONE) + { + } + + TransactionBody::~TransactionBody() + { + lock("TransactionBody::~TransactionBody"); + if (mTransactionSpecific) { + delete mTransactionSpecific; + mTransactionSpecific = nullptr; + } + unlock(); + } + + Poco::AutoPtr TransactionBody::create(const std::string& memo, Poco::AutoPtr user, proto::gradido::GroupMemberUpdate_MemberUpdateType type, const std::string& targetGroupAlias) + { + Poco::AutoPtr obj = new TransactionBody; + obj->mTransactionBody.set_memo(memo); + auto group_member_update = obj->mTransactionBody.mutable_group_member_update(); + + group_member_update->set_user_pubkey(user->getModel()->getPublicKey(), KeyPairEd25519::getPublicKeySize()); + group_member_update->set_member_update_type(type); + group_member_update->set_target_group(targetGroupAlias); + + obj->mType = TRANSACTION_GROUP_MEMBER_UPDATE; + obj->mTransactionSpecific = new GroupMemberUpdate(memo, obj->mTransactionBody.group_member_update()); + obj->mTransactionSpecific->prepare(); + + return obj; + } + + Poco::AutoPtr TransactionBody::create(const std::string& memo, Poco::AutoPtr sender, const MemoryBin* receiverPublicKey, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId, Poco::AutoPtr group/* = nullptr*/) + { + if (sender.isNull() || !sender->getModel()) { + return nullptr; + } + auto sender_model = sender->getModel(); + + + Poco::AutoPtr obj = new TransactionBody; + obj->mTransactionBody.set_memo(memo); + auto gradido_transfer = obj->mTransactionBody.mutable_transfer(); + proto::gradido::TransferAmount* transfer_amount = nullptr; + std::string* receiver = nullptr; + + + if (group.isNull()) + { + auto local = gradido_transfer->mutable_local(); + transfer_amount = local->mutable_sender(); + receiver = local->mutable_receiver(); + } + else + { + auto group_model = group->getModel(); + proto::gradido::CrossGroupTransfer* cross_group_transfer = nullptr; + if (group->getModel()->getID() != sender->getModel()->getGroupId()) { + cross_group_transfer = gradido_transfer->mutable_outbound(); + } + else { + cross_group_transfer = gradido_transfer->mutable_inbound(); + } + transfer_amount = cross_group_transfer->mutable_sender(); + receiver = cross_group_transfer->mutable_receiver(); + auto paired_transaction_id = cross_group_transfer->mutable_paired_transaction_id(); + DataTypeConverter::convertToProtoTimestamp(pairedTransactionId, paired_transaction_id); + cross_group_transfer->set_other_group(group_model->getAlias()); + } + transfer_amount->set_amount(amount); + transfer_amount->set_pubkey(sender_model->getPublicKey(), sender_model->getPublicKeySize()); + *receiver = std::string((const char*)receiverPublicKey->data(), receiverPublicKey->size()); + + obj->mType = TRANSACTION_TRANSFER; + obj->mTransactionSpecific = new TransactionTransfer(memo, obj->mTransactionBody.transfer()); + obj->mTransactionSpecific->prepare(); + + return obj; + } + + Poco::AutoPtr TransactionBody::create(const std::string& memo, const MemoryBin* senderPublicKey, Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId /*= Poco::Timestamp()*/, Poco::AutoPtr group/* = nullptr*/) + { + if (receiver.isNull() || !receiver->getModel()) { + return nullptr; + } + auto receiver_model = receiver->getModel(); + + + Poco::AutoPtr obj = new TransactionBody; + obj->mTransactionBody.set_memo(memo); + auto gradido_transfer = obj->mTransactionBody.mutable_transfer(); + proto::gradido::TransferAmount* transfer_amount = nullptr; + std::string* sender = nullptr; + + auto group_model = group->getModel(); + proto::gradido::CrossGroupTransfer* cross_group_transfer = nullptr; + + cross_group_transfer = gradido_transfer->mutable_inbound(); + + transfer_amount = cross_group_transfer->mutable_sender(); + sender = transfer_amount->mutable_pubkey(); + auto paired_transaction_id = cross_group_transfer->mutable_paired_transaction_id(); + DataTypeConverter::convertToProtoTimestamp(pairedTransactionId, paired_transaction_id); + cross_group_transfer->set_other_group(group_model->getAlias()); + + transfer_amount->set_amount(amount); + transfer_amount->set_pubkey(senderPublicKey, KeyPairEd25519::getPublicKeySize()); + cross_group_transfer->set_receiver(receiver_model->getPublicKey(), receiver_model->getPublicKeySize()); + *sender = std::string((const char*)senderPublicKey->data(), senderPublicKey->size()); + + obj->mType = TRANSACTION_TRANSFER; + obj->mTransactionSpecific = new TransactionTransfer(memo, obj->mTransactionBody.transfer()); + obj->mTransactionSpecific->prepare(); + + return obj; + } + + Poco::AutoPtr TransactionBody::create(const std::string& memo, const MemoryBin* senderPublicKey, const MemoryBin* receiverPublicKey, Poco::UInt32 amount, const std::string groupAlias, TransactionTransferType transferType, Poco::Timestamp pairedTransactionId/* = Poco::Timestamp()*/) + { + assert(transferType == TRANSFER_CROSS_GROUP_INBOUND || transferType == TRANSFER_CROSS_GROUP_OUTBOUND || transferType == TRANSFER_LOCAL); + if (!senderPublicKey || !receiverPublicKey) { + return nullptr; + } + + Poco::AutoPtr obj = new TransactionBody; + obj->mTransactionBody.set_memo(memo); + auto gradido_transfer = obj->mTransactionBody.mutable_transfer(); + proto::gradido::TransferAmount* transfer_amount = nullptr; + proto::gradido::CrossGroupTransfer* cross_group_transfer = nullptr; + proto::gradido::LocalTransfer* local_transfer = nullptr; + + switch (transferType) + { + case TRANSFER_CROSS_GROUP_INBOUND: + cross_group_transfer = gradido_transfer->mutable_inbound(); + break; + case TRANSFER_CROSS_GROUP_OUTBOUND: + cross_group_transfer = gradido_transfer->mutable_outbound(); + break; + case TRANSFER_LOCAL: + local_transfer = gradido_transfer->mutable_local(); + break; + } + + + if (local_transfer) { + transfer_amount = local_transfer->mutable_sender(); + local_transfer->set_receiver((const char*)receiverPublicKey->data(), receiverPublicKey->size()); + } + else if (cross_group_transfer) { + transfer_amount = cross_group_transfer->mutable_sender(); + auto paired_transaction_id = cross_group_transfer->mutable_paired_transaction_id(); + DataTypeConverter::convertToProtoTimestamp(pairedTransactionId, paired_transaction_id); + cross_group_transfer->set_other_group(groupAlias); + + cross_group_transfer->set_receiver((const char*)receiverPublicKey->data(), receiverPublicKey->size()); + } + + + transfer_amount->set_amount(amount); + transfer_amount->set_pubkey((const unsigned char*)senderPublicKey->data(), senderPublicKey->size()); + + obj->mType = TRANSACTION_TRANSFER; + obj->mTransactionSpecific = new TransactionTransfer(memo, obj->mTransactionBody.transfer()); + obj->mTransactionSpecific->prepare(); + + return obj; + } + + Poco::AutoPtr TransactionBody::create(const std::string& memo, Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::DateTime targetDate) + { + if (receiver.isNull() || !receiver->getModel()) { + return nullptr; + } + auto receiver_model = receiver->getModel(); + + Poco::AutoPtr obj = new TransactionBody; + obj->mTransactionBody.set_memo(memo); + + auto creation = obj->mTransactionBody.mutable_creation(); + auto target_date_timestamp_seconds = creation->mutable_target_date(); + target_date_timestamp_seconds->set_seconds(targetDate.timestamp().epochTime()); + + auto transfer_amount = creation->mutable_receiver(); + transfer_amount->set_amount(amount); + std::string* pubkey_str = transfer_amount->mutable_pubkey(); + *pubkey_str = std::string((const char*)receiver_model->getPublicKey(), receiver_model->getPublicKeySize()); + + obj->mType = TRANSACTION_CREATION; + obj->mTransactionSpecific = new TransactionCreation(memo, obj->mTransactionBody.creation()); + obj->mTransactionSpecific->prepare(); + + return obj; + + } + + Poco::AutoPtr TransactionBody::load(const std::string& protoMessageBin) + { + Poco::AutoPtr obj = new TransactionBody; + + if (!obj->mTransactionBody.ParseFromString(protoMessageBin)) { + return nullptr; + } + + // check Type + if (obj->mTransactionBody.has_creation()) { + obj->mType = TRANSACTION_CREATION; + obj->mTransactionSpecific = new model::gradido::TransactionCreation(obj->mTransactionBody.memo(), obj->mTransactionBody.creation()); + } + else if (obj->mTransactionBody.has_transfer()) { + obj->mType = TRANSACTION_TRANSFER; + obj->mTransactionSpecific = new model::gradido::TransactionTransfer(obj->mTransactionBody.memo(), obj->mTransactionBody.transfer()); + } + else if (obj->mTransactionBody.has_group_member_update()) { + obj->mType = TRANSACTION_GROUP_MEMBER_UPDATE; + obj->mTransactionSpecific = new model::gradido::GroupMemberUpdate(obj->mTransactionBody.memo(), obj->mTransactionBody.group_member_update()); + } + obj->mTransactionSpecific->prepare(); + return obj; + } + + + std::string TransactionBody::getMemo() + { + Poco::ScopedLock _lock(mWorkMutex); + if (mTransactionBody.IsInitialized()) { + std::string result(mTransactionBody.memo()); + + return result; + } + return ""; + } + + void TransactionBody::setMemo(const std::string& memo) + { + Poco::ScopedLock _lock(mWorkMutex); + mTransactionBody.set_memo(memo); + } + + std::string TransactionBody::getBodyBytes() + { + Poco::ScopedLock _lock(mWorkMutex); + if (mTransactionBody.IsInitialized()) { + auto size = mTransactionBody.ByteSize(); + //auto bodyBytesSize = MemoryManager::getInstance()->getFreeMemory(mProtoCreation.ByteSizeLong()); + std::string resultString(size, 0); + if (!mTransactionBody.SerializeToString(&resultString)) { + //addError(new Error("TransactionCreation::getBodyBytes", "error serializing string")); + throw new Poco::Exception("error serializing string"); + } + + return resultString; + } + + return ""; + } + + const char* TransactionBody::transactionTypeToString(TransactionType type) + { + switch (type) + { + case model::gradido::TRANSACTION_NONE: return "NONE"; + case model::gradido::TRANSACTION_CREATION: return "Creation"; + case model::gradido::TRANSACTION_TRANSFER: return "Transfer"; + case model::gradido::TRANSACTION_GROUP_MEMBER_UPDATE: return "Group Member Update"; + } + return ""; + } + + + + TransactionCreation* TransactionBody::getCreationTransaction() + { + return dynamic_cast(mTransactionSpecific); + } + + TransactionTransfer* TransactionBody::getTransferTransaction() + { + return dynamic_cast(mTransactionSpecific); + } + + GroupMemberUpdate* TransactionBody::getGroupMemberUpdate() + { + return dynamic_cast(mTransactionSpecific); + } + + TransactionBase* TransactionBody::getTransactionBase() + { + return mTransactionSpecific; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/TransactionBody.h b/login_server/src/cpp/model/gradido/TransactionBody.h new file mode 100644 index 000000000..f88344eb2 --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionBody.h @@ -0,0 +1,71 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_BASE_H +#define GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_BASE_H + +#include "../../controller/User.h" +#include "../../controller/Group.h" +#include "GroupMemberUpdate.h" +#include "TransactionCreation.h" +#include "TransactionTransfer.h" + +#include "../../proto/gradido/TransactionBody.pb.h" + +#include "../../lib/MultithreadContainer.h" + +namespace model { + namespace gradido { + + enum TransactionType { + TRANSACTION_NONE, + TRANSACTION_CREATION, + TRANSACTION_TRANSFER, + TRANSACTION_GROUP_MEMBER_UPDATE + }; + + + + class TransactionBody : public Poco::RefCountedObject, UniLib::lib::MultithreadContainer + { + public: + ~TransactionBody(); + + //! \brief GroupMemberUpdate Transaction + static Poco::AutoPtr create(const std::string& memo, Poco::AutoPtr user, proto::gradido::GroupMemberUpdate_MemberUpdateType type, const std::string& targetGroupAlias); + //! \brief GradidoTransfer Transaction + //! \param group if group.isNull() it is a local transfer, else cross group transfer, + //! \param group if group is same as sender group outbound, else inbound + static Poco::AutoPtr create(const std::string& memo, Poco::AutoPtr sender, const MemoryBin* receiverPublicKey, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId = Poco::Timestamp(), Poco::AutoPtr group = nullptr); + static Poco::AutoPtr create(const std::string& memo, const MemoryBin* senderPublicKey, Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId = Poco::Timestamp(), Poco::AutoPtr group = nullptr); + static Poco::AutoPtr create(const std::string& memo, const MemoryBin* senderPublicKey, const MemoryBin* receiverPublicKey, Poco::UInt32 amount, const std::string groupAlias, TransactionTransferType transferType, Poco::Timestamp pairedTransactionId = Poco::Timestamp()); + //! \brief GradidoCreation Transaction + static Poco::AutoPtr create(const std::string& memo, Poco::AutoPtr receiver, Poco::UInt32 amount, Poco::DateTime targetDate); + + + static Poco::AutoPtr load(const std::string& protoMessageBin); + + inline TransactionType getType() { Poco::ScopedLock _lock(mWorkMutex); return mType; } + static const char* transactionTypeToString(TransactionType type); + std::string getMemo(); + void setMemo(const std::string& memo); + + bool isCreation() { Poco::ScopedLock _lock(mWorkMutex); return mType == TRANSACTION_CREATION; } + bool isTransfer() { Poco::ScopedLock _lock(mWorkMutex); return mType == TRANSACTION_TRANSFER; } + bool isGroupMemberUpdate() { Poco::ScopedLock _lock(mWorkMutex); return mType == TRANSACTION_GROUP_MEMBER_UPDATE; } + + std::string getBodyBytes(); + const proto::gradido::TransactionBody* getBody() { return &mTransactionBody; } + + TransactionCreation* getCreationTransaction(); + TransactionTransfer* getTransferTransaction(); + GroupMemberUpdate* getGroupMemberUpdate(); + TransactionBase* getTransactionBase(); + + protected: + TransactionBody(); + proto::gradido::TransactionBody mTransactionBody; + TransactionBase* mTransactionSpecific; + TransactionType mType; + }; + } +} + +#endif //GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_BASE_H \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/TransactionCreation.cpp b/login_server/src/cpp/model/gradido/TransactionCreation.cpp new file mode 100644 index 000000000..e53a5544b --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionCreation.cpp @@ -0,0 +1,127 @@ +#include "TransactionCreation.h" +#include "Poco/DateTimeFormatter.h" +#include + +namespace model { + namespace gradido { + + TransactionCreation::TransactionCreation(const std::string& memo, const proto::gradido::GradidoCreation& protoCreation) + : TransactionBase(memo), mProtoCreation(protoCreation) + { + memset(mReceiverPublicHex, 0, 65); + } + + TransactionCreation::~TransactionCreation() + { + + } + + int TransactionCreation::prepare() + { + const static char functionName[] = { "TransactionCreation::prepare" }; + if (!mProtoCreation.has_receiver()) { + addError(new Error(functionName, "hasn't receiver amount")); + return -1; + } + auto receiver_amount = mProtoCreation.receiver(); + + auto receiverPublic = receiver_amount.pubkey(); + if (receiverPublic.size() != KeyPairEd25519::getPublicKeySize()) { + addError(new ParamError(functionName, "receiver public invalid: ", receiverPublic.size())); + return -2; + } + mReceiverUser = controller::User::create(); + //mReceiverUser = new User((const unsigned char*)receiverPublic.data()); + mReceiverUser->load((const unsigned char*)receiverPublic.data()); + getErrors(mReceiverUser->getModel()); + if (mReceiverUser->getUserState() == USER_EMPTY) { + sodium_bin2hex(mReceiverPublicHex, 65, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); + mReceiverUser.assign(nullptr); + } + else { + memcpy(mReceiverPublicHex, mReceiverUser->getModel()->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; + }*/ + } + // + mMinSignatureCount = 1; + auto mm = MemoryManager::getInstance(); + auto pubkey_copy = mm->getFreeMemory(KeyPairEd25519::getPublicKeySize()); + memcpy(*pubkey_copy, receiverPublic.data(), KeyPairEd25519::getPublicKeySize()); + mForbiddenSignPublicKeys.push_back(pubkey_copy); + + mIsPrepared = true; + 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"); + } + + TransactionValidation TransactionCreation::validate() + { + static const char function_name[] = "TransactionCreation::validate"; + auto target_date = Poco::DateTime(DataTypeConverter::convertFromProtoTimestampSeconds(mProtoCreation.target_date())); + auto now = Poco::DateTime(); + if (target_date.year() == now.year()) + { + if (target_date.month() + 3 < now.month()) { + addError(new Error(function_name, "year is the same, target date month is more than 3 month in past")); + return TRANSACTION_VALID_INVALID_TARGET_DATE; + } + if (target_date.month() > now.month()) { + addError(new Error(function_name, "year is the same, target date month is in future")); + return TRANSACTION_VALID_INVALID_TARGET_DATE; + } + } + else if(target_date.year() > now.year()) + { + addError(new Error(function_name, "target date year is in future")); + return TRANSACTION_VALID_INVALID_TARGET_DATE; + } + else if(target_date.year() +1 < now.year()) + { + addError(new Error(function_name, "target date year is in past")); + return TRANSACTION_VALID_INVALID_TARGET_DATE; + } + else + { + // target_date.year +1 == now.year + if (target_date.month() + 3 < now.month() + 12) { + addError(new Error(function_name, "target date is more than 3 month in past")); + return TRANSACTION_VALID_INVALID_TARGET_DATE; + } + } + if (mProtoCreation.receiver().amount() > 1000 * 10000) { + addError(new Error(function_name, "creation amount to high, max 1000 per month")); + return TRANSACTION_VALID_CREATION_OUT_OF_BORDER; + } + + if (mProtoCreation.receiver().pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "receiver pubkey has invalid size")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + + // TODO: check creation amount from last 3 month from node server + + + return TRANSACTION_VALID_OK; + } + + void TransactionCreation::transactionAccepted(Poco::AutoPtr user) + { + + } + + } +} + diff --git a/login_server/src/cpp/model/gradido/TransactionCreation.h b/login_server/src/cpp/model/gradido/TransactionCreation.h new file mode 100644 index 000000000..7304f49cd --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionCreation.h @@ -0,0 +1,50 @@ +/*! +* +* \author: einhornimmond +* +* \date: 25.10.19 +* +* \brief: Creation Transaction +*/ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE + +#pragma warning(disable:4800) + +#include "TransactionBase.h" +#include "../proto/gradido/GradidoCreation.pb.h" +#include "../controller/User.h" + +namespace model { + namespace gradido { + + class TransactionCreation : public TransactionBase + { + public: + TransactionCreation(const std::string& memo, const proto::gradido::GradidoCreation& protoCreation); + ~TransactionCreation(); + + int prepare(); + //! TODO: check created sum in the last 3 month if 1.000 per month isn't exceed + //! maybe ask node server and hope the answer came fast + TransactionValidation validate(); + + inline Poco::AutoPtr getUser() { return mReceiverUser; } + inline google::protobuf::int64 getAmount() { return mProtoCreation.receiver().amount(); } + inline char* getPublicHex() { return mReceiverPublicHex; } + + inline std::string getAmountString() { return amountToString(getAmount()); } + std::string getTargetDateString(); + + void transactionAccepted(Poco::AutoPtr user); + + protected: + const proto::gradido::GradidoCreation& mProtoCreation; + char mReceiverPublicHex[65]; + Poco::AutoPtr mReceiverUser; + }; + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_CREATION_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/TransactionTransfer.cpp b/login_server/src/cpp/model/gradido/TransactionTransfer.cpp new file mode 100644 index 000000000..6e458a87a --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionTransfer.cpp @@ -0,0 +1,297 @@ +#include "TransactionTransfer.h" +#include "Transaction.h" +#include "../../SingletonManager/ErrorManager.h" +#include "../../controller/HederaId.h" + +namespace model { + namespace gradido { + + 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 = ""; + kontoNameCell += user->getNameWithEmailHtml(); + kontoNameCell += ""; + } + + TransactionTransfer::KontoTableEntry::KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount/* = false*/) + { + composeAmountCellString(amount, negativeAmount); + //kontoNameCell = ""; + 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 proto::gradido::GradidoTransfer& protoTransfer) + : TransactionBase(memo), mProtoTransfer(protoTransfer) + { + + } + + TransactionTransfer::~TransactionTransfer() + { + mKontoTable.clear(); + } + + int TransactionTransfer::prepare() + { + Poco::ScopedLock _lock(mWorkMutex); + const static char functionName[] = { "TransactionTransfer::prepare" }; + + mKontoTable.reserve(2); + + proto::gradido::TransferAmount* sender = nullptr; + std::string* receiver_pubkey = nullptr; + if (mProtoTransfer.has_local()) { + auto local_transfer = mProtoTransfer.local(); + sender = local_transfer.mutable_sender(); + receiver_pubkey = local_transfer.mutable_receiver(); + return prepare(sender, receiver_pubkey); + } + else if (mProtoTransfer.has_inbound()) { + auto inbound_transfer = mProtoTransfer.inbound(); + sender = inbound_transfer.mutable_sender(); + receiver_pubkey = inbound_transfer.mutable_receiver(); + return prepare(sender, receiver_pubkey); + } + else if (mProtoTransfer.has_outbound()) { + auto outbound_transfer = mProtoTransfer.outbound(); + sender = outbound_transfer.mutable_sender(); + receiver_pubkey = outbound_transfer.mutable_receiver(); + return prepare(sender, receiver_pubkey); + } + return -1; + } + + int TransactionTransfer::prepare(proto::gradido::TransferAmount* sender, std::string* receiver_pubkey) + { + assert(sender && receiver_pubkey); + + char pubkeyHexTemp[65]; + auto sender_pubkey = sender->pubkey(); + auto amount = sender->amount(); + auto sender_user = controller::User::create(); + auto receiver_user = controller::User::create(); + + if (!sender_user->load((const unsigned char*)sender_pubkey.data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)sender_pubkey.data(), sender_pubkey.size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, amount, true)); + } + else { + mKontoTable.push_back(KontoTableEntry(sender_user->getModel(), amount, true)); + } + + if (!receiver_user->load((const unsigned char*)receiver_pubkey->data())) { + sodium_bin2hex(pubkeyHexTemp, 65, (const unsigned char*)receiver_pubkey->data(), receiver_pubkey->size()); + mKontoTable.push_back(KontoTableEntry(pubkeyHexTemp, amount, false)); + } + else { + mKontoTable.push_back(KontoTableEntry(receiver_user->getModel(), amount, false)); + } + mMinSignatureCount = 1; + auto mm = MemoryManager::getInstance(); + auto pubkey_copy = mm->getFreeMemory(KeyPairEd25519::getPublicKeySize()); + memcpy(*pubkey_copy, sender_pubkey.data(), KeyPairEd25519::getPublicKeySize()); + mRequiredSignPublicKeys.push_back(pubkey_copy); + + mIsPrepared = true; + return 0; + } + + TransactionValidation TransactionTransfer::validate() + { + Poco::ScopedLock _lock(mWorkMutex); + static const char function_name[] = "TransactionTransfer::validate"; + /*if (!mProtoTransfer.has_local()) { + addError(new Error(function_name, "only local currently implemented")); + return TRANSACTION_VALID_CODE_ERROR; + }*/ + proto::gradido::TransferAmount* sender = nullptr; + std::string* receiver_pubkey = nullptr; + if (mProtoTransfer.has_local()) { + auto local_transfer = mProtoTransfer.local(); + sender = local_transfer.mutable_sender(); + receiver_pubkey = local_transfer.mutable_receiver(); + return validate(sender, receiver_pubkey); + } + else if (mProtoTransfer.has_inbound()) { + auto inbound_transfer = mProtoTransfer.inbound(); + sender = inbound_transfer.mutable_sender(); + receiver_pubkey = inbound_transfer.mutable_receiver(); + return validate(sender, receiver_pubkey); + } + else if (mProtoTransfer.has_outbound()) { + auto outbound_transfer = mProtoTransfer.outbound(); + sender = outbound_transfer.mutable_sender(); + receiver_pubkey = outbound_transfer.mutable_receiver(); + return validate(sender, receiver_pubkey); + } + + return TRANSACTION_VALID_CODE_ERROR; + } + + TransactionValidation TransactionTransfer::validate(proto::gradido::TransferAmount* sender, std::string* receiver_pubkey) + { + assert(sender && receiver_pubkey); + + static const char function_name[] = "TransactionTransfer::validate"; + auto amount = sender->amount(); + if (0 == amount) { + addError(new Error(function_name, "amount is empty")); + return TRANSACTION_VALID_INVALID_AMOUNT; + } + else if (amount < 0) { + addError(new Error(function_name, "negative amount")); + return TRANSACTION_VALID_INVALID_AMOUNT; + } + if (receiver_pubkey->size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "invalid size of receiver pubkey")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + if (sender->pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "invalid size of sender pubkey")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + return TRANSACTION_VALID_OK; + } + + std::string TransactionTransfer::getTargetGroupAlias() + { + Poco::ScopedLock _lock(mWorkMutex); + if (mProtoTransfer.has_local()) { + return ""; + } + else if (mProtoTransfer.has_inbound()) { + auto inbound_transfer = mProtoTransfer.inbound(); + return inbound_transfer.other_group(); + } + else if (mProtoTransfer.has_outbound()) { + auto outbound_transfer = mProtoTransfer.outbound(); + return outbound_transfer.other_group(); + } + return ""; + } + + Poco::AutoPtr TransactionTransfer::createOutbound(const std::string& memo) + { + const char* function_name = "TransactionTransfer::createOutbound"; + auto mm = MemoryManager::getInstance(); + auto em = ErrorManager::getInstance(); + if (!mProtoTransfer.has_inbound()) { + return nullptr; + } + // Poco::AutoPtr sender, const MemoryBin* receiverPubkey, Poco::AutoPtr receiverGroup, Poco::UInt32 amount, const std::string& memo + //Transaction::createTransfer() + auto inbound = mProtoTransfer.inbound(); + + auto sender_pubkey = mm->getFreeMemory(inbound.sender().pubkey().size()); + memcpy(*sender_pubkey, inbound.sender().pubkey().data(), inbound.sender().pubkey().size()); + auto receiver_pubkey = mm->getFreeMemory(inbound.receiver().size()); + memcpy(*receiver_pubkey, inbound.receiver().data(), inbound.receiver().size()); + + auto body = TransactionBody::create( + memo, sender_pubkey, receiver_pubkey, + inbound.sender().amount(), mTargetGroupAlias, TRANSFER_CROSS_GROUP_OUTBOUND, + DataTypeConverter::convertFromProtoTimestamp(inbound.paired_transaction_id()) + ); + + auto transaction = Poco::AutoPtr(new Transaction(body)); + transaction->setTopicIdByGroup(mOwnGroupAlias); + + mm->releaseMemory(receiver_pubkey); + mm->releaseMemory(sender_pubkey); + return transaction; + + } + + Poco::AutoPtr TransactionTransfer::createInbound(const std::string& memo) + { + const char* function_name = "TransactionTransfer::createInbound"; + auto mm = MemoryManager::getInstance(); + + if (!mProtoTransfer.has_outbound()) { + return nullptr; + } + // Poco::AutoPtr sender, const MemoryBin* receiverPubkey, Poco::AutoPtr receiverGroup, Poco::UInt32 amount, const std::string& memo + //Transaction::createTransfer() + auto outbound = mProtoTransfer.outbound(); + + auto sender_pubkey = mm->getFreeMemory(outbound.sender().pubkey().size()); + memcpy(*sender_pubkey, outbound.sender().pubkey().data(), outbound.sender().pubkey().size()); + auto receiver_pubkey = mm->getFreeMemory(outbound.receiver().size()); + memcpy(*receiver_pubkey, outbound.receiver().data(), outbound.receiver().size()); + + auto body = TransactionBody::create( + memo, sender_pubkey, receiver_pubkey, + outbound.sender().amount(), mOwnGroupAlias, TRANSFER_CROSS_GROUP_INBOUND, + DataTypeConverter::convertFromProtoTimestamp(outbound.paired_transaction_id()) + ); + + auto transaction = Poco::AutoPtr(new Transaction(body)); + transaction->setTopicIdByGroup(mTargetGroupAlias); + + mm->releaseMemory(receiver_pubkey); + mm->releaseMemory(sender_pubkey); + return transaction; + } + + const std::string& TransactionTransfer::getKontoNameCell(int index) + { + Poco::ScopedLock _lock(mWorkMutex); + + if (index >= mKontoTable.size()) { + return mInvalidIndexMessage; + } + + return mKontoTable[index].kontoNameCell; + } + + const std::string& TransactionTransfer::getAmountCell(int index) + { + Poco::ScopedLock _lock(mWorkMutex); + if (index >= mKontoTable.size()) { + return mInvalidIndexMessage; + } + + return mKontoTable[index].amountCell; + } + + void TransactionTransfer::transactionAccepted(Poco::AutoPtr user) + { + + } + + + + } +} diff --git a/login_server/src/cpp/model/gradido/TransactionTransfer.h b/login_server/src/cpp/model/gradido/TransactionTransfer.h new file mode 100644 index 000000000..57259059f --- /dev/null +++ b/login_server/src/cpp/model/gradido/TransactionTransfer.h @@ -0,0 +1,84 @@ +/*! +* +* \author: einhornimmond +* +* \date: 25.10.19 +* +* \brief: Creation Transaction +*/ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE + +#pragma warning(disable:4800) + +#include "TransactionBase.h" +//#include "Transaction.h" +#include "../proto/gradido/GradidoTransfer.pb.h" + +#include "../controller/User.h" + +namespace model { + namespace gradido { + + class Transaction; + + enum TransactionTransferType + { + TRANSFER_LOCAL, + TRANSFER_CROSS_GROUP_INBOUND, + TRANSFER_CROSS_GROUP_OUTBOUND + }; + + class TransactionTransfer : public TransactionBase + { + public: + TransactionTransfer(const std::string& memo, const proto::gradido::GradidoTransfer& protoTransfer); + ~TransactionTransfer(); + + int prepare(); + TransactionValidation validate(); + + inline size_t getKontoTableSize() { Poco::ScopedLock _lock(mWorkMutex); return mKontoTable.size(); } + const std::string& getKontoNameCell(int index); + const std::string& getAmountCell(int index); + + std::string getTargetGroupAlias(); + bool isInbound() { return mProtoTransfer.has_inbound(); } + bool isOutbound() { return mProtoTransfer.has_outbound(); } + Poco::AutoPtr createOutbound(const std::string& memo); + Poco::AutoPtr createInbound(const std::string& memo); + + void transactionAccepted(Poco::AutoPtr user); + + inline void setOwnGroupAlias(const std::string& ownGroupAlias) { mOwnGroupAlias = ownGroupAlias; } + inline void setTargetGroupAlias(const std::string& targetGroupAlias) { mTargetGroupAlias = targetGroupAlias; } + + protected: + const static std::string mInvalidIndexMessage; + + int prepare(proto::gradido::TransferAmount* sender, std::string* receiver_pubkey); + TransactionValidation validate(proto::gradido::TransferAmount* sender, std::string* receiver_pubkey); + + struct KontoTableEntry + { + public: + KontoTableEntry(model::table::User* user, google::protobuf::int64 amount, bool negativeAmount = false); + KontoTableEntry(const std::string& pubkeyHex, google::protobuf::int64 amount, bool negativeAmount = false); + // first name, last name and email or pubkey hex if no user in db found + std::string kontoNameCell; + std::string amountCell; + + protected: + void composeAmountCellString(google::protobuf::int64 amount, bool negativeAmount); + }; + + const proto::gradido::GradidoTransfer& mProtoTransfer; + std::vector mKontoTable; + std::string mOwnGroupAlias; + std::string mTargetGroupAlias; + }; + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusCreateTopic.cpp b/login_server/src/cpp/model/hedera/ConsensusCreateTopic.cpp new file mode 100644 index 000000000..6a425456d --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusCreateTopic.cpp @@ -0,0 +1,50 @@ + + +#include "ConsensusCreateTopic.h" + +namespace model { + namespace hedera { + ConsensusCreateTopic::ConsensusCreateTopic(Poco::AutoPtr autoRenewHederaAccountId, Poco::UInt32 autoRenewPeriod) + : mProtoCreateTopic(nullptr) + { + mProtoCreateTopic = new proto::ConsensusCreateTopicTransactionBody; + auto auto_renew_period = mProtoCreateTopic->mutable_autorenewperiod(); + auto_renew_period->set_seconds(autoRenewPeriod); + + if (!autoRenewHederaAccountId.isNull()) { + auto auto_renew_account = mProtoCreateTopic->mutable_autorenewaccount(); + autoRenewHederaAccountId->copyToProtoAccountId(auto_renew_account); + } + + } + ConsensusCreateTopic::~ConsensusCreateTopic() + { + if (mProtoCreateTopic) { + delete mProtoCreateTopic; + mProtoCreateTopic = nullptr; + } + } + + void ConsensusCreateTopic::setAdminKey(const MemoryBin* adminPublicKey) + { + auto admin_key = mProtoCreateTopic->mutable_adminkey(); + auto admin_key_string = admin_key->mutable_ed25519(); + *admin_key_string = std::string((const char)*adminPublicKey, adminPublicKey->size()); + } + void ConsensusCreateTopic::setSubmitKey(const MemoryBin* submitPublicKey) + { + auto submit_key = mProtoCreateTopic->mutable_submitkey(); + auto submit_key_string = submit_key->mutable_ed25519(); + *submit_key_string = std::string((const char)*submitPublicKey, submitPublicKey->size()); + } + + bool ConsensusCreateTopic::validate() + { + + if (mProtoCreateTopic->autorenewperiod().seconds() == 7890000) {// && 0 != mProtoCreateTopic->autorenewaccount().accountnum()) { + return true; + } + return false; + } + } +} diff --git a/login_server/src/cpp/model/hedera/ConsensusCreateTopic.h b/login_server/src/cpp/model/hedera/ConsensusCreateTopic.h new file mode 100644 index 000000000..b639ee305 --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusCreateTopic.h @@ -0,0 +1,32 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H + + +#include "../../SingletonManager/MemoryManager.h" +#include "../../controller/HederaId.h" +#include "../../proto/hedera/ConsensusCreateTopic.pb.h" + +namespace model { + namespace hedera { + class ConsensusCreateTopic + { + public: + ConsensusCreateTopic(Poco::AutoPtr autoRenewHederaAccountId, Poco::UInt32 autoRenewPeriod); + ~ConsensusCreateTopic(); + + inline void setMemo(const std::string& memo) { mProtoCreateTopic->set_memo(memo); } + void setAdminKey(const MemoryBin* adminPublicKey); + void setSubmitKey(const MemoryBin* submitPublicKey); + + bool validate(); + + inline proto::ConsensusCreateTopicTransactionBody* getProtoTransactionBody() { return mProtoCreateTopic; } + inline void resetPointer() { mProtoCreateTopic = nullptr; } + protected: + proto::ConsensusCreateTopicTransactionBody* mProtoCreateTopic; + }; + } +} + + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusDeleteTopic.cpp b/login_server/src/cpp/model/hedera/ConsensusDeleteTopic.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/ConsensusDeleteTopic.h b/login_server/src/cpp/model/hedera/ConsensusDeleteTopic.h new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.cpp b/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.cpp new file mode 100644 index 000000000..18da97c73 --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.cpp @@ -0,0 +1,42 @@ +#include "ConsensusSubmitMessage.h" + +namespace model { + namespace hedera { + ConsensusSubmitMessage::ConsensusSubmitMessage(Poco::AutoPtr topicID) + : mConsensusMessageBody(nullptr) + { + mConsensusMessageBody = new proto::ConsensusSubmitMessageTransactionBody; + topicID->copyToProtoTopicId(mConsensusMessageBody->mutable_topicid()); + } + + ConsensusSubmitMessage::~ConsensusSubmitMessage() + { + if (mConsensusMessageBody) { + delete mConsensusMessageBody; + mConsensusMessageBody = nullptr; + } + } + + bool ConsensusSubmitMessage::validate() + { + // TODO: unpack gradido transaction and make simple validation check + assert(mConsensusMessageBody); + if (0 == mConsensusMessageBody->message().size()) { + printf("[ConsensusSubmitMessage::validate] empty message\n"); + return false; + } + if (!mConsensusMessageBody->has_topicid()) { + printf("[ConsensusSubmitMessage::validate] empty topic id\n"); + return false; + } + + return true; + } + + void ConsensusSubmitMessage::setMessage(std::string byteString) + { + assert(mConsensusMessageBody); + mConsensusMessageBody->set_message(byteString); + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.h b/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.h new file mode 100644 index 000000000..d08b72279 --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusSubmitMessage.h @@ -0,0 +1,32 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_SUBMIT_MESSAGE_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_SUBMIT_MESSAGE_H + +#include "../../proto/hedera/ConsensusSubmitMessage.pb.h" +#include "../../controller/HederaId.h" + +namespace model { + namespace hedera { + + class ConsensusSubmitMessage + { + public: + ConsensusSubmitMessage(Poco::AutoPtr topicID); + ~ConsensusSubmitMessage(); + + inline proto::ConsensusSubmitMessageTransactionBody* getProtoTransactionBody() { return mConsensusMessageBody; } + inline void resetPointer() { mConsensusMessageBody = nullptr; } + void setMessage(std::string byteString); + inline void setMessage(const MemoryBin* message) { setMessage(std::string((const char*)message->data(), message->size())); } + + bool validate(); + + + + protected: + proto::ConsensusSubmitMessageTransactionBody* mConsensusMessageBody; + + }; + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_SUBMIT_MESSAGE_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusTopicInfo.cpp b/login_server/src/cpp/model/hedera/ConsensusTopicInfo.cpp new file mode 100644 index 000000000..38b7d44bc --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusTopicInfo.cpp @@ -0,0 +1,68 @@ +#include "ConsensusTopicInfo.h" + +#include +#include "../../lib/DataTypeConverter.h" +#include "Poco/DateTimeFormatter.h" + +namespace model { + namespace hedera { + ConsensusTopicInfo::ConsensusTopicInfo(const proto::ConsensusTopicInfo& consensusTopicInfo) + : mProto(consensusTopicInfo) + { + } + + ConsensusTopicInfo::~ConsensusTopicInfo() + { + + } + + MemoryBin* ConsensusTopicInfo::getRunningHashCopy() const + { + auto mm = MemoryManager::getInstance(); + auto running_hash = mProto.runninghash(); + auto running_hash_bin = mm->getFreeMemory(running_hash.size()); + memcpy(*running_hash_bin, running_hash.data(), running_hash.size()); + return running_hash_bin; + } + + std::string ConsensusTopicInfo::toString() + { + std::stringstream ss; + ss << "memo: " << mProto.memo() << std::endl; + ss << "running hash: " << DataTypeConverter::binToHex((const unsigned char*)mProto.runninghash().data(), mProto.runninghash().size()) << std::endl; + ss << "sequence number: " << mProto.sequencenumber() << std::endl; + Poco::DateTime expiration_time = DataTypeConverter::convertFromProtoTimestamp(mProto.expirationtime()); + + ss << "expiration time: " << Poco::DateTimeFormatter::format(expiration_time, "%f.%m.%Y %H:%M:%S") << std::endl; + ss << "has admin key: " << mProto.has_adminkey() << std::endl; + ss << "has submit key: " << mProto.has_submitkey() << std::endl; + auto auto_renew_period = DataTypeConverter::convertFromProtoDuration(mProto.autorenewperiod()); + ss << "auto renew period: " << std::to_string(auto_renew_period.seconds()) << " seconds" << std::endl; + auto acc_id = mProto.autorenewaccount(); + ss << "auto renew account: " << acc_id.shardnum() << ", " << acc_id.realmnum() << ", " << acc_id.accountnum() << std::endl; + + return ss.str(); + } + + std::string ConsensusTopicInfo::toStringHtml() + { + std::stringstream ss; + ss << "
    "; + ss << "
  • memo: " << mProto.memo() << "
  • "; + ss << "
  • running hash: " << DataTypeConverter::binToHex((const unsigned char*)mProto.runninghash().data(), mProto.runninghash().size()) << "
  • "; + ss << "
  • sequence number: " << mProto.sequencenumber() << "
  • "; + Poco::DateTime expiration_time = DataTypeConverter::convertFromProtoTimestamp(mProto.expirationtime()); + + ss << "
  • expiration time: " << Poco::DateTimeFormatter::format(expiration_time, "%f.%m.%Y %H:%M:%S") << "
  • "; + ss << "
  • has admin key: " << mProto.has_adminkey() << "
  • "; + ss << "
  • has submit key: " << mProto.has_submitkey() << "
  • "; + auto auto_renew_period = DataTypeConverter::convertFromProtoDuration(mProto.autorenewperiod()); + ss << "
  • auto renew period: " << std::to_string(mProto.autorenewperiod().seconds()) << " seconds" << "
  • "; + auto acc_id = mProto.autorenewaccount(); + ss << "
  • auto renew account: " << acc_id.shardnum() << ", " << acc_id.realmnum() << ", " << acc_id.accountnum() << "
  • "; + ss << "
"; + + return ss.str(); + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusTopicInfo.h b/login_server/src/cpp/model/hedera/ConsensusTopicInfo.h new file mode 100644 index 000000000..123b9496b --- /dev/null +++ b/login_server/src/cpp/model/hedera/ConsensusTopicInfo.h @@ -0,0 +1,34 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_GET_TOPIC_INFO_RESPONSE_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_GET_TOPIC_INFO_RESPONSE_H + +#include "../proto/hedera/ConsensusTopicInfo.pb.h" +#include "../SingletonManager/MemoryManager.h" +#include "../../lib/DataTypeConverter.h" +#include "Poco/DateTime.h" + +namespace model +{ + namespace hedera + { + class ConsensusTopicInfo + { + public: + ConsensusTopicInfo(const proto::ConsensusTopicInfo& consensusTopicInfo); + ~ConsensusTopicInfo(); + + inline std::string getMemo() const { return mProto.memo(); } + MemoryBin* getRunningHashCopy() const; + Poco::UInt64 getSequenceNumber() const { return mProto.sequencenumber(); } + inline Poco::DateTime getExpirationTime() const { return DataTypeConverter::convertFromProtoTimestamp(mProto.expirationtime());} + inline proto::Duration getAutoRenewPeriod() const { return mProto.autorenewperiod(); } + + std::string toString(); + std::string toStringHtml(); + + protected: + proto::ConsensusTopicInfo mProto; + }; + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_GET_TOPIC_INFO_RESPONSE_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ConsensusUpdateTopic.cpp b/login_server/src/cpp/model/hedera/ConsensusUpdateTopic.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/ConsensusUpdateTopic.h b/login_server/src/cpp/model/hedera/ConsensusUpdateTopic.h new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/CryptoCreateTransaction.cpp b/login_server/src/cpp/model/hedera/CryptoCreateTransaction.cpp new file mode 100644 index 000000000..1c5d58e11 --- /dev/null +++ b/login_server/src/cpp/model/hedera/CryptoCreateTransaction.cpp @@ -0,0 +1,34 @@ +#include "CryptoCreateTransaction.h" + +namespace model { + namespace hedera { + + CryptoCreateTransaction::CryptoCreateTransaction(const unsigned char* publicKey, Poco::UInt64 initialBalance, int autoRenewPeriod) + { + mCryptoCreateBody = new proto::CryptoCreateTransactionBody; + // public key + auto key = mCryptoCreateBody->mutable_key(); + auto public_key = new std::string((const char*)publicKey, KeyPairHedera::getPublicKeySize()); + key->set_allocated_ed25519(public_key); + + mCryptoCreateBody->set_initialbalance(initialBalance); + + auto auto_renew_period = mCryptoCreateBody->mutable_autorenewperiod(); + auto_renew_period->set_seconds(autoRenewPeriod); + + } + + CryptoCreateTransaction::~CryptoCreateTransaction() + { + if (mCryptoCreateBody) { + delete mCryptoCreateBody; + mCryptoCreateBody = nullptr; + } + } + + bool CryptoCreateTransaction::validate() + { + return true; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/CryptoCreateTransaction.h b/login_server/src/cpp/model/hedera/CryptoCreateTransaction.h new file mode 100644 index 000000000..7182f3506 --- /dev/null +++ b/login_server/src/cpp/model/hedera/CryptoCreateTransaction.h @@ -0,0 +1,31 @@ +#ifndef __GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H +#define __GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H + +#include "../../proto/hedera/CryptoCreate.pb.h" + +#include "../Crypto/KeyPairHedera.h" + +namespace model { + namespace hedera { + + class CryptoCreateTransaction + { + public: + //! \param publicKey newly created public key from ed25519 public-private key pair for hedera + CryptoCreateTransaction(const unsigned char* publicKey, Poco::UInt64 initialBalance, int autoRenewPeriod); + ~CryptoCreateTransaction(); + + proto::CryptoCreateTransactionBody* getProtoTransactionBody() { return mCryptoCreateBody; } + inline void resetPointer() { mCryptoCreateBody = nullptr; } + + bool validate(); + + protected: + proto::CryptoCreateTransactionBody* mCryptoCreateBody; + }; + } +} + + + +#endif //__GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/CryptoTransferTransaction.cpp b/login_server/src/cpp/model/hedera/CryptoTransferTransaction.cpp new file mode 100644 index 000000000..171e239f4 --- /dev/null +++ b/login_server/src/cpp/model/hedera/CryptoTransferTransaction.cpp @@ -0,0 +1,48 @@ +#include "CryptoTransferTransaction.h" + +namespace model { + namespace hedera { + + CryptoTransferTransaction::CryptoTransferTransaction() + : mCryptoTransfer(nullptr) + { + mCryptoTransfer = new proto::CryptoTransferTransactionBody; + } + + CryptoTransferTransaction::~CryptoTransferTransaction() + { + if (mCryptoTransfer) { + delete mCryptoTransfer; + mCryptoTransfer = nullptr; + } + } + + void CryptoTransferTransaction::addSender(Poco::AutoPtr senderAccountId, Poco::UInt64 amountTinybars) + { + auto transfers = mCryptoTransfer->mutable_transfers(); + auto accountAmounts = transfers->add_accountamounts(); + accountAmounts->set_amount(-(Poco::Int64)amountTinybars); + senderAccountId->copyToProtoAccountId(accountAmounts->mutable_accountid()); + } + void CryptoTransferTransaction::addReceiver(Poco::AutoPtr receiverAccountId, Poco::UInt64 amountTinybars) + { + auto transfers = mCryptoTransfer->mutable_transfers(); + auto accountAmounts = transfers->add_accountamounts(); + accountAmounts->set_amount(amountTinybars); + receiverAccountId->copyToProtoAccountId(accountAmounts->mutable_accountid()); + } + + bool CryptoTransferTransaction::validate() + { + auto transfers = mCryptoTransfer->mutable_transfers(); + auto account_amounts = transfers->accountamounts(); + Poco::Int64 sum = 0; + for (int i = 0; i < transfers->accountamounts_size(); i++) { + auto account_amount = account_amounts.Mutable(i); + sum += account_amount->amount(); + } + return 0 == sum && transfers->accountamounts_size() > 0; + } + } +} + diff --git a/login_server/src/cpp/model/hedera/CryptoTransferTransaction.h b/login_server/src/cpp/model/hedera/CryptoTransferTransaction.h new file mode 100644 index 000000000..21d9bd3c3 --- /dev/null +++ b/login_server/src/cpp/model/hedera/CryptoTransferTransaction.h @@ -0,0 +1,40 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CRYPTO_TRANSFER_TRANSACTION_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CRYPTO_TRANSFER_TRANSACTION_H + +/*! +* @author: Dario Rekowski +* +* @date: 02.09.20 +* +* @brief: class for creating a hedera transfer transaction +* +*/ + +#include "../../proto/hedera/CryptoTransfer.pb.h" +#include "../../controller/HederaId.h" + +namespace model { + namespace hedera { + class CryptoTransferTransaction + { + public: + CryptoTransferTransaction(); + ~CryptoTransferTransaction(); + + void addSender(Poco::AutoPtr senderAccountId, Poco::UInt64 amountTinybars); + void addReceiver(Poco::AutoPtr receiverAccountId, Poco::UInt64 amountTinybars); + + bool validate(); + // set pointer to zero, after hand over pointer to transaction body + inline void resetPointer() { mCryptoTransfer = nullptr; } + + inline proto::CryptoTransferTransactionBody* getProtoTransactionBody() { return mCryptoTransfer; } + + protected: + proto::CryptoTransferTransactionBody* mCryptoTransfer; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CRYPTO_TRANSFER_TRANSACTION_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/Query.cpp b/login_server/src/cpp/model/hedera/Query.cpp new file mode 100644 index 000000000..9bff55438 --- /dev/null +++ b/login_server/src/cpp/model/hedera/Query.cpp @@ -0,0 +1,193 @@ +#include "Query.h" +#include "QueryHeader.h" +#include "Poco/Timestamp.h" +#include "../../SingletonManager/MemoryManager.h" + +#include + +#include "Transaction.h" +#include "TransactionBody.h" +#include "CryptoTransferTransaction.h" + +namespace model { + namespace hedera { + + Query::Query() + : mTransactionBody(nullptr) + { + + } + + Query::~Query() + { + if (mTransactionBody) { + delete mTransactionBody; + } + } + + Query* Query::getBalance(Poco::AutoPtr accountId, const controller::NodeServerConnection& connection) + { + + assert(!accountId.isNull() && accountId->getModel()); + + printf("[Query::getBalance] account id: %s\n", accountId->getModel()->toString().data()); + + auto query = new Query; + auto get_account_balance = query->mQueryProto.mutable_cryptogetaccountbalance(); + accountId->copyToProtoAccountId(get_account_balance->mutable_accountid()); + auto query_header = get_account_balance->mutable_header(); + query_header->set_responsetype(proto::COST_ANSWER); + + query->mTransactionBody = new TransactionBody(accountId, connection); + CryptoTransferTransaction crypto_transaction; + crypto_transaction.addSender(accountId, 0); + crypto_transaction.addReceiver(connection.hederaId, 0); + query->mTransactionBody->setCryptoTransfer(crypto_transaction); + + //auto transaction = query_header->mutable_payment(); + //auto transaction_body = transaction->mutable_body(); + // body content + // node account id + + + return query; + } + + Query* Query::getTopicInfo(Poco::AutoPtr topicId, Poco::AutoPtr payerAccountId, const controller::NodeServerConnection& connection) + { + assert(!topicId.isNull() && topicId->getModel()); + assert(!payerAccountId.isNull() && payerAccountId->getModel()); + + printf("[Query::getTopicInfo] topic id: %s\n", topicId->getModel()->toString().data()); + printf("[Query::getTopicInfo] payer account id: %s\n", payerAccountId->getModel()->toString().data()); + + auto query = new Query; + auto get_topic_info = query->mQueryProto.mutable_consensusgettopicinfo(); + topicId->copyToProtoTopicId(get_topic_info->mutable_topicid()); + + auto query_header = get_topic_info->mutable_header(); + query_header->set_responsetype(proto::ANSWER_ONLY); + + query->mTransactionBody = new TransactionBody(payerAccountId, connection); + CryptoTransferTransaction crypto_transaction; + // 0.003317 Hashbars + // fee from https://www.hedera.com/fees + crypto_transaction.addSender(payerAccountId, 3317); + crypto_transaction.addReceiver(connection.hederaId, 3317); + query->mTransactionBody->setCryptoTransfer(crypto_transaction); + + return query; + } + + Query* Query::getTransactionGetReceiptQuery( + const proto::TransactionID& transactionId, + Poco::AutoPtr payerAccount, + const controller::NodeServerConnection& connection + ) + { + assert(!payerAccount.isNull()); + auto query = new Query; + query->mQueryHeader = QueryHeader::createWithPaymentTransaction(payerAccount, connection, 1000); + auto transaction_get_receipt_query = query->mQueryProto.mutable_transactiongetreceipt(); + transaction_get_receipt_query->set_allocated_header(query->mQueryHeader->getProtoQueryHeader()); + auto transaction_id = transaction_get_receipt_query->mutable_transactionid(); + *transaction_id = transactionId; + + return query; + } + Query* Query::getTransactionGetRecordQuery( + const proto::TransactionID& transactionId, + Poco::AutoPtr payerAccount, + const controller::NodeServerConnection& connection + ) + { + assert(!payerAccount.isNull()); + auto query = new Query; + query->mQueryHeader = QueryHeader::createWithPaymentTransaction(payerAccount, connection, 1000); + + auto transaction_get_record_query = query->mQueryProto.mutable_transactiongetrecord(); + transaction_get_record_query->set_allocated_header(query->mQueryHeader->getProtoQueryHeader()); + auto transaction_id = transaction_get_record_query->mutable_transactionid(); + *transaction_id = transactionId; + + return query; + } + + + std::string Query::getConnectionString() const + { + if (mTransactionBody) { + return mTransactionBody->getConnectionString(); + } + if (!mQueryHeader.isNull()) { + return mQueryHeader->getConnectionString(); + } + return ""; + } + + proto::QueryHeader* Query::getQueryHeader() + { + if (mQueryProto.has_cryptogetaccountbalance()) { + return mQueryProto.mutable_cryptogetaccountbalance()->mutable_header(); + } + else if (mQueryProto.has_consensusgettopicinfo()) { + return mQueryProto.mutable_consensusgettopicinfo()->mutable_header(); + } + else { + return mQueryHeader->getProtoQueryHeader(); + } + return nullptr; + } + + bool Query::sign(std::unique_ptr keyPairHedera) + { + Transaction transaction; + mTransactionBody->updateTimestamp(); + auto sign_result = transaction.sign(std::move(keyPairHedera), mTransactionBody); + auto query_header = getQueryHeader(); + query_header->set_allocated_payment(transaction.getTransaction()); + transaction.resetPointer(); + + return sign_result; + } + + void Query::setResponseType(proto::ResponseType type) + { + auto query_header = getQueryHeader(); + query_header->set_responsetype(type); + } + + proto::ResponseType Query::getResponseType() + { + auto query_header = getQueryHeader(); + return query_header->responsetype(); + } + + std::string Query::toJsonString() const + { + std::string json_message = ""; + std::string json_message_body = ""; + google::protobuf::util::JsonPrintOptions options; + options.add_whitespace = true; + options.always_print_primitive_fields = true; + + auto status = google::protobuf::util::MessageToJsonString(mQueryProto, &json_message, options); + if (!status.ok()) { + return "error parsing query"; + } + + if (mTransactionBody) { + status = google::protobuf::util::MessageToJsonString(*mTransactionBody->getProtoTransactionBody(), &json_message_body, options); + if (!status.ok()) { + return "error parsing body"; + } + //\"bodyBytes\": \"MigKIC7Sihz14RbYNhVAa8V3FSIhwvd0pWVvZqDnVA91dtcbIgRnZGQx\" + int startBodyBytes = json_message.find("bodyBytes") + std::string("\"bodyBytes\": \"").size() - 2; + int endCur = json_message.find_first_of('\"', startBodyBytes + 2) + 1; + json_message.replace(startBodyBytes, endCur - startBodyBytes, json_message_body); + } + return json_message; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/Query.h b/login_server/src/cpp/model/hedera/Query.h new file mode 100644 index 000000000..0f149684c --- /dev/null +++ b/login_server/src/cpp/model/hedera/Query.h @@ -0,0 +1,60 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_H + +/*! + * @author: Dario Rekowski + * + * @date: 31.08.20 + * + * @brief: class for put together hedera querys (ask for state data, not a transaction, but needs a payment transaction) + * +*/ + +#include "../../proto/hedera/Query.pb.h" +#include "../../controller/NodeServer.h" +#include "../../Crypto/KeyPairHedera.h" +#include "TransactionBody.h" +#include "QueryHeader.h" + +namespace model { + namespace hedera { + class Query + { + public: + ~Query(); + static Query* getBalance(Poco::AutoPtr accountId, const controller::NodeServerConnection& connection); + static Query* getTopicInfo(Poco::AutoPtr topicId, Poco::AutoPtr payerAccountId, const controller::NodeServerConnection& connection); + static Query* getTransactionGetReceiptQuery( + const proto::TransactionID& transactionId, + Poco::AutoPtr payerAccount, + const controller::NodeServerConnection& connection + ); + static Query* getTransactionGetRecordQuery( + const proto::TransactionID& transactionId, + Poco::AutoPtr payerAccount, + const controller::NodeServerConnection& connection + ); + bool sign(std::unique_ptr keyPairHedera); + + void setResponseType(proto::ResponseType type); + proto::ResponseType getResponseType(); + inline bool setTransactionFee(Poco::UInt64 fee) { return mTransactionBody->updateCryptoTransferAmount(fee);} + + inline const proto::Query* getProtoQuery() const { return &mQueryProto; } + std::string getConnectionString() const; + + proto::QueryHeader* getQueryHeader(); + + std::string toJsonString() const; + + protected: + Query(); + proto::Query mQueryProto; + Poco::AutoPtr mQueryHeader; + TransactionBody* mTransactionBody; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/QueryHeader.cpp b/login_server/src/cpp/model/hedera/QueryHeader.cpp new file mode 100644 index 000000000..9f5d3ac8a --- /dev/null +++ b/login_server/src/cpp/model/hedera/QueryHeader.cpp @@ -0,0 +1,43 @@ +#include "QueryHeader.h" + +#include "Transaction.h" + +namespace model { + namespace hedera { + + QueryHeader::QueryHeader() + { + mProtoQueryHeader.set_responsetype(proto::ANSWER_ONLY); + } + + QueryHeader::~QueryHeader() + { + + } + + Poco::AutoPtr QueryHeader::createWithPaymentTransaction( + Poco::AutoPtr operatorAccount, + const controller::NodeServerConnection& connection, + Poco::UInt32 cost + ) { + Poco::AutoPtr query_header(new QueryHeader); + auto proto_query_header = query_header->getProtoQueryHeader(); + proto_query_header->set_responsetype(proto::ANSWER_ONLY); + auto payment_transaction = proto_query_header->mutable_payment(); + + query_header->mConnectionString = connection.getUriWithPort(); + + Transaction transactionObj(payment_transaction); + TransactionBody body(operatorAccount->getHederaId(), connection); + CryptoTransferTransaction transfer_transaction; + transfer_transaction.addSender(operatorAccount->getHederaId(), cost); + transfer_transaction.addReceiver(connection.hederaId, cost); + body.setCryptoTransfer(transfer_transaction); + transactionObj.sign(operatorAccount->getCryptoKey()->getKeyPair(), &body); + transactionObj.resetPointer(); + + return query_header; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/QueryHeader.h b/login_server/src/cpp/model/hedera/QueryHeader.h new file mode 100644 index 000000000..9ecb50040 --- /dev/null +++ b/login_server/src/cpp/model/hedera/QueryHeader.h @@ -0,0 +1,41 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_HEADER_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_HEADER_H + +#include "../proto/hedera/QueryHeader.pb.h" +#include "Transaction.h" + +#include "../../controller/User.h" +#include "../../controller/HederaAccount.h" + +namespace model { + namespace hedera { + class QueryHeader : public Poco::RefCountedObject + { + public: + ~QueryHeader(); + + //! for cost look here: https://www.hedera.com/fees + //! or make query first with response type COST_ANSWER + //! TODO: get cost from network + static Poco::AutoPtr createWithPaymentTransaction( + Poco::AutoPtr operatorAccount, + const controller::NodeServerConnection& connection, + Poco::UInt32 cost + ); + + void setResponseType(proto::ResponseType type) { mProtoQueryHeader.set_responsetype(type); }; + proto::ResponseType getResponseType() const { return mProtoQueryHeader.responsetype(); } + + proto::QueryHeader* getProtoQueryHeader() { return &mProtoQueryHeader; } + + const std::string& getConnectionString() const { return mConnectionString; } + + protected: + proto::QueryHeader mProtoQueryHeader; + std::string mConnectionString; + QueryHeader(); + }; + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_QUERY_HEADER_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/Response.cpp b/login_server/src/cpp/model/hedera/Response.cpp new file mode 100644 index 000000000..016be2b72 --- /dev/null +++ b/login_server/src/cpp/model/hedera/Response.cpp @@ -0,0 +1,78 @@ +#include "Response.h" + +namespace model { + namespace hedera { + Response::Response() + { + } + + Response::~Response() + { + + } + + Poco::UInt64 Response::getAccountBalance() + { + if (isCryptoGetAccountBalanceResponse()) { + auto balance_response = mResponseProto.cryptogetaccountbalance(); + return balance_response.balance(); + } + return 0; + } + + std::unique_ptr Response::getConsensusTopicInfo() + { + if (mResponseProto.has_consensusgettopicinfo()) { + return std::make_unique(mResponseProto.consensusgettopicinfo().topicinfo()); + } + return nullptr; + } + + TransactionReceipt* Response::getTransactionReceipt() + { + if (mResponseProto.has_transactiongetreceipt()) { + return new TransactionReceipt(mResponseProto.transactiongetreceipt().receipt()); + } + if (mResponseProto.has_transactiongetrecord()) { + return new TransactionReceipt(mResponseProto.transactiongetrecord().transactionrecord().receipt()); + } + return nullptr; + } + + TransactionRecord* Response::getTransactionRecord() + { + if (mResponseProto.has_transactiongetrecord()) { + return new TransactionRecord(mResponseProto.transactiongetrecord().transactionrecord()); + } + return nullptr; + } + + Poco::UInt64 Response::getQueryCost() + { + proto::ResponseHeader* response_header = nullptr; + if (mResponseProto.has_consensusgettopicinfo()) { + response_header = mResponseProto.mutable_consensusgettopicinfo()->mutable_header(); + } + else if (mResponseProto.has_cryptogetaccountbalance()) { + response_header = mResponseProto.mutable_cryptogetaccountbalance()->mutable_header(); + } + if (response_header) { + return response_header->cost(); + } + return 0; + } + + proto::ResponseCodeEnum Response::getResponseCode() + { + if (isCryptoGetAccountBalanceResponse()) { + auto balance_response = mResponseProto.cryptogetaccountbalance(); + return balance_response.header().nodetransactionprecheckcode(); + } + else if (mResponseProto.has_consensusgettopicinfo()) { + auto response = mResponseProto.consensusgettopicinfo(); + return response.header().nodetransactionprecheckcode(); + } + return proto::NOT_SUPPORTED; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/Response.h b/login_server/src/cpp/model/hedera/Response.h new file mode 100644 index 000000000..ea2445774 --- /dev/null +++ b/login_server/src/cpp/model/hedera/Response.h @@ -0,0 +1,47 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_RESPONSE_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_RESPONSE_H + +/*! +* @author: Dario Rekowski +* +* @date: 03.09.20 +* +* @brief: class for simply accessing hedera responses +* +*/ + +#include "../../proto/hedera/Response.pb.h" +#include "ConsensusTopicInfo.h" +#include "TransactionReceipt.h" +#include "TransactionRecord.h" +#include "Poco/Types.h" + +namespace model { + namespace hedera { + class Response + { + public: + Response(); + ~Response(); + + inline proto::Response* getResponsePtr() { return &mResponseProto; } + Poco::UInt64 getAccountBalance(); + std::unique_ptr getConsensusTopicInfo(); + TransactionReceipt* getTransactionReceipt(); + TransactionRecord* getTransactionRecord(); + Poco::UInt64 getQueryCost(); + proto::ResponseCodeEnum getResponseCode(); + + + inline bool isCryptoGetAccountBalanceResponse() { return mResponseProto.has_cryptogetaccountbalance(); } + inline bool isConsensusGetTopicInfoResponse() { return mResponseProto.has_consensusgettopicinfo(); } + + protected: + proto::Response mResponseProto; + + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_RESPONSE_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/ResponseHeader.cpp b/login_server/src/cpp/model/hedera/ResponseHeader.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/ResponseHeader.h b/login_server/src/cpp/model/hedera/ResponseHeader.h new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/model/hedera/Transaction.cpp b/login_server/src/cpp/model/hedera/Transaction.cpp new file mode 100644 index 000000000..e4d0f2bd5 --- /dev/null +++ b/login_server/src/cpp/model/hedera/Transaction.cpp @@ -0,0 +1,81 @@ +#include "Transaction.h" + +namespace model { + namespace hedera { + Transaction::Transaction() + : mTransaction(nullptr) + { + mTransaction = new proto::Transaction; + } + Transaction::Transaction(proto::Transaction* transaction) + : mTransaction(transaction) + { + + } + + Transaction::~Transaction() + { + if (mTransaction) { + delete mTransaction; + mTransaction = nullptr; + } + } + + bool Transaction::sign(std::unique_ptr keyPairHedera, const TransactionBody* transactionBody) + { + mType = transactionBody->getType(); + + auto mm = MemoryManager::getInstance(); + mConnection = transactionBody->getConnection(); + auto transaction_body_proto = transactionBody->getProtoTransactionBody(); + auto body_bytes = transaction_body_proto->SerializeAsString(); + mTransaction->set_bodybytes(body_bytes.data()); + auto signature_map = mTransaction->mutable_sigmap(); + auto signature_pairs = signature_map->mutable_sigpair(); + signature_map->add_sigpair(); + auto signature_pair = signature_pairs->Mutable(0); + auto public_key = keyPairHedera->getPublicKey(); + + auto sign = keyPairHedera->sign(body_bytes); + if (!sign) { + printf("[Query::sign] error signing message\n"); + return false; + } + signature_pair->set_pubkeyprefix(public_key, keyPairHedera->getPublicKeySize()); + signature_pair->set_ed25519(*sign, sign->size()); + + mm->releaseMemory(sign); + return true; + } + + bool Transaction::sign(std::unique_ptr keyPairHedera, std::unique_ptr transactionBody) + { + mType = transactionBody->getType(); + + auto mm = MemoryManager::getInstance(); + mConnection = transactionBody->getConnection(); + transactionBody->updateTimestamp(); + auto transaction_body_proto = transactionBody->getProtoTransactionBody(); + auto body_bytes = transaction_body_proto->SerializeAsString(); + mTransaction->set_bodybytes(body_bytes.data(), body_bytes.size()); + auto signature_map = mTransaction->mutable_sigmap(); + auto signature_pairs = signature_map->mutable_sigpair(); + signature_map->add_sigpair(); + auto signature_pair = signature_pairs->Mutable(0); + auto public_key = keyPairHedera->getPublicKey(); + + mTransactionId = transactionBody->getProtoTransactionBody()->transactionid(); + + auto sign = keyPairHedera->sign(body_bytes); + if (!sign) { + printf("[Query::sign] error signing message\n"); + return false; + } + signature_pair->set_pubkeyprefix(public_key, keyPairHedera->getPublicKeySize()); + signature_pair->set_ed25519(*sign, sign->size()); + + mm->releaseMemory(sign); + return true; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/Transaction.h b/login_server/src/cpp/model/hedera/Transaction.h new file mode 100644 index 000000000..63d273eb0 --- /dev/null +++ b/login_server/src/cpp/model/hedera/Transaction.h @@ -0,0 +1,46 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_H + +/*! +* @author: Dario Rekowski +* +* @date: 02.09.20 +* +* @brief: class for composing hedera transaction +* +*/ + +#include "../../proto/hedera/Transaction.pb.h" +#include "../../Crypto/KeyPairHedera.h" +#include "TransactionBody.h" + +namespace model { + namespace hedera { + class Transaction + { + public: + Transaction(); + Transaction(proto::Transaction* transaction); + ~Transaction(); + + bool sign(std::unique_ptr keyPairHedera, const TransactionBody* transactionBody); + bool sign(std::unique_ptr keyPairHedera, std::unique_ptr transactionBody); + + inline proto::Transaction* getTransaction() { return mTransaction; } + inline std::string getConnectionString() const { return mConnection.getUriWithPort(); } + const controller::NodeServerConnection& getConnection() const { return mConnection; } + void resetPointer() { mTransaction = nullptr; } + inline TransactionBodyType getType() const { return mType; } + inline proto::TransactionID getTransactionId() const { return mTransactionId; } + + protected: + proto::Transaction* mTransaction; + controller::NodeServerConnection mConnection; + TransactionBodyType mType; + proto::TransactionID mTransactionId; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionBody.cpp b/login_server/src/cpp/model/hedera/TransactionBody.cpp new file mode 100644 index 000000000..291dd5542 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionBody.cpp @@ -0,0 +1,153 @@ +#include "TransactionBody.h" + +namespace model { + namespace hedera { + TransactionBody::TransactionBody(Poco::AutoPtr operatorAccountId, const controller::NodeServerConnection& connection) + : mConnection(connection), mHasBody(false) + { + connection.hederaId->copyToProtoAccountId(mTransactionBody.mutable_nodeaccountid()); + auto transaction_id = mTransactionBody.mutable_transactionid(); + operatorAccountId->copyToProtoAccountId(transaction_id->mutable_accountid()); + mTransactionBody.set_transactionfee(10000000); + auto transaction_valid_duration = mTransactionBody.mutable_transactionvalidduration(); + transaction_valid_duration->set_seconds(120); + + updateTimestamp(); + } + + TransactionBody::~TransactionBody() + { + + } + + bool TransactionBody::setCryptoTransfer(CryptoTransferTransaction& cryptoTransferTransaction) + { + if (mHasBody) { + printf("[TransactionBody::setCryptoTransfer] has already a body\n"); + return false; + } + if (cryptoTransferTransaction.validate()) { + mTransactionBody.set_allocated_cryptotransfer(cryptoTransferTransaction.getProtoTransactionBody()); + cryptoTransferTransaction.resetPointer(); + mHasBody = true; + mType = TRANSACTION_CRYPTO_TRANSFER; + return true; + } + return false; + } + + bool TransactionBody::updateCryptoTransferAmount(Poco::UInt64 newAmount) + { + assert(mHasBody); + + if (!mTransactionBody.has_cryptotransfer()) { + printf("[TransactionBody::updateCryptoTransferAmount] hasn't crypto transfer\n"); + return false; + } + + auto crypto_transfer = mTransactionBody.mutable_cryptotransfer(); + auto transfers = crypto_transfer->mutable_transfers(); + if (transfers->accountamounts_size() != 2) { + printf("[TransactionBody::updateCryptoTransferAmount] structure not like expected, transfers has %d accountamounts\n", transfers->accountamounts_size()); + return false; + } + proto::AccountAmount* account_amounts[] = { transfers->mutable_accountamounts(0), transfers->mutable_accountamounts(1) }; + for (int i = 0; i < 2; i++) { + if (account_amounts[i]->amount() > 0) { + account_amounts[i]->set_amount(newAmount); + } + else if (account_amounts[i]->amount() < 0) { + account_amounts[i]->set_amount(-newAmount); + } + } + return true; + + } + + bool TransactionBody::setCreateTopic(ConsensusCreateTopic& consensusCreateTopicTransaction) + { + if (mHasBody) { + printf("[TransactionBody::setCreateTopic] has already a body\n"); + return false; + } + if (consensusCreateTopicTransaction.validate()) { + mTransactionBody.set_allocated_consensuscreatetopic(consensusCreateTopicTransaction.getProtoTransactionBody()); + consensusCreateTopicTransaction.resetPointer(); + mHasBody = true; + mType = TRANSACTION_CONSENSUS_CREATE_TOPIC; + mTransactionBody.set_transactionfee(1000000000); + return true; + } + return false; + } + + bool TransactionBody::setCryptoCreate(CryptoCreateTransaction& cryptoCreateTransaction) + { + if (mHasBody) { + printf("[TransactionBody::setCryptoCreate] has already a body\n"); + return false; + } + if (cryptoCreateTransaction.validate()) { + mTransactionBody.set_allocated_cryptocreateaccount(cryptoCreateTransaction.getProtoTransactionBody()); + cryptoCreateTransaction.resetPointer(); + mHasBody = true; + mType = TRANSACTION_CRYPTO_CREATE; + return true; + } + return false; + } + + bool TransactionBody::setConsensusSubmitMessage(ConsensusSubmitMessage& consensusSubmitMessageTransaction) + { + if (mHasBody) { + printf("[TransactionBody::setConsensusSubmitMessage] has already a body\n"); + return false; + } + if (consensusSubmitMessageTransaction.validate()) { + mTransactionBody.set_allocated_consensussubmitmessage(consensusSubmitMessageTransaction.getProtoTransactionBody()); + consensusSubmitMessageTransaction.resetPointer(); + mHasBody = true; + mType = TRANSACTION_CONSENSUS_SUBMIT_MESSAGE; + return true; + } + return false; + } + + const char* TransactionBody::TransactionBodyTypeToString(TransactionBodyType type) + { + switch (type) { + case TRANSACTION_CONSENSUS_CREATE_TOPIC: return "Consensus Create Topic"; + case TRANSACTION_CONSENSUS_SUBMIT_MESSAGE: return "Consensus Submit Message"; + case TRANSACTION_CRYPTO_CREATE: return "Crypto Create"; + case TRANSACTION_CRYPTO_TRANSFER: return "Crypto Transfer"; + } + return ""; + } + + void TransactionBody::setMemo(const std::string& memo) + { + mTransactionBody.set_memo(memo); + } + void TransactionBody::setFee(Poco::UInt64 fee) + { + mTransactionBody.set_transactionfee(fee); + } + + void TransactionBody::updateTimestamp() + { + auto transaction_id = mTransactionBody.mutable_transactionid(); + auto timestamp = transaction_id->mutable_transactionvalidstart(); + Poco::Timestamp now; + auto micros = now.epochMicroseconds(); + auto s = now.epochTime(); + auto res = now.resolution(); + auto microseconds = now.epochMicroseconds() - now.epochTime() * now.resolution(); // 1*10^6 + // 1s = 1000000000 ns + timestamp->set_seconds(now.epochTime()-2); + timestamp->set_nanos(microseconds * 1000); + // make sure timestamp is some nanos old + //timestamp->set_nanos(microseconds * 900); + // printf("hedera transaction body timestamp: %d.%d\n", timestamp->seconds(), timestamp->nanos()); + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionBody.h b/login_server/src/cpp/model/hedera/TransactionBody.h new file mode 100644 index 000000000..b9c25d0c4 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionBody.h @@ -0,0 +1,67 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_BODY_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_BODY_H + +/*! +* @author: Dario Rekowski +* +* @date: 02.09.20 +* +* @brief: class for composing transaction body for hedera transaction +* +*/ + + +#include "../../controller/NodeServer.h" +#include "CryptoTransferTransaction.h" +#include "CryptoCreateTransaction.h" +#include "ConsensusCreateTopic.h" +#include "ConsensusSubmitMessage.h" + +#include "../../proto/hedera/TransactionBody.pb.h" + +namespace model { + namespace hedera { + + enum TransactionBodyType + { + TRANSACTION_CRYPTO_TRANSFER, + TRANSACTION_CRYPTO_CREATE, + TRANSACTION_CONSENSUS_CREATE_TOPIC, + TRANSACTION_CONSENSUS_SUBMIT_MESSAGE + }; + + class TransactionBody + { + public: + TransactionBody(Poco::AutoPtr operatorAccountId, const controller::NodeServerConnection& connection); + ~TransactionBody(); + + void setMemo(const std::string& memo); + void setFee(Poco::UInt64 fee); + + bool setCryptoTransfer(CryptoTransferTransaction& cryptoTransferTransaction); + bool updateCryptoTransferAmount(Poco::UInt64 newAmount); + bool setCryptoCreate(CryptoCreateTransaction& cryptoCreateTransaction); + bool setCreateTopic(ConsensusCreateTopic& consensusCreateTopicTransaction); + bool setConsensusSubmitMessage(ConsensusSubmitMessage& consensusSubmitMessageTransaction); + //bool + + inline const proto::TransactionBody* getProtoTransactionBody() const { return &mTransactionBody; } + inline std::string getConnectionString() const { return mConnection.getUriWithPort(); } + inline controller::NodeServerConnection getConnection() const { return mConnection; } + inline TransactionBodyType getType() const { return mType; } + static const char* TransactionBodyTypeToString(TransactionBodyType type); + + void updateTimestamp(); + protected: + + proto::TransactionBody mTransactionBody; + controller::NodeServerConnection mConnection; + bool mHasBody; + TransactionBodyType mType; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_BODY_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionGetReceipt.cpp b/login_server/src/cpp/model/hedera/TransactionGetReceipt.cpp new file mode 100644 index 000000000..402dfd81d --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionGetReceipt.cpp @@ -0,0 +1,15 @@ +#include "TransactionGetReceipt.h" + +namespace model { + namespace hedera { + TransactionGetReceipt::TransactionGetReceipt() + { + + } + + TransactionGetReceipt::~TransactionGetReceipt() + { + + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionGetReceipt.h b/login_server/src/cpp/model/hedera/TransactionGetReceipt.h new file mode 100644 index 000000000..e03623d58 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionGetReceipt.h @@ -0,0 +1,17 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_H +#define GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_H + +namespace model { + namespace hedera { + class TransactionGetReceipt + { + public: + TransactionGetReceipt(); + ~TransactionGetReceipt(); + }; + } +} + + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.cpp b/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.cpp new file mode 100644 index 000000000..c8e2db73e --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.cpp @@ -0,0 +1,18 @@ +#include "TransactionGetReceiptQuery.h" + +namespace model { + namespace hedera { + TransactionGetReceiptQuery::TransactionGetReceiptQuery(Poco::AutoPtr queryHeader, const Transaction* target) + : mQueryHeader(queryHeader) + { + mProtoReceiptQuery.set_allocated_header(queryHeader->getProtoQueryHeader()); + auto transaction_id = mProtoReceiptQuery.transactionid(); + transaction_id = target->getTransactionId(); + } + + TransactionGetReceiptQuery::~TransactionGetReceiptQuery() + { + + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.h b/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.h new file mode 100644 index 000000000..bf035a941 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionGetReceiptQuery.h @@ -0,0 +1,29 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_QUERY_H +#define GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_QUERY_H + +#include "QueryHeader.h" +#include "../../proto/hedera/TransactionGetReceipt.pb.h" + +namespace model { + namespace hedera { + class TransactionGetReceiptQuery + { + public: + TransactionGetReceiptQuery(Poco::AutoPtr queryHeader, const Transaction* target); + ~TransactionGetReceiptQuery(); + + proto::TransactionGetReceiptQuery* getProto() { return &mProtoReceiptQuery; } + + const std::string& getConnectionString() const { return mQueryHeader->getConnectionString(); } + + protected: + Poco::AutoPtr mQueryHeader; + proto::TransactionGetReceiptQuery mProtoReceiptQuery; + + }; + } +} + + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_GET_RECEIPT_QUERY_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionId.cpp b/login_server/src/cpp/model/hedera/TransactionId.cpp new file mode 100644 index 000000000..df6606af1 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionId.cpp @@ -0,0 +1,47 @@ +#include "TransactionId.h" + +#include "../../lib/DataTypeConverter.h" + +namespace model { + namespace hedera { + TransactionId::TransactionId() + : shard(0), realm(0), num(0) + { + + } + + TransactionId::TransactionId(const proto::TransactionID& transaction) + { + auto account_id = transaction.accountid(); + shard = account_id.shardnum(); + realm = account_id.realmnum(); + num = account_id.accountnum(); + mTransactionValidStart = DataTypeConverter::convertFromProtoTimestamp(transaction.transactionvalidstart()); + + } + + TransactionId::TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart) + : shard(shard), realm(realm), num(num), mTransactionValidStart(transactionValidStart) + { + + } + + TransactionId::~TransactionId() + { + + } + + Poco::JSON::Object::Ptr TransactionId::convertToJSON() + { + Poco::JSON::Object::Ptr result = new Poco::JSON::Object; + result->set("transactionValidStart", mTransactionValidStart); + Poco::JSON::Object accountId; + accountId.set("shard", shard); + accountId.set("realm", realm); + accountId.set("num", num); + result->set("accountId", accountId); + return result; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionId.h b/login_server/src/cpp/model/hedera/TransactionId.h new file mode 100644 index 000000000..dcc877271 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionId.h @@ -0,0 +1,44 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H + +/*! +* @author: Dario Rekowski +* +* @date: 02.09.20 +* +* @brief: class for composing hedera transaction +* +*/ + +#include "../../proto/hedera/BasicTypes.pb.h" + +#include "Poco/JSON/Object.h" + +namespace model { + namespace hedera { + class TransactionId + { + public: + TransactionId(); + TransactionId(const proto::TransactionID& transaction); + TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart); + ~TransactionId(); + + Poco::JSON::Object::Ptr convertToJSON(); + + protected: + Poco::Timestamp mTransactionValidStart; + union { + struct { + int shard; + int realm; + int num; + }; + int val[3]; + }; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionReceipt.cpp b/login_server/src/cpp/model/hedera/TransactionReceipt.cpp new file mode 100644 index 000000000..04a5f0c82 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionReceipt.cpp @@ -0,0 +1,25 @@ +#include "TransactionReceipt.h" + +namespace model { + namespace hedera { + + TransactionReceipt::TransactionReceipt(const proto::TransactionReceipt& protoReceipt) + : mProtoReceipt(protoReceipt) + { + + } + + TransactionReceipt::~TransactionReceipt() + { + + } + + MemoryBin* TransactionReceipt::getRunningHash() + { + auto hash = mProtoReceipt.topicrunninghash(); + auto hashBin = MemoryManager::getInstance()->getFreeMemory(hash.size()); + memcpy(*hashBin, hash.data(), hash.size()); + return hashBin; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionReceipt.h b/login_server/src/cpp/model/hedera/TransactionReceipt.h new file mode 100644 index 000000000..5c3aabdb8 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionReceipt.h @@ -0,0 +1,31 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECEIPT_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECEIPT_H + +#include "../proto/hedera/TransactionReceipt.pb.h" +#include "../../SingletonManager/MemoryManager.h" + +namespace model { + namespace hedera { + class TransactionReceipt + { + public: + TransactionReceipt(const proto::TransactionReceipt& protoReceipt); + ~TransactionReceipt(); + + proto::TopicID getTopicId() { return mProtoReceipt.topicid(); } + google::protobuf::uint64 getSequenceNumber() { return mProtoReceipt.topicsequencenumber(); } + google::protobuf::uint64 getRunningHashVersion() { return mProtoReceipt.topicrunninghashversion(); } + //! caller must release memory after finish with it + MemoryBin* getRunningHash(); + proto::ResponseCodeEnum getStatus() { return mProtoReceipt.status(); } + + inline proto::TransactionReceipt* getProto() { return &mProtoReceipt; } + + protected: + proto::TransactionReceipt mProtoReceipt; + + }; + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECEIPT_H \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionRecord.cpp b/login_server/src/cpp/model/hedera/TransactionRecord.cpp new file mode 100644 index 000000000..7d691b944 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionRecord.cpp @@ -0,0 +1,12 @@ +#include "TransactionRecord.h" + +namespace model { + namespace hedera { + TransactionRecord::TransactionRecord(const proto::TransactionRecord& transaction_record) + : mProtoRecord(transaction_record) + { + + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionRecord.h b/login_server/src/cpp/model/hedera/TransactionRecord.h new file mode 100644 index 000000000..d14f42303 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionRecord.h @@ -0,0 +1,26 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECORD_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECORD_H + +#include "../../proto/hedera/TransactionRecord.pb.h" + +namespace model +{ + namespace hedera + { + class TransactionRecord + { + public: + TransactionRecord(const proto::TransactionRecord& transaction_record); + + + inline proto::TransactionRecord* getProto() { return &mProtoRecord; } + + protected: + proto::TransactionRecord mProtoRecord; + }; + + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RECORD_H + diff --git a/login_server/src/cpp/model/hedera/TransactionResponse.cpp b/login_server/src/cpp/model/hedera/TransactionResponse.cpp new file mode 100644 index 000000000..2e9a66ea1 --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionResponse.cpp @@ -0,0 +1,18 @@ +#include "TransactionResponse.h" + +namespace model { + namespace hedera { + + TransactionResponse::TransactionResponse() + { + + } + + TransactionResponse::~TransactionResponse() + { + + } + + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/hedera/TransactionResponse.h b/login_server/src/cpp/model/hedera/TransactionResponse.h new file mode 100644 index 000000000..325cbe73f --- /dev/null +++ b/login_server/src/cpp/model/hedera/TransactionResponse.h @@ -0,0 +1,30 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RESPONSE_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RESPONSE_H + +#include "../../proto/hedera/TransactionResponse.pb.h" +#include "Poco/Types.h" + +namespace model { + namespace hedera { + + class TransactionResponse + { + public: + TransactionResponse(); + ~TransactionResponse(); + + inline proto::ResponseCodeEnum getPrecheckCode() const { return mProtoResponse.nodetransactionprecheckcode();} + inline std::string getPrecheckCodeString() const { return proto::ResponseCodeEnum_Name(mProtoResponse.nodetransactionprecheckcode()); } + inline Poco::UInt64 getCost() const { return mProtoResponse.cost(); } + + proto::TransactionResponse* getProtoResponse() { return &mProtoResponse; } + protected: + proto::TransactionResponse mProtoResponse; + + }; + } +} + + + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_RESPONSE_H \ No newline at end of file diff --git a/login_server/src/cpp/model/table/AppAccessToken.cpp b/login_server/src/cpp/model/table/AppAccessToken.cpp new file mode 100644 index 000000000..55e1e3917 --- /dev/null +++ b/login_server/src/cpp/model/table/AppAccessToken.cpp @@ -0,0 +1,130 @@ +#include "AppAccessToken.h" + + +using namespace Poco::Data::Keywords; + +namespace model +{ + namespace table { + + + + AppAccessToken::AppAccessToken() + : mUserId(0), mAccessCode(0) + { + + } + + AppAccessToken::AppAccessToken(int user_id, const Poco::UInt64& code) + : mUserId(user_id), mAccessCode(code) + { + + } + + AppAccessToken::AppAccessToken(const AppAccessCodeTuple& tuple) + : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mAccessCode(tuple.get<2>()), mCreated(tuple.get<3>()), mUpdated(tuple.get<4>()) + { + + } + + AppAccessToken::~AppAccessToken() + { + + } + + std::string AppAccessToken::toString() + { + std::stringstream ss; + ss << "id: " << std::to_string(mID) << std::endl; + ss << "user id: " << std::to_string(mUserId) << std::endl; + ss << "code: " << std::to_string(mAccessCode) << std::endl; + + return ss.str(); + } + + Poco::Data::Statement AppAccessToken::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + + lock("AppAccessToken::_insertIntoDB"); + assert(mUserId > 0); + assert(mAccessCode > 0); + + insert << "INSERT INTO " << getTableName() + << " (user_id, access_code) VALUES(?,?)" + , use(mUserId), use(mAccessCode); + unlock(); + mUpdated = Poco::DateTime(); + mCreated = Poco::DateTime(); + return insert; + } + + size_t AppAccessToken::update() + { + return updateIntoDB("update", Poco::DateTime()); + } + + + Poco::Data::Statement AppAccessToken::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUserId), into(mAccessCode), into(mCreated), into(mUpdated); + + + return select; + } + + Poco::Data::Statement AppAccessToken::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id FROM " << getTableName() + << " where access_code = ?" + , into(mID), use(mAccessCode); + + return select; + } + Poco::Data::Statement AppAccessToken::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldName << " = ?"; + + + return select; + } + + Poco::Data::Statement AppAccessToken::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + { + Poco::Data::Statement select(session); + if (fieldNames.size() <= 1) { + throw Poco::NullValueException("AppAccessToken::_loadFromDB fieldNames empty or contain only one field"); + } + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldNames[0] << " = ? "; + if (conditionType == MYSQL_CONDITION_AND) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " AND " << fieldNames[i] << " = ? "; + } + } + else if (conditionType == MYSQL_CONDITION_OR) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " OR " << fieldNames[i] << " = ? "; + } + } + else { + addError(new ParamError("AppAccessToken::_loadFromDB", "condition type not implemented", conditionType)); + } + //<< " where " << fieldName << " = ?" + select, into(mID), into(mUserId), into(mAccessCode), into(mCreated), into(mUpdated); + + + return select; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/AppAccessToken.h b/login_server/src/cpp/model/table/AppAccessToken.h new file mode 100644 index 000000000..821cb6e3c --- /dev/null +++ b/login_server/src/cpp/model/table/AppAccessToken.h @@ -0,0 +1,54 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_APP_ACCESS_TOKEN_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_APP_ACCESS_TOKEN_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" +#include "Poco/Tuple.h" + +namespace model { + namespace table { + + typedef Poco::Tuple AppAccessCodeTuple; + + class AppAccessToken : public ModelBase + { + public: + AppAccessToken(int user_id, const Poco::UInt64& code); + AppAccessToken(const AppAccessCodeTuple& tuple); + AppAccessToken(); + ~AppAccessToken(); + + // generic db operations + const char* getTableName() const { return "app_access_tokens"; } + std::string toString(); + + inline Poco::UInt64 getCode() const { return mAccessCode; } + inline int getUserId() const { return mUserId; } + inline Poco::DateTime getCreated() const { return mCreated; } + inline Poco::DateTime getUpdated() const { Poco::ScopedLock _lock(mWorkMutex); return mUpdated; } + inline void setCode(Poco::UInt64 code) { mAccessCode = code; } + inline void setUserId(int user_Id) { mUserId = user_Id; } + + size_t update(); + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + + int mUserId; + // data type must be a multiple of 4 + Poco::UInt64 mAccessCode; + Poco::DateTime mCreated; + Poco::DateTime mUpdated; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_EMAIL_OPT_IN_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/CryptoKey.cpp b/login_server/src/cpp/model/table/CryptoKey.cpp new file mode 100644 index 000000000..816782786 --- /dev/null +++ b/login_server/src/cpp/model/table/CryptoKey.cpp @@ -0,0 +1,169 @@ +#include "CryptoKey.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + CryptoKey::CryptoKey() + { + + } + + CryptoKey::CryptoKey(MemoryBin* privateKey, MemoryBin* publicKey, KeyType keyType) + : mKeyType(keyType) + { + if (!privateKey) { + mPrivateKey = Poco::Nullable(); + } else { + mPrivateKey = Poco::Nullable(Poco::Data::BLOB(*privateKey, privateKey->size())); + } + + if (!publicKey) { + mPublicKey = Poco::Nullable(); + } else { + mPublicKey = Poco::Nullable(Poco::Data::BLOB(*publicKey, publicKey->size())); + } + } + + CryptoKey::~CryptoKey() + { + + } + + std::string CryptoKey::toString() + { + assert(mKeyType < KEY_TYPE_COUNT && mKeyType >= 0); + std::stringstream ss; + ss << "Key Type: " << typeToString(static_cast(mKeyType)) << std::endl; + ss << "Public Key: " << DataTypeConverter::binToHex(mPublicKey); + return ss.str(); + } + + + const char* CryptoKey::typeToString(KeyType type) + { + switch (type) { + case KEY_TYPE_ED25519_SODIUM_ENCRYPTED: return "ed25519 sodium encrypted"; + case KEY_TYPE_ED25519_HEDERA_ENCRYPTED: return "ed22519 for hedera encrypted"; + case KEY_TYPE_ED25519_SODIUM_CLEAR: return "ed25519 sodium clear"; + case KEY_TYPE_ED25519_HEDERA_CLEAR: return "ed25519 hedera clear"; + } + return ""; + } + + + + bool CryptoKey::hasPrivateKeyEncrypted() const + { + const KeyType type = (KeyType)(mKeyType); + if (type == KEY_TYPE_ED25519_HEDERA_ENCRYPTED || type == KEY_TYPE_ED25519_SODIUM_ENCRYPTED) { + return !mPrivateKey.isNull(); + } + return false; + } + + bool CryptoKey::isEncrypted() const + { + const KeyType type = (KeyType)(mKeyType); + if (type == KEY_TYPE_ED25519_HEDERA_ENCRYPTED || + type == KEY_TYPE_ED25519_SODIUM_ENCRYPTED) { + return true; + } + return false; + } + + void CryptoKey::setPrivateKey(const MemoryBin* privateKey) + { + if (!privateKey) { + mPrivateKey = Poco::Nullable(); + } + else { + mPrivateKey = Poco::Nullable(Poco::Data::BLOB(*privateKey, privateKey->size())); + } + + } + + bool CryptoKey::changeKeyTypeToggleEncrypted() + { + const KeyType type = (KeyType)(mKeyType); + if (type == KEY_TYPE_ED25519_SODIUM_ENCRYPTED) { + mKeyType = KEY_TYPE_ED25519_SODIUM_CLEAR; + return true; + } + if (type == KEY_TYPE_ED25519_HEDERA_ENCRYPTED) { + mKeyType = KEY_TYPE_ED25519_HEDERA_CLEAR; + return true; + } + if (type == KEY_TYPE_ED25519_SODIUM_CLEAR) { + mKeyType = KEY_TYPE_ED25519_SODIUM_ENCRYPTED; + return true; + } + if (type == KEY_TYPE_ED25519_HEDERA_CLEAR) { + mKeyType = KEY_TYPE_ED25519_HEDERA_ENCRYPTED; + return true; + } + return false; + } + + Poco::Data::Statement CryptoKey::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, private_key, public_key, crypto_key_type_id FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mPrivateKey), into(mPublicKey), into(mKeyType); + + return select; + } + + Poco::Data::Statement CryptoKey::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where public_key = ?" + , into(mID), use(mPublicKey); + return select; + } + + + Poco::Data::Statement CryptoKey::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + insert << "INSERT INTO " << getTableName() + << " (private_key, public_key, crypto_key_type_id) VALUES(?,?,?)" + , use(mPrivateKey), use(mPublicKey), use(mKeyType); + return insert; + } + + size_t CryptoKey::updatePrivkeyAndKeyType() + { + Poco::ScopedLock _lock(mWorkMutex); + if (mPrivateKey.isNull() || !mID) { + return 0; + } + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement update(session); + + update << "UPDATE " << getTableName() << " SET private_key = ?, crypto_key_type_id = ? where id = ?;", + use(mPrivateKey), use(mKeyType), use(mID); + + + size_t resultCount = 0; + try { + return update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "[updatePrivkeyAndKeyType] mysql error by update", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: \n", toString().data())); + } + //printf("data valid: %s\n", toString().data()); + return 0; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/CryptoKey.h b/login_server/src/cpp/model/table/CryptoKey.h new file mode 100644 index 000000000..0dcbb618f --- /dev/null +++ b/login_server/src/cpp/model/table/CryptoKey.h @@ -0,0 +1,62 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_CRYPTO_KEYS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_CRYPTO_KEYS_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" +#include "../../lib/DataTypeConverter.h" + +namespace model { + namespace table { + + enum KeyType { + KEY_TYPE_ED25519_SODIUM_ENCRYPTED = 0, + KEY_TYPE_ED25519_HEDERA_ENCRYPTED = 1, + KEY_TYPE_ED25519_SODIUM_CLEAR = 2, + KEY_TYPE_ED25519_HEDERA_CLEAR = 3, + KEY_TYPE_COUNT + }; + + class CryptoKey : public ModelBase + { + public: + CryptoKey(); + CryptoKey(MemoryBin* privateKey, MemoryBin* publicKey, KeyType keyType); + ~CryptoKey(); + + // generic db operations + const char* getTableName() const { return "crypto_keys"; } + std::string toString(); + + inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } + inline std::string getPublicKeyHexString() const { return DataTypeConverter::binToHex(mPublicKey); }; + size_t getPublicKeySize() const { if (mPublicKey.isNull()) return 0; return mPublicKey.value().content().size(); } + + bool hasPrivateKeyEncrypted() const; + bool isEncrypted() const; + bool changeKeyTypeToggleEncrypted(); + inline bool hasPrivateKey() const { return !mPrivateKey.isNull(); } + inline const std::vector& getPrivateKey() const { return mPrivateKey.value().content(); } + + size_t updatePrivkeyAndKeyType(); + + //! \brief set encrypted private key + //! \param privateKey copy data, didn't move memory bin + void setPrivateKey(const MemoryBin* privateKey); + + static const char* typeToString(KeyType type); + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + Poco::Nullable mPrivateKey; + Poco::Nullable mPublicKey; + int mKeyType; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_CRYPTO_KEYS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/EmailOptIn.cpp b/login_server/src/cpp/model/table/EmailOptIn.cpp index 55358215b..b3a1af9f0 100644 --- a/login_server/src/cpp/model/table/EmailOptIn.cpp +++ b/login_server/src/cpp/model/table/EmailOptIn.cpp @@ -42,7 +42,7 @@ namespace model { { Poco::Data::Statement insert(session); - lock(); + lock("EmailOptIn::_insertIntoDB"); assert(mUserId > 0); assert(mEmailVerificationCode > 0); diff --git a/login_server/src/cpp/model/table/Group.cpp b/login_server/src/cpp/model/table/Group.cpp new file mode 100644 index 000000000..9e4a6af66 --- /dev/null +++ b/login_server/src/cpp/model/table/Group.cpp @@ -0,0 +1,93 @@ +#include "Group.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + Group::Group() + { + } + + Group::Group(const std::string& alias, const std::string& name, const std::string& url, const std::string& home, const std::string& description) + : mAlias(alias), mName(name), mUrl(url), mHome(home), mDescription(description) + { + + } + + Group::Group(GroupTuple tuple) + : ModelBase(tuple.get<0>()), + mAlias(tuple.get<1>()), mName(tuple.get<2>()), mUrl(tuple.get<3>()), mHome(tuple.get<4>()), mDescription(tuple.get<5>()) + { + + } + + Group::~Group() + { + + } + + std::string Group::toString() + { + std::stringstream ss; + ss << "Alias: " << mAlias << std::endl; + ss << "Name: " << mName << std::endl; + ss << "Url: " << mUrl << std::endl; + ss << "Home: " << mHome << std::endl; + ss << "Description:" << mDescription << std::endl; + return ss.str(); + } + + Poco::Data::Statement Group::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, alias, name, url, home, description FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mAlias), into(mName), into(mUrl), into(mHome), into(mDescription); + + return select; + } + + Poco::Data::Statement Group::_loadAllFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id, alias, name, url, home, description FROM " << getTableName(); + + return select; + } + + Poco::Data::Statement Group::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + // typedef Poco::Tuple, int> UserTuple; + select << "SELECT id, alias, name, url, home, description FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; + + return select; + } + Poco::Data::Statement Group::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where alias = ?" + , into(mID), use(mAlias); + + return select; + + } + Poco::Data::Statement Group::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + + insert << "INSERT INTO " << getTableName() + << " (alias, name, url, home, description) VALUES(?,?,?,?,?)" + , use(mAlias), use(mName), use(mUrl), use(mHome), use(mDescription); + + return insert; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/Group.h b/login_server/src/cpp/model/table/Group.h new file mode 100644 index 000000000..5feb8ba14 --- /dev/null +++ b/login_server/src/cpp/model/table/Group.h @@ -0,0 +1,54 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_GROUPS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_GROUPS_INCLUDE + +#include "ModelBase.h" +#include "Poco/Tuple.h" + +namespace model { + namespace table { + + typedef Poco::Tuple GroupTuple; + + class Group : public ModelBase + { + public: + Group(); + Group(const std::string& alias, const std::string& name, const std::string& url, const std::string& home, const std::string& description); + Group(GroupTuple userTuple); + ~Group(); + + // generic db operations + const char* getTableName() const { return "groups"; } + std::string toString(); + + inline const std::string& getAlias() const { return mAlias; } + inline const std::string& getName() const { std::shared_lock _lock(mSharedMutex); return mName; } + inline const std::string& getDescription() const { std::shared_lock _lock(mSharedMutex); return mDescription; } + inline const std::string& getUrl() const { std::shared_lock _lock(mSharedMutex); return mUrl; } + inline const std::string& getHome() const { SHARED_LOCK; return mHome; } + + inline void setName(const std::string& name) { std::unique_lock _lock(mSharedMutex); mName = name; } + inline void setDescription(const std::string& desc) { std::unique_lock _lock(mSharedMutex); mDescription = desc; } + inline void setUrl(const std::string& url) { std::unique_lock _lock(mSharedMutex); mUrl = url; } + inline void setHome(const std::string& home) { UNIQUE_LOCK; mHome = home; } + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + std::string mAlias; + std::string mName; + std::string mUrl; + std::string mHome; + std::string mDescription; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_GROUPS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaAccount.cpp b/login_server/src/cpp/model/table/HederaAccount.cpp new file mode 100644 index 000000000..14850b272 --- /dev/null +++ b/login_server/src/cpp/model/table/HederaAccount.cpp @@ -0,0 +1,135 @@ +#include "HederaAccount.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + + HederaAccount::HederaAccount() + : mUserId(0), mAccountHederaId(0), mAccountKeyId(0), mBalance(0), mType(0) + { + + } + + HederaAccount::HederaAccount(int user_id, int account_hedera_id, int account_key_id, Poco::UInt64 balance/* = 0*/, ServerConfig::HederaNetworkType type /*= ServerConfig::HEDERA_MAINNET*/) + : mUserId(user_id), mAccountHederaId(account_hedera_id), mAccountKeyId(account_key_id), mBalance(balance), mType(type) + { + + } + + HederaAccount::HederaAccount(const HederaAccountTuple& tuple) + : ModelBase(tuple.get<0>()), + mUserId(tuple.get<1>()), mAccountHederaId(tuple.get<2>()), mAccountKeyId(tuple.get<3>()), + mBalance(tuple.get<4>()), mType(tuple.get<5>()), mUpdated(tuple.get<6>()) + { + + } + + HederaAccount::~HederaAccount() + { + + } + + std::string HederaAccount::toString() + { + std::stringstream ss; + ss << "user id: " << std::to_string(mUserId) << std::endl; + ss << "account hedera id: " << std::to_string(mAccountHederaId) << std::endl; + ss << "account crypto key id: " << std::to_string(mAccountKeyId) << std::endl; + // balance in tinybars, 100,000,000 tinybar = 1 HashBar + ss << "account balance: " << std::to_string((double)(mBalance) * 100000000.0) << " HBAR" << std::endl; + ss << "Hedera Net Type: " << hederaNetworkTypeToString((ServerConfig::HederaNetworkType)mType) << std::endl; + ss << "last update: " << Poco::DateTimeFormatter::format(mUpdated, "%f.%m.%Y %H:%M:%S") << std::endl; + + return ss.str(); + } + + std::string HederaAccount::getBalanceString() + { + char buffer[65]; memset(buffer, 0, 65); + //100,000,000 +#ifdef _WIN32 + sprintf_s(buffer, 64, "%.8f HBAR", (double)(mBalance) / 100000000.0); +#else + sprintf(buffer, "%.8f HBAR", (double)(mBalance) / 100000000.0); +#endif + return std::string(buffer); + } + + + const char* HederaAccount::hederaNetworkTypeToString(ServerConfig::HederaNetworkType type) + { + switch (type) { + case ServerConfig::HEDERA_MAINNET: return "Mainnet"; + case ServerConfig::HEDERA_TESTNET: return "Testnet"; + case ServerConfig::HEDERA_UNKNOWN: return "unknown"; + default: return ""; + } + } + + ServerConfig::HederaNetworkType HederaAccount::hederaNetworkTypeFromString(const std::string& typeString) + { + if ("MAINNET" == typeString || "Mainnet" == typeString) { + return ServerConfig::HEDERA_MAINNET; + } + if ("TESTNET" == typeString || "Testnet" == typeString) { + return ServerConfig::HEDERA_TESTNET; + } + return ServerConfig::HEDERA_UNKNOWN; + } + + NodeServerType HederaAccount::networkTypeToNodeServerType(ServerConfig::HederaNetworkType type) + { + switch (type) { + case ServerConfig::HEDERA_MAINNET: return NODE_SERVER_HEDERA_MAINNET_NODE; + case ServerConfig::HEDERA_TESTNET: return NODE_SERVER_HEDERA_TESTNET_NODE; + default: return NODE_SERVER_TYPE_NONE; + } + } + + Poco::Data::Statement HederaAccount::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, account_hedera_id, account_key_id, balance, network_type, updated FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUserId), into(mAccountHederaId), into(mAccountKeyId), into(mBalance), into(mType), into(mUpdated); + + return select; + + } + + Poco::Data::Statement HederaAccount::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + select << "SELECT id, user_id, account_hedera_id, account_key_id, balance, network_type, updated FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; + + return select; + } + Poco::Data::Statement HederaAccount::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where account_hedera_id = ?" + , into(mID), use(mAccountHederaId); + + return select; + } + Poco::Data::Statement HederaAccount::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + + insert << "INSERT INTO " << getTableName() + << " (user_id, account_hedera_id, account_key_id, balance, network_type) VALUES(?,?,?,?,?)" + , use(mUserId), use(mAccountHederaId), use(mAccountKeyId), use(mBalance), use(mType); + + return insert; + } + + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaAccount.h b/login_server/src/cpp/model/table/HederaAccount.h new file mode 100644 index 000000000..c3557afbe --- /dev/null +++ b/login_server/src/cpp/model/table/HederaAccount.h @@ -0,0 +1,65 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_ACCOUNTS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_ACCOUNTS_INCLUDE + +//#include "ModelBase.h" +#include "../../ServerConfig.h" +#include "Poco/Tuple.h" + +#include "NodeServer.h" + +namespace model { + namespace table { + + typedef Poco::Tuple HederaAccountTuple; + + + + class HederaAccount : public ModelBase + { + public: + HederaAccount(); + HederaAccount(int user_id, int account_hedera_id, int account_key_id, Poco::UInt64 balance = 0, ServerConfig::HederaNetworkType type = ServerConfig::HEDERA_MAINNET); + HederaAccount(const HederaAccountTuple& tuple); + ~HederaAccount(); + + // generic db operations + const char* getTableName() const { return "hedera_accounts"; } + std::string toString(); + + + static const char* hederaNetworkTypeToString(ServerConfig::HederaNetworkType type); + static NodeServerType networkTypeToNodeServerType(ServerConfig::HederaNetworkType type); + static ServerConfig::HederaNetworkType hederaNetworkTypeFromString(const std::string& typeString); + + inline int getAccountHederaId() const { return mAccountHederaId; } + inline int getCryptoKeyId() const { return mAccountKeyId; } + inline int getUserId() const { return mUserId; } + + inline Poco::UInt64 getBalance() { return mBalance; } + inline double getBalanceDouble() { return (double)mBalance / 100000000.0; } + std::string getBalanceString(); + + inline ServerConfig::HederaNetworkType getNetworkType() { return (ServerConfig::HederaNetworkType)mType; } + + + inline std::string getUpdatedString() { return Poco::DateTimeFormatter::format(mUpdated, "%f.%m.%Y %H:%M:%S"); } + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + int mUserId; + int mAccountHederaId; + int mAccountKeyId; + Poco::UInt64 mBalance; + int mType; + Poco::DateTime mUpdated; + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_ACCOUNTS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaId.cpp b/login_server/src/cpp/model/table/HederaId.cpp new file mode 100644 index 000000000..c9fe71631 --- /dev/null +++ b/login_server/src/cpp/model/table/HederaId.cpp @@ -0,0 +1,100 @@ +#include "HederaId.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + HederaId::HederaId() + : mShardNum(0), mRealmNum(0), mNum(0) + { + + } + + HederaId::HederaId(Poco::UInt64 shardNum, Poco::UInt64 realmNum, Poco::UInt64 num) + : mShardNum(shardNum), mRealmNum(realmNum), mNum(num) + { + + } + + HederaId::HederaId(const HederaIdTuple& tuple) + : ModelBase(tuple.get<0>()), + mShardNum(tuple.get<1>()), mRealmNum(tuple.get<2>()), mNum(tuple.get<3>()) + { + + } + + HederaId::~HederaId() + { + + } + + std::string HederaId::toString() + { + std::stringstream ss; + ss << std::to_string(mShardNum) << "." << std::to_string(mRealmNum) << "." << std::to_string(mNum) << std::endl; + return ss.str(); + } + + int HederaId::getID() + { + auto cm = ConnectionManager::getInstance(); + Poco::ScopedLock _lock(mWorkMutex); + + assert(mNum != 0|| mShardNum != 0 || mRealmNum != 0); + if (mID) return mID; + + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + select << "SELECT id FROM " << getTableName() + << " where shardNum = ? AND realmNum = ? AND num = ?" + , into(mID), use(mShardNum), use(mRealmNum), use(mNum); + + try { + if (1 == select.execute()) { + return mID; + } + } + catch (Poco::Exception& ex) { + addError(new ParamError("HederaId::getID", "mysql error try to find existing entry", ex.message())); + sendErrorsAsEmail(); + } + insertIntoDB(true); + return mID; + } + + + Poco::Data::Statement HederaId::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + + Poco::Data::Statement select(session); + + select << "SELECT id, shardNum, realmNum, num FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mShardNum), into(mRealmNum), into(mNum); + + return select; + } + Poco::Data::Statement HederaId::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where shardNum = ? AND realmNum = ? AND num = ?" + , into(mID), use(mShardNum), use(mRealmNum), use(mNum); + + return select; + } + Poco::Data::Statement HederaId::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + + insert << "INSERT INTO " << getTableName() + << " (shardNum, realmNum, num) VALUES(?,?,?)" + , use(mShardNum), use(mRealmNum), use(mNum); + + return insert; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaId.h b/login_server/src/cpp/model/table/HederaId.h new file mode 100644 index 000000000..bed00168f --- /dev/null +++ b/login_server/src/cpp/model/table/HederaId.h @@ -0,0 +1,46 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_IDS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_IDS_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" + +namespace model { + namespace table { + + typedef Poco::Tuple HederaIdTuple; + + class HederaId : public ModelBase + { + public: + HederaId(); + HederaId(Poco::UInt64 shardNum, Poco::UInt64 realmNum, Poco::UInt64 num); + HederaId(const HederaIdTuple& tuple); + ~HederaId(); + + // generic db operations + const char* getTableName() const { return "hedera_ids"; } + std::string toString(); + + //! \brief check if hedera id already in db, then return id, else insert in db and return + int getID(); + + inline Poco::UInt64 getShardNum() const { return mShardNum; } + inline Poco::UInt64 getRealmNum() const { return mRealmNum; } + inline Poco::UInt64 getNum() const { return mNum; } + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + Poco::UInt64 mShardNum; + Poco::UInt64 mRealmNum; + Poco::UInt64 mNum; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_IDS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaTopic.cpp b/login_server/src/cpp/model/table/HederaTopic.cpp new file mode 100644 index 000000000..0f03e8373 --- /dev/null +++ b/login_server/src/cpp/model/table/HederaTopic.cpp @@ -0,0 +1,113 @@ +#include "HederaTopic.h" +#include "Poco/DateTimeFormatter.h" +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + HederaTopic::HederaTopic() + : mTopicHederaId(0), mAutoRenewAccountHederaId(0), mAutoRenewPeriod(0), mGroupId(0), mAdminKeyId(0), mSubmitKeyId(0),mSequenceNumber(0) + { + + } + + HederaTopic::HederaTopic(const HederaTopicTuple& tuple) + : ModelBase(tuple.get<0>()), mTopicHederaId(tuple.get<1>()), mName(tuple.get<2>()), mAutoRenewAccountHederaId(tuple.get<3>()), + mAutoRenewPeriod(tuple.get<4>()), mGroupId(tuple.get<5>()), mAdminKeyId(tuple.get<6>()), mSubmitKeyId(tuple.get<7>()), + mCurrentTimeout(tuple.get<8>()), mSequenceNumber(tuple.get<9>()), mUpdated(tuple.get<10>()) + { + + } + + HederaTopic::HederaTopic(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId) + : mTopicHederaId(0), mName(name), mAutoRenewAccountHederaId(autoRenewAccountId), mAutoRenewPeriod(autoRenewPeriod), mGroupId(groupId), + mAdminKeyId(0), mSubmitKeyId(0), mSequenceNumber(0) + { + + } + + HederaTopic::~HederaTopic() + { + } + + std::string HederaTopic::toString() + { + std::stringstream ss; + ss << std::endl; + ss << "Topic Hedera id: " << std::to_string(mTopicHederaId) << std::endl; + ss << "Name: " << mName << std::endl; + ss << "Auto Renew Account Hedera id: " << std::to_string(mAutoRenewAccountHederaId) << std::endl; + ss << "Auto Renew Period: " << std::to_string(mAutoRenewPeriod) << " seconds" << std::endl; + ss << "Group id: " << std::to_string(mGroupId) << std::endl; + ss << "Admin Key id: " << std::to_string(mAdminKeyId) << std::endl; + ss << "Submit Key id: " << std::to_string(mSubmitKeyId) << std::endl; + ss << "Hedera Topic Timeout: " << Poco::DateTimeFormatter::format(mCurrentTimeout, "%f.%m.%Y %H:%M:%S") << std::endl; + ss << "Hedera Topic Sequence Number: " << std::to_string(mSequenceNumber) << std::endl; + ss << "Updated: " << Poco::DateTimeFormatter::format(mUpdated, "%f.%m.%Y %H:%M:%S") << std::endl; + return ss.str(); + } + + std::string HederaTopic::getAutoRenewPeriodString() const + { + return secondsToReadableDuration(mAutoRenewPeriod) + " (" + std::to_string(mAutoRenewPeriod) + " seconds)"; + } + + std::string HederaTopic::getCurrentTimeoutString() const + { + return Poco::DateTimeFormatter::format(mCurrentTimeout, "%Y-%m-%d %H:%M:%S"); + } + std::string HederaTopic::getUpdatedString() const + { + return Poco::DateTimeFormatter::format(mUpdated, "%Y-%m-%d %H:%M:%S"); + } + + Poco::Data::Statement HederaTopic::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, topic_hedera_id, name, auto_renew_account_hedera_id, auto_renew_period, " + << "group_id, admin_key_id, submit_key_id, current_timeout, sequence_number, updated FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mTopicHederaId), into(mName), into(mAutoRenewAccountHederaId), into(mAutoRenewPeriod) + , into(mGroupId), into(mAdminKeyId), into(mSubmitKeyId), into(mCurrentTimeout), into(mSequenceNumber), into(mUpdated); + + return select; + + } + Poco::Data::Statement HederaTopic::_loadAllFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + //typedef Poco::Tuple HederaTopicTuple; + + select << "SELECT id, topic_hedera_id, name, auto_renew_account_hedera_id, auto_renew_period, " + << "group_id, admin_key_id, submit_key_id, current_timeout, sequence_number, updated FROM " << getTableName(); + + return select; + } + Poco::Data::Statement HederaTopic::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where topic_hedera_id = ? " + << " AND name = ? " + , into(mID), use(mTopicHederaId), use(mName); + + return select; + } + Poco::Data::Statement HederaTopic::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + + insert << "INSERT INTO " << getTableName() + << " (topic_hedera_id, name, auto_renew_account_hedera_id, auto_renew_period," + << " group_id, admin_key_id, submit_key_id, current_timeout, sequence_number) VALUES(?,?,?,?,?,?,?,?,?)" + , use(mTopicHederaId), use(mName), use(mAutoRenewAccountHederaId), use(mAutoRenewPeriod) + , use(mGroupId), use(mAdminKeyId), use(mSubmitKeyId), use(mCurrentTimeout), use(mSequenceNumber); + + return insert; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/HederaTopic.h b/login_server/src/cpp/model/table/HederaTopic.h new file mode 100644 index 000000000..8ae2c5c13 --- /dev/null +++ b/login_server/src/cpp/model/table/HederaTopic.h @@ -0,0 +1,67 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_TOPICS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_TOPICS_INCLUDE + +#include "ModelBase.h" + +namespace model { + namespace table { + + + typedef Poco::Tuple HederaTopicTuple; + + class HederaTopic : public ModelBase + { + public: + HederaTopic(); + HederaTopic(const HederaTopicTuple& tuple); + HederaTopic(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId); + ~HederaTopic(); + + // generic db operations + const char* getTableName() const { return "hedera_topics"; } + std::string toString(); + + inline Poco::UInt32 getTopicHederaId() const { return mTopicHederaId; } + inline std::string getName() const { return mName; } + inline Poco::UInt32 getAutoRenewAccountId() const { return mAutoRenewAccountHederaId; } + inline Poco::UInt32 getAutoRenewPeriod() const { return mAutoRenewPeriod; } + std::string getAutoRenewPeriodString() const; + inline Poco::UInt32 getGroupId() const { return mGroupId;} + inline Poco::DateTime getCurrentTimeout() const { return mCurrentTimeout; } + std::string getCurrentTimeoutString() const; + inline Poco::UInt64 getSequenceNumber() const { return mSequenceNumber; } + inline Poco::DateTime getUpdated() const { return mUpdated; } + std::string getUpdatedString() const; + + inline void setTopicHederaID(Poco::UInt32 topidHederaId) { mTopicHederaId = topidHederaId;} + inline void setName(std::string name) { mName = name; } + inline void setAutoRenewPeriod(Poco::UInt32 autoRenewPeriod) { mAutoRenewPeriod = autoRenewPeriod; } + inline void setGroupId(Poco::UInt32 groupId) { mGroupId = groupId; } + inline void setCurrentTimeout(Poco::DateTime currentTimeOut) { mCurrentTimeout = currentTimeOut; } + inline void setSequeceNumber(Poco::UInt64 sequenceNumber) { mSequenceNumber = sequenceNumber; } + + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + Poco::UInt32 mTopicHederaId; + std::string mName; + Poco::UInt32 mAutoRenewAccountHederaId; + // in seconds + Poco::UInt32 mAutoRenewPeriod; + Poco::UInt32 mGroupId; + Poco::UInt32 mAdminKeyId; + Poco::UInt32 mSubmitKeyId; + Poco::DateTime mCurrentTimeout; + Poco::UInt64 mSequenceNumber; + Poco::DateTime mUpdated; + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_HEDERA_TOPICS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/ModelBase.cpp b/login_server/src/cpp/model/table/ModelBase.cpp index ad64a4e54..d8c4803df 100644 --- a/login_server/src/cpp/model/table/ModelBase.cpp +++ b/login_server/src/cpp/model/table/ModelBase.cpp @@ -42,23 +42,33 @@ namespace model { { //printf("ModelBase::insertIntoDB with table: %s\n", getTableName()); auto cm = ConnectionManager::getInstance(); - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement insert = _insertIntoDB(session); size_t resultCount = 0; try { - if (insert.execute() == 1) { + if (insert.execute(true) == 1) { // load id from db if (loadId) { - Poco::Data::Statement select = _loadIdFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); + Poco::Data::Statement select = _loadIdFromDB(session); try { - return select.execute() == 1; + select.executeAsync(); + auto result_count = select.wait(); + if (result_count != 1) { + int zahl = 0; + } + return result_count; } catch (Poco::Exception& ex) { addError(new ParamError(getTableName(), "mysql error by select id", ex.displayText().data())); addError(new ParamError(getTableName(), "data set: ", toString().data())); } + session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + select = _loadIdFromDB(session); + //Poco::Data::Statement select = _loadIdFromDB(session); + select.execute(); } else { return true; @@ -73,9 +83,29 @@ namespace model { return false; } + bool ModelBase::isExistInDB() + { + auto cm = ConnectionManager::getInstance(); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement select = _loadIdFromDB(session); + try { + select.executeAsync(); + return select.wait() == 1; + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by select id, check if exist in db", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: ", toString().data())); + } + return false; + } + bool ModelBase::deleteFromDB() { - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; if (mID == 0) { addError(new Error(getTableName(), "id is zero, couldn't delete from db")); return false; @@ -89,10 +119,8 @@ namespace model { return deleteStmt.execute() == 1; } catch (Poco::Exception& ex) { - lock(); addError(new ParamError(getTableName(), "mysql error by delete", ex.displayText().data())); addError(new ParamError(getTableName(), "id: ", mID)); - unlock(); } return false; } @@ -138,6 +166,13 @@ namespace model { throw Poco::Exception(message); } + Poco::Data::Statement ModelBase::_loadAllFromDB(Poco::Data::Session session) + { + std::string message = getTableName(); + message += "::_loadAllFromDB not implemented"; + throw Poco::Exception(message); + } + Poco::DateTime ModelBase::parseElopageDate(std::string dateString) { std::string decodedDateString = ""; @@ -174,5 +209,29 @@ namespace model { return Poco::DateTime(Poco::Timestamp()); } + + std::string ModelBase::secondsToReadableDuration(Poco::UInt64 seconds) + { + Poco::UInt64 value = 0; + std::string result; + std::string unit_name; + + if (seconds <= 60) { + return std::to_string(seconds) + " seconds"; + } + else if (seconds <= 60 * 60) { + Poco::UInt64 minutes = round(seconds / 60); + return "~" + std::to_string(minutes) + " minutes"; + } + else if (seconds <= 60 * 60 * 24) { + Poco::UInt64 hours = round(seconds / 60 / 60); + return "~" + std::to_string(hours) + " hours"; + } + else { + Poco::UInt64 days = round(seconds / 60 / 60 / 24); + return "~" + std::to_string(days) + " days"; + } + return ""; + } } } diff --git a/login_server/src/cpp/model/table/ModelBase.h b/login_server/src/cpp/model/table/ModelBase.h index 3d3bc3ab8..2c62d6528 100644 --- a/login_server/src/cpp/model/table/ModelBase.h +++ b/login_server/src/cpp/model/table/ModelBase.h @@ -16,6 +16,9 @@ #include //using namespace Poco::Data::Keywords; +#define SHARED_LOCK std::shared_lock _lock(mSharedMutex) +#define UNIQUE_LOCK std::unique_lock _lock(mSharedMutex) + namespace model { namespace table { @@ -24,7 +27,7 @@ namespace model { MYSQL_CONDITION_OR }; - class ModelBase : public UniLib::lib::MultithreadContainer, public ErrorList + class ModelBase : public UniLib::lib::MultithreadContainer, public NotificationList { public: ModelBase(int id) :mID(id), mReferenceCount(1) {} @@ -32,16 +35,29 @@ namespace model { virtual ~ModelBase(); virtual const char* getTableName() const = 0; + //! called from within of some catch to give more information for debugging, don't lock mutex! virtual std::string toString() = 0; template size_t updateIntoDB(const std::string& fieldName, const T& fieldValue ); + template + size_t updateIntoDB(std::string fieldNames[2], const T1& fieldValue1, const T2& fieldValue2); + template + size_t updateIntoDB(std::string fieldNames[3], const T1& fieldValue1, const T2& fieldValue2, const T3& fieldValue3); + template + size_t updateIntoDB(std::string fieldNames[4], const T1& fieldValue1, const T2& fieldValue2, const T3& fieldValue3, const T4& fieldValue4); template size_t loadFromDB(const std::string& fieldName, const T& fieldValue); + //! \brief count columes for "SELECT count(id) from where = group by id"; + template + size_t countColumns(const std::string& fieldName, const T& fieldValue); template bool isExistInDB(const std::string& fieldName, const T& fieldValue); + bool isExistInDB(); template std::vector loadFromDB(const std::string& fieldName, const WhereFieldType& fieldValue, int expectedResults = 0); + template + std::vector loadAllFromDB(); template size_t loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND); template @@ -50,11 +66,13 @@ namespace model { bool deleteFromDB(); - inline void setID(int id) { lock(); mID = id; unlock(); } - inline int getID() { lock(); int id = mID; unlock(); return id; } + inline void setID(int id) { UNIQUE_LOCK; mID = id; } + inline int getID() const { SHARED_LOCK; return mID; } static Poco::DateTime parseElopageDate(std::string dateString); + static std::string secondsToReadableDuration(Poco::UInt64 seconds); + // for poco auto ptr void duplicate(); void release(); @@ -62,6 +80,7 @@ namespace model { virtual Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session) = 0; virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName) = 0; virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + virtual Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); virtual Poco::Data::Statement _insertIntoDB(Poco::Data::Session session) = 0; @@ -69,7 +88,9 @@ namespace model { int mID; // for poco auto ptr - int mReferenceCount; + int mReferenceCount; + + mutable std::shared_mutex mSharedMutex; }; @@ -77,7 +98,8 @@ namespace model { size_t ModelBase::loadFromDB(const std::string& fieldName, const T& fieldValue) { auto cm = ConnectionManager::getInstance(); - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement select = _loadFromDB(session, fieldName); select, Poco::Data::Keywords::useRef(fieldValue); @@ -93,11 +115,36 @@ namespace model { return resultCount; } + template + size_t ModelBase::countColumns(const std::string& fieldName, const T& fieldValue) + { + auto cm = ConnectionManager::getInstance(); + //Poco::ScopedLock _lock(mWorkMutex); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select(session); + size_t count = 0; + select + << "SELECT count(id) from " << getTableName() + << " where " << fieldName << " LIKE ? group by " << fieldName + ,Poco::Data::Keywords::into(count) + ,Poco::Data::Keywords::useRef(fieldValue); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by selecting", ex.displayText().data())); + addError(new ParamError(getTableName(), "field name for select: ", fieldName.data())); + } + return count; + } + template bool ModelBase::isExistInDB(const std::string& fieldName, const T& fieldValue) { auto cm = ConnectionManager::getInstance(); - Poco::ScopedLock _lock(mWorkMutex); + //Poco::ScopedLock _lock(mWorkMutex); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement select(session); int id; @@ -124,7 +171,8 @@ namespace model { { //printf("ModelBase::loadFromDB multi\n"); std::vector results; - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; //return results; if (expectedResults > 0) { results.reserve(expectedResults); @@ -139,7 +187,7 @@ namespace model { resultCount = select.execute(); } catch (Poco::Exception& ex) { - lock(); + lock("ModelBase::loadFromDB"); addError(new ParamError(getTableName(), "mysql error by multi selecting", ex.displayText().data())); addError(new ParamError(getTableName(), "field name for select: ", fieldName.data())); unlock(); @@ -147,15 +195,42 @@ namespace model { return results; } + template + std::vector ModelBase::loadAllFromDB() + { + std::vector results; + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; + auto cm = ConnectionManager::getInstance(); + try { + auto connection = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select = _loadAllFromDB(connection); + select, Poco::Data::Keywords::into(results); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by selecting all", ex.displayText().data())); + } + + return results; + } + catch (Poco::Exception& ex) { + addError(new Error(getTableName(), "loadAllFromDB not implemented!")); + return results; + } + } + template std::vector ModelBase::loadFromDB(const std::vector& fieldNames, const std::vector& fieldValues, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/, int expectedResults/* = 0*/) { std::vector results; - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; if (fieldNames.size() != fieldValues.size() || fieldNames.size() <= 1) { - lock(); addError(new Error(getTableName(), "fieldNames and fieldValues size don't match or smaller as 1")); - unlock(); return results; } if (expectedResults > 0) { @@ -174,12 +249,10 @@ namespace model { resultCount = select.execute(); } catch (Poco::Exception& ex) { - lock(); addError(new ParamError(getTableName(), "mysql error by multi selecting", ex.displayText().data())); for (auto it = fieldNames.begin(); it != fieldNames.end(); it++) { addError(new ParamError(getTableName(), "field name for select: ", (*it).data())); } - unlock(); } return results; } @@ -188,7 +261,8 @@ namespace model { size_t ModelBase::loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { auto cm = ConnectionManager::getInstance(); - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement select = _loadFromDB(session, fieldNames, conditionType); select, Poco::Data::Keywords::useRef(field1Value), Poco::Data::Keywords::useRef(field2Value); @@ -198,7 +272,6 @@ namespace model { resultCount = select.execute(); } catch (Poco::Exception& ex) { - lock(); addError(new ParamError(getTableName(), "mysql error by selecting, maybe more than one result?", ex.displayText())); int count = 0; for (auto it = fieldNames.begin(); it != fieldNames.end(); it++) { @@ -206,7 +279,6 @@ namespace model { } //addError(new ParamError(getTableName(), "field name for select: ", fieldName.data())); - unlock(); } return resultCount; } @@ -216,7 +288,8 @@ namespace model { size_t ModelBase::updateIntoDB(const std::string& fieldName, const T& fieldValue) { auto cm = ConnectionManager::getInstance(); - Poco::ScopedLock _lock(mWorkMutex); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement update(session); @@ -233,14 +306,127 @@ namespace model { resultCount = update.execute(); } catch (Poco::Exception& ex) { - lock(); addError(new ParamError(getTableName(), "mysql error by update", ex.displayText().data())); addError(new ParamError(getTableName(), "field name for update: ", fieldName.data())); - unlock(); + } return resultCount; } + template + size_t ModelBase::updateIntoDB(std::string fieldNames[2], const T1& fieldValue1, const T2& fieldValue2) + { + auto cm = ConnectionManager::getInstance(); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement update(session); + + if (mID == 0) { + addError(new Error("ModelBase::updateIntoDB", "id is zero")); + return 0; + } + + update << "UPDATE " << getTableName() << " SET "; + for (int i = 0; i < 2; i++) { + if (i) update << ", "; + update << fieldNames[i] << " = ? "; + } + update << "WHERE id = ?" + , Poco::Data::Keywords::bind(fieldValue1), Poco::Data::Keywords::bind(fieldValue2) + , Poco::Data::Keywords::bind(mID); + + + size_t resultCount = 0; + try { + resultCount = update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by update 2", ex.displayText())); + for (int i = 0; i < 2; i++) { + addError(new ParamError(getTableName(), "field name for update: ", fieldNames[i])); + } + } + return resultCount; + } + template + size_t ModelBase::updateIntoDB(std::string fieldNames[3], const T1& fieldValue1, const T2& fieldValue2, const T3& fieldValue3) + { + auto cm = ConnectionManager::getInstance(); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement update(session); + + if (mID == 0) { + addError(new Error("ModelBase::updateIntoDB", "id is zero")); + return 0; + } + + update << "UPDATE " << getTableName() << " SET "; + for (int i = 0; i < 3; i++) { + if (i) update << ", "; + update << fieldNames[i] << " = ? "; + } + update << "WHERE id = ?" + , Poco::Data::Keywords::bind(fieldValue1), Poco::Data::Keywords::bind(fieldValue2), Poco::Data::Keywords::bind(fieldValue3) + , Poco::Data::Keywords::bind(mID); + + + size_t resultCount = 0; + try { + resultCount = update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by update 3", ex.displayText())); + for (int i = 0; i < 3; i++) { + addError(new ParamError(getTableName(), "field name for update: ", fieldNames[i])); + } + + } + return resultCount; + } + + template + size_t ModelBase::updateIntoDB(std::string fieldNames[4], const T1& fieldValue1, const T2& fieldValue2, const T3& fieldValue3, const T4& fieldValue4) + { + auto cm = ConnectionManager::getInstance(); + Poco::ScopedLock _poco_lock(mWorkMutex); + UNIQUE_LOCK; + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement update(session); + + if (mID == 0) { + addError(new Error("ModelBase::updateIntoDB", "id is zero")); + return 0; + } + + update << "UPDATE " << getTableName() << " SET "; + for (int i = 0; i < 4; i++) { + if (i) update << ", "; + update << fieldNames[i] << " = ? "; + } + update << "WHERE id = ?" + , Poco::Data::Keywords::bind(fieldValue1), Poco::Data::Keywords::bind(fieldValue2) + , Poco::Data::Keywords::bind(fieldValue3), Poco::Data::Keywords::bind(fieldValue4) + , Poco::Data::Keywords::bind(mID); + + + size_t resultCount = 0; + try { + resultCount = update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "mysql error by update 4", ex.displayText())); + for (int i = 0; i < 3; i++) { + addError(new ParamError(getTableName(), "field name for update: ", fieldNames[i])); + } + + } + return resultCount; + } + + // ******************** Generic Tasks ************************************ diff --git a/login_server/src/cpp/model/table/NodeServer.cpp b/login_server/src/cpp/model/table/NodeServer.cpp new file mode 100644 index 000000000..a7431e3ac --- /dev/null +++ b/login_server/src/cpp/model/table/NodeServer.cpp @@ -0,0 +1,132 @@ + +#include "NodeServer.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + + bool NodeServerIsHederaNode(NodeServerType type) { + return type == NODE_SERVER_HEDERA_MAINNET_NODE || type == NODE_SERVER_HEDERA_TESTNET_NODE; + } + bool NodeServerHasGroup(NodeServerType type) { + return type == NODE_SERVER_GRADIDO_NODE || type == NODE_SERVER_GRADIDO_COMMUNITY; + } + + + NodeServer::NodeServer() + : mPort(0), mGroupId(0), mServerType(0), mNodeHederaId(0) + { + + } + + NodeServer::NodeServer(const std::string& url, int port, int groupId, NodeServerType type, int nodeHederaId) + : mUrl(url), mPort(port), mGroupId(groupId), mServerType(type), mNodeHederaId(nodeHederaId) + { + } + + + + NodeServer::NodeServer(const NodeServerTuple& tuple) + : ModelBase(tuple.get<0>()), + mUrl(tuple.get<1>()), mPort(tuple.get<2>()), mGroupId(tuple.get<3>()), + mServerType(tuple.get<4>()), mNodeHederaId(tuple.get<5>()), mLastLiveSign(tuple.get<6>()) + { + + } + + NodeServer::~NodeServer() + { + + } + + std::string NodeServer::toString() + { + std::stringstream ss; + + ss << "id: " << getID() << std::endl; + ss << mUrl << ":" << mPort << std::endl; + ss << "group id: " << mGroupId << std::endl; + ss << "server type: " << nodeServerTypeToString((NodeServerType)mServerType) << std::endl; + ss << "node hedera id: " << mNodeHederaId << std::endl; + ss << "last live sign: " << Poco::DateTimeFormatter::format(mLastLiveSign, "%f.%m.%Y %H:%M:%S") << std::endl; + + return ss.str(); + } + + const char* NodeServer::nodeServerTypeToString(NodeServerType type) + { + switch (type) { + case NODE_SERVER_NONE: return "none"; + case NODE_SERVER_GRADIDO_NODE: return "Gradido Node"; + case NODE_SERVER_GRADIDO_COMMUNITY: return "Gradido Community"; + case NODE_SERVER_HEDERA_MAINNET_NODE: return "Hedera Mainnet Node"; + case NODE_SERVER_HEDERA_TESTNET_NODE: return "Hedera Testnet Node"; + default: return ""; + } + } + + Poco::Data::Statement NodeServer::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, url, port, group_id, server_type, node_hedera_id, last_live_sign FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUrl), into(mPort), into(mGroupId), into(mServerType), into(mNodeHederaId), into(mLastLiveSign); + + return select; + } + + Poco::Data::Statement NodeServer::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + // typedef Poco::Tuple, int> UserTuple; + select << "SELECT id, url, port, group_id, server_type, node_hedera_id, last_live_sign FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; + + return select; + } + Poco::Data::Statement NodeServer::_loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + { + Poco::Data::Statement select(session); + select << "SELECT id, url, port, group_id, server_type, node_hedera_id, last_live_sign FROM " << getTableName() + << " where " << fieldNames[0] << " = ? "; + if (conditionType == MYSQL_CONDITION_AND) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " AND " << fieldNames[i] << " = ?"; + } + } + else if (conditionType == MYSQL_CONDITION_OR) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " OR " << fieldNames[i] << " = ?"; + } + } + return select; + } + + Poco::Data::Statement NodeServer::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + Poco::ScopedLock _lock(mWorkMutex); + + select << "SELECT id FROM " << getTableName() + << " where url = ? AND port = ? " + , into(mID), use(mUrl), use(mPort); + + return select; + } + + Poco::Data::Statement NodeServer::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); + + insert << "INSERT INTO " << getTableName() + << " (url, port, group_id, server_type, node_hedera_id) VALUES(?,?,?,?,?)" + , use(mUrl), use(mPort), use(mGroupId), use(mServerType), use(mNodeHederaId); + + return insert; + } + + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/NodeServer.h b/login_server/src/cpp/model/table/NodeServer.h new file mode 100644 index 000000000..ea1e3e10e --- /dev/null +++ b/login_server/src/cpp/model/table/NodeServer.h @@ -0,0 +1,75 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_NODE_SERVER_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_NODE_SERVER_INCLUDE + +#include "ModelBase.h" +#include "Poco/Tuple.h" + +namespace model { + namespace table { + + typedef Poco::Tuple NodeServerTuple; + + enum NodeServerType { + NODE_SERVER_NONE, + NODE_SERVER_GRADIDO_NODE, + NODE_SERVER_GRADIDO_COMMUNITY, + NODE_SERVER_HEDERA_MAINNET_NODE, + NODE_SERVER_HEDERA_TESTNET_NODE, + NODE_SERVER_TYPE_COUNT, + NODE_SERVER_TYPE_NONE + }; + bool NodeServerIsHederaNode(NodeServerType type); + bool NodeServerHasGroup(NodeServerType type); + + + class NodeServer : public ModelBase + { + public: + NodeServer(); + NodeServer(const std::string& url, int port, int groupId, NodeServerType type, int nodeHederaId); + NodeServer(const NodeServerTuple& tuple); + ~NodeServer(); + + // generic db operations + const char* getTableName() const { return "node_servers"; } + std::string toString(); + + static const char* nodeServerTypeToString(NodeServerType type); + + inline void setLastLiveSign(Poco::DateTime lastLiveSign) { UNIQUE_LOCK; mLastLiveSign = lastLiveSign; } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !ATTENTION! if using set port or set url review CronManager code + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + inline std::string getUrl() const { return mUrl; } + inline int getPort() const { return mPort; } + inline std::string getUrlWithPort() const { return mUrl + ":" + std::to_string(mPort); } + inline int getGroupId() const { return mGroupId; } + inline NodeServerType getNodeServerType() const { return (NodeServerType)mServerType; } + inline bool isHederaNode() const { return NodeServerIsHederaNode((NodeServerType)mServerType);} + inline bool hasGroup() const {return NodeServerHasGroup((NodeServerType)mServerType);} + inline int getNodeHederaId() const { return mNodeHederaId; } + inline Poco::DateTime getLastLiveSign() const { SHARED_LOCK; return mLastLiveSign; } + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + std::string mUrl; + int mPort; + int mGroupId; + int mServerType; + int mNodeHederaId; + Poco::DateTime mLastLiveSign; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_NODE_SERVER_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/PendingTask.cpp b/login_server/src/cpp/model/table/PendingTask.cpp new file mode 100644 index 000000000..72fe10a21 --- /dev/null +++ b/login_server/src/cpp/model/table/PendingTask.cpp @@ -0,0 +1,226 @@ +#include "PendingTask.h" + +#include "Poco/JSON/Parser.h" +//#include + +using namespace Poco::Data::Keywords; + +namespace model +{ + namespace table + { + PendingTask::PendingTask() + : mUserId(0), mTaskTypeId(TASK_TYPE_NONE) + { + + } + PendingTask::PendingTask(int userId, std::string serializedProtoRequest, TaskType type) + : mUserId(userId), mRequest((const unsigned char*)serializedProtoRequest.data(), serializedProtoRequest.size()), + mTaskTypeId(TASK_TYPE_NONE) + { + + } + PendingTask::PendingTask(const PendingTaskTuple& tuple) + : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mHederaId(tuple.get<2>()), + mRequest(tuple.get<3>()), mCreated(tuple.get<4>()), mFinished(tuple.get<5>()), + mResultJsonString(tuple.get<6>()), mTaskTypeId(tuple.get<7>()), mChildPendingTaskId(tuple.get<8>()), mParentPendingTaskId(tuple.get<9>()) + { + + } + PendingTask::~PendingTask() + { + + } + + void PendingTask::setRequest(const std::string& serializedProto) + { + UNIQUE_LOCK; + mRequest.assignRaw((const unsigned char*)serializedProto.data(), serializedProto.size()); + } + + void PendingTask::setResultJson(Poco::JSON::Object::Ptr result) + { + UNIQUE_LOCK; + std::stringstream ss; + result->stringify(ss); + mResultJsonString = ss.str(); + } + + Poco::JSON::Object::Ptr PendingTask::getResultJson() const + { + std::string temp; + { + SHARED_LOCK; + temp = mResultJsonString; + } + Poco::JSON::Parser parser; + Poco::Dynamic::Var result; + try + { + result = parser.parse(temp); + } + catch (Poco::JSON::JSONException& jsone) + { + return nullptr; + } + + return result.extract(); + + } + + bool PendingTask::updateRequest() + { + Poco::ScopedLock _poco_lock(mWorkMutex); + SHARED_LOCK; + if (!mID) { + return 0; + } + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement update(session); + + update << "UPDATE " << getTableName() << " SET request = ? where id = ?;", + use(mRequest), use(mID); + + try { + return 1 == update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "[updateRequest] mysql error by update", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: \n", toString().data())); + } + //printf("data valid: %s\n", toString().data()); + return 0; + } + + bool PendingTask::updateFinishedAndResult() + { + Poco::ScopedLock _poco_lock(mWorkMutex); + SHARED_LOCK; + if (!mID) { + return 0; + } + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement update(session); + + update << "UPDATE " << getTableName() << " SET finished = ?, result_json = ? where id = ?;", + use(mFinished), use(mResultJsonString), use(mID); + + try { + return 1 == update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "[updateFinishedAndResult] mysql error by update", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: \n", toString().data())); + } + //printf("data valid: %s\n", toString().data()); + return 0; + } + + + + std::string PendingTask::toString() + { + std::stringstream ss; + ss << "id: " << mID << std::endl; + ss << "user_id: " << mUserId << std::endl; + ss << "created: " << Poco::DateTimeFormatter::format(mCreated, "%f.%m.%Y %H:%M:%S") << std::endl; + ss << "task type: " << typeToString((TaskType)mTaskTypeId) << std::endl; + ss << "child pending task id: " << std::to_string(mChildPendingTaskId) << std::endl; + ss << "parent pending task id: " << std::to_string(mParentPendingTaskId) << std::endl; + return ss.str(); + } + + + const char* PendingTask::typeToString(TaskType type) + { + switch (type) { + case TASK_TYPE_GROUP_CREATE: return "group create"; + case TASK_TYPE_GROUP_ADD_MEMBER: return "group add member"; + case TASK_TYPE_CREATION: return "creation"; + case TASK_TYPE_TRANSFER: return "transfer"; + case TASK_TYPE_HEDERA_TOPIC_CREATE: return "hedera topic create"; + case TASK_TYPE_HEDERA_TOPIC_MESSAGE: return "hedera topic send message"; + case TASK_TYPE_HEDERA_ACCOUNT_CREATE: return "hedera account create"; + default: return ""; + } + return ""; + } + /*enum TaskType { + TASK_TYPE_NONE = 0, + TASK_TYPE_GROUP_CREATE = 1, + TASK_TYPE_GROUP_ADD_MEMBER = 2, + TASK_TYPE_CREATION = 10, + TASK_TYPE_TRANSFER = 11, + TASK_TYPE_HEDERA_TOPIC_CREATE = 20, + TASK_TYPE_HEDERA_TOPIC_MESSAGE = 21, + TASK_TYPE_HEDERA_ACCOUNT_CREATE = 25, + + };*/ + bool PendingTask::isGradidoTransaction(TaskType type) + { + if (type && type < TASK_TYPE_HEDERA_TOPIC_CREATE) + return true; + return false; + } + + bool PendingTask::isHederaTransaction(TaskType type) + { + if (type && type >= TASK_TYPE_HEDERA_TOPIC_CREATE) + return true; + return false; + } + + Poco::Data::Statement PendingTask::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, hedera_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUserId), into(mHederaId), into(mRequest), into(mCreated), into(mFinished), into(mResultJsonString), + into(mTaskTypeId), into(mChildPendingTaskId), into(mParentPendingTaskId); + + return select; + } + + Poco::Data::Statement PendingTask::_loadAllFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, hedera_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " + << getTableName() << " order by id"; + + return select; + } + + Poco::Data::Statement PendingTask::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id FROM " << getTableName() + << " WHERE user_id = ? " + << " AND hedera_id = ? " + << " AND request = ?" + << " AND TIMESTAMPDIFF(SECOND, created, ?) = 0 " + << " AND task_type_id = ? " + , into(mID), use(mUserId), use(mHederaId), use(mRequest), use(mCreated), use(mTaskTypeId); + + return select; + } + + + Poco::Data::Statement PendingTask::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + + insert << "INSERT INTO " << getTableName() + << " (user_id, hedera_id, request, created, task_type_id, child_pending_task_id, parent_pending_task_id) VALUES(?,?,?,?,?,?,?)" + , use(mUserId), use(mHederaId), use(mRequest), use(mCreated), use(mTaskTypeId), use(mChildPendingTaskId), use(mParentPendingTaskId); + + return insert; + } + } +} \ No newline at end of file diff --git a/login_server/src/cpp/model/table/PendingTask.h b/login_server/src/cpp/model/table/PendingTask.h new file mode 100644 index 000000000..4fa84a73b --- /dev/null +++ b/login_server/src/cpp/model/table/PendingTask.h @@ -0,0 +1,95 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_PENDING_TASKS_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_PENDING_TASKS_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" + +#include + +namespace model { + namespace table { + + enum TaskType { + TASK_TYPE_NONE = 0, + TASK_TYPE_GROUP_CREATE = 1, + TASK_TYPE_GROUP_ADD_MEMBER = 2, + TASK_TYPE_CREATION = 10, + TASK_TYPE_TRANSFER = 11, + TASK_TYPE_HEDERA_TOPIC_CREATE = 20, + TASK_TYPE_HEDERA_TOPIC_MESSAGE = 21, + TASK_TYPE_HEDERA_ACCOUNT_CREATE = 25, + TASK_TYPE_HEDERA_ACCOUNT_TRANSFER = 26 + + }; + + typedef Poco::Tuple PendingTaskTuple; + + class PendingTask : public ModelBase + { + public: + + PendingTask(); + PendingTask(int userId, std::string serializedProtoRequest, TaskType type); + PendingTask(const PendingTaskTuple& tuple); + + ~PendingTask(); + + // generic db operations + const char* getTableName() const { return "pending_tasks"; } + std::string toString(); + + //! \brief update table row with current request + bool updateRequest(); + + bool updateFinishedAndResult(); + + inline int getUserId() const { SHARED_LOCK; return mUserId; } + inline int getHederaId() const { SHARED_LOCK; return mHederaId; } + inline const std::vector& getRequest() const { SHARED_LOCK; return mRequest.content(); } + inline std::string getRequestCopy() const { SHARED_LOCK; return std::string((const char*)mRequest.content().data(), mRequest.content().size()); } + Poco::JSON::Object::Ptr getResultJson() const; + inline Poco::DateTime getCreated() const { SHARED_LOCK; return mCreated; } + inline TaskType getTaskType() const { SHARED_LOCK; return (TaskType)mTaskTypeId; } + inline const char* getTaskTypeString() const { SHARED_LOCK; return typeToString((TaskType)mTaskTypeId); } + inline int getChildPendingTaskId() const { SHARED_LOCK; return mChildPendingTaskId; } + inline int getParentPendingTaskId() const { SHARED_LOCK; return mParentPendingTaskId; } + + inline void setUserId(int userId) { UNIQUE_LOCK; mUserId = userId; } + inline void setHederaId(int hederaId) { UNIQUE_LOCK; mHederaId = hederaId; } + void setRequest(const std::string& serializedProto); + inline void setFinished(Poco::DateTime date) { UNIQUE_LOCK; mFinished = date; } + void setResultJson(Poco::JSON::Object::Ptr result); + inline void setTaskType(TaskType type) { UNIQUE_LOCK; mTaskTypeId = type; } + inline void setChildPendingTaskId(int childPendingTaskId) {UNIQUE_LOCK; mChildPendingTaskId = childPendingTaskId;} + inline void setParentPendingTaskId(int parentPendingTaskId) { UNIQUE_LOCK; mParentPendingTaskId = parentPendingTaskId; } + + inline bool isGradidoTransaction() { SHARED_LOCK; return isGradidoTransaction((TaskType)mTaskTypeId); } + static bool isGradidoTransaction(TaskType type); + inline bool isHederaTransaction() { SHARED_LOCK; return isHederaTransaction((TaskType)mTaskTypeId); } + static bool isHederaTransaction(TaskType type); + + static const char* typeToString(TaskType type); + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + int mUserId; + int mHederaId; + Poco::Data::BLOB mRequest; + Poco::DateTime mCreated; + Poco::DateTime mFinished; + std::string mResultJsonString; + int mTaskTypeId; + int mChildPendingTaskId; + int mParentPendingTaskId; + + std::shared_mutex mSharedMutex; + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_PENDING_TASKS_INCLUDE \ No newline at end of file diff --git a/login_server/src/cpp/model/table/User.cpp b/login_server/src/cpp/model/table/User.cpp index e6f694c71..91cfbf7f1 100644 --- a/login_server/src/cpp/model/table/User.cpp +++ b/login_server/src/cpp/model/table/User.cpp @@ -7,6 +7,8 @@ #include "../../SingletonManager/MemoryManager.h" +#include "../../controller/Group.h" + using namespace Poco::Data::Keywords; namespace model { @@ -17,16 +19,17 @@ namespace model { { } - User::User(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) - : mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mDisabled(false), mRole(ROLE_NOT_LOADED) + User::User(const std::string& email, const std::string& first_name, const std::string& last_name, int group_id, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) + : mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mDisabled(false), mGroupId(group_id), mRole(ROLE_NOT_LOADED) { + setEmail(email); } //id, first_name, last_name, email, pubkey, created, email_checked User::User(UserTuple tuple) : ModelBase(tuple.get<0>()), - mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()), - mPublicKey(tuple.get<4>()), mCreated(tuple.get<5>()), mEmailChecked(tuple.get<6>()), mDisabled(tuple.get<7>()), + mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()), mUsername(tuple.get<4>()), + mPublicKey(tuple.get<5>()), mCreated(tuple.get<6>()), mEmailChecked(tuple.get<7>()), mDisabled(tuple.get<8>()), mGroupId(tuple.get<9>()), mPasswordHashed(0), mLanguageKey("de"), mRole(ROLE_NOT_LOADED) { @@ -60,18 +63,31 @@ namespace model { } } + void User::setEmail(const std::string& email) + { + std::unique_lock _lock(mSharedMutex); + mEmail = email; + + unsigned char email_hash[crypto_generichash_BYTES]; + + crypto_generichash(email_hash, crypto_generichash_BYTES, + (const unsigned char*)email.data(), email.size(), + NULL, 0); + mEmailHash = Poco::Nullable(Poco::Data::BLOB(email_hash, crypto_generichash_BYTES)); + } + Poco::Data::Statement User::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); if (mPasswordHashed) { - insert << "INSERT INTO users (email, first_name, last_name, password, language) VALUES(?,?,?,?,?);", - use(mEmail), use(mFirstName), use(mLastName), bind(mPasswordHashed), use(mLanguageKey); + insert << "INSERT INTO users (email, first_name, last_name, username, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?);", + use(mEmail), use(mFirstName), use(mLastName), use(mUsername), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId); } else { - insert << "INSERT INTO users (email, first_name, last_name, language) VALUES(?,?,?,?);", - use(mEmail), use(mFirstName), use(mLastName), use(mLanguageKey); + insert << "INSERT INTO users (email, first_name, last_name, username, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?);", + use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mEmailHash), use(mLanguageKey), use(mGroupId); } return insert; @@ -84,13 +100,13 @@ namespace model { _fieldName = getTableName() + std::string(".id"); } Poco::Data::Statement select(session); - select << "SELECT " << getTableName() << ".id, email, first_name, last_name, password, pubkey, privkey, created, email_checked, language, disabled, user_roles.role_id " + select << "SELECT " << getTableName() << ".id, email, first_name, last_name, username, password, pubkey, privkey, email_hash, created, email_checked, language, disabled, group_id, user_roles.role_id " << " FROM " << getTableName() << " LEFT JOIN user_roles ON " << getTableName() << ".id = user_roles.user_id " << " WHERE " << _fieldName << " = ?" , - into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), - into(mPublicKey), into(mPrivateKey), into(mCreated), into(mEmailChecked), - into(mLanguageKey), into(mDisabled), into(mRole); + into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mUsername), into(mPasswordHashed), + into(mPublicKey), into(mPrivateKey), into(mEmailHash), into(mCreated), into(mEmailChecked), + into(mLanguageKey), into(mDisabled), into(mGroupId), into(mRole); return select; @@ -100,7 +116,7 @@ namespace model { { Poco::Data::Statement select(session); // typedef Poco::Tuple, int> UserTuple; - select << "SELECT id, first_name, last_name, email, pubkey, created, email_checked, disabled FROM " << getTableName() + select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << getTableName() << " where " << fieldName << " LIKE ?"; @@ -116,7 +132,7 @@ namespace model { } // typedef Poco::Tuple, int> UserTuple; - select << "SELECT id, first_name, last_name, email, pubkey, created, email_checked, disabled FROM " << getTableName() + select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << getTableName() << " where " << fieldNames[0] << " LIKE ?"; if (conditionType == MYSQL_CONDITION_AND) { for (int i = 1; i < fieldNames.size(); i++) { @@ -228,8 +244,8 @@ namespace model { auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement update(session); - update << "UPDATE users SET first_name = ?, last_name = ?, disabled = ?, language = ? where id = ?;", - use(mFirstName), use(mLastName), use(mDisabled), use(mLanguageKey), use(mID); + update << "UPDATE users SET first_name = ?, last_name = ?, username = ?, disabled = ?, language = ? where id = ?;", + use(mFirstName), use(mLastName), use(mUsername), use(mDisabled), use(mLanguageKey), use(mID); try { @@ -266,12 +282,14 @@ namespace model { auto mm = MemoryManager::getInstance(); auto pubkeyHex = mm->getFreeMemory(65); auto privkeyHex = mm->getFreeMemory(161); + auto email_hash = mm->getFreeMemory(crypto_generichash_BYTES+1); //char pubkeyHex[65], privkeyHex[161]; //memset(pubkeyHex, 0, 65); //memset(privkeyHex, 0, 161); memset(*pubkeyHex, 0, 65); memset(*privkeyHex, 0, 161); + memset(*email_hash, 0, crypto_generichash_BYTES + 1); std::stringstream ss; @@ -281,18 +299,25 @@ namespace model { if (!mPrivateKey.isNull()) { sodium_bin2hex(*privkeyHex, 161, mPrivateKey.value().content().data(), mPrivateKey.value().content().size()); } - + if (!mEmailHash.isNull()) { + sodium_bin2hex(*email_hash, crypto_generichash_BYTES + 1, mEmailHash.value().content().data(), mEmailHash.value().content().size()); + } + + ss << mUsername << std::endl; ss << mFirstName << " " << mLastName << " <" << mEmail << ">" << std::endl; ss << "password hash: " << mPasswordHashed << std::endl; ss << "public key: " << (char*)*pubkeyHex << std::endl; ss << "private key: " << (char*)*privkeyHex << std::endl; + ss << "email hash: " << (char*)*email_hash << std::endl; ss << "created: " << Poco::DateTimeFormatter::format(mCreated, "%f.%m.%Y %H:%M:%S") << std::endl; ss << "email checked: " << mEmailChecked << std::endl; ss << "language key: " << mLanguageKey << std::endl; ss << "disabled: " << mDisabled << std::endl; + ss << "group id: " << std::to_string(mGroupId) << std::endl; mm->releaseMemory(pubkeyHex); mm->releaseMemory(privkeyHex); + mm->releaseMemory(email_hash); return ss.str(); } @@ -301,8 +326,10 @@ namespace model { { auto mm = MemoryManager::getInstance(); auto pubkeyHex = mm->getFreeMemory(65); + auto email_hash = mm->getFreeMemory(crypto_generichash_BYTES + 1); memset(*pubkeyHex, 0, 65); + memset(*email_hash, 0, crypto_generichash_BYTES + 1); std::stringstream ss; @@ -310,15 +337,23 @@ namespace model { sodium_bin2hex(*pubkeyHex, 65, mPublicKey.value().content().data(), mPublicKey.value().content().size()); } + if (!mEmailHash.isNull()) { + sodium_bin2hex(*email_hash, crypto_generichash_BYTES + 1, mEmailHash.value().content().data(), mEmailHash.value().content().size()); + } + + ss << "" << mUsername << "
"; ss << "" << mFirstName << " " << mLastName << " <" << mEmail << ">" << "
"; ss << "public key: " << (char*)*pubkeyHex << "
"; + ss << "email hash: " << (char*)*email_hash << "
"; ss << "created: " << Poco::DateTimeFormatter::format(mCreated, "%f.%m.%Y %H:%M:%S") << "
"; ss << "email checked: " << mEmailChecked << "
"; ss << "language key: " << mLanguageKey << "
"; - ss << "role: " << UserRoles::typeToString(getRole()) << "
"; + ss << "role: " << UserRole::typeToString(getRole()) << "
"; ss << "disabled: " << mDisabled << "
"; + ss << "group_id: " << std::to_string(mGroupId) << std::endl; mm->releaseMemory(pubkeyHex); + mm->releaseMemory(email_hash); return ss.str(); } @@ -339,6 +374,36 @@ namespace model { return pubkeyHexString; } + MemoryBin* User::getPublicKeyCopy() const + { + SHARED_LOCK; + auto mm = MemoryManager::getInstance(); + auto public_key_size = getPublicKeySize(); + if (!public_key_size) return nullptr; + auto pubkey = mm->getFreeMemory(getPublicKeySize()); + memcpy(*pubkey, getPublicKey(), public_key_size); + return pubkey; + } + + std::string User::getPrivateKeyEncryptedHex() const + { + std::shared_lock _lock(mSharedMutex); + auto mm = MemoryManager::getInstance(); + std::string privkeyHexString; + + if (!mPrivateKey.isNull()) { + auto priv_key_size = mPrivateKey.value().content().size(); + auto privkeyHex = mm->getFreeMemory(priv_key_size+1); + + memset(*privkeyHex, 0, priv_key_size+1); + sodium_bin2hex(*privkeyHex, 65, mPrivateKey.value().content().data(), priv_key_size); + privkeyHexString = std::string((const char*)privkeyHex->data(), privkeyHex->size() - 1); + mm->releaseMemory(privkeyHex); + } + + return privkeyHexString; + } + Poco::JSON::Object User::getJson() { @@ -349,6 +414,7 @@ namespace model { userObj.set("first_name", mFirstName); userObj.set("last_name", mLastName); userObj.set("email", mEmail); + userObj.set("username", mUsername); //userObj.set("state", userStateToString(mState)); auto createTimeStamp = mCreated.timestamp(); @@ -357,12 +423,16 @@ namespace model { userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); userObj.set("disabled", mDisabled); try { - userObj.set("role", UserRoles::typeToString(getRole())); + userObj.set("role", UserRole::typeToString(getRole())); } catch (Poco::Exception ex) { addError(new ParamError("User::getJson", "exception by getting role", ex.displayText().data())); sendErrorsAsEmail(); } + auto group = controller::Group::load(mGroupId); + if (!group.isNull()) { + userObj.set("group_alias", group->getModel()->getAlias()); + } unlock(); return userObj; diff --git a/login_server/src/cpp/model/table/User.h b/login_server/src/cpp/model/table/User.h index 50908b049..876803cf8 100644 --- a/login_server/src/cpp/model/table/User.h +++ b/login_server/src/cpp/model/table/User.h @@ -9,9 +9,8 @@ //#include "Poco/Nullable.h" //#include "Poco/Data/LOB.h" -#include -#include "UserRoles.h" +#include "UserRole.h" namespace model { namespace table { @@ -29,14 +28,14 @@ namespace model { USER_FIELDS_LANGUAGE }; - typedef Poco::Tuple, Poco::DateTime, int, int> UserTuple; + typedef Poco::Tuple, Poco::DateTime, int, int, int> UserTuple; class User : public ModelBase { public: User(); User(UserTuple tuple); - User(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); + User(const std::string& email, const std::string& first_name, const std::string& last_name, int group_id, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); ~User(); // generic db operations @@ -54,34 +53,42 @@ namespace model { size_t updateFieldsFromCommunityServer(); // default getter unlocked - inline const std::string getEmail() const { std::shared_lock _lock(mSharedMutex); return mEmail; } - inline const std::string getFirstName() const { std::shared_lock _lock(mSharedMutex); return mFirstName; } - inline const std::string getLastName() const { std::shared_lock _lock(mSharedMutex); return mLastName; } - inline std::string getNameWithEmailHtml() const { std::shared_lock _lock(mSharedMutex); return mFirstName + " " + mLastName + " <" + mEmail + ">"; } - inline std::string getNameWithEmail() const { std::shared_lock _lock(mSharedMutex); return mFirstName + " " + mLastName + "<" + mEmail + ">"; } - inline const Poco::UInt64 getPasswordHashed() const { std::shared_lock _lock(mSharedMutex); return mPasswordHashed; } - inline RoleType getRole() const { std::shared_lock _lock(mSharedMutex); if (mRole.isNull()) return ROLE_NONE; return static_cast(mRole.value()); } - inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } + inline const std::string getEmail() const { SHARED_LOCK; return mEmail; } + inline const std::string getFirstName() const { SHARED_LOCK; return mFirstName; } + inline const std::string getLastName() const { SHARED_LOCK; return mLastName; } + inline const std::string getUsername() const { SHARED_LOCK; return mUsername; } + inline std::string getNameWithEmailHtml() const { SHARED_LOCK; return mFirstName + " " + mLastName + " <" + mEmail + ">"; } + inline const Poco::UInt64 getPasswordHashed() const { SHARED_LOCK; return mPasswordHashed; } + inline int getGroupId() const { SHARED_LOCK; return mGroupId; } + inline RoleType getRole() const { SHARED_LOCK; if (mRole.isNull()) return ROLE_NONE; return static_cast(mRole.value()); } + inline const unsigned char* getPublicKey() const { SHARED_LOCK; if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } + MemoryBin* getPublicKeyCopy() const; + inline size_t getPublicKeySize() const { SHARED_LOCK; if (mPublicKey.isNull()) return 0; return mPublicKey.value().content().size(); } std::string getPublicKeyHex() const; + std::string getPrivateKeyEncryptedHex() const; - inline bool hasPrivateKeyEncrypted() const { std::shared_lock _lock(mSharedMutex); return !mPrivateKey.isNull(); } - inline const std::vector& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); } - inline bool isEmailChecked() const { std::shared_lock _lock(mSharedMutex); return mEmailChecked; } - inline const std::string getLanguageKey() const { std::shared_lock _lock(mSharedMutex); return mLanguageKey; } - inline bool isDisabled() const { std::shared_lock _lock(mSharedMutex); return mDisabled; } + inline bool hasPrivateKeyEncrypted() const { SHARED_LOCK; return !mPrivateKey.isNull(); } + inline bool hasPublicKey() const { SHARED_LOCK; return !mPublicKey.isNull(); } + inline bool hasEmailHash() const { SHARED_LOCK; return !mEmailHash.isNull(); } + inline const std::vector& getPrivateKeyEncrypted() const { SHARED_LOCK; return mPrivateKey.value().content(); } + inline bool isEmailChecked() const { SHARED_LOCK; return mEmailChecked; } + inline const std::string getLanguageKey() const { SHARED_LOCK; return mLanguageKey; } + inline bool isDisabled() const { SHARED_LOCK; return mDisabled; } // default setter unlocked - inline void setEmail(const std::string& email) { std::unique_lock _lock(mSharedMutex); mEmail = email; } - inline void setFirstName(const std::string& first_name) { std::unique_lock _lock(mSharedMutex); mFirstName = first_name; } - inline void setLastName(const std::string& last_name) { std::unique_lock _lock(mSharedMutex); mLastName = last_name; } - inline void setPasswordHashed(const Poco::UInt64& passwordHashed) { std::unique_lock _lock(mSharedMutex); mPasswordHashed = passwordHashed; } + void setEmail(const std::string& email); + inline void setFirstName(const std::string& first_name) { UNIQUE_LOCK; mFirstName = first_name; } + inline void setLastName(const std::string& last_name) { UNIQUE_LOCK; mLastName = last_name; } + inline void setUsername(const std::string& username) { UNIQUE_LOCK; mUsername = username; } + inline void setPasswordHashed(const Poco::UInt64& passwordHashed) { UNIQUE_LOCK; mPasswordHashed = passwordHashed; } void setPublicKey(const unsigned char* publicKey); //! \brief set encrypted private key //! \param privateKey copy data, didn't move memory bin void setPrivateKey(const MemoryBin* privateKey); - inline void setEmailChecked(bool emailChecked) { std::unique_lock _lock(mSharedMutex); mEmailChecked = emailChecked; } - inline void setLanguageKey(const std::string& languageKey) { std::unique_lock _lock(mSharedMutex); mLanguageKey = languageKey; } - inline void setDisabled(bool disabled) { std::unique_lock _lock(mSharedMutex); mDisabled = disabled; } + inline void setEmailChecked(bool emailChecked) { UNIQUE_LOCK; mEmailChecked = emailChecked; } + inline void setLanguageKey(const std::string& languageKey) { UNIQUE_LOCK; mLanguageKey = languageKey; } + inline void setDisabled(bool disabled) { UNIQUE_LOCK; mDisabled = disabled; } + inline void setGroupId(int groupId) { UNIQUE_LOCK; mGroupId = groupId; } Poco::JSON::Object getJson(); @@ -97,11 +104,13 @@ namespace model { std::string mEmail; std::string mFirstName; std::string mLastName; + std::string mUsername; Poco::UInt64 mPasswordHashed; Poco::Nullable mPublicKey; Poco::Nullable mPrivateKey; + Poco::Nullable mEmailHash; // sodium generic hash (currently blake2b) // created: Mysql DateTime Poco::DateTime mCreated; @@ -111,10 +120,12 @@ namespace model { //! if set to true, prevent login bool mDisabled; + int mGroupId; + // from neighbor tables Poco::Nullable mRole; - mutable std::shared_mutex mSharedMutex; + }; } } diff --git a/login_server/src/cpp/model/table/UserBackups.cpp b/login_server/src/cpp/model/table/UserBackup.cpp similarity index 77% rename from login_server/src/cpp/model/table/UserBackups.cpp rename to login_server/src/cpp/model/table/UserBackup.cpp index 0dbf0adfa..eac412b85 100644 --- a/login_server/src/cpp/model/table/UserBackups.cpp +++ b/login_server/src/cpp/model/table/UserBackup.cpp @@ -1,4 +1,4 @@ -#include "UserBackups.h" +#include "UserBackup.h" #include "../../controller/User.h" using namespace Poco::Data::Keywords; @@ -6,44 +6,44 @@ using namespace Poco::Data::Keywords; namespace model { namespace table { - UserBackups::UserBackups() + UserBackup::UserBackup() : mUserId(0), mMnemonicType(0) { detectMnemonic(); } - UserBackups::UserBackups(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) + UserBackup::UserBackup(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type) : mUserId(user_id), mPassphrase(passphrase), mMnemonicType(type) { detectMnemonic(); } - UserBackups::UserBackups(const UserBackupsTuple& tuple) + UserBackup::UserBackup(const UserBackupsTuple& tuple) : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mPassphrase(tuple.get<2>()), mMnemonicType(tuple.get<3>()) { detectMnemonic(); } - UserBackups::~UserBackups() + UserBackup::~UserBackup() { } - Poco::Data::Statement UserBackups::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement UserBackup::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); - - lock(); + Poco::ScopedLock _lock(mWorkMutex); + insert << "INSERT INTO " << getTableName() << " (user_id, passphrase, mnemonic_type) VALUES(?,?,?)" , use(mUserId), bind(mPassphrase), use(mMnemonicType); - unlock(); + return insert; } - Poco::Data::Statement UserBackups::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserBackup::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -55,7 +55,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement UserBackup::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); @@ -66,7 +66,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserBackup::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -77,7 +77,7 @@ namespace model { return select; } - Poco::Data::Statement UserBackups::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + Poco::Data::Statement UserBackup::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { Poco::Data::Statement select(session); if (fieldNames.size() <= 1) { @@ -107,7 +107,7 @@ namespace model { } // generic db operations - std::string UserBackups::toString() + std::string UserBackup::toString() { std::stringstream ss; ss << "user_id: " << mUserId << std::endl; @@ -116,7 +116,7 @@ namespace model { return ss.str(); } - void UserBackups::detectMnemonic() + void UserBackup::detectMnemonic() { if (mMnemonicType == -1) { const static char* function_name = "UserBackups::detectMnemonic"; diff --git a/login_server/src/cpp/model/table/UserBackups.h b/login_server/src/cpp/model/table/UserBackup.h similarity index 88% rename from login_server/src/cpp/model/table/UserBackups.h rename to login_server/src/cpp/model/table/UserBackup.h index d307f8f5d..c5084b0f7 100644 --- a/login_server/src/cpp/model/table/UserBackups.h +++ b/login_server/src/cpp/model/table/UserBackup.h @@ -9,13 +9,13 @@ namespace model { typedef Poco::Tuple UserBackupsTuple; - class UserBackups : public ModelBase + class UserBackup : public ModelBase { public: - UserBackups(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); - UserBackups(const UserBackupsTuple& tuple); - UserBackups(); - ~UserBackups(); + UserBackup(int user_id, const std::string& passphrase, ServerConfig::Mnemonic_Types type); + UserBackup(const UserBackupsTuple& tuple); + UserBackup(); + ~UserBackup(); // generic db operations const char* getTableName() const { return "user_backups"; } diff --git a/login_server/src/cpp/model/table/UserRoles.cpp b/login_server/src/cpp/model/table/UserRole.cpp similarity index 72% rename from login_server/src/cpp/model/table/UserRoles.cpp rename to login_server/src/cpp/model/table/UserRole.cpp index 0d1f673e9..37281699e 100644 --- a/login_server/src/cpp/model/table/UserRoles.cpp +++ b/login_server/src/cpp/model/table/UserRole.cpp @@ -1,4 +1,4 @@ -#include "UserRoles.h" +#include "UserRole.h" using namespace Poco::Data::Keywords; @@ -6,41 +6,41 @@ namespace model { namespace table { - UserRoles::UserRoles(int user_id, RoleType type) + UserRole::UserRole(int user_id, RoleType type) : mUserId(user_id), mType(type) { } - UserRoles::UserRoles(const UserRolesTuple& tuple) + UserRole::UserRole(const UserRolesTuple& tuple) : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mType(tuple.get<2>()) { } - UserRoles::UserRoles() + UserRole::UserRole() { } - UserRoles::~UserRoles() + UserRole::~UserRole() { } - Poco::Data::Statement UserRoles::_insertIntoDB(Poco::Data::Session session) + Poco::Data::Statement UserRole::_insertIntoDB(Poco::Data::Session session) { Poco::Data::Statement insert(session); + Poco::ScopedLock _lock(mWorkMutex); - lock(); insert << "INSERT INTO " << getTableName() << " (user_id, role_id) VALUES(?,?)" , use(mUserId), bind(mType); - unlock(); + return insert; } - Poco::Data::Statement UserRoles::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserRole::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -52,7 +52,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadIdFromDB(Poco::Data::Session session) + Poco::Data::Statement UserRole::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); @@ -63,7 +63,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + Poco::Data::Statement UserRole::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); @@ -74,7 +74,7 @@ namespace model { return select; } - Poco::Data::Statement UserRoles::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + Poco::Data::Statement UserRole::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { Poco::Data::Statement select(session); if (fieldNames.size() <= 1) { @@ -104,7 +104,7 @@ namespace model { } // generic db operations - std::string UserRoles::toString() + std::string UserRole::toString() { std::stringstream ss; ss << "user_id: " << mUserId << std::endl; @@ -112,7 +112,7 @@ namespace model { return ss.str(); } - const char* UserRoles::typeToString(RoleType type) + const char* UserRole::typeToString(RoleType type) { switch (type) { case ROLE_NOT_LOADED: return "not loaded"; diff --git a/login_server/src/cpp/model/table/UserRoles.h b/login_server/src/cpp/model/table/UserRole.h similarity index 90% rename from login_server/src/cpp/model/table/UserRoles.h rename to login_server/src/cpp/model/table/UserRole.h index 7b3fad790..7683bff94 100644 --- a/login_server/src/cpp/model/table/UserRoles.h +++ b/login_server/src/cpp/model/table/UserRole.h @@ -17,13 +17,13 @@ namespace model { typedef Poco::Tuple UserRolesTuple; - class UserRoles : public ModelBase + class UserRole : public ModelBase { public: - UserRoles(int user_id, RoleType type); - UserRoles(const UserRolesTuple& tuple); - UserRoles(); - ~UserRoles(); + UserRole(int user_id, RoleType type); + UserRole(const UserRolesTuple& tuple); + UserRole(); + ~UserRole(); // generic db operations const char* getTableName() const { return "user_roles"; } diff --git a/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp b/login_server/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp index fa8048e6a..5e035f3de 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 SecretKeyCryptography; + Profiler timeUsed; + if (SecretKeyCryptography::AUTH_CREATE_ENCRYPTION_KEY_SUCCEED != 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/CPUSheduler.cpp b/login_server/src/cpp/tasks/CPUSheduler.cpp index 9f4552ec4..b1c71c0ce 100644 --- a/login_server/src/cpp/tasks/CPUSheduler.cpp +++ b/login_server/src/cpp/tasks/CPUSheduler.cpp @@ -58,7 +58,7 @@ namespace UniLib { { // look at pending tasks TaskPtr task; - mPendingTasksMutex.lock(); + mPendingTasksMutex.lock("CPUSheduler::getNextUndoneTask"); for (std::list::iterator it = mPendingTasks.begin(); it != mPendingTasks.end(); it++) { if ((*it)->isAllParentsReady()) { task = *it; diff --git a/login_server/src/cpp/tasks/CPUShedulerThread.cpp b/login_server/src/cpp/tasks/CPUShedulerThread.cpp index e60a9a004..9529b536f 100644 --- a/login_server/src/cpp/tasks/CPUShedulerThread.cpp +++ b/login_server/src/cpp/tasks/CPUShedulerThread.cpp @@ -41,15 +41,21 @@ namespace UniLib { std::string name = mWaitingTask->getName(); //l->addTaskLogEntry((HASH)mWaitingTask.getResourcePtrHolder(), mWaitingTask->getResourceType(), mName.data(), name); #endif - int returnValue = mWaitingTask->run(); - if (!returnValue) { - mWaitingTask->setTaskFinished(); - } + try { + int returnValue = mWaitingTask->run(); + if (!returnValue) { + mWaitingTask->setTaskFinished(); + } #ifdef _UNI_LIB_DEBUG - //l->removeTaskLogEntry((HASH)mWaitingTask.getResourcePtrHolder()); - mSpeedLog.information("%s used on thread: %s by Task: %s of: %s (returned: %d)", - counter.string(), mName, std::string(mWaitingTask->getResourceType()), name, returnValue); + //l->removeTaskLogEntry((HASH)mWaitingTask.getResourcePtrHolder()); + mSpeedLog.information("%s used on thread: %s by Task: %s of: %s (returned: %d)", + counter.string(), mName, std::string(mWaitingTask->getResourceType()), name, returnValue); #endif + } + catch (Poco::NullPointerException& ex) { + printf("[CPUShedulerThread::ThreadFunction] Null Pointer Exception for Task type: %s\n", mWaitingTask->getResourceType()); + } + mWaitingTask = mParent->getNextUndoneTask(this); } return 0; diff --git a/login_server/src/cpp/tasks/GradidoTask.cpp b/login_server/src/cpp/tasks/GradidoTask.cpp new file mode 100644 index 000000000..cd68a6e19 --- /dev/null +++ b/login_server/src/cpp/tasks/GradidoTask.cpp @@ -0,0 +1,13 @@ +#include "GradidoTask.h" + +GradidoTask::GradidoTask() + : controller::PendingTask(new model::table::PendingTask) +{ + +} + +GradidoTask::GradidoTask(model::table::PendingTask* dbModel) + : controller::PendingTask(dbModel) +{ + +} \ No newline at end of file diff --git a/login_server/src/cpp/tasks/GradidoTask.h b/login_server/src/cpp/tasks/GradidoTask.h new file mode 100644 index 000000000..efc68601a --- /dev/null +++ b/login_server/src/cpp/tasks/GradidoTask.h @@ -0,0 +1,22 @@ +#ifndef GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_TASK +#define GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_TASK + +#include "../controller/PendingTask.h" +#include "../model/gradido/TransactionBody.h" + +class GradidoTask : public controller::PendingTask, public NotificationList +{ +public: + GradidoTask(); + GradidoTask(model::table::PendingTask* dbModel); + bool isTimeoutTask() { return false; } + + + + +protected: + + +}; + +#endif //GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_TASK \ No newline at end of file diff --git a/login_server/src/cpp/tasks/HederaTask.cpp b/login_server/src/cpp/tasks/HederaTask.cpp new file mode 100644 index 000000000..07d13c841 --- /dev/null +++ b/login_server/src/cpp/tasks/HederaTask.cpp @@ -0,0 +1,218 @@ +#include "HederaTask.h" +#include "../lib/DataTypeConverter.h" + +#include "../proto/hedera/TransactionGetReceipt.pb.h" + +#include "../controller/NodeServer.h" +#include "../controller/HederaAccount.h" +#include "../controller/HederaRequest.h" +#include "../controller/HederaTopic.h" + +#include "../SingletonManager/PendingTasksManager.h" + +HederaTask::HederaTask(const model::gradido::Transaction* transaction) + : controller::PendingTask(new model::table::PendingTask), mTransactionReceipt(nullptr), mTryCount(0) +{ + auto hedera_task_model = getModel(); + auto gradido_task_model = transaction->getModel(); + hedera_task_model->setParentPendingTaskId(gradido_task_model->getID()); + hedera_task_model->setUserId(gradido_task_model->getUserId()); + hedera_task_model->setTaskType(model::table::TASK_TYPE_HEDERA_TOPIC_MESSAGE); +} + +HederaTask::HederaTask(const model::hedera::Transaction* transaction) +: controller::PendingTask(new model::table::PendingTask), mTransactionReceipt(nullptr), mTryCount(0) +{ + auto hedera_task_model = getModel(); + //auto gradido_task_model = transaction->getModel(); + //hedera_task_model->setUserId(gradido_task_model->getUserId()); + model::table::TaskType task_type; + auto transaction_type = transaction->getType(); + switch (transaction_type) { + case model::hedera::TRANSACTION_CONSENSUS_CREATE_TOPIC: + task_type = model::table::TASK_TYPE_HEDERA_TOPIC_CREATE; break; + case model::hedera::TRANSACTION_CONSENSUS_SUBMIT_MESSAGE: + task_type = model::table::TASK_TYPE_HEDERA_TOPIC_MESSAGE; break; + case model::hedera::TRANSACTION_CRYPTO_CREATE: + task_type = model::table::TASK_TYPE_HEDERA_ACCOUNT_CREATE; break; + case model::hedera::TRANSACTION_CRYPTO_TRANSFER: + task_type = model::table::TASK_TYPE_HEDERA_ACCOUNT_TRANSFER; break; + } + hedera_task_model->setTaskType(task_type); + mTransactionID = transaction->getTransactionId(); +} + +HederaTask::HederaTask(model::table::PendingTask* dbModel) + : controller::PendingTask(dbModel), mTransactionReceipt(nullptr), mTryCount(0) +{ + +} + +HederaTask::~HederaTask() +{ + if (mTransactionReceipt) { + delete mTransactionReceipt; + mTransactionReceipt = nullptr; + } +} + +Poco::AutoPtr HederaTask::load(model::table::PendingTask* dbModel) +{ + if (!dbModel || !dbModel->isHederaTransaction()) { + return nullptr; + } + + return new HederaTask(dbModel); +} + + +Poco::DateTime HederaTask::getNextRunTime() +{ + printf("[HederaTask::getNextRunTime]\n"); + std::shared_lock _lock(mWorkingMutex); + return mLastCheck + 2000 * mTryCount * 2000; +} + +int HederaTask::run() +{ + auto result = tryQueryReceipt(); + // keep also by -1 task in db for debugging + if (result != 1 && result != -1) { + deleteFromDB(); + + } + if (result == -1 ) { + return 0; + } + + return result; +} + +void HederaTask::setTransactionReceipt(model::hedera::TransactionReceipt* transactionReceipt) +{ + assert(transactionReceipt); + + std::unique_lock _lock(mWorkingMutex); + if (mTransactionReceipt) { + printf("[HederaTask::setTransactionReceipt] warning, receipt already set\n"); + delete mTransactionReceipt; + } + mTransactionReceipt = transactionReceipt; +} + +//! \return 0 by success +//! \return 1 if hedera query failed +//! \return -1 if run after failed +//! \return -2 if not enough data for query +//! \return -3 if error in query + +int HederaTask::tryQueryReceipt() +{ + printf("[HederaTask::tryQueryReceipt]\n"); + static const char* function_name = "HederaTask::tryQueryReceipt"; + std::unique_lock _lock(mWorkingMutex); + auto node_server_type = model::table::HederaAccount::networkTypeToNodeServerType(ServerConfig::g_HederaNetworkType); + auto connection = controller::NodeServer::pick(node_server_type); + if (!connection.isValid()) { + addError(new ParamError(function_name, "couldn't find node server for server type: ", model::table::NodeServer::nodeServerTypeToString(node_server_type))); + return -2; + } + auto operator_account = controller::HederaAccount::pick(ServerConfig::g_HederaNetworkType, false); + if (operator_account.isNull()) { + addError(new ParamError(function_name, "couldn't find unencrypted operator account for hedera network type: ", ServerConfig::g_HederaNetworkType)); + return -2; + } + //auto query = model::hedera::Query::getTransactionGetReceiptQuery(mTransactionID, operator_account, connection); + auto query = model::hedera::Query::getTransactionGetReceiptQuery(mTransactionID, operator_account, connection); + HederaRequest request; + model::hedera::Response response; + try { + if (HEDERA_REQUEST_RETURN_OK == request.request(query, &response)) { + mTransactionReceipt = response.getTransactionReceipt(); + if (mTransactionReceipt) { + if (runAfterGettingReceipt()) { + return 0; + } + else { + return -1; + } + } + } + else { + if (response.getResponseCode() == proto::NOT_SUPPORTED) { + addError(new ParamError(function_name, "query in json-format:", query->toJsonString())); + //query->toJsonString() + return -3; + } + mLastCheck = Poco::Timestamp(); + mTryCount++; + } + } + catch (std::exception& ex) { + addError(new ParamError(function_name, "exception calling hedera request: ", ex.what())); + mLastCheck = Poco::Timestamp(); + mTryCount++; + } + + + return 1; +} + +bool HederaTask::runAfterGettingReceipt() +{ + assert(getModel()); + auto type = getModel()->getTaskType(); + switch (type) { + case model::table::TASK_TYPE_HEDERA_TOPIC_CREATE: + return runForHederaTopic(); + case model::table::TASK_TYPE_HEDERA_TOPIC_MESSAGE: + case model::table::TASK_TYPE_HEDERA_ACCOUNT_CREATE: + case model::table::TASK_TYPE_HEDERA_ACCOUNT_TRANSFER: + return false; + } + return true; +} + +bool HederaTask::runForHederaTopic() +{ + static const char* function_name = "HederaTask::runForHederaTopic"; + // parent pending task is set to hedera_topic.id in db + auto model = getModel(); + auto hedera_topic = controller::HederaTopic::load(model->getParentPendingTaskId()); + if (!hedera_topic.isNull()) { + auto hedera_topic_model = hedera_topic->getModel(); + auto topic_id = mTransactionReceipt->getTopicId(); + auto hedera_id = controller::HederaId::create(topic_id.shardnum(), topic_id.realmnum(), topic_id.topicnum()); + if (!hedera_id->getModel()->insertIntoDB(true)) { + addError(new Error(function_name, "error saving hedera_id")); + addError(new ParamError(function_name, "for hedera topic: ", hedera_topic_model->getID())); + addError(new ParamError(function_name, "shardnum: ", topic_id.shardnum())); + addError(new ParamError(function_name, "realmnum: ", topic_id.realmnum())); + addError(new ParamError(function_name, "topicnum", topic_id.topicnum())); + + return false; + } + hedera_topic_model->setTopicHederaID(hedera_id->getModel()->getID()); + hedera_topic_model->setSequeceNumber(mTransactionReceipt->getSequenceNumber()); + std::string fieldNames[] = { "topic_hedera_id", "sequence_number" }; + if (1 != hedera_topic_model->updateIntoDB( + fieldNames, + hedera_topic_model->getTopicHederaId(), + hedera_topic_model->getSequenceNumber() + )) { + addError(new Error(function_name, "error updating topic id")); + addError(new ParamError(function_name, "for hedera topic: ", hedera_topic_model->getID())); + addError(new ParamError(function_name, "shardnum: ", topic_id.shardnum())); + addError(new ParamError(function_name, "realmnum: ", topic_id.realmnum())); + addError(new ParamError(function_name, "topicnum", topic_id.topicnum())); + return false; + } + //! TODO think about saving also the last running hash + + } + else { + addError(new ParamError(function_name, "hedera topic not found, id: ", model->getParentPendingTaskId())); + return false; + } + return true; +} \ No newline at end of file diff --git a/login_server/src/cpp/tasks/HederaTask.h b/login_server/src/cpp/tasks/HederaTask.h new file mode 100644 index 000000000..7d6d2b98c --- /dev/null +++ b/login_server/src/cpp/tasks/HederaTask.h @@ -0,0 +1,81 @@ +#ifndef __GRADIDO_LOGIN_TASKS_HEDERA_TASKS_H +#define __GRADIDO_LOGIN_TASKS_HEDERA_TASKS_H + +#include "../model/hedera/TransactionResponse.h" +#include "../model/hedera/TransactionReceipt.h" +#include "../model/hedera/Transaction.h" +#include "../model/hedera/Query.h" +#include "../proto/hedera/BasicTypes.pb.h" +#include "../proto/hedera/Duration.pb.h" + +#include "../model/gradido/Transaction.h" + +#include "../controller/PendingTask.h" +#include "../controller/HederaAccount.h" + +#include "Poco/Timestamp.h" + +#include + +/*! + * + * \brief: Managing hedera task, especially check on receipt availability + * + * \author: Dario Rekowski + * + */ + +class HederaTask : public controller::PendingTask, public NotificationList +{ +public: + + HederaTask(const model::gradido::Transaction* transaction); + HederaTask(const model::hedera::Transaction* transaction); + HederaTask(model::table::PendingTask* dbModel); + //HederaTask(model::hedera::Query) + ~HederaTask(); + + static Poco::AutoPtr load(model::table::PendingTask* dbModel); + + inline model::hedera::TransactionResponse* getTransactionResponse() { std::shared_lock _lock(mWorkingMutex); return &mTransactionResponse; } + inline void setTransactionId(const proto::TransactionID& transactionId) { std::unique_lock _lock(mWorkingMutex); mTransactionID = transactionId; } + inline void setValidDuration(const proto::Duration& validDuration) { std::unique_lock _lock(mWorkingMutex); mValidDuration = validDuration; } + //! \param transactionReceipt take ownership and call delete if done + void setTransactionReceipt(model::hedera::TransactionReceipt* transactionReceipt); + + inline const proto::TransactionID& getTransactionId() const { std::shared_lock _lock(mWorkingMutex); return mTransactionID; } + inline const proto::Duration& getDuration() const { std::shared_lock _lock(mWorkingMutex); return mValidDuration; } + inline const model::hedera::TransactionReceipt* getTransactionReceipt() const{ std::shared_lock _lock(mWorkingMutex); return mTransactionReceipt; } + + + bool isTimeoutTask() { return true; } + Poco::DateTime getNextRunTime(); + int run(); + + //! \return 0 by success + //! \return 1 if hedera query failed + //! \return -1 if run after failed + //! \return -2 if not enough data for query + int tryQueryReceipt(); + + +protected: + + bool runAfterGettingReceipt(); + bool runForHederaTopic(); + + model::hedera::TransactionResponse mTransactionResponse; + model::hedera::TransactionReceipt* mTransactionReceipt; + + + proto::TransactionID mTransactionID; + proto::Duration mValidDuration; + + // last time checked if transaction receipt is available + Poco::Timestamp mLastCheck; + int mTryCount; + + mutable std::shared_mutex mWorkingMutex; +}; + +#endif //__GRADIDO_LOGIN_TASKS_HEDERA_TASKS_H \ No newline at end of file diff --git a/login_server/src/cpp/tasks/PendingTask.h b/login_server/src/cpp/tasks/PendingTask.h new file mode 100644 index 000000000..3e6bd976d --- /dev/null +++ b/login_server/src/cpp/tasks/PendingTask.h @@ -0,0 +1,12 @@ +#ifndef GRADIDO_LOGIN_SERVER_TASKS_PENDING_TASK +#define GRADIDO_LOGIN_SERVER_TASKS_PENDING_TASK + +/* + * @author: Dario Rekowski + * + * @date: 13.10.2020 + * + * @brief: + */ + +#endif //GRADIDO_LOGIN_SERVER_TASKS_PENDING_TASK \ 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..4ed9c3c6e 100644 --- a/login_server/src/cpp/tasks/ProcessingTransaction.cpp +++ b/login_server/src/cpp/tasks/ProcessingTransaction.cpp @@ -1,17 +1,18 @@ #include "ProcessingTransaction.h" #include -#include "../model/TransactionCreation.h" -#include "../model/TransactionTransfer.h" +#include "../model/gradido/TransactionCreation.h" +#include "../model/gradido/TransactionTransfer.h" +#include "../model/gradido/GroupMemberUpdate.h" #include "../SingletonManager/SingletonTaskObserver.h" #include "../lib/DataTypeConverter.h" #include "../lib/JsonRequest.h" -ProcessingTransaction::ProcessingTransaction(const std::string& proto_message_base64, DHASH userEmailHash, Languages lang) - : mType(TRANSACTION_NONE), mProtoMessageBase64(proto_message_base64), mTransactionSpecific(nullptr), mUserEmailHash(userEmailHash), - mLang(lang) +ProcessingTransaction::ProcessingTransaction(const std::string& proto_message_base64, DHASH userEmailHash, Languages lang, Poco::DateTime transactionCreated/* = Poco::DateTime()*/) + : mProtoMessageBase64(proto_message_base64), mUserEmailHash(userEmailHash), + mLang(lang), mTransactionCreated(transactionCreated) { mHashMutex.lock(); mHash = calculateHash(proto_message_base64); @@ -23,13 +24,18 @@ ProcessingTransaction::ProcessingTransaction(const std::string& proto_message_ba } } +ProcessingTransaction::ProcessingTransaction(Poco::AutoPtr transactionBody, DHASH userEmailHash, Languages lang, Poco::DateTime transactionCreated/* = Poco::DateTime()*/) + : mTransactionBody(transactionBody), mUserEmailHash(userEmailHash), + mLang(lang), mTransactionCreated(transactionCreated) +{ + auto observer = SingletonTaskObserver::getInstance(); + if (userEmailHash != 0) { + observer->addTask(userEmailHash, TASK_OBSERVER_PREPARE_TRANSACTION); + } +} ProcessingTransaction::~ProcessingTransaction() { lock(); - if (mTransactionSpecific) { - delete mTransactionSpecific; - mTransactionSpecific = nullptr; - } auto observer = SingletonTaskObserver::getInstance(); if (mUserEmailHash != 0) { observer->removeTask(mUserEmailHash, TASK_OBSERVER_PREPARE_TRANSACTION); @@ -77,48 +83,37 @@ void ProcessingTransaction::reportErrorToCommunityServer(std::string error, std: int ProcessingTransaction::run() { lock(); - //mTransactionBody.ParseFromString(); - unsigned char* binBuffer = (unsigned char*)malloc(mProtoMessageBase64.size()); - size_t resultingBinSize = 0; - size_t base64_size = mProtoMessageBase64.size(); + + auto mm = MemoryManager::getInstance(); auto langM = LanguageManager::getInstance(); auto catalog = langM->getFreeCatalog(mLang); - if (sodium_base642bin( - binBuffer, base64_size, - mProtoMessageBase64.data(), base64_size, - nullptr, &resultingBinSize, nullptr, - sodium_base64_VARIANT_ORIGINAL)) - { - free(binBuffer); - addError(new Error("ProcessingTransaction", "error decoding base64")); - reportErrorToCommunityServer(catalog->gettext("decoding error"), catalog->gettext("Error decoding base64 string"), "-1"); - unlock(); - return -1; + if (mProtoMessageBase64 != "") { + auto protoMessageBin = DataTypeConverter::base64ToBin(mProtoMessageBase64); + + if (!protoMessageBin) + { + addError(new Error("ProcessingTransaction", "error decoding base64")); + reportErrorToCommunityServer(catalog->gettext("decoding error"), catalog->gettext("Error decoding base64 string"), "-1"); + unlock(); + return -1; + } + auto proto_message_string = std::string((const char*)protoMessageBin->data(), protoMessageBin->size()); + mTransactionBody = model::gradido::TransactionBody::load(proto_message_string); + mm->releaseMemory(protoMessageBin); } - std::string binString((char*)binBuffer, resultingBinSize); - free(binBuffer); - if (!mTransactionBody.ParseFromString(binString)) { + if (mTransactionBody.isNull()) { addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message")); reportErrorToCommunityServer(catalog->gettext("decoding error"), catalog->gettext("Error by parsing to protobuf message"), "-1"); unlock(); return -2; } - - // check Type - if (mTransactionBody.has_creation()) { - mType = TRANSACTION_CREATION; - mTransactionSpecific = new TransactionCreation(mTransactionBody.memo(), mTransactionBody.creation()); - } - else if (mTransactionBody.has_transfer()) { - mType = TRANSACTION_TRANSFER; - mTransactionSpecific = new TransactionTransfer(mTransactionBody.memo(), mTransactionBody.transfer()); - } - if (mTransactionSpecific) { - if (mTransactionSpecific->prepare()) { - getErrors(mTransactionSpecific); + auto transaction_specific = mTransactionBody->getTransactionBase(); + if (transaction_specific) { + if (transaction_specific->prepare()) { + getErrors(transaction_specific); addError(new Error("ProcessingTransaction", "error preparing")); - reportErrorToCommunityServer(catalog->gettext("format error"), catalog->gettext("format of specific transaction not known, wrong proto version?"), std::to_string(mTransactionBody.created().seconds())); + reportErrorToCommunityServer(catalog->gettext("format error"), catalog->gettext("format of specific transaction not known, wrong proto version?"), Poco::DateTimeFormatter::format(mTransactionCreated, "%s")); unlock(); return -3; } @@ -126,44 +121,3 @@ int ProcessingTransaction::run() unlock(); return 0; } - -std::string ProcessingTransaction::getMemo() -{ - lock(); - if (mTransactionBody.IsInitialized()) { - std::string result(mTransactionBody.memo()); - unlock(); - return result; - } - unlock(); - return ""; -} - -std::string ProcessingTransaction::getBodyBytes() -{ - lock(); - if (mTransactionBody.IsInitialized()) { - auto size = mTransactionBody.ByteSize(); - //auto bodyBytesSize = MemoryManager::getInstance()->getFreeMemory(mProtoCreation.ByteSizeLong()); - std::string resultString(size, 0); - if (!mTransactionBody.SerializeToString(&resultString)) { - addError(new Error("TransactionCreation::getBodyBytes", "error serializing string")); - unlock(); - return ""; - } - unlock(); - return resultString; - } - unlock(); - return ""; -} - -TransactionCreation* ProcessingTransaction::getCreationTransaction() -{ - return dynamic_cast(mTransactionSpecific); -} - -TransactionTransfer* ProcessingTransaction::getTransferTransaction() -{ - return dynamic_cast(mTransactionSpecific); -} \ No newline at end of file diff --git a/login_server/src/cpp/tasks/ProcessingTransaction.h b/login_server/src/cpp/tasks/ProcessingTransaction.h index 9886bac8a..5f1dc4507 100644 --- a/login_server/src/cpp/tasks/ProcessingTransaction.h +++ b/login_server/src/cpp/tasks/ProcessingTransaction.h @@ -3,11 +3,9 @@ #include "CPUTask.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" #include "../lib/DRHash.h" -#include "../model/TransactionBase.h" - -#include "../proto/gradido/TransactionBody.pb.h" +#include "../model/gradido/TransactionBody.h" #include "../SingletonManager/LanguageManager.h" @@ -18,58 +16,53 @@ * @desc: Task for processing Transactions */ -enum TransactionType { - TRANSACTION_NONE, - TRANSACTION_CREATION, - TRANSACTION_TRANSFER -}; -class TransactionCreation; -class TransactionTransfer; +namespace model { + namespace gradido { + class TransactionCreation; + class TransactionTransfer; + class GroupMemberUpdate; + } +} class SigningTransaction; -class ProcessingTransaction : public UniLib::controller::CPUTask, public ErrorList + +class ProcessingTransaction : public UniLib::controller::CPUTask, public NotificationList { friend SigningTransaction; public: //! \param lang for error messages in user language - ProcessingTransaction(const std::string& proto_message_base64, DHASH userEmailHash, Languages lang); + ProcessingTransaction(const std::string& proto_message_base64, DHASH userEmailHash, Languages lang, Poco::DateTime transactionCreated = Poco::DateTime()); + ProcessingTransaction(Poco::AutoPtr transactionBody, DHASH userEmailHash, Languages lang, Poco::DateTime transactionCreated = Poco::DateTime()); + //ProcessingTransaction(const model::gradido::TransactionBody) virtual ~ProcessingTransaction(); int run(); const char* getResourceType() const { return "ProcessingTransaction"; }; - inline TransactionType getType() { lock(); auto t = mType; unlock(); return t; } - std::string getMemo(); - // not secured zone, no locking - bool isCreation() { return mType == TRANSACTION_CREATION; } - bool isTransfer() { return mType == TRANSACTION_TRANSFER; } - - TransactionCreation* getCreationTransaction(); - TransactionTransfer* getTransferTransaction(); - static HASH calculateHash(const std::string& proto_message_base64); static std::string calculateGenericHash(const std::string& protoMessageBase64); inline HASH getHash() { mHashMutex.lock(); HASH hs = mHash; mHashMutex.unlock(); return hs; } - std::string getBodyBytes(); + inline Poco::AutoPtr getTransactionBody() { return mTransactionBody; } + protected: void reportErrorToCommunityServer(std::string error, std::string errorDetails, std::string created); - TransactionType mType; + std::string mProtoMessageBase64; - - model::messages::gradido::TransactionBody mTransactionBody; - TransactionBase* mTransactionSpecific; + Poco::AutoPtr mTransactionBody; + HASH mHash; DHASH mUserEmailHash; Languages mLang; Poco::Mutex mHashMutex; + Poco::DateTime mTransactionCreated; private: }; diff --git a/login_server/src/cpp/tasks/SigningTransaction.cpp b/login_server/src/cpp/tasks/SigningTransaction.cpp index f28946c0c..98272f3e7 100644 --- a/login_server/src/cpp/tasks/SigningTransaction.cpp +++ b/login_server/src/cpp/tasks/SigningTransaction.cpp @@ -1,278 +1,324 @@ -#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())); - - FILE* f = fopen("response.html", "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 + +#include "SigningTransaction.h" + + +#include + +#include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/MemoryManager.h" +#include "../SingletonManager/SingletonTaskObserver.h" + +#include "../lib/Profiler.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" + +// stuff for hedera transaction +#include "../controller/HederaAccount.h" +#include "../controller/HederaRequest.h" +#include "../model/hedera/TransactionBody.h" +#include "../model/hedera/Transaction.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 + proto::gradido::GradidoTransaction transaction; + auto bodyBytes = transaction.mutable_body_bytes(); + auto transaction_body = mProcessingeTransaction->getTransactionBody(); + if (!transaction_body.isNull()) { + *bodyBytes = transaction_body->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_sig_map(); + 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()); + proto::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; + } + + auto network_type = ServerConfig::HEDERA_TESTNET; + auto topic_id = controller::HederaId::find(1, network_type); + auto hedera_operator_account = controller::HederaAccount::pick(network_type, false); + + /*if (!topic_id.isNull() && !hedera_operator_account.isNull()) { + auto crypto_key = hedera_operator_account->getCryptoKey(); + if (!crypto_key.isNull()) { + model::hedera::ConsensusSubmitMessage consensus_submit_message(topic_id); + consensus_submit_message.setMessage(finalTransactionBin); + auto hedera_transaction_body = hedera_operator_account->createTransactionBody(); + hedera_transaction_body->setConsensusSubmitMessage(consensus_submit_message); + model::hedera::Transaction hedera_transaction; + hedera_transaction.sign(crypto_key->getKeyPair(), std::move(hedera_transaction_body)); + + HederaRequest hedera_request; + HederaTask hedera_task;// placeholder + if (HEDERA_REQUEST_RETURN_OK != hedera_request.request(&hedera_transaction, &hedera_task)) { + addError(new Error("SigningTransaction", "error send transaction to hedera")); + getErrors(&hedera_request); + sendErrorsAsEmail(); + } + else { + auto hedera_precheck_code_string = hedera_task.getTransactionResponse()->getPrecheckCodeString(); + auto cost = hedera_task.getTransactionResponse()->getCost(); + printf("hedera response: %s, cost: %" PRIu64 "\n", hedera_precheck_code_string.data(), cost); + } + //model::hedera::TransactionBody hedera_transaction_body() + } + else { + printf("[SigningTransaction] crypto key not found\n"); + } + } + else { + printf("[SigningTransaction] hedera topic id or operator account not found\n"); + }*/ + + // 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())); + + FILE* f = fopen("response.html", "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..d02a95bec 100644 --- a/login_server/src/cpp/tasks/SigningTransaction.h +++ b/login_server/src/cpp/tasks/SigningTransaction.h @@ -1,46 +1,43 @@ -#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/NotificationList.h" +#include "../controller/User.h" + +#include "../proto/gradido/GradidoTransaction.pb.h" + +#include "ProcessingTransaction.h" + +/* +* @author: Dario Rekowski +* +* @date: 28.10.19 +* @desc: Task for signing Transactions +*/ + +class SigningTransaction : public UniLib::controller::CPUTask, public NotificationList +{ +public: + SigningTransaction(Poco::AutoPtr processingeTransaction, Poco::AutoPtr newUser); + 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/cpp/tasks/Task.cpp b/login_server/src/cpp/tasks/Task.cpp index e75b1a53d..07bb4c3fc 100644 --- a/login_server/src/cpp/tasks/Task.cpp +++ b/login_server/src/cpp/tasks/Task.cpp @@ -1,5 +1,5 @@ #include "Task.h" -#include "../lib/ErrorList.h" +#include "../lib/NotificationList.h" namespace UniLib { namespace controller { @@ -87,7 +87,7 @@ namespace UniLib { mWorkingMutex.lock(500); } catch (Poco::TimeoutException& ex) { - ErrorList errors; + NotificationList errors; errors.addError(new ParamError("Task::lock", getResourceType(), ex.displayText())); errors.sendErrorsAsEmail(); } diff --git a/login_server/src/cpp/tasks/Thread.cpp b/login_server/src/cpp/tasks/Thread.cpp index 0c095aeb9..ada5abeda 100644 --- a/login_server/src/cpp/tasks/Thread.cpp +++ b/login_server/src/cpp/tasks/Thread.cpp @@ -80,6 +80,11 @@ namespace UniLib { return; } } + catch (Poco::NullPointerException& e) { + threadUnlock(); + printf("[Thread::%s] NULL pointer exception\n", __FUNCTION__); + return; + } catch (Poco::Exception& e) { //unlock mutex and exit threadUnlock(); diff --git a/login_server/src/cpp/test/controller/TestHederaAccount.cpp b/login_server/src/cpp/test/controller/TestHederaAccount.cpp new file mode 100644 index 000000000..772377d2e --- /dev/null +++ b/login_server/src/cpp/test/controller/TestHederaAccount.cpp @@ -0,0 +1,14 @@ +#include "TestHederaAccount.h" +#include "../SingletonManager/ConnectionManager.h" +namespace controller { + + void TestHederaAccount::SetUp() + { + + } + + TEST_F(TestHederaAccount, TestPick) { + auto hedera_account = controller::HederaAccount::pick(ServerConfig::HEDERA_TESTNET, false); + EXPECT_FALSE(hedera_account.isNull()); + } +} diff --git a/login_server/src/cpp/test/controller/TestHederaAccount.h b/login_server/src/cpp/test/controller/TestHederaAccount.h new file mode 100644 index 000000000..7e8e7843a --- /dev/null +++ b/login_server/src/cpp/test/controller/TestHederaAccount.h @@ -0,0 +1,13 @@ +#include "gtest/gtest.h" + +#include "../controller/HederaAccount.h" + + +namespace controller { + + class TestHederaAccount : public ::testing::Test { + protected: + void SetUp() override; + }; + +} \ No newline at end of file diff --git a/login_server/src/cpp/test/controller/TestHederaId.cpp b/login_server/src/cpp/test/controller/TestHederaId.cpp new file mode 100644 index 000000000..c2fed10dd --- /dev/null +++ b/login_server/src/cpp/test/controller/TestHederaId.cpp @@ -0,0 +1,14 @@ +#include "TestHederaId.h" +#include "../SingletonManager/ConnectionManager.h" +namespace controller { + + void TestHederaId::SetUp() + { + + } + + TEST_F(TestHederaId, TestFindTopicId) { + auto hedera_topic_id = controller::HederaId::find(1, ServerConfig::HEDERA_TESTNET); + EXPECT_FALSE(hedera_topic_id.isNull()); + } +} diff --git a/login_server/src/cpp/test/controller/TestHederaId.h b/login_server/src/cpp/test/controller/TestHederaId.h new file mode 100644 index 000000000..b6e4b574e --- /dev/null +++ b/login_server/src/cpp/test/controller/TestHederaId.h @@ -0,0 +1,13 @@ +#include "gtest/gtest.h" + +#include "../controller/HederaId.h" + + +namespace controller { + + class TestHederaId : public ::testing::Test { + protected: + void SetUp() override; + }; + +} \ No newline at end of file diff --git a/login_server/src/cpp/test/controller/TestHederaTopic.cpp b/login_server/src/cpp/test/controller/TestHederaTopic.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/test/controller/TestHederaTopic.h b/login_server/src/cpp/test/controller/TestHederaTopic.h new file mode 100644 index 000000000..e69de29bb diff --git a/login_server/src/cpp/test/crypto/TestAuthenticatedEncryption.cpp b/login_server/src/cpp/test/crypto/TestAuthenticatedEncryption.cpp index 93c19bc9b..e863e773d 100644 --- a/login_server/src/cpp/test/crypto/TestAuthenticatedEncryption.cpp +++ b/login_server/src/cpp/test/crypto/TestAuthenticatedEncryption.cpp @@ -1,6 +1,6 @@ #include "TestAuthenticatedEncryption.h" -#include "../../Crypto/AuthenticatedEncryption.h" +#include "../../Crypto/SecretKeyCryptography.h" #include "../../lib/Profiler.h" #include "../../lib/DataTypeConverter.h" @@ -12,12 +12,12 @@ void TestAuthenticatedEncryption::SetUp() } TEST_F(TestAuthenticatedEncryption, encryptDecryptTest) { - AuthenticatedEncryption authenticated_encryption; + SecretKeyCryptography authenticated_encryption; EXPECT_FALSE(authenticated_encryption.hasKey()); EXPECT_EQ(authenticated_encryption.getKeyHashed(), 0); Profiler time_used; - EXPECT_EQ(authenticated_encryption.createKey("dariofrodo@gmx.de", "r3an7d_spassw"), AuthenticatedEncryption::AUTH_ENCRYPT_OK); + EXPECT_EQ(authenticated_encryption.createKey("dariofrodo@gmx.de", "r3an7d_spassw"), SecretKeyCryptography::AUTH_ENCRYPT_OK); printf("create key duration: %s\n", time_used.string().data()); EXPECT_TRUE(authenticated_encryption.hasKey()); @@ -29,12 +29,12 @@ TEST_F(TestAuthenticatedEncryption, encryptDecryptTest) { memcpy(*test_message_bin, test_message.data(), test_message.size()); time_used.reset(); - EXPECT_EQ(authenticated_encryption.encrypt(test_message_bin, &encrypted_message), AuthenticatedEncryption::AUTH_ENCRYPT_OK); + EXPECT_EQ(authenticated_encryption.encrypt(test_message_bin, &encrypted_message), SecretKeyCryptography::AUTH_ENCRYPT_OK); printf("encrypt message duration: %s\n", time_used.string().data()); MemoryBin* decrypted_message = nullptr; time_used.reset(); - EXPECT_EQ(authenticated_encryption.decrypt(encrypted_message, &decrypted_message), AuthenticatedEncryption::AUTH_DECRYPT_OK); + EXPECT_EQ(authenticated_encryption.decrypt(encrypted_message, &decrypted_message), SecretKeyCryptography::AUTH_DECRYPT_OK); printf("decrypt message duration: %s\n", time_used.string().data()); EXPECT_EQ(std::string((const char*)*decrypted_message, decrypted_message->size()), test_message); diff --git a/login_server/src/cpp/test/crypto/TestKeyPairEd25519.cpp b/login_server/src/cpp/test/crypto/TestKeyPairEd25519.cpp index 314fb9cdc..51f714776 100644 --- a/login_server/src/cpp/test/crypto/TestKeyPairEd25519.cpp +++ b/login_server/src/cpp/test/crypto/TestKeyPairEd25519.cpp @@ -1,6 +1,6 @@ #include "TestPassphrase.h" -#include "../../Crypto/KeyPair.h" + #include "../../Crypto/KeyPairEd25519.h" #include "../../Crypto/Passphrase.h" #include "../../lib/DataTypeConverter.h" @@ -14,12 +14,12 @@ TEST_F(PassphraseTest, TestEd25519KeyPair) { auto word_indices = tr->getWordIndices(); auto key_pair_ed25519 = KeyPairEd25519::create(tr); - KeyPair key_pair; + //KeyPair key_pair; - key_pair.generateFromPassphrase(test_data_set.passphrases[test_data_set.mnemonicType].data(), mnemonic); + //key_pair.generateFromPassphrase(test_data_set.passphrases[test_data_set.mnemonicType].data(), mnemonic); - EXPECT_EQ(key_pair.getPubkeyHex(), test_data_set.pubkeyHex); - EXPECT_EQ(DataTypeConverter::pubkeyToHex(key_pair_ed25519->getPublicKey()), key_pair.getPubkeyHex()); + //EXPECT_EQ(key_pair.getPubkeyHex(), test_data_set.pubkeyHex); + //EXPECT_EQ(DataTypeConverter::pubkeyToHex(key_pair_ed25519->getPublicKey()), key_pair.getPubkeyHex()); //auto key_pair_old delete key_pair_ed25519; diff --git a/login_server/src/cpp/test/crypto/TestPassphrase.cpp b/login_server/src/cpp/test/crypto/TestPassphrase.cpp index 128a461f6..010353e17 100644 --- a/login_server/src/cpp/test/crypto/TestPassphrase.cpp +++ b/login_server/src/cpp/test/crypto/TestPassphrase.cpp @@ -10,7 +10,6 @@ #include "../../lib/DataTypeConverter.h" #include "../../Crypto/KeyPairEd25519.h" -#include "../../Crypto/KeyPair.h" @@ -170,10 +169,10 @@ TEST_F(PassphraseTest, createAndTransform) { EXPECT_EQ(word_indices[i], test_data_set.wordIndices[i]); } auto key_pair_ed25519 = KeyPairEd25519::create(tr); - KeyPair key_pair; - key_pair.generateFromPassphrase(test_data_set.passphrases[test_data_set.mnemonicType].data(), mnemonic); - //EXPECT_EQ(DataTypeConverter::pubkeyToHex(key_pair_ed25519->getPublicKey()), test_data_set.pubkeyHex); - EXPECT_EQ(key_pair.getPubkeyHex(), test_data_set.pubkeyHex); + //KeyPair key_pair; + //key_pair.generateFromPassphrase(test_data_set.passphrases[test_data_set.mnemonicType].data(), mnemonic); + EXPECT_EQ(DataTypeConverter::pubkeyToHex(key_pair_ed25519->getPublicKey()), test_data_set.pubkeyHex); + //EXPECT_EQ(key_pair.getPubkeyHex(), test_data_set.pubkeyHex); //auto key_pair_old delete key_pair_ed25519; diff --git a/login_server/src/cpp/test/main.cpp b/login_server/src/cpp/test/main.cpp index 5fcab4163..62482c664 100644 --- a/login_server/src/cpp/test/main.cpp +++ b/login_server/src/cpp/test/main.cpp @@ -8,6 +8,8 @@ #include "../SingletonManager/ConnectionManager.h" +#include "../lib/Profiler.h" + std::list gTests; @@ -20,6 +22,21 @@ void fillTests() // gTests.push_back(new LoginTest()); } +void runMysql(std::string sqlQuery) +{ + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement mysqlStatement(session); + mysqlStatement << sqlQuery; + + try { + mysqlStatement.execute(true); + } + catch (Poco::Exception& ex) { + printf("exception in runMysql: %s\n", ex.displayText().data()); + } +} + int load() { // init server config, init seed array @@ -54,7 +71,186 @@ int load() { //printf("try connect php server mysql \n"); conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_PHP_SERVER); + Profiler timeUsed; + // clean up and fill db + std::string tables[] = { + "hedera_accounts", + "hedera_ids", + "crypto_keys", + "hedera_topics", + "groups", + "node_servers", + "users" + }; + for (int i = 0; i < 7; i++) { + runMysql("TRUNCATE " + tables[i]); + runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1"); + } + + std::stringstream ss; + ss << "INSERT INTO `users` (`id`, `email`, `first_name`, `last_name`, `password`, `pubkey`, `privkey`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`) VALUES " + << "(1, 'einhorn_silas@ist-allein.info', 'DDD', 'Schultz', 13134558453895551556, 0x146d3fb9e88abc0fca0b0091c1ab1b32b399be037436f340befa8bf004461889, 0x0dcc08960f45f631fe23bc7ddee0724cedc9ec0c861ce30f5091d20ffd96062d08ca215726fb9bd64860c754772e945eea4cc872ed0a36c7b640e8b0bf7a873ec6765fa510711622341347ce2307b5ce, '2020-02-20 16:05:44', 1, 0, 'de', 0), " + << "(2, 'Dario.Rekowski@buerotiger.de', 'Darios', 'Bruder', 12910944485867375321, 0x952e215a21d4376b4ac252c4bf41e156e1498e1b6b8ccf2a6826d96712f4f461, 0x4d40bf0860655f728312140dc3741e897bc2d13d00ea80a63e2961046a5a7bd8315397dfb488b89377087bc1a5f4f3af8ffdcf203329ae23ba04be7d38ad3852699d90ff1fc00e5b1ca92b64cc59c01f, '2020-02-20 16:05:44', 1, 0, 'de', 0), " + << "(3, 'morgenstern175@es-ist-liebe.de', 'Dieter', 'Schultz', 13528673707291575501, 0xb539944bf6444a2bfc988244f0c0c9dc326452be9b8a2a43fcd90663719f4f6d, 0x5461fda60b719b65ba00bd6298e48410c4cbf0e89deb13cc784ba8978cf047454e8556ee3eddc8487ee835c33a83163bc8d8babbf2a5c431876bc0a0c114ff0a0d6b57baa12cf8f23c64fb642c862db5, '2020-02-20 16:05:45', 1, 0, 'de', 0), " + << "(4, 'spaceteam@gmx.de', 'Bernd', 'Hückstädt', 15522411320147607375, 0x476b059744f08b0995522b484c90f8d2f47d9b59f4b3c96d9dc0ae6ab7b84979, 0x5277bf044cba4fec64e6f4d38da132755b029161231daefc9a7b4692ad37e05cdd88e0a2c2215baf854dd3a813578c214167af1113607e9f999ca848a7598ba5068e38f2a1afb097e4752a88024d79c8, '2020-02-20 16:05:46', 1, 0, 'de', 0), " + << "(5, 'em741@gmx.de', 'Thomas', 'Markuk', 7022671043835614958, 0xb1584e169d60a7e771d3a348235dfd7b5f9e8235fcc26090761a0264b0daa6ff, 0xb46fb7110bf91e28f367aa80f84d1bbd639b6f689f4b0aa28c0f71529232df9bf9ee0fb02fa4c1b9f5a6799c82d119e5646f7231d011517379faaacf6513d973ac3043d4c786490ba62d56d75b86164d, '2020-02-20 16:05:46', 1, 0, 'de', 0), " + << "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 1548398919826089202, 0x4046ae49c1b620f2a321aba0c874fa2bc7ba844ab808bb0eeb18a908d468db14, 0x9522657ecd7456eedf86d065aa087ba7a94a8961a8e4950d044136155d38fe0840f2c0a2876ce055b3eaa6e9ab95c5feba89e535e0434fb2648d94d6e6ec68211aa2ea9e42d1ccd40b6b3c31e41f848e, '2020-02-20 16:05:47', 1, 0, 'de', 0), " + << "(7, 'info@einhornimmond.de', 'Alex', 'Wesper', 5822761891727948301, 0xb13ede3402abb8f29722b14fec0a2006ae7a3a51fb677cd6a2bbd797ac6905a5, 0x6aa39d7670c64a31639c7d89b874ad929b2eaeb2e5992dbad71b6cea700bf9e3c6cf866d0f0fdc22b44a0ebf51a860799e880ef86266199931dd0a301e5552db44b9b7fa99ed5945652bc7b31eff767c, '2020-02-20 16:05:47', 1, 0, 'de', 0); "; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `description`) VALUES " + << "(1, 'gdd1', 'Gradido1', 'gdd1.gradido.com', 'Der erste offizielle Gradido Server (zum Testen)'); "; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `hedera_accounts` (`id`, `user_id`, `account_hedera_id`, `account_key_id`, `balance`, `network_type`, `updated`) VALUES " + << "(1, 2, 15, 1, 1000000000000, 1, '2020-09-03 11:13:52'), " + << "(2, 2, 17, 2, 22787166159, 0, '2020-09-03 11:13:56'); "; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `hedera_ids` (`id`, `shardNum`, `realmNum`, `num`) VALUES " + << "(1, 0, 0, 3), " + << "(2, 0, 0, 4)," + << "(3, 0, 0, 5)," + << "(4, 0, 0, 6)," + << "(6, 0, 0, 3)," + << "(10, 0, 0, 7)," + << "(11, 0, 0, 8)," + << "(12, 0, 0, 9)," + << "(13, 0, 0, 10)," + << "(14, 0, 0, 12)," + << "(15, 0, 0, 3327)," + << "(16, 0, 0, 3323)," + << "(17, 0, 0, 8707)," + << "(18, 0, 0, 39446);"; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `crypto_keys` (`id`, `private_key`, `public_key`, `crypto_key_type_id`) VALUES " + << "(1, 0xd2d4735174e6d2577573a0ec2767fba6511b1e37cd1cd98674912797fd37e12373d6b4d771034cc114f80b2afb2956b6b3e020ddea2db1142c61f3fa87c72a6c, 0x73d6b4d771034cc114f80b2afb2956b6b3e020ddea2db1142c61f3fa87c72a6c, 3), " + << "(2, 0xf1c3285be6ef869a2a8deef6caee56a5a7c2660e2bce24f39e420dd8d42fe8894bd027b2799e46dc7111a4fdd0eac3848054331f844a358de15c5b0ed3eb1740fab13ecb5a271d480e040c9266bcd584, 0xd6f6d29fb277f86ac7c3098dc799028974223e8dce6b1dd57b03940bf35fae7f, 1); "; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `hedera_topics` (`id`, `topic_hedera_id`, `name`, `auto_renew_account_hedera_id`, `auto_renew_period`, `group_id`, `admin_key_id`, `submit_key_id`, `current_timeout`, `sequence_number`, `updated`) VALUES " + << "(1, 18, 'from Pauls created with his python script', 1, 0, 1, NULL, NULL, '1999-12-31 23:00:00', 0, '2020-09-14 18:29:04'); "; + runMysql(ss.str()); + ss.str(std::string()); + + ss << "INSERT INTO `node_servers` (`id`, `url`, `port`, `group_id`, `server_type`, `node_hedera_id`, `last_live_sign`) VALUES " + << "(1, 'http://0.testnet.hedera.com', 50211, 0, 4, 1, '2000-01-01 00:00:00'), " + << "(2, 'http://1.testnet.hedera.com', 50211, 0, 4, 2, '2000-01-01 00:00:00'), " + << "(3, 'http://2.testnet.hedera.com', 50211, 0, 4, 3, '2000-01-01 00:00:00'), " + << "(4, 'http://3.testnet.hedera.com', 50211, 0, 4, 4, '2000-01-01 00:00:00'), " + << "(5, 'http://35.237.200.180', 50211, 0, 3, 6, '2000-01-01 00:00:00'), " + << "(6, 'http://35.186.191.247', 50211, 0, 3, 2, '2000-01-01 00:00:00'), " + << "(7, 'http://35.192.2.25', 50211, 0, 3, 3, '2000-01-01 00:00:00'), " + << "(8, 'http://35.199.161.108', 50211, 0, 3, 4, '2000-01-01 00:00:00'), " + << "(9, 'http://35.203.82.240', 50211, 0, 3, 10, '2000-01-01 00:00:00'), " + << "(10, 'http://35.236.5.219', 50211, 0, 3, 11, '2000-01-01 00:00:00'), " + << "(11, 'http://35.197.192.225', 50211, 0, 3, 12, '2000-01-01 00:00:00'), " + << "(12, 'http://35.242.233.154', 50211, 0, 3, 13, '2000-01-01 00:00:00'), " + << "(13, 'http://35.240.118.96', 50211, 0, 3, 12, '2000-01-01 00:00:00'), " + << "(14, 'http://35.204.86.32', 50211, 0, 3, 14, '2000-01-01 00:00:00'), " + << "(15, 'https://gradido.dario-rekowski.de/', 443, 1, 2, 0, '2000-01-01 00:00:00'), " + << "(16, 'http://192.168.178.232', 8340, 1, 1, 0, '2000-01-01 00:00:00'); "; + runMysql(ss.str()); + + printf("init db in : %s\n", timeUsed.string().data()); + + /*mysqlStatement + << "TRUNCATE hedera_accounts; " + << "ALTER TABLE hedera_accounts AUTO_INCREMENT = 1; " + << "TRUNCATE hedera_ids; " + << "ALTER TABLE hedera_ids AUTO_INCREMENT = 1; " + << "TRUNCATE crypto_keys; " + << "ALTER TABLE crypto_keys AUTO_INCREMENT = 1; " + << "TRUNCATE hedera_topics; " + << "ALTER TABLE hedera_topics AUTO_INCREMENT = 1; " + << "TRUNCATE groups; " + << "ALTER TABLE groups AUTO_INCREMENT = 1; " + << "TRUNCATE node_servers; " + << "ALTER TABLE node_servers AUTO_INCREMENT = 1; " + << "TRUNCATE users; " + << "ALTER TABLE users AUTO_INCREMENT = 1; " + ; + + try { + mysqlStatement.execute(true); + } + catch (Poco::Exception& ex) { + printf("exception by cleaning up db: %s\n", ex.displayText().data()); + } + mysqlStatement.reset(session); + mysqlStatement + << "INSERT INTO `users` (`id`, `email`, `first_name`, `last_name`, `password`, `pubkey`, `privkey`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`) VALUES " + << "(1, 'einhorn_silas@ist-allein.info', 'DDD', 'Schultz', 13134558453895551556, 0x146d3fb9e88abc0fca0b0091c1ab1b32b399be037436f340befa8bf004461889, 0x0dcc08960f45f631fe23bc7ddee0724cedc9ec0c861ce30f5091d20ffd96062d08ca215726fb9bd64860c754772e945eea4cc872ed0a36c7b640e8b0bf7a873ec6765fa510711622341347ce2307b5ce, '2020-02-20 16:05:44', 1, 0, 'de', 0), " + << "(2, 'Dario.Rekowski@buerotiger.de', 'Darios', 'Bruder', 12910944485867375321, 0x952e215a21d4376b4ac252c4bf41e156e1498e1b6b8ccf2a6826d96712f4f461, 0x4d40bf0860655f728312140dc3741e897bc2d13d00ea80a63e2961046a5a7bd8315397dfb488b89377087bc1a5f4f3af8ffdcf203329ae23ba04be7d38ad3852699d90ff1fc00e5b1ca92b64cc59c01f, '2020-02-20 16:05:44', 1, 0, 'de', 0), " + << "(3, 'morgenstern175@es-ist-liebe.de', 'Dieter', 'Schultz', 13528673707291575501, 0xb539944bf6444a2bfc988244f0c0c9dc326452be9b8a2a43fcd90663719f4f6d, 0x5461fda60b719b65ba00bd6298e48410c4cbf0e89deb13cc784ba8978cf047454e8556ee3eddc8487ee835c33a83163bc8d8babbf2a5c431876bc0a0c114ff0a0d6b57baa12cf8f23c64fb642c862db5, '2020-02-20 16:05:45', 1, 0, 'de', 0), " + << "(4, 'spaceteam@gmx.de', 'Bernd', 'Hückstädt', 15522411320147607375, 0x476b059744f08b0995522b484c90f8d2f47d9b59f4b3c96d9dc0ae6ab7b84979, 0x5277bf044cba4fec64e6f4d38da132755b029161231daefc9a7b4692ad37e05cdd88e0a2c2215baf854dd3a813578c214167af1113607e9f999ca848a7598ba5068e38f2a1afb097e4752a88024d79c8, '2020-02-20 16:05:46', 1, 0, 'de', 0), " + << "(5, 'em741@gmx.de', 'Thomas', 'Markuk', 7022671043835614958, 0xb1584e169d60a7e771d3a348235dfd7b5f9e8235fcc26090761a0264b0daa6ff, 0xb46fb7110bf91e28f367aa80f84d1bbd639b6f689f4b0aa28c0f71529232df9bf9ee0fb02fa4c1b9f5a6799c82d119e5646f7231d011517379faaacf6513d973ac3043d4c786490ba62d56d75b86164d, '2020-02-20 16:05:46', 1, 0, 'de', 0), " + << "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 1548398919826089202, 0x4046ae49c1b620f2a321aba0c874fa2bc7ba844ab808bb0eeb18a908d468db14, 0x9522657ecd7456eedf86d065aa087ba7a94a8961a8e4950d044136155d38fe0840f2c0a2876ce055b3eaa6e9ab95c5feba89e535e0434fb2648d94d6e6ec68211aa2ea9e42d1ccd40b6b3c31e41f848e, '2020-02-20 16:05:47', 1, 0, 'de', 0), " + << "(7, 'info@einhornimmond.de', 'Alex', 'Wesper', 5822761891727948301, 0xb13ede3402abb8f29722b14fec0a2006ae7a3a51fb677cd6a2bbd797ac6905a5, 0x6aa39d7670c64a31639c7d89b874ad929b2eaeb2e5992dbad71b6cea700bf9e3c6cf866d0f0fdc22b44a0ebf51a860799e880ef86266199931dd0a301e5552db44b9b7fa99ed5945652bc7b31eff767c, '2020-02-20 16:05:47', 1, 0, 'de', 0); " + + << "INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `description`) VALUES " + << "(1, 'gdd1', 'Gradido1', 'gdd1.gradido.com', 'Der erste offizielle Gradido Server (zum Testen)'); " + + << "INSERT INTO `hedera_accounts` (`id`, `user_id`, `account_hedera_id`, `account_key_id`, `balance`, `network_type`, `updated`) VALUES " + << "(1, 2, 15, 1, 1000000000000, 1, '2020-09-03 11:13:52'), " + << "(2, 2, 17, 2, 22787166159, 0, '2020-09-03 11:13:56'); " + + << "INSERT INTO `hedera_ids` (`id`, `shardNum`, `realmNum`, `num`) VALUES " + << "(1, 0, 0, 3), " + << "(2, 0, 0, 4)," + << "(3, 0, 0, 5)," + << "(4, 0, 0, 6)," + << "(6, 0, 0, 3)," + << "(10, 0, 0, 7)," + << "(11, 0, 0, 8)," + << "(12, 0, 0, 9)," + << "(13, 0, 0, 10)," + << "(14, 0, 0, 12)," + << "(15, 0, 0, 3327)," + << "(16, 0, 0, 3323)," + << "(17, 0, 0, 8707)," + << "(18, 0, 0, 39446);" + + << "INSERT INTO `crypto_keys` (`id`, `private_key`, `public_key`, `crypto_key_type_id`) VALUES " + << "(1, 0xd2d4735174e6d2577573a0ec2767fba6511b1e37cd1cd98674912797fd37e12373d6b4d771034cc114f80b2afb2956b6b3e020ddea2db1142c61f3fa87c72a6c, 0x73d6b4d771034cc114f80b2afb2956b6b3e020ddea2db1142c61f3fa87c72a6c, 3), " + << "(2, 0xf1c3285be6ef869a2a8deef6caee56a5a7c2660e2bce24f39e420dd8d42fe8894bd027b2799e46dc7111a4fdd0eac3848054331f844a358de15c5b0ed3eb1740fab13ecb5a271d480e040c9266bcd584, 0xd6f6d29fb277f86ac7c3098dc799028974223e8dce6b1dd57b03940bf35fae7f, 1); " + + << "INSERT INTO `hedera_topics` (`id`, `topic_hedera_id`, `name`, `auto_renew_account_hedera_id`, `auto_renew_period`, `group_id`, `admin_key_id`, `submit_key_id`, `current_timeout`, `sequence_number`, `updated`) VALUES " + << "(1, 18, 'from Pauls created with his python script', 1, 0, 1, NULL, NULL, '1999-12-31 23:00:00', 0, '2020-09-14 18:29:04'); " + + << "INSERT INTO `node_servers` (`id`, `url`, `port`, `group_id`, `server_type`, `node_hedera_id`, `last_live_sign`) VALUES " + << "(1, 'http://0.testnet.hedera.com', 50211, 0, 4, 1, '2000-01-01 00:00:00'), " + << "(2, 'http://1.testnet.hedera.com', 50211, 0, 4, 2, '2000-01-01 00:00:00'), " + << "(3, 'http://2.testnet.hedera.com', 50211, 0, 4, 3, '2000-01-01 00:00:00'), " + << "(4, 'http://3.testnet.hedera.com', 50211, 0, 4, 4, '2000-01-01 00:00:00'), " + << "(5, 'http://35.237.200.180', 50211, 0, 3, 6, '2000-01-01 00:00:00'), " + << "(6, 'http://35.186.191.247', 50211, 0, 3, 2, '2000-01-01 00:00:00'), " + << "(7, 'http://35.192.2.25', 50211, 0, 3, 3, '2000-01-01 00:00:00'), " + << "(8, 'http://35.199.161.108', 50211, 0, 3, 4, '2000-01-01 00:00:00'), " + << "(9, 'http://35.203.82.240', 50211, 0, 3, 10, '2000-01-01 00:00:00'), " + << "(10, 'http://35.236.5.219', 50211, 0, 3, 11, '2000-01-01 00:00:00'), " + << "(11, 'http://35.197.192.225', 50211, 0, 3, 12, '2000-01-01 00:00:00'), " + << "(12, 'http://35.242.233.154', 50211, 0, 3, 13, '2000-01-01 00:00:00'), " + << "(13, 'http://35.240.118.96', 50211, 0, 3, 12, '2000-01-01 00:00:00'), " + << "(14, 'http://35.204.86.32', 50211, 0, 3, 14, '2000-01-01 00:00:00'), " + << "(15, 'https://gradido.dario-rekowski.de/', 443, 1, 2, 0, '2000-01-01 00:00:00'), " + << "(16, 'http://192.168.178.232', 8340, 1, 1, 0, '2000-01-01 00:00:00'); " + ; + + try { + mysqlStatement.execute(); + } + catch (Poco::Exception& ex) { + printf("exception by init db with data: %s\n", ex.displayText().data()); + } + */ fillTests(); for (std::list::iterator it = gTests.begin(); it != gTests.end(); it++) { diff --git a/login_server/src/cpsp/.gitignore b/login_server/src/cpsp/.gitignore index 863ee1751..7d12f04b4 100644 --- a/login_server/src/cpsp/.gitignore +++ b/login_server/src/cpsp/.gitignore @@ -1,2 +1,5 @@ /compile.sh /*.dll +/.vscode +/*.exe +/*.bat \ No newline at end of file diff --git a/login_server/src/cpsp/Error500.cpsp b/login_server/src/cpsp/Error500.cpsp index 7cea4f563..0cc255eed 100644 --- a/login_server/src/cpsp/Error500.cpsp +++ b/login_server/src/cpsp/Error500.cpsp @@ -10,18 +10,18 @@ <% const char* pageName = "Error"; response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - Poco::AutoPtr user; + Poco::AutoPtr user; if(mSession) { - auto user = mSession->getUser(); + auto user = mSession->getNewUser(); } %><%@ include file="header_old.cpsp" %>

Ein Fehler auf dem Server trat ein, der Admin bekam eine E-Mail.

<% if(mSession) { %> - <%= mSession->getErrorsHtml() %> + <%= mSession->getErrorsHtmlNewFormat() %> <% } %> <% if(!user.isNull()) {%> - <%= user->getErrorsHtml() %> + <%= user->getModel()->getErrorsHtmlNewFormat() %> <% } %>
<%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/PassphrasedTransaction.cpsp b/login_server/src/cpsp/PassphrasedTransaction.cpsp index debc1f296..ac772ceab 100644 --- a/login_server/src/cpsp/PassphrasedTransaction.cpsp +++ b/login_server/src/cpsp/PassphrasedTransaction.cpsp @@ -6,7 +6,7 @@ <%! #include "../SingletonManager/MemoryManager.h" #include "../SingletonManager/SessionManager.h" -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" #include "../ServerConfig.h" #include "Poco/JSON/Object.h" @@ -23,29 +23,28 @@ enum PageState { <%% std::string pageName = "Gradidos mit Passphrase überweisen"; PageState state = PAGE_STATE_INPUT; - Mnemonic* wordSource = &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER]; + Mnemonic* wordSource = &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES]; auto sm = SessionManager::getInstance(); auto mm = MemoryManager::getInstance(); std::string errorString =""; if(!form.empty()) { auto passphrase = form.get("passphrase", ""); - bool passphraseValid = User::validatePassphrase(passphrase, &wordSource); + auto passphrase_obj = Passphrase::create(passphrase, wordSource); + bool keysGenerated = false; - KeyPair keys; - if(!passphraseValid) - { + KeyPairEd25519* keys = nullptr; + if(!passphrase_obj.isNull()) { addError(new Error("Passphrase", "Fehler beim validieren der Passphrase")); } - else - { - keysGenerated = keys.generateFromPassphrase(passphrase.data(), wordSource); - if(!keysGenerated) + else { + keys = KeyPairEd25519::create(passphrase_obj); + if(!keys) { addError(new Error("Passphrase", "Konnte keine Keys aus der Passphrase generieren")); } } - if(passphraseValid && keysGenerated) + if(keys) { // create session only for transaction int session_id = 0; @@ -53,7 +52,7 @@ enum PageState { // create payload Poco::JSON::Object requestJson; Poco::JSON::Object pubkeys; - pubkeys.set("sender", keys.getPubkeyHex()); + pubkeys.set("sender", keys->getPublicKeyHex()); pubkeys.set("receiver", form.get("recevier", "")); requestJson.set("method", "moveTransaction"); requestJson.set("pubkeys", pubkeys); @@ -104,7 +103,8 @@ enum PageState { Poco::Thread::sleep(10); currentActiveTransaction = session->getNextReadyTransaction(); } - if(!currentActiveTransaction->isTransfer()) { + auto transaction_body = currentActiveTransaction->getTransactionBody(); + if(transaction_body.isNull() || !transaction_body->isTransfer()) { addError(new Error("Transaction", "Falsche Transaktion, bitte erst alle anderen Transaktionen abschließen und dann Seite neuladen")); } else { //auto signing = new SigningTransaction(currentActiveTransaction, user); @@ -129,6 +129,8 @@ enum PageState { if(session) { sm->releaseSession(session); } + delete keys; + keys = nullptr; } } diff --git a/login_server/src/cpsp/adminCheckUserBackup.cpsp b/login_server/src/cpsp/adminCheckUserBackup.cpsp index bca35b05a..66156796d 100644 --- a/login_server/src/cpsp/adminCheckUserBackup.cpsp +++ b/login_server/src/cpsp/adminCheckUserBackup.cpsp @@ -5,10 +5,11 @@ <%@ page ctorArg="Session*" %> <%@ header include="SessionHTTPRequestHandler.h" %> <%! -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" +#include "../Crypto/Passphrase.h" #include "../SingletonManager/ConnectionManager.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" #include "Poco/Data/Binding.h" using namespace Poco::Data::Keywords; @@ -18,14 +19,14 @@ typedef Poco::Tuple, std::string> UserBack struct SListEntry { Poco::AutoPtr user; - std::vector> backups; + std::vector> backups; }; %> <%% const char* pageName = "Admin Check User Backups"; auto cm = ConnectionManager::getInstance(); - KeyPair keys; + std::list notMatchingEntrys; auto con = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); @@ -44,21 +45,24 @@ struct SListEntry if(pubkey.isNull()) { continue; } - auto passphrase = KeyPair::filterPassphrase(tuple.get<2>()); + auto passphrase = Passphrase::filter(tuple.get<2>()); auto user_id = tuple.get<0>(); - Mnemonic* wordSource = nullptr; - if(!User::validatePassphrase(passphrase, &wordSource)) { + KeyPairEd25519 key_pair(pubkey.value().content().data()); + + auto wordSource = Passphrase::detectMnemonic(passphrase); + if(!wordSource) { addError(new Error("admin Check user backup", "invalid passphrase"), false); addError(new ParamError("admin Check user backup", "passphrase", passphrase.data()), false); addError(new ParamError("admin Check user backup", "user id", user_id), false); continue; - } else { - keys.generateFromPassphrase(passphrase.data(), wordSource); - } + } + auto passphrase_object = Passphrase::create(passphrase, wordSource); + auto key_pair_from_passhrase = KeyPairEd25519::create(passphrase_object); bool matching = false; - if(keys.isPubkeysTheSame(pubkey.value().content().data())) { + if(key_pair_from_passhrase->isTheSame(key_pair)) { matching = true; } + delete key_pair_from_passhrase; if(user_id != last_user_id) { last_user_id = user_id; if(matching) continue; @@ -73,7 +77,7 @@ struct SListEntry SListEntry entry; entry.user = controller::User::create(); entry.user->load(user_id); - entry.backups = controller::UserBackups::load(user_id); + entry.backups = controller::UserBackup::load(user_id); notMatchingEntrys.push_back(entry); diff --git a/login_server/src/cpsp/adminGroups.cpsp b/login_server/src/cpsp/adminGroups.cpsp new file mode 100644 index 000000000..64df38205 --- /dev/null +++ b/login_server/src/cpsp/adminGroups.cpsp @@ -0,0 +1,87 @@ +<%@ page class="AdminGroupsPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + #include "../controller/Group.h" +%> +<%% + const char* pageName = "Gruppen"; + + auto user = mSession->getNewUser(); + + // add + if(!form.empty()) { + auto alias = form.get("group-alias"); + if(alias == "") + { + addError(new Error("Add Group", "Alias is empty!")); + } + else + { + auto newGroup = controller::Group::create( + alias, + form.get("group-name", ""), + form.get("group-url", ""), + form.get("group-home", ""), + form.get("group-desc", "") + ); + newGroup->getModel()->insertIntoDB(false); + } + } + + // select all + auto groups = controller::Group::listAll(); + //auto groups = controller::Group::load("gdd1"); + //std::vector> groups; + +%><%@ include file="header_large.cpsp" %> +<%= getErrorsHtml() %> +
+
+
+

Alle Gruppen

+
+
+
+
ID
+
Name
+
Alias
+
Url
+
Home
+
<%= gettext("Description") %>
+
+ <% for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); %> +
+
<%= group_model->getID() %>
+
<%= group_model->getName() %>
+
<%= group_model->getAlias() %>
+
<%= group_model->getUrl() %>
+
<%= group_model->getHome() %>
+
<%= group_model->getDescription()%>
+
+ <% } %> +
+
+
+

Eine neue Gruppe anlegen

+
+
+
+ + + + + + + + + + + "> + +
+<%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/adminHederaAccount.cpsp b/login_server/src/cpsp/adminHederaAccount.cpsp new file mode 100644 index 000000000..d4e5561dd --- /dev/null +++ b/login_server/src/cpsp/adminHederaAccount.cpsp @@ -0,0 +1,351 @@ +<%@ page class="AdminHederaAccountPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + +#include "../controller/HederaAccount.h" +#include "../controller/HederaId.h" +#include "../controller/CryptoKey.h" +#include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" +#include "../lib/Success.h" +#include "../SingletonManager/SessionManager.h" + +#include "../ServerConfig.h" + +#include "Poco/URI.h" + +%> +<%% + const char* pageName = "Hedera Account"; + auto sm = SessionManager::getInstance(); + auto mm = MemoryManager::getInstance(); + auto user = mSession->getNewUser(); + int auto_renew_period = 604800; // 7 Tage + int auto_renew_account = 0; + double initial_balance = 0.0; + Profiler hedera_time; + std::string hedera_time_string; + + Poco::URI uri(request.getURI()); + auto uri_query = uri.getQueryParameters(); + std::string action = ""; + Poco::AutoPtr query_hedera_account; + + // parsing get query params + if(uri_query.size() >= 2) { + if(uri_query[0].first == "action") { + action = uri_query[0].second; + } + if(uri_query[1].first == "account_id") { + std::string account_id_from_query; + int account_id = 0; + account_id_from_query = uri_query[1].second; + if(DataTypeConverter::strToInt(account_id_from_query, account_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting account_id_from_query to int")); + } else { + auto hedera_accounts = controller::HederaAccount::load("id", account_id); + if(!hedera_accounts.size() || hedera_accounts[0].isNull()) { + addError(new Error("Action", "hedera account not found")); + } else { + query_hedera_account = hedera_accounts[0]; + } + } + } + } + // actions + if(!query_hedera_account.isNull()) + { + if(action == "updateBalance") + { + hedera_time.reset(); + if(query_hedera_account->hederaAccountGetBalance(user)) { + addNotification(new ParamSuccess("Hedera", "crypto get balance success in ", hedera_time.string())); + } else { + addError(new ParamError("Hedera", "crypto get balance failed in ", hedera_time.string())); + } + } + else if(action == "changeEncryption") + { + if(query_hedera_account->changeEncryption(user)) { + addNotification(new Success("Hedera Account", "success in changing encryption")); + } + } + } + else if(!form.empty()) // add or create + { + auto creationButton = form.get("create",""); + if(creationButton != "") { + + // collect + auto auto_renew_account_string = form.get("account-auto-renew-account", "0"); + auto auto_renew_period_string = form.get("account-auto-renew-period", "604800"); + auto account_initial_balance_string = form.get("account-initial-balance", "0"); + + if(!sm->isValid(auto_renew_account_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account", "auto renew account id not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_account_string, auto_renew_account) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew account id to int")); + } + } + + if(!sm->isValid(auto_renew_period_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account", "auto renew period not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_period_string, auto_renew_period) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew period to int")); + } + } + + if(!sm->isValid(account_initial_balance_string, VALIDATE_ONLY_DECIMAL)) { + addError(new Error("Account", "initial balance not an decimal")); + } else { + if(DataTypeConverter::strToDouble(account_initial_balance_string, initial_balance) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Double convert error", "Error converting initial balance to double")); + } + } + if(0 == errorCount()) + { + } + + } else { + + // collect + auto shardNumString = form.get("account-shard-num", "0"); + auto realmNumString = form.get("account-realm-num", "0"); + auto numString = form.get("account-num", "0"); + auto privateKeyString = form.get("account-private-key", ""); + auto privateKeyEncryptedString = form.get("account-private-key-encrypted", "false"); + auto publicKeyString = form.get("account-public-key", ""); + auto networkTypeString = form.get("account-network-type", "0"); + + //printf("private key encrypted: %s\n", privateKeyEncryptedString.data()); + + int shardNum = 0; + int realmNum = 0; + int num = 0; + int networkType = 0; + + MemoryBin* private_key = nullptr; + MemoryBin* public_key = nullptr; + + // validate + if(!sm->isValid(shardNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "shard num not integer")); + } else { + if(DataTypeConverter::strToInt(shardNumString, shardNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting shardNumString to int")); + } + } + if(!sm->isValid(realmNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "realm num not integer")); + } else { + if(DataTypeConverter::strToInt(realmNumString, realmNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting realmNumString to int")); + } + } + if(!sm->isValid(numString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "num not integer")); + } else { + if(DataTypeConverter::strToInt(numString, num) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting num to int")); + } + } + if(!sm->isValid(privateKeyString, VALIDATE_ONLY_HEX)) { + addError(new Error("Account Keys", "private key not hex")); + } + if(!sm->isValid(publicKeyString, VALIDATE_ONLY_HEX)) { + addError(new Error("Account Keys", "public key not hex")); + } + if(!sm->isValid(networkTypeString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Network Type", "not integer")); + } else { + if(DataTypeConverter::strToInt(networkTypeString, networkType) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting network type to int")); + } + if(networkType < 0 || networkType >= (int)ServerConfig::HEDERA_NET_COUNT) { + addError(new Error("Network Type", "invalid value")); + } + } + + if(0 == errorCount()) { + + auto hedera_id = controller::HederaId::create(shardNum, realmNum, num); + + private_key = DataTypeConverter::hexToBin(privateKeyString); + public_key = DataTypeConverter::hexToBin(publicKeyString); + + + KeyPairHedera key_pair(private_key, public_key); + auto crypto_key = controller::CryptoKey::load(key_pair.getPublicKey(), crypto_sign_PUBLICKEYBYTES); + + if(crypto_key.isNull()) { + crypto_key = controller::CryptoKey::create(&key_pair, user, privateKeyEncryptedString == "true"); + if(!crypto_key->getModel()->insertIntoDB(true)) { + addError(new Error("DB Error", "Error saving crypto key in DB")); + } + } else { + printf("crypto key found in db\n"); + } + if(0 == errorCount()) { + + if(hedera_id->isExistInDB()) { + auto hedera_account = controller::HederaAccount::load(hedera_id); + if(hedera_account.isNull()) { + addError(new Error("DB Error", "Couldn't load hedera account from db, but it should exist")); + } else { + addError(new Error("Hedera Account", "Account already exist (same account id")); + } + + } else { + auto hedera_account = controller::HederaAccount::create( + user->getModel()->getID(), + hedera_id->getModel()->getID(), + crypto_key->getModel()->getID(), + 0, + (ServerConfig::HederaNetworkType)networkType + ); + if(!hedera_account->getModel()->insertIntoDB(false)) { + addError(new Error("DB Error", "Error saving hedera account into DB")); + } + } + } + + mm->releaseMemory(private_key); + mm->releaseMemory(public_key); + } + } + } + if(!query_hedera_account.isNull()) { + getErrors(query_hedera_account); + } + // list accounts + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + +%><%@ include file="header_large.cpsp" %> + +<%= getErrorsHtml() %> + +
+
+
+

Deine Hedera Accounts

+
+
+
+
Hedera Id
+
Balance
+
Server Type
+
Verschlüsselt?
+
Last Updated
+
Aktionen
+
+ <% for(auto it = hedera_accounts.begin(); it != hedera_accounts.end(); it++) { + auto hedera_account_model = (*it)->getModel(); + auto updateUrl = ServerConfig::g_serverPath + "/hedera_account?action=updateBalance&account_id=" + std::to_string(hedera_account_model->getID()); + std::string changeEncryption(""); + if(hedera_account_model->getUserId() == user->getModel()->getID()) { + changeEncryption = ServerConfig::g_serverPath + "/hedera_account?action=changeEncryption&account_id=" + std::to_string(hedera_account_model->getID()); + } + auto isEncrypted = (*it)->getCryptoKey()->getModel()->isEncrypted(); + //printf("change encryption: %s\n", changeEncryption.data()); + + std::string kabuto_url = "https://explorer.kabuto.sh/";; + + if(hedera_account_model->getNetworkType() == ServerConfig::HEDERA_TESTNET) { + kabuto_url += "testnet/"; + } else if(hedera_account_model->getNetworkType() == ServerConfig::HEDERA_MAINNET) { + kabuto_url += "mainnet/"; + } + kabuto_url += "id/"; + auto hedera_id_string = (*it)->getHederaId()->getModel()->toString(); + kabuto_url += hedera_id_string; + %> +
+ +
<%= hedera_account_model->getBalanceString() %>
+
<%= model::table::HederaAccount::hederaNetworkTypeToString(hedera_account_model->getNetworkType()) %>
+
"><%= isEncrypted ? "Ja": "Nein" %>
+
<%= hedera_account_model->getUpdatedString() %>
+
+ + <% if(changeEncryption != "") { %> + + <% } %> +
+
+ <% } %> +
+
+
+

Ein existierenden Account eintragen

+
+
+
+ + + + + + + + + + + + + "> + +
+
+

Ein neuen Account anlegen

+

Bei Hedera einen neuen Account anlegen und zum Start Hashbars von einem existierenden Account überweisen.

+
+
+
+ + + +
+ + + "> + +
+
+<%@ include file="footer.cpsp" %> + + diff --git a/login_server/src/cpsp/adminHederaTopic.cpsp b/login_server/src/cpsp/adminHederaTopic.cpsp new file mode 100644 index 000000000..bc1fcf36e --- /dev/null +++ b/login_server/src/cpsp/adminHederaTopic.cpsp @@ -0,0 +1,21 @@ +<%@ page class="AdminHederaTopic" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + + +%> +<%% + const char* pageName = "Admin Hedera Topic"; + + +%><%@ include file="header_old.cpsp" %> +
+

Admin Hedera Topic

+ <%= getErrorsHtml() %> + +
+<%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/adminNodeServer.cpsp b/login_server/src/cpsp/adminNodeServer.cpsp new file mode 100644 index 000000000..679c4377d --- /dev/null +++ b/login_server/src/cpsp/adminNodeServer.cpsp @@ -0,0 +1,201 @@ +<%@ page class="AdminNodeServerPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + +#include "../controller/NodeServer.h" +#include "../controller/Group.h" +#include "../SingletonManager/SessionManager.h" +#include "../lib/DataTypeConverter.h" + +%> +<%% + const char* pageName = "Node Server"; + auto sm = SessionManager::getInstance(); + auto user = mSession->getNewUser(); + + // add + if(!form.empty()) { + // collect + auto url = form.get("node-server-url", ""); + auto portString = form.get("node-server-port", ""); + auto nodeServerTypeString = form.get("node-server-type", "0"); + auto shardNumString = form.get("account-shard-num", "0"); + auto realmNumString = form.get("account-realm-num", "0"); + auto numString = form.get("account-num", "0"); + auto nodeServerGroupString = form.get("node-server-group", ""); + + int port = 0; + int shardNum = 0; + int realmNum = 0; + int num = 0; + model::table::NodeServerType nodeServerType = model::table::NODE_SERVER_NONE; + int group_id = 0; + + + // validate + if(!sm->isValid(url, VALIDATE_ONLY_URL)) { + addError(new ParamError("Node Server", "Url not valid, must start with http or https", url)); + + } + if(!sm->isValid(portString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Node Server", "Port isn't valid integer")); + } else { + if(DataTypeConverter::strToInt(portString, port) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting port to int")); + } + } + + if(!sm->isValid(nodeServerTypeString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Node Server Type", "not integer")); + } else { + int node_server_type_int = 0; + if(DataTypeConverter::strToInt(nodeServerTypeString, node_server_type_int) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting node server type to int")); + } + if(node_server_type_int < 0 || node_server_type_int >= (int)model::table::NODE_SERVER_TYPE_COUNT) { + addError(new Error("Node Server Type", "invalid value")); + } else { + nodeServerType = (model::table::NodeServerType)node_server_type_int; + } + } + if(model::table::NodeServerIsHederaNode(nodeServerType)) { + + if(!sm->isValid(shardNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "shard num not integer")); + } else { + if(DataTypeConverter::strToInt(shardNumString, shardNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting shardNumString to int")); + } + } + if(!sm->isValid(realmNumString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "realm num not integer")); + } else { + if(DataTypeConverter::strToInt(realmNumString, realmNum) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting realmNumString to int")); + } + } + if(!sm->isValid(numString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Account ID", "num not integer")); + } else { + if(DataTypeConverter::strToInt(numString, num) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting num to int")); + } + } + } else if(model::table::NodeServerHasGroup(nodeServerType)) { + if(!sm->isValid(nodeServerGroupString, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Group id", "group_id not integer")); + } else { + if(DataTypeConverter::strToInt(nodeServerGroupString, group_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting group_id to int")); + } + } + } + + + + if(0 == errorCount()) { + int hedera_id_int = 0; + if(NodeServerIsHederaNode(nodeServerType)) { + auto hedera_id = controller::HederaId::create(shardNum, realmNum, num); + hedera_id_int = hedera_id->getModel()->getID(); + } + + auto node_server = controller::NodeServer::create( + url, port, group_id, (model::table::NodeServerType)nodeServerType, hedera_id_int + ); + if(!node_server->getModel()->insertIntoDB(false)) { + addError(new Error("DB Error", "Error saving Node Server in DB")); + } + } + } + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } + + auto node_servers = controller::NodeServer::listAll(); + + +%><%@ include file="header_large.cpsp" %> +<%= getErrorsHtml() %> +
+
+
+

Alle Node Server

+
+
+
+
Server Type
+
Url:Port
+
Group / Hedera Id
+
+ <% for(auto it = node_servers.begin(); it != node_servers.end(); it++) { + auto node_server_model = (*it)->getModel(); + %> +
+
<%= model::table::NodeServer::nodeServerTypeToString(node_server_model->getNodeServerType()) %>
+
<%= node_server_model->getUrlWithPort() %>
+
+ <% if(node_server_model->isHederaNode()) { + auto hedera_id_model = (*it)->getHederaId()->getModel(); %> + <%= hedera_id_model->toString() %> + <% } else if(node_server_model->hasGroup()){ + auto groupIt = group_indices.find(node_server_model->getGroupId()); + if(groupIt != group_indices.end()) { + auto group_model = groups[groupIt->second]->getModel(); %> + <%= group_model->getName() %> + <% } else { %> + <%= node_server_model->getGroupId() %> + <% } %> + <% } %> +
+
+ <% } %> +
+
+
+

Ein Node Server hinzufügen

+
+
+
+ + + + + + +
+ Nur für Hedera Nodes + + + + +
+
+ Nur für Gradido Nodes + + +
+ + "> + +
+ +<%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/adminNodeServerTest.cpsp b/login_server/src/cpsp/adminNodeServerTest.cpsp new file mode 100644 index 000000000..a1cc0a295 --- /dev/null +++ b/login_server/src/cpsp/adminNodeServerTest.cpsp @@ -0,0 +1,424 @@ +<%@ page class="AdminNodeServerTestPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="PageRequestMessagedHandler" %> +<%@ header include="PageRequestMessagedHandler.h" %> +<%! + +#include "../controller/NodeServer.h" +#include "../controller/User.h" +#include "../controller/HederaTopic.h" +#include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" +#include "../lib/JsonRPCRequest.h" +#include "../model/gradido/Transaction.h" + +#include "Poco/Thread.h" +#include "Poco/DateTime.h" +#include "Poco/JSON/Stringifier.h" + +enum PageType +{ + PAGE_CHOOSE_TEST, + PAGE_RUN_4_SET_TEST, + PAGE_GET_TRANSACTION_RPC_CALL +}; + +%> +<%% + const char* pageName = "Node Server Test"; + PageType page = PAGE_CHOOSE_TEST; + Poco::AutoPtr node_server; + Poco::AutoPtr node_server2; + Poco::AutoPtr user; + Poco::AutoPtr hedera_topic; + Poco::AutoPtr hedera_topic2; + int hedera_timeout = 4; + int sleep_ms_between_transactions = 1000; + + bool steps[8]; memset(steps, 1, 8 * sizeof(bool)); + + + if(!form.empty()) + { + auto node_server_id_string = form.get("test-node-servers", ""); + if(node_server_id_string != "") { + int node_server_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) { + node_server = controller::NodeServer::load(node_server_id); + } + } + node_server_id_string = form.get("test-node-servers2", ""); + if(node_server_id_string != "") { + int node_server_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) { + node_server2 = controller::NodeServer::load(node_server_id); + } + } + auto topic_id_string = form.get("test-hedera-topic", ""); + if(topic_id_string != "") { + int topic_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) { + hedera_topic = controller::HederaTopic::load(topic_id); + } + } + topic_id_string = form.get("test-hedera-topic2", ""); + if(topic_id_string != "") { + int topic_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) { + hedera_topic2 = controller::HederaTopic::load(topic_id); + } + } + auto test_timeout_string = form.get("test-timeout", ""); + if(test_timeout_string != "") { + DataTypeConverter::strToInt(test_timeout_string, hedera_timeout); + } + auto test_part_timeout_string = form.get("test-part-timeout", ""); + if(test_part_timeout_string != "") { + DataTypeConverter::strToInt(test_part_timeout_string, sleep_ms_between_transactions); + } + auto submit = form.get("submit", ""); + if(submit == "Run 6-Test") { + page = PAGE_RUN_4_SET_TEST; + } else if(submit == "json-rpc getTransactions") { + page = PAGE_GET_TRANSACTION_RPC_CALL; + } + std::string step_temp; + for(int i = 0; i < 8; i++) { + std::string name = "step-"; + name += std::to_string(i+2); + step_temp = form.get(name, ""); + if(step_temp == "1") { + steps[i] = true; + } else { + steps[i] = false; + } + } + } + + auto node_servers = controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_NODE); + auto hedera_topics = controller::HederaTopic::listAll(); + +%><%@ include file="header_large.cpsp" %> +<%= getErrorsHtml() %> +
+ +
+ + +
+
style="display:block" <% } %>> +
+

Test 6-Set (3 AddMember, Creation, 2 Transfer) +

+
+
+

1. Create three new accounts and show user public keys for comparisation

+

checked="checked" <% } %> name="step-2" value="1"/> 2. Send a add-member transaction to hedera topic with one signature (first user)

+

checked="checked" <% } %> name="step-3" value="1"/> 3. Send a add-member transaction to hedera topic with two signatures (first user and second user)

+

checked="checked" <% } %> name="step-4" value="1"/> 4. Send a creation transaction to second user, signed by first user

+

checked="checked" <% } %> name="step-5" value="1"/> 5. Send a transfer transaction from second user to first user signed by second user

+

checked="checked" <% } %> name="step-6" value="1"/> 6. Send a add-member transaction to hedera topic 2 with one signature (third user)

+

checked="checked" <% } %> name="step-7" value="1"/> 7. Send a cross group transfer from second user to third user signed by second user

+

checked="checked" <% } %> name="step-8" value="1"/> 8. Wait x seconds to give hedera time to process transactions

+

checked="checked" <% } %> name="step-9" value="1"/> 9. Ask choosen node for transaction and print result

+
+ Group 1 + + <% if(node_servers.size() == 0) { %> + Edit Node-Servers + <% } %> + + + <% if(hedera_topics.size() == 0) { %> + Edit Hedera-Topics + <% } %> + +
+
+ Group 2 + + <% if(node_servers.size() == 0) { %> + Edit Node-Servers + <% } %> + + + <% if(hedera_topics.size() == 0) { %> + Edit Hedera-Topics + <% } %> + +
+ + + seconds + + ms + + +
+
+
style="display:block" <% } %>> +
+

Test 4-Set (2 AddMember, Creation, Transfer) +

+
+
+ + <% if(node_servers.size() == 0) { %> + Edit Node-Servers + <% } %> + + + +
+
+ <% if(PAGE_RUN_4_SET_TEST == page && !hedera_topic.isNull() && !node_server.isNull()) { %> +
    +
  • +

    1. Create three new accounts and show user public keys for comparisation:

    + <% + Profiler time2; + auto group_id = hedera_topic->getModel()->getGroupId(); + auto group_id2 = hedera_topic2->getModel()->getGroupId(); + auto user_group = controller::Group::load(group_id); + auto user_group2 = controller::Group::load(group_id2); + auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; + + std::string password1 = "hsaj(2askaslASlllak3wjjeudsaj"; + auto user_1 = controller::User::create("testEmail@google.de", "Max", "Mustermann", group_id); + auto passphrase_1 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_1 = KeyPairEd25519::create(passphrase_1); + user_1->setGradidoKeyPair(gradido_key_pair_1); + user_1->login(password1); + + std::string password2 = "uweia8saiSale,dsasA"; + auto user_2 = controller::User::create("testEmail2@google.de", "MJax", "Mustrermann", group_id); + auto passphrase_2 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_2 = KeyPairEd25519::create(passphrase_2); + user_2->setGradidoKeyPair(gradido_key_pair_2); + user_2->login(password2); + + std::string password3 = "jaue_skaiellasealaK"; + auto user_3 = controller::User::create("testEmail3@gmail.com", "Morpheus", "Miaufull", group_id2); + auto passphrase_3 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]); + auto gradido_key_pair_3 = KeyPairEd25519::create(passphrase_3); + user_3->setGradidoKeyPair(gradido_key_pair_3); + user_3->login(password3); + %> +
    <%= user_group->getModel()->getName() %> +

    User 1: <%= user_1->getPublicHex() %>

    +

    User 2: <%= user_2->getPublicHex() %>

    +
    +
    <%= user_group2->getModel()->getName() %> +

    User 3: <%= user_3->getPublicHex() %>

    +
    +

    Time: <%= time2.string() %> +

  • +
  • +

    2. Send a add-member transaction to hedera topic with one signature (first user)

    + <% + time2.reset(); + if(!steps[0]) { %> +

    skipped

    + <% } else { + auto transaction1 = model::gradido::Transaction::createGroupMemberUpdate(user_1, user_group); + transaction1->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1); + transaction1->sign(user_1); + auto transaction1_json = transaction1->getTransactionAsJson(true); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction1_json) %>

    + <% } %> +

    Time: <%= time2.string() %> +

  • +
  • +

    3. Send a add-member transaction to hedera topic with two signatures (first user and second user)

    + <% + time2.reset(); + if(!steps[1]) { %> +

    skipped

    + <% } else { + auto transaction2 = model::gradido::Transaction::createGroupMemberUpdate(user_2, user_group); + transaction2->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(2); + transaction2->sign(user_2); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction2->sign(user_1); + auto transaction2_json = transaction2->getTransactionAsJson(true); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction2_json) %>

    + <% } %> +

    Time: <%= time2.string() %> +

  • +
  • +

    4. Send a creation transaction to second user, signed by first user

    + <% + time2.reset(); + if(!steps[2]) { %> +

    skipped

    + <% } else { + auto transaction3 = model::gradido::Transaction::createCreation(user_2, 10000000, Poco::DateTime(), "Test Creation"); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction3->sign(user_1); + auto transaction3_json = transaction3->getTransactionAsJson(true); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction3_json) %>

    + <% } %> +

    Time: <%= time2.string() %>

    +
  • +
  • +

    5. Send a transfer transaction from second user to first user signed by second user

    + <% + time2.reset(); + if(!steps[3]) { %> +

    skipped

    + <% } else { + auto user_1_pubkey = user_1->getModel()->getPublicKeyCopy(); + auto transaction4 = model::gradido::Transaction::createTransfer(user_2, user_1_pubkey, user_group, 5000000, "Test Transfer"); + // wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction4[0]->sign(user_2); + auto transaction4_json = transaction4[0]->getTransactionAsJson(true); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction4_json) %>

    + <% } %> +

    Time: <%= time2.string() %>

    +
  • +
  • +

    6. Send a add-member transaction to hedera topic 2 with one signature (third user)

    + <% + time2.reset(); + if(!steps[4]) { %> +

    skipped

    + <% } else { + auto transaction5 = model::gradido::Transaction::createGroupMemberUpdate(user_3, user_group2); + transaction5->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1); + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction5->sign(user_3); + auto transaction5_json = transaction5->getTransactionAsJson(true); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction5_json) %>

    + <% } %> +

    Time: <%= time2.string() %>

    +
  • +
  • +

    7. Send a cross group transfer from second user to third user signed by second user

    + <% + time2.reset(); + if(!steps[5]) { %> +

    skipped

    + <% } else { + auto user_3_pubkey = user_3->getModel()->getPublicKeyCopy(); + auto transaction6 = model::gradido::Transaction::createTransfer(user_2, user_3_pubkey, user_group2, 4000000, "Test Group Transfer", false); + if(!transaction6.size()) { + %> + + <% + } else { + Poco::Thread::sleep(sleep_ms_between_transactions); + transaction6[0]->sign(user_2); + auto transaction6_json = transaction6[0]->getTransactionAsJson(true); + auto paired_transaction = transaction6[0]->getPairedTransaction(); + %> +

    <%= DataTypeConverter::replaceNewLineWithBr(transaction6_json) %>

    + <% if(!paired_transaction.isNull()) { + auto transaction6_2_json = paired_transaction->getTransactionAsJson(true); + %>

    <%= DataTypeConverter::replaceNewLineWithBr(transaction6_2_json) %>

    + <% } %> + <% } %> + <% } %> +

    Time: <%= time2.string() %>

    +
  • +
  • +

    8. Wait <%= hedera_timeout %> seconds to give hedera time to process transactions

    + <% if(!steps[6]) { %> +

    skipped

    + <% } else { + Poco::Thread::sleep(hedera_timeout * 1000); + } %> +
  • +
  • +

    9. Ask choosen node for transaction and print result

    + <% time2.reset(); + if(!steps[7] || node_server.isNull()) { + %>

    skipped

    + <% } else { + auto node_server_model = node_server->getModel(); + JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort()); + Poco::JSON::Object params; + params.set("groupAlias", user_group->getModel()->getAlias()); + params.set("lastKnownSequenceNumber", 0); + auto gn_answear = jsonrpc.request("getTransactions", params); + if(!gn_answear.isNull()) { + std::stringstream ss; + Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER); + std::string answear_string = ss.str(); %> + <%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><% + } + } %> +

    Time: <%= time2.string() %>

    +
  • +
+ <% } else if(PAGE_GET_TRANSACTION_RPC_CALL == page && !node_server.isNull()) { + Profiler time3; + auto node_server_model = node_server->getModel(); + auto user_group = controller::Group::load(node_server_model->getGroupId()); + JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort()); + Poco::JSON::Object params; + params.set("groupAlias", user_group->getModel()->getAlias()); + params.set("lastKnownSequenceNumber", 0); + auto gn_answear = jsonrpc.request("getTransactions", params); + if(!gn_answear.isNull()) { + std::stringstream ss; + Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER); + std::string answear_string = ss.str();%> + <%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><% + } + %> +

Time: <%= time3.string() %>

+ <% } %> + +
+ +<%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/adminTopic.cpsp b/login_server/src/cpsp/adminTopic.cpsp new file mode 100644 index 000000000..78c2a7b96 --- /dev/null +++ b/login_server/src/cpsp/adminTopic.cpsp @@ -0,0 +1,322 @@ +<%@ page class="AdminTopicPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + #include "../controller/HederaAccount.h" + #include "../controller/HederaTopic.h" + #include "../controller/Group.h" + #include "../SingletonManager/SessionManager.h" + #include "../ServerConfig.h" + + #include "../lib/DataTypeConverter.h" + #include "../lib/Profiler.h" + #include "../lib/Success.h" + + #include "Poco/Timespan.h" + #include "Poco/URI.h" +%> +<%% + const char* pageName = "Topic"; + auto user = mSession->getNewUser(); + auto sm = SessionManager::getInstance(); + Profiler hedera_time; + + std::string name = ""; + std::string topic_id_string = ""; + int auto_renew_account = 0; + int auto_renew_period = 7890000; // 3 Monate + + int group_id = 0; + + Poco::URI uri(request.getURI()); + auto uri_query = uri.getQueryParameters(); + std::string action = ""; + Poco::AutoPtr query_hedera_topic; + + // parsing get query params + if(uri_query.size() >= 2) { + if(uri_query[0].first == "action") { + action = uri_query[0].second; + } + if(uri_query[1].first == "topic_id") { + std::string topic_id_from_query; + int topic_id = 0; + topic_id_from_query = uri_query[1].second; + if(DataTypeConverter::strToInt(topic_id_from_query, topic_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int Convert Error", "Error converting topic_id_from_query to int")); + } else { + auto hedera_topic = controller::HederaTopic::load(topic_id); + if(hedera_topic.isNull()) { + addError(new Error("Action", "hedera topic not found")); + } else { + query_hedera_topic = hedera_topic; + } + } + } + } + // actions + if(!query_hedera_topic.isNull()) + { + if(action == "getTopicInfos") + { + hedera_time.reset(); + if(query_hedera_topic->updateWithGetTopicInfos(user)) { + addNotification(new ParamSuccess("Hedera", "hedera get topic infos success in ", hedera_time.string())); + } else { + addError(new ParamError("Hedera", "hedera get topic infos failed in ", hedera_time.string())); + } + getErrors(query_hedera_topic); + } + } + else if(!form.empty()) + { + name = form.get("topic-name", ""); + topic_id_string = form.get("topic-id", ""); + auto auto_renew_account_string = form.get("topic-auto-renew-account", "0"); + auto auto_renew_period_string = form.get("topic-auto-renew-period", "7890000"); + auto group_id_string = form.get("topic-group", "-1"); + Poco::AutoPtr topic_id; + + if(topic_id_string != "" && sm->isValid(topic_id_string, VALIDATE_HEDERA_ID)) { + topic_id = controller::HederaId::create(topic_id_string); + if(topic_id.isNull()) { + addError(new Error("Hedera Id", "cannot parse hedera id")); + } + + } else { + + if(name != "" && !sm->isValid(name, VALIDATE_NAME)) { + addError(new Error("Topic", "Name not valid, at least 3 Character")); + } + + if(!sm->isValid(auto_renew_account_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew account id not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_account_string, auto_renew_account) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew account id to int")); + } + } + + if(!sm->isValid(auto_renew_period_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew period not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_period_string, auto_renew_period) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew period to int")); + } + } + } + + if(!sm->isValid(group_id_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "group_id not an integer")); + } else { + if(DataTypeConverter::strToInt(group_id_string, group_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting group_id to int")); + } + } + //const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId + + // add or create topic? + // add topic + if(!topic_id.isNull()) { + if(topic_id->getModel()->insertIntoDB(true)) { + auto hedera_topic = controller::HederaTopic::loadFromHedera(topic_id, group_id, user); + if(!hedera_topic.isNull()) { + hedera_topic->getModel()->insertIntoDB(false); + } else { + addError(new Error("Hedera Topic", "error load topic from hedera")); + } + } else { + addError(new Error("Hedera Id", "Error saving hedera id")); + } + // create topic + } else { + auto hedera_topic = controller::HederaTopic::create(name, auto_renew_account, auto_renew_period, group_id); + if(!hedera_topic->getModel()->insertIntoDB(true)) { + addError(new Error("Topic", "error saving into db")); + } else { + auto payer = controller::HederaAccount::load(auto_renew_account); + if(payer.isNull()) { + addError(new Error("Payer", "payer account not found")); + } else { + auto hedera_task = hedera_topic->createTopic(payer, user); + if(hedera_task.isNull()) { + addError(new Error("Create Topic", "Failed")); + getErrors(hedera_topic); + } + } + } + } + + } + + + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + //std::vector> hedera_accounts; + + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } + + auto hedera_topics = controller::HederaTopic::listAll(); + //std::vector> hedera_topics; + +%><%@ include file="header_large.cpsp" %> + + +<%= getErrorsHtml() %> +
+

Topic Admin Page

+
+
+
+
+

Hedera Topics

+
+
+
+
Topic ID
+
Name
+
Network Type
+
Auto Renew Account Balance
+
Auto Renew Period
+
Group ID
+
Current Timeout
+
Sequence Number
+
Last Updated
+
Aktionen
+
+ <% for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) { + auto hedera_topic_model = (*it)->getModel(); + auto updateUrl = ServerConfig::g_serverPath + "/topic?action=getTopicInfos&topic_id=" + std::to_string(hedera_topic_model->getID()); + std::string kabuto_url = "https://explorer.kabuto.sh/";//testnet/id/0.0.132132; + + + auto auto_renew_account = (*it)->getAutoRenewAccount(); + auto renew_account_model = auto_renew_account->getModel(); + + if(renew_account_model->getNetworkType() == ServerConfig::HEDERA_TESTNET) { + kabuto_url += "testnet/"; + } else if(renew_account_model->getNetworkType() == ServerConfig::HEDERA_MAINNET) { + kabuto_url += "mainnet/"; + } + kabuto_url += "id/"; + + std::string timeout_color = "success-color"; + if(hedera_topic_model->getCurrentTimeout() < Poco::DateTime()) { + timeout_color = "alert-color"; + } else if((hedera_topic_model->getCurrentTimeout() - Poco::DateTime()) < Poco::Timespan(2,0,0,0,0)) { + timeout_color = "orange-color"; + } + std::string topic_hedera_id_string = ""; + auto topic_hedera_id = (*it)->getTopicHederaId(); + if(!topic_hedera_id.isNull()) { + topic_hedera_id_string = topic_hedera_id->getModel()->toString(); + kabuto_url += topic_hedera_id_string; + } + + + %> +
+ +
<%= hedera_topic_model->getName() %>
+
<%= model::table::HederaAccount::hederaNetworkTypeToString(renew_account_model->getNetworkType()) %>
+
<%= renew_account_model->getBalanceString() %>
+
<%= hedera_topic_model->getAutoRenewPeriodString() %>
+
<%= hedera_topic_model->getGroupId() %>
+
<%= hedera_topic_model->getCurrentTimeoutString() %>
+
<%= hedera_topic_model->getSequenceNumber() %>
+
<%= hedera_topic_model->getUpdatedString() %>
+
<% if(!topic_hedera_id.isNull()) { %> + + <% } %> +
+
+ <% } %> +
+
+ +
+ + +
+
+
+

Ein neues Topic anlegen

+
+
+
+ + + + + +
+ + + + "> + +
+
+
+
+

Ein bestehendes Topic eintragen

+
+
+
+ + + + + + "> + +
+
+
+<%@ include file="footer.cpsp" %> + + + \ No newline at end of file diff --git a/login_server/src/cpsp/adminUserPasswordReset.cpsp b/login_server/src/cpsp/adminUserPasswordReset.cpsp index 648a18f61..7022b42d9 100644 --- a/login_server/src/cpsp/adminUserPasswordReset.cpsp +++ b/login_server/src/cpsp/adminUserPasswordReset.cpsp @@ -8,7 +8,7 @@ // includes #include "../controller/User.h" #include "../controller/EmailVerificationCode.h" -#include "../controller/UserBackups.h" +#include "../controller/UserBackup.h" enum PageState @@ -21,7 +21,7 @@ enum PageState PageState state = PAGE_ASK_EMAIL; Poco::AutoPtr user = controller::User::create(); Poco::AutoPtr code; - Poco::AutoPtr userBackup; + Poco::AutoPtr userBackup; bool validUser = false; std::string pageName = "Admin User Passwort Reset"; @@ -47,11 +47,11 @@ enum PageState } } - auto backups = controller::UserBackups::load(userId); + auto backups = controller::UserBackup::load(userId); auto userPubkey = user->getModel()->getPublicKey(); for(auto it = backups.begin(); it != backups.end(); it++) { auto keys = (*it)->getKeyPair(); - if(keys->isPubkeysTheSame(userPubkey)) { + if(keys->isTheSame(userPubkey)) { userBackup = *it; break; } @@ -102,7 +102,7 @@ enum PageState hier findest du deine Passphrase mit dessen Hilfe du dir ein neues Passwort einstellen kannst. Bitte schreibe sie dir auf und packe sie gut weg. -<%= controller::UserBackups::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) %> +<%= controller::UserBackup::formatPassphrase(userBackup->getPassphrase(ServerConfig::Mnemonic_Types::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER)) %> diff --git a/login_server/src/cpsp/checkEmail.cpsp b/login_server/src/cpsp/checkEmail.cpsp index f60b7e647..25da63ee6 100644 --- a/login_server/src/cpsp/checkEmail.cpsp +++ b/login_server/src/cpsp/checkEmail.cpsp @@ -21,6 +21,7 @@ enum PageState auto lm = LanguageManager::getInstance(); auto em = EmailManager::getInstance(); + auto user = mSession->getNewUser(); auto lang = chooseLanguage(request); auto langCatalog = lm->getFreeCatalog(lang); unsigned long long verificationCode = 0; @@ -72,10 +73,10 @@ enum PageState

<%= langCatalog->gettext("E-Mail verifizieren") %>

-
+ <% if(EMAIL_ACTIVATED == state) { %>

<%= langCatalog->gettext("Deine E-Mail wurde erfolgreich bestätigt. Du kannst nun Gradidos versenden.") %>

- <%= langCatalog->gettext("Zur Startseite") %> + <%= langCatalog->gettext("Zur Startseite") %> <% } else { %> " <% if(verificationCode) { %>value="<%= verificationCode %>" <% } %>> diff --git a/login_server/src/cpsp/checkTransaction.cpsp b/login_server/src/cpsp/checkTransaction.cpsp index 660eb08bd..ed22883bd 100644 --- a/login_server/src/cpsp/checkTransaction.cpsp +++ b/login_server/src/cpsp/checkTransaction.cpsp @@ -8,14 +8,18 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/SingletonTaskObserver.h" #include "../SingletonManager/EmailManager.h" -#include "../model/TransactionCreation.h" -#include "../model/TransactionTransfer.h" +#include "../SingletonManager/PendingTasksManager.h" +#include "../model/gradido/TransactionCreation.h" +#include "../model/gradido/TransactionTransfer.h" + +#include "../lib/DataTypeConverter.h" #include "Poco/Thread.h" enum PageState { PAGE_TRANSACTION_CREATION, PAGE_TRANSACTION_TRANSFER, + PAGE_TRANSACTION_GROUP_ADD_MEMBER, PAGE_NO_TRANSACTIONS, PAGE_USER_DATA_CORRUPTED }; @@ -24,23 +28,43 @@ enum PageState { <%% const char* pageName = gettext("Überprüfe Transaktion"); auto account_user = mSession->getNewUser(); + auto user = account_user; auto user_model = account_user->getModel(); auto em = EmailManager::getInstance(); + auto pt = PendingTasksManager::getInstance(); auto userBalance = account_user->getBalance(); std::string memo = ""; bool hasErrors = false; bool enableLogout = true; + bool enableSign = true; + int skip_count = 0; + int pending_task_id = 0; + + std::string community_server_base_path = ServerConfig::g_php_serverPath; + if(user_model->getGroupId() != 0) { + community_server_base_path = user->getGroupBaseUrl(); + } PageState state = PAGE_NO_TRANSACTIONS; - + if(!user_model->isEmailChecked()) { addError(new Error(gettext("E-Mail Aktivierung"), gettext("E-Mail wurde noch nicht aktiviert, du kannst leider noch keine Transaktionen ausführen!"))); hasErrors = true; } - + bool transaction_finalize_run = false; bool transaction_finalize_result = false; + auto transactions_to_sign = pt->getTransactionsUserMustSign(account_user); + Poco::AutoPtr pending_task; + model::gradido::Transaction* transaction = nullptr; + Poco::AutoPtr transaction_body; + + if(!form.empty()) + { + transaction = dynamic_cast(transactions_to_sign[0].get()); + transaction_body = transaction->getTransactionBody(); + if(!form.empty()) { auto ok = form.get("ok", ""); auto abort = form.get("abort", ""); @@ -98,25 +122,171 @@ enum PageState { breakCount++; Poco::Thread::sleep(10); }*/ - auto lastExternReferer = mSession->getLastReferer(); - //lastExternReferer = ""; - if(lastExternReferer != "" && lastExternReferer.find("transaction-send-coins") == std::string::npos) { - //printf("last extern referer: %s\n", lastExternReferer.data()); - response.redirect(lastExternReferer); + auto pending_task_id_string = form.get("pending-task-id", ""); + int pending_task_id = 0; + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(pending_task_id_string, pending_task_id)) + { + // make sure we have the correct transaction + transaction = nullptr; + printf("transaction_body isNull: %d\n", transaction_body.isNull()); + transaction_body.assign(nullptr); + for(auto it = transactions_to_sign.begin(); it != transactions_to_sign.end(); it++) + { + if((*it)->getModel()->getID() == pending_task_id) { + transaction = dynamic_cast(it->get()); + transaction_body = transaction->getTransactionBody(); + printf("set new transaction and transaction_body\n"); + break; + } + } + if(abort != "") +/* + auto ok = form.get("ok", ""); + auto abort = form.get("abort", ""); + auto skip = form.get("skip", ""); + auto skip_count_str = form.get("skip-count", "0"); + auto pending_task_id_string = form.get("pending-task-id", ""); + DataTypeConverter::strToInt(skip_count_str, skip_count); + + if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(pending_task_id_string, pending_task_id)) + { + // load transaction from pending task manager + pending_task = pt->getPendingTask(pending_task_id); + if(!pending_task.isNull() && pending_task->getModel()->isGradidoTransaction()) +*/ + { + transaction = dynamic_cast(pending_task.get()); + if(transaction->hasSigned(account_user)) { + transaction = nullptr; + } else { + transaction_body = transaction->getTransactionBody(); + } + + if(abort != "") + { + //mSession->finalizeTransaction(false, true); + // + if(transaction && transaction->getModel()->getUserId() == user_model->getID()) + { + transaction->deleteFromDB(); + transaction = nullptr; + } + } + else if(ok != "") + { + if(!account_user->hasPassword()) { + auto pwd = form.get("sign-password", ""); + auto loginResult = account_user->login(pwd); + switch(loginResult) { + case 0: + addError(new Error(gettext("Passwort"), gettext("Das Passwort stimmt nicht. Bitte verwende dein Passwort von der Registrierung"))); + hasErrors = true; + break; + case -1: + case -2: + addError(new Error(gettext("Passwort"), gettext("Gespeicherte Daten sind korrupt!"))); + hasErrors = true; + state = PAGE_USER_DATA_CORRUPTED; + enableSign = false; + break; + case -3: + addError(new Error(gettext("Passwort"), gettext("Passwortprüfung läuft schon, bitte versuche es in 1-2 Minuten erneut."))); + hasErrors = true; + break; + } + } + if(!hasErrors) { + //mSession->finalizeTransaction(true, false); + if(transaction && transaction->sign(account_user)) { + transaction = nullptr; + } + } + } + else if(skip != "") + { + skip_count++; + transaction = nullptr; + } + } else { + addError(new Error(gettext("Input Error"), gettext("Task no found"))); + } } else { - response.redirect(ServerConfig::g_php_serverPath + "state-balances/overview"); + addError(new Error(gettext("Form Error"), gettext("error with field"))); + } + } + + auto transactions_user_must_sign = pt->getTransactionsUserMustSign(account_user); + std::vector> transactions_someone_must_sign; + // TODO: work with community server roles + if(user_model->getRole() == model::table::ROLE_ADMIN) { + transactions_someone_must_sign = pt->getTransactionSomeoneMustSign(account_user); + } + std::vector> transactions_to_sign; + bool transaction_removeable = false; + int transaction_to_sign_index = 0; + if(!transaction) + { + if(transactions_user_must_sign.size() > skip_count) { + transactions_to_sign = transactions_user_must_sign; + transaction_to_sign_index = skip_count; + } else if(transactions_someone_must_sign.size() > (skip_count - transactions_user_must_sign.size())) { + transactions_to_sign = transactions_someone_must_sign; + transaction_to_sign_index = skip_count - transactions_user_must_sign.size(); + } + + if(transactions_to_sign.size() > transaction_to_sign_index) + { + transaction = dynamic_cast(transactions_to_sign[transaction_to_sign_index].get()); + transaction_body = transaction->getTransactionBody(); + // user can only delete there own transactions + // TODO: Auto timeout for community transactions + if(transaction->getModel()->getUserId() == user_model->getID()) { + transaction_removeable = true; + } + } + } + size_t sumTransactions = transactions_user_must_sign.size() + transactions_someone_must_sign.size(); + if(sumTransactions == 0) + { + auto lastExternReferer = mSession->getLastReferer(); + auto callerUri = mSession->getCallerUri(); + //lastExternReferer = ""; + account_user->reload(); + if(callerUri != "") { + response.redirect(callerUri); + } else if(lastExternReferer != "" && lastExternReferer.find("transaction-send-coins") == std::string::npos) { + response.redirect(lastExternReferer); + } else if(!account_user->getModel()->getGroupId()) { + response.redirect(getBaseUrl() + "/userUpdateGroup"); + } else { + response.redirect(account_user->getGroupBaseUrl() + "/state-balances/overview"); } return; } - auto processingTransaction = mSession->getNextReadyTransaction(¬ReadyTransactions); - if(sumTransactions > 0) { + + if(transactions_user_must_sign.size() > 0) + { enableLogout = false; } - if(PAGE_NO_TRANSACTIONS == state && !processingTransaction.isNull()) { - auto transactionType = processingTransaction->getType(); + if(PAGE_NO_TRANSACTIONS == state && transaction && !transaction_body.isNull()) + { + auto transactionType = transaction_body->getType(); + memo = transaction_body->getMemo(); switch(transactionType) { - case TRANSACTION_CREATION: state = PAGE_TRANSACTION_CREATION; break; - case TRANSACTION_TRANSFER: state = PAGE_TRANSACTION_TRANSFER; break; + case model::gradido::TRANSACTION_CREATION: state = PAGE_TRANSACTION_CREATION; break; + case model::gradido::TRANSACTION_TRANSFER: state = PAGE_TRANSACTION_TRANSFER; break; + case model::gradido::TRANSACTION_GROUP_MEMBER_UPDATE: + state = PAGE_TRANSACTION_GROUP_ADD_MEMBER; + //community_server_base_path + break; + } + if(model::gradido::TRANSACTION_GROUP_MEMBER_UPDATE != transactionType) + { + if(!user_model->isEmailChecked()) { + addError(new Error(gettext("E-Mail Aktivierung"), gettext("E-Mail wurde noch nicht aktiviert, du kannst leider noch keine Transaktionen ausführen!"))); + hasErrors = true; + enableSign = false; + } } } @@ -136,22 +306,17 @@ enum PageState {
<% } %> +
- <% if(sumTransactions > 0 && sumTransactions - notReadyTransactions != 1) { %> - <% if(notReadyTransactions > 0) { %> - <%= sumTransactions - notReadyTransactions %> <%= gettext("von") %> <%= sumTransactions %> <%= gettext("Transaktionen sind bereit zum bestätigen") %> - <% } else { %> - <%= sumTransactions %> <%= gettext("Transaktionen warten darauf bestätigt zu werden.") %> + <% if(sumTransactions == 0) { %> + <%= gettext("Es gibt zurzeit keine Transaktionen zum bestätigen") %> + <% } else { %> +

<%= sumTransactions %> <%= gettext("Transaktionen warten darauf bestätigt zu werden.") %>

+ <% if(skip_count > 0) { %> +

<%= skip_count %> <%= gettext("Transaktionen übersprungen.") %>

<% } %> <% } %> - <% if(state == PAGE_NO_TRANSACTIONS) { %> - <% if(sumTransactions == 0) { %> - <%= gettext("Es gibt zurzeit keine Transaktionen zum bestätigen") %> - <% } else { %> - <%= gettext("Transaktion(en) werden noch vorbereitet, bitte lade die Seite in wenigen Augenblicken erneut.") %> - <% } %> - <% } %>
@@ -159,8 +324,7 @@ enum PageState {

<%= gettext("Transaktion Unterzeichnen") %>

<% if(state == PAGE_TRANSACTION_TRANSFER) { - auto transferTransaction = processingTransaction->getTransferTransaction(); - memo = transferTransaction->getMemo(); + auto transferTransaction = transaction_body->getTransferTransaction(); %>

<%= gettext("Überweisung") %>

@@ -175,14 +339,16 @@ enum PageState {
<% } %> <%= transferTransaction->getKontoNameCell(i) %> + <% if(((i+1) % 2) == 0 && transferTransaction->getTargetGroupAlias() != "") { %> + (<%= transferTransaction->getTargetGroupAlias() %>) + <% } %> <%= transferTransaction->getAmountCell(i) %>
<% } %>
<% } else if(PAGE_TRANSACTION_CREATION == state) { - auto creationTransaction = processingTransaction->getCreationTransaction(); + auto creationTransaction = transaction_body->getCreationTransaction(); auto transactionUser = creationTransaction->getUser(); - memo = creationTransaction->getMemo(); %>

<%= gettext("Schöpfung") %>

@@ -192,8 +358,10 @@ enum PageState { <%= gettext("Gradido") %>
- <% if(transactionUser) { %> - <%= transactionUser->getFirstName() %> <%= transactionUser->getLastName() %> <<%= transactionUser->getEmail() %>> + <% if(!transactionUser.isNull()) { + auto user_model = transactionUser->getModel(); + %> + <%= user_model->getFirstName() %> <%= user_model->getLastName() %> <<%= user_model->getEmail() %>> <% } else { %> 0x<%= creationTransaction->getPublicHex() %> <% } %> @@ -201,9 +369,44 @@ enum PageState { <%= creationTransaction->getAmountString() %> GDD
+ <% } else if(PAGE_TRANSACTION_GROUP_ADD_MEMBER == state) { + auto groupMemberUpdateTransaction = transaction_body->getGroupMemberUpdate(); + auto groups = controller::Group::load(groupMemberUpdateTransaction->getTargetGroupAlias()); + Poco::AutoPtr group_model; + Poco::AutoPtr user; + if(groups.size() == 1 && !groups[0].isNull()) group_model = groups[0]->getModel(); + auto user_id = transaction->getModel()->getUserId(); + if(user_id == user_model->getID()) { + user = account_user; + } else { + user = controller::User::sload(user_id); + } + %> +

<%= gettext("Benutzer zu einer Gruppe hinzufügen") %>

+
+

<% if(!user.isNull()) { %> + Benutzer: <%= user->getEmailWithNames() %> + <% } else { %> + Account public key: <%= groupMemberUpdateTransaction->getPublicKeyHex() %> + <% } %>

+ <% if(!group_model.isNull()) { %> +

<%= gettext("Gruppe") %>:

+
    +
  • <%= gettext("Name") %>: <%= group_model->getName() %>
  • +
  • <%= gettext("Alias") %>: <%= group_model->getAlias() %>
  • +
  • <%= gettext("Url") %>: <%= group_model->getUrl() %>
  • +
  • <%= group_model->getDescription() %>
  • +
+ <% } else { %> + <%= gettext("Unbekannte Gruppe") %> + <% } %> + <%= gettext("Es haben bereits ") %><%= std::to_string(transaction->getSignCount()) %><%= gettext(" unterzeichnet") %> +
+ <% } else if(PAGE_USER_DATA_CORRUPTED == state) { %>

<%= gettext("Es gibt ein Problem mit deinen gespeicherten Daten, bitte wende dich an den")%><%=gettext("Support") %>

<% } %> + + <% if(PAGE_NO_TRANSACTIONS == state) { %> + <%= gettext("Zurück") %> + <% } else { %> +
+
+ Aktives Konto +
+
+ <%= user_model->getNameWithEmailHtml() %> +
+
+
+
+ Verwendungszweck +
+
+ <%= memo %> +
+
+ + <% if(transaction) { %> + + <% } %> + + <% if(!account_user->hasPassword()) {%> +
+ + "> +
+ <% } %> + <% if(enableSign && !hasErrors) { %> + + <% } %> + <% if(transaction_removeable) { %> + + <% } else { %> + + <% } %> + + <% } %>
diff --git a/login_server/src/cpsp/dashboard.cpsp b/login_server/src/cpsp/dashboard.cpsp index 687c6a709..aaf084fee 100644 --- a/login_server/src/cpsp/dashboard.cpsp +++ b/login_server/src/cpsp/dashboard.cpsp @@ -10,17 +10,20 @@ %> <%% const char* pageName = "Dashboard"; + auto user = mSession->getNewUser(); + auto user_model = user->getModel(); //Poco::Net::NameValueCollection cookies; //request.getCookies(cookies); if(!form.empty()) { //form.get("email-verification-code") } - auto uri_start = ServerConfig::g_serverPath;//request.serverParams().getServerName(); - response.redirect(ServerConfig::g_php_serverPath + "/"); + auto uri_start = getBaseUrl(); + //response.redirect(ServerConfig::g_php_serverPath); + response.redirect(user->getGroupBaseUrl()); return; %><%@ include file="header_old.cpsp" %>
-

Willkommen <%= mSession->getUser()->getFirstName() %> <%= mSession->getUser()->getLastName() %>

+

Willkommen <%= user_model->getFirstName() %> <%= user_model->getLastName() %>

<%= mSession->getErrorsHtml() %>

Status

<%= mSession->getSessionStateString() %>

@@ -43,8 +46,8 @@ diff --git a/login_server/src/cpsp/debugMnemonic.cpsp b/login_server/src/cpsp/debugMnemonic.cpsp index 06f0c5f86..aa52d4561 100644 --- a/login_server/src/cpsp/debugMnemonic.cpsp +++ b/login_server/src/cpsp/debugMnemonic.cpsp @@ -6,7 +6,7 @@ <%@ header include="SessionHTTPRequestHandler.h" %> <%! #include "../ServerConfig.h" -#include "../Crypto/KeyPair.h" +#include "../Crypto/Passphrase.h" struct WordChecked { WordChecked() : index(0), bSet(false) {}; @@ -48,7 +48,7 @@ { if("" != form.get("check_word", "")) { - auto word = KeyPair::filterPassphrase(form.get("word", "")); + auto word = Passphrase::filter(form.get("word", "")); if("" != word) { checkedWord.bSet = true; checkedWord.word = word; diff --git a/login_server/src/cpsp/debugPassphrase.cpsp b/login_server/src/cpsp/debugPassphrase.cpsp index 936a4629f..416bdf0a3 100644 --- a/login_server/src/cpsp/debugPassphrase.cpsp +++ b/login_server/src/cpsp/debugPassphrase.cpsp @@ -5,45 +5,36 @@ <%@ page ctorArg="Session*" %> <%@ header include="SessionHTTPRequestHandler.h" %> <%! -#include "../Crypto/KeyPair.h" +#include "../Crypto/KeyPairEd25519.h" +#include "../controller/User.h" %> <%% const char* pageName = "Debug Passphrase"; - auto mm = MemoryManager::getInstance(); - KeyPair keys; - std::string privKeyHex = ""; + + KeyPairEd25519* keys = nullptr; std::string privKeyCryptedHex = ""; - User::passwordHashed pwdHashed = 0; + Poco::UInt64 pwdHashed = 0; Poco::AutoPtr existingUser; if(!form.empty()) { - auto passphrase = KeyPair::filterPassphrase(form.get("passphrase", "")); - Mnemonic* wordSource = nullptr; - if(!User::validatePassphrase(passphrase, &wordSource)) { + auto passphrase_string = form.get("passphrase", ""); + auto wordSource = Passphrase::detectMnemonic(passphrase_string); + if(!wordSource) { addError(new Error("debug Passphrase", "invalid passphrase"), false); } else { - keys.generateFromPassphrase(passphrase.data(), wordSource); + keys = KeyPairEd25519::create(Passphrase::create(passphrase_string, wordSource)); } auto email = form.get("email", ""); - auto newUser = new User(email.data(), "first_name", "last_name"); - if(email != "") { existingUser = controller::User::create(); - existingUser->load(email); - } - newUser->validatePwd(form.get("password", ""), this); - pwdHashed = newUser->getPwdHashed(); - auto privKey = keys.getPrivateKey(); - if(privKey) { - privKeyHex = KeyPair::getHex(privKey); - auto privKeyCrypted = newUser->encrypt(privKey); - if(privKeyCrypted) { - privKeyCryptedHex = KeyPair::getHex(privKeyCrypted); - mm->releaseMemory(privKeyCrypted); + if(1 == existingUser->load(email)) { + auto user_model = existingUser->getModel(); + pwdHashed = user_model->getPasswordHashed(); + if(user_model->hasPrivateKeyEncrypted()) { + privKeyCryptedHex = user_model->getPrivateKeyEncryptedHex(); + } } } - getErrors(newUser); - delete newUser; } @@ -58,23 +49,21 @@ "/>

-

- - -

-

Public key:
<%= keys.getPubkeyHex() %>

-

Private Key:
<%= privKeyHex %>

-

Passwort Hashed:
<%= std::to_string(pwdHashed) %>

-

Private key crypted:
<%= privKeyCryptedHex %>

- <% if(!existingUser.isNull()) { - auto userModel = existingUser->getModel(); - auto dbPubkey = userModel->getPublicKey(); - %> -

user Public:
<%= KeyPair::getHex(dbPubkey, ed25519_pubkey_SIZE) %>

+ <% if(keys) { %> +

Public key:
<%= keys->getPublicKeyHex() %>

+

Private key crypted:
<%= privKeyCryptedHex %>

+

Passwort Hashed:
<%= std::to_string(pwdHashed) %>

+ <% if(!existingUser.isNull()) { + auto userModel = existingUser->getModel(); + auto dbPubkey = userModel->getPublicKey(); + %> +

user Public:
<%= keys->getPublicKeyHex() %>

+ <% } %> <% } %>
+<% if(keys) delete keys; %> <%@ include file="footer.cpsp" %> diff --git a/login_server/src/cpsp/decodeTransaction.cpsp b/login_server/src/cpsp/decodeTransaction.cpsp index 2755c751d..b015f7fa9 100644 --- a/login_server/src/cpsp/decodeTransaction.cpsp +++ b/login_server/src/cpsp/decodeTransaction.cpsp @@ -6,14 +6,17 @@ <%@ header include="SessionHTTPRequestHandler.h" %> <%! #include "sodium.h" +#include "../proto/gradido/GradidoTransaction.pb.h" #include "../proto/gradido/TransactionBody.pb.h" #include "../controller/User.h" -#include "../model/TransactionBase.h" -#include "../model/TransactionCreation.h" +#include "../model/gradido/TransactionBase.h" +#include "../model/gradido/TransactionCreation.h" +#include "../lib/DataTypeConverter.h" %> <%% const char* pageName = "Decode Transaction"; - model::messages::gradido::TransactionBody transactionBody; + proto::gradido::TransactionBody transactionBody; + proto::gradido::GradidoTransaction transaction; bool decoded = false; bool adminUser = false; if(mSession && mSession->getNewUser()) { @@ -30,6 +33,7 @@ size_t resultingBinSize = 0; size_t base64_size = base64.size(); bool encodingValid = false; + bool encodedTransaction = false; if (!sodium_base642bin( binBuffer, base64_size, base64.data(), base64_size, @@ -42,9 +46,10 @@ base64.data(), base64_size, nullptr, &resultingBinSize, nullptr, sodium_base64_VARIANT_URLSAFE_NO_PADDING)) { - //encodingValid = true; + encodingValid = true; //free(binBuffer); - addError(new Error("ProcessingTransaction", "it is maybe a Transaction, but I support only TransactionBodys"), false); + //addError(new Error("ProcessingTransaction", "it is maybe a Transaction, but I support only TransactionBodys"), false); + encodedTransaction = true; } if(false == encodingValid) { free(binBuffer); @@ -52,11 +57,24 @@ } else { std::string binString((char*)binBuffer, resultingBinSize); free(binBuffer); - - if (!transactionBody.ParseFromString(binString)) { - addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message"), false); + if(!encodedTransaction) { + + if (!transactionBody.ParseFromString(binString)) { + addError(new Error("ProcessingTransaction", "error creating Transaction Body from binary Message"), false); + } else { + decoded = true; + } } else { - decoded = true; + + if(!transaction.ParseFromString(binString)) { + addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message"), false); + } else { + if(!transactionBody.ParseFromString(transaction.body_bytes())) { + addError(new Error("ProcessingTransaction", "error creating Transaction Body from Transaction body bytes"), false); + } else { + decoded = true; + } + } } } @@ -82,37 +100,35 @@

<%= transactionBody.memo() %>

<% if(transactionBody.has_transfer()) { auto transfer = transactionBody.transfer(); + char hex[65]; memset(hex, 0, 65); %> -

Transfer

- Sender - <% for(int i = 0; i < transfer.senderamounts_size(); i++) { - auto sender = transfer.senderamounts(i); - char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)sender.ed25519_sender_pubkey().data(), sender.ed25519_sender_pubkey().size()); + <% if(transfer.has_local()) { + auto local_transfer = transfer.local(); + auto sender_pubkey = local_transfer.sender().pubkey(); + auto receiver_pubkey = local_transfer.receiver(); + sodium_bin2hex(hex, 65, (const unsigned char*)sender_pubkey.data(), sender_pubkey.size()); %> -

pubkey: <%= hex %>

-

amount: <%= TransactionBase::amountToString(sender.amount()) %> GDD

- <% } %> - Receiver - <% for(int i = 0; i < transfer.receiveramounts_size(); i++) { - auto receiver = transfer.receiveramounts(i); - char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)receiver.ed25519_receiver_pubkey().data(), receiver.ed25519_receiver_pubkey().size()); - %> -

pubkey: <%= hex %>

-

amount: <%= TransactionBase::amountToString(receiver.amount()) %> GDD

- <% } %> +

Local Transfer

+ From: <%= hex %> + <% sodium_bin2hex(hex, 65, (const unsigned char*)receiver_pubkey.data(), receiver_pubkey.size()); %> + To: <%= hex %> + Amount: <%= model::gradido::TransactionBase::amountToString(local_transfer.sender().amount()) %> + <% } else { %> +

- Not implemented yet (Group Transfer) -

+ <% } %> + <% } else if(transactionBody.has_creation()) { auto creation = transactionBody.creation(); + //model::gradido::TransactionCreation creationObject("", creation); TransactionCreation creationObject("", creation); - auto receiver = creation.receiveramount(); + auto receiver = creation.receiver(); char hex[65]; memset(hex, 0, 65); - sodium_bin2hex(hex, 65, (const unsigned char*)receiver.ed25519_receiver_pubkey().data(), receiver.ed25519_receiver_pubkey().size()); + sodium_bin2hex(hex, 65, (const unsigned char*)receiver.pubkey().data(), receiver.pubkey().size()); Poco::AutoPtr user = nullptr; if(adminUser) { user = controller::User::create(); - if(!user->load((const unsigned char*)receiver.ed25519_receiver_pubkey().data())) { + if(!user->load((const unsigned char*)receiver.pubkey().data())) { user.assign(nullptr); } } @@ -125,8 +141,18 @@

user:

<%= user->getModel()->toHTMLString() %>

<% } %> -

amount: <%= TransactionBase::amountToString(receiver.amount()) %> GDD

+

amount: <%= model::gradido::TransactionBase::amountToString(receiver.amount()) %> GDD

target date: <%= creationObject.getTargetDateString() %>

+ <% } else if(transactionBody.has_group_member_update()) { + auto group_member_update = transactionBody.group_member_update(); + auto paired_transaction_id = group_member_update.paired_transaction_id(); + std::string paired_transaction_string = std::to_string(paired_transaction_id.seconds()) + "." + std::to_string(paired_transaction_id.nanos()); + %> +

Group Member Update

+

Target group alias: <%= group_member_update.target_group() %>

+

Paired transaction id: <%= paired_transaction_string %>

+

Member Update Type: <%= proto::gradido::GroupMemberUpdate_MemberUpdateType_Name(group_member_update.member_update_type()) %>

+

User Public Key Hex: <%= DataTypeConverter::pubkeyToHex((const unsigned char*)group_member_update.user_pubkey().data()) %>

<% } %> <% } %> diff --git a/login_server/src/cpsp/header_large.cpsp b/login_server/src/cpsp/header_large.cpsp new file mode 100644 index 000000000..0704867d4 --- /dev/null +++ b/login_server/src/cpsp/header_large.cpsp @@ -0,0 +1,32 @@ +<%! +#include "../ServerConfig.h" +%><%% + bool withMaterialIcons = false; +%> + + + + + +Gradido Login Server: <%= pageName %> + +<% if(withMaterialIcons) { %> + +<% } %> + + +
+ +
\ No newline at end of file diff --git a/login_server/src/cpsp/header_navi_chr.cpsp b/login_server/src/cpsp/header_navi_chr.cpsp index cb4acaea4..2c37a49b3 100644 --- a/login_server/src/cpsp/header_navi_chr.cpsp +++ b/login_server/src/cpsp/header_navi_chr.cpsp @@ -5,10 +5,10 @@ Gradido Login Server: <%= pageName %> - - - - + + + + @@ -16,16 +16,16 @@
"; -#line 102 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 106 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( userModel->getID() ); responseStream << ""; -#line 103 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 107 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( userModel->getFirstName() ); responseStream << ""; -#line 104 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 108 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( userModel->getLastName() ); responseStream << ""; -#line 105 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 109 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( userModel->getEmail() ); responseStream << ""; -#line 106 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" +#line 110 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminCheckUserBackup.cpsp" responseStream << ( (*it).backups.size() ); responseStream << "
"; - kontoNameCell += user->getFirstName(); - kontoNameCell += " "; - kontoNameCell += user->getLastName(); - kontoNameCell += " <"; - kontoNameCell += user->getEmail(); - kontoNameCell += ">0x" + pubkeyHex + ""; + kontoNameCell += user->getFirstName(); + kontoNameCell += " "; + kontoNameCell += user->getLastName(); + kontoNameCell += " <"; + kontoNameCell += user->getEmail(); + kontoNameCell += ">0x" + pubkeyHex + ""; + kontoNameCell += user->getFirstName(); + kontoNameCell += " "; + kontoNameCell += user->getLastName(); + kontoNameCell += " <"; + kontoNameCell += user->getEmail(); + kontoNameCell += ">0x" + pubkeyHex + "