diff --git a/CMakeLists.txt b/CMakeLists.txt index 142fc29aa..4e9bf3587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,11 +26,18 @@ FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp") FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp") FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h") FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h") -SET(LOCAL_SRCS ${TINF} ${MAIN} ${HTTPInterface} ${JSONInterface} ${CRYPTO} ${MODEL} ${SINGLETON_MANAGER} ${MYSQL} ${TASKS}) +FILE(GLOB PROTO_GRADIDO "src/cpp/proto/gradido/*.cc" "src/cpp/proto/gradido/*.h") +SET(LOCAL_SRCS + ${TINF} ${MAIN} ${HTTPInterface} + ${JSONInterface} ${CRYPTO} ${MODEL} + ${SINGLETON_MANAGER} ${MYSQL} ${TASKS} + ${PROTO_GRADIDO} +) aux_source_directory("src/cpp" LOCAL_SRCS) if(MSVC) # src +source_group("proto" FILES ${PROTO_GRADIDO}) source_group("tinf" FILES ${TINF}) source_group("crypto" FILES ${CRYPTO}) source_group("tasks" FILES ${TASKS}) diff --git a/compile_proto.sh b/compile_proto.sh index 25905d850..2429fdeea 100755 --- a/compile_proto.sh +++ b/compile_proto.sh @@ -2,4 +2,8 @@ if [ ! -d "./src/cpp/proto" ] ; then mkdir ./src/cpp/proto fi -protoc --cpp_out=./src/cpp/proto --proto_path=./src/proto/gradido ./src/proto/gradido/*.proto +if [ ! -d "./src/cpp/proto/gradido" ] ; then + mkdir ./src/cpp/proto/gradido +fi + +protoc --cpp_out=./src/cpp/proto/gradido --proto_path=./src/proto/gradido ./src/proto/gradido/*.proto diff --git a/dependencies/iroha-ed25519 b/dependencies/iroha-ed25519 index 1fdf5b6e1..7307ffb8a 160000 --- a/dependencies/iroha-ed25519 +++ b/dependencies/iroha-ed25519 @@ -1 +1 @@ -Subproject commit 1fdf5b6e10be2b1d7118aa3c32dc7acde02cb0cd +Subproject commit 7307ffb8a89d2459f0c07ea5cab27c0d3496df00 diff --git a/dependencies/mariadb-connector-c b/dependencies/mariadb-connector-c index 947357354..9ba8e32f6 160000 --- a/dependencies/mariadb-connector-c +++ b/dependencies/mariadb-connector-c @@ -1 +1 @@ -Subproject commit 947357354a92cbb7c15b1e9087d085fe65f75f5e +Subproject commit 9ba8e32f6d0fe449114d8eb369cf29303257b460 diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index dd0b6d2ec..180b2393c 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -1,8 +1,11 @@ #include "Gradido_LoginServer.h" #include +#include "proto/gradido/TransactionBody.pb.h" + 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 initing sodium, early exit\n"); diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index bd58c0337..0e77d4924 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -79,7 +79,7 @@ int WritePassphraseIntoDB::run() // -------------------------------------------------------------------------------------------------------------- Session::Session(int handle) - : mHandleId(handle), mSessionUser(nullptr), mEmailVerificationCode(0), mState(SESSION_STATE_EMPTY), mActive(false) + : mHandleId(handle), mSessionUser(nullptr), mEmailVerificationCode(0), mState(SESSION_STATE_EMPTY), mActive(false), mProcessingTransaction(nullptr) { } @@ -98,6 +98,7 @@ void Session::reset() lock(); mSessionUser = nullptr; + mProcessingTransaction = nullptr; // watch out //updateTimeout(); @@ -278,6 +279,39 @@ bool Session::updateEmailVerification(Poco::UInt64 emailVerificationCode) return false; } +bool Session::startProcessingTransaction(std::string proto_message_base64) +{ + lock(); + HASH hs = ProcessingTransaction::calculateHash(proto_message_base64); + // check if it is already running or waiting + for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { + if (it->isNull()) { + it = mProcessingTransactions.erase(it); + } + if (hs == (*it)->getHash()) { + addError(new Error("Session::startProcessingTransaction", "transaction already in list")); + unlock(); + return false; + } + } + UniLib::controller::TaskPtr processorTask(new ProcessingTransaction(proto_message_base64)); + processorTask->scheduleTask(processorTask); + mProcessingTransactions.push_back(processorTask); + unlock(); + return true; + +} + +Poco::AutoPtr Session::getNextReadyTransaction() +{ + lock(); + for (auto it = mProcessingTransactions.begin(); it != mProcessingTransactions.end(); it++) { + if ((*it)->isTaskFinished()) { + + } + } +} + bool Session::isPwdValid(const std::string& pwd) { if (mSessionUser) { diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index e32588e3d..274201399 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -14,6 +14,7 @@ #include "User.h" #include "../tasks/MultithreadContainer.h" +#include "../tasks/ProcessingTransaction.h" #include "Poco/Thread.h" #include "Poco/Types.h" @@ -64,6 +65,8 @@ public: bool updateEmailVerification(Poco::UInt64 emailVerificationCode); + bool startProcessingTransaction(std::string proto_message_base64); + Poco::Net::HTTPCookie getLoginCookie(); Poco::AutoPtr getUser() { @@ -95,6 +98,7 @@ public: inline Poco::DateTime getLastActivity() { return mLastActivity; } + Poco::AutoPtr getNextReadyTransaction(); protected: void updateTimeout(); @@ -105,6 +109,8 @@ protected: void detectSessionState(); static const char* translateSessionStateToString(SessionStates state); + + private: int mHandleId; Poco::AutoPtr mSessionUser; @@ -116,7 +122,8 @@ private: SessionStates mState; bool mActive; - + std::list> mProcessingTransactions; + std::list> }; diff --git a/src/cpp/model/TransactionBase.h b/src/cpp/model/TransactionBase.h new file mode 100644 index 000000000..d61e21196 --- /dev/null +++ b/src/cpp/model/TransactionBase.h @@ -0,0 +1,20 @@ +/*! +* +* \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 + +#include "ErrorList.h" + +class TransactionBase : public ErrorList +{ +public: + virtual int prepare() = 0; +}; + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_BASE_INCLUDE \ No newline at end of file diff --git a/src/cpp/model/TransactionCreation.cpp b/src/cpp/model/TransactionCreation.cpp new file mode 100644 index 000000000..73f46303d --- /dev/null +++ b/src/cpp/model/TransactionCreation.cpp @@ -0,0 +1,50 @@ +#include "TransactionCreation.h" +#include + +TransactionCreation::TransactionCreation(const model::messages::gradido::TransactionCreation& protoCreation) + : 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(); + + 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(receiverPublic.data()); + getErrors(mReceiverUser); + if (mReceiverUser->getUserState() == USER_EMPTY) { + sodium_bin2hex(mReceiverPublicHex, 64, (const unsigned char*)receiverPublic.data(), receiverPublic.size()); + delete mReceiverUser; + mReceiverUser = nullptr; + } + else { + memcpy(mReceiverPublicHex, mReceiverUser->getPublicKeyHex().data(), 64); + if (!mReceiverUser->validateIdentHash(mProtoCreation.ident_hash())) { + addError(new Error(functionName, "ident hash isn't the same")); + return -3; + } + } + // + + + return 0; +} \ No newline at end of file diff --git a/src/cpp/model/TransactionCreation.h b/src/cpp/model/TransactionCreation.h new file mode 100644 index 000000000..94c229392 --- /dev/null +++ b/src/cpp/model/TransactionCreation.h @@ -0,0 +1,35 @@ +/*! +* +* \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 + +#include "TransactionBase.h" +#include "../proto/gradido/TransactionCreation.pb.h" +#include "User.h" + +class TransactionCreation : public TransactionBase +{ +public: + TransactionCreation(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; } + + +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/src/cpp/model/TransactionTransfer.cpp b/src/cpp/model/TransactionTransfer.cpp new file mode 100644 index 000000000..7cf1b2cb8 --- /dev/null +++ b/src/cpp/model/TransactionTransfer.cpp @@ -0,0 +1,14 @@ +#include "TransactionTransfer.h" + +TransactionTransfer::TransactionTransfer(const model::messages::gradido::Transfer& protoTransfer) + : mProtoTransfer(protoTransfer) +{ + +} + + +int TransactionTransfer::prepare() +{ + + return 0; +} \ No newline at end of file diff --git a/src/cpp/model/TransactionTransfer.h b/src/cpp/model/TransactionTransfer.h new file mode 100644 index 000000000..a977cd3f6 --- /dev/null +++ b/src/cpp/model/TransactionTransfer.h @@ -0,0 +1,26 @@ +/*! +* +* \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 + +#include "TransactionBase.h" +#include "../proto/gradido/Transfer.pb.h" + +class TransactionTransfer : public TransactionBase +{ +public: + TransactionTransfer(const model::messages::gradido::Transfer& protoTransfer); + + int prepare(); + +protected: + const model::messages::gradido::Transfer& mProtoTransfer; +}; + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TRANSACTION_TRANSFER_INCLUDE \ No newline at end of file diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index 40bb7f9c7..532961375 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -266,6 +266,50 @@ User::User(int user_id) } } +User::User(const unsigned char* pubkey_array) + : mState(USER_EMPTY), mDBId(0), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), 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); + + Poco::Data::BLOB pubkey(pubkey_array, 32); + Poco::Nullable privkey; + + Poco::Data::Statement select(session); + int email_checked = 0; + select << "SELECT id, email, first_name, last_name, password, privkey, email_checked from users where pubkey = ?", + into(mDBId), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), into(privkey), into(email_checked), use(pubkey); + try { + auto result = select.execute(); + if (result == 1) { + mState = USER_LOADED_FROM_DB; + 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(); + mPrivateKey = new ObfusArray(privkey_value.size(), privkey_value.content().data()); + } + + } + + } + catch (Poco::Exception& ex) { + addError(new ParamError("User::User", "mysql error", ex.displayText().data())); + } +} User::~User() @@ -372,7 +416,7 @@ Poco::JSON::Object User::getJson() userObj.set("public_hex", mPublicHex); userObj.set("state", userStateToString(mState)); userObj.set("email_checked", mEmailChecked); - userObj.set("ident_hash", DRMakeStringHash(mEmail.data())); + userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); unlock(); return userObj; } @@ -455,6 +499,14 @@ bool User::validatePwd(const std::string& pwd, ErrorList* validationErrorsToPrin return false; } +bool User::validateIdentHash(HASH hash) +{ + lock(); + HASH local_hash = DRMakeStringHash(mEmail.data(), mEmail.size()); + unlock(); + return local_hash == hash; +} + bool User::deleteFromDB() { auto cm = ConnectionManager::getInstance(); diff --git a/src/cpp/model/User.h b/src/cpp/model/User.h index 75599f872..13be5d3f4 100644 --- a/src/cpp/model/User.h +++ b/src/cpp/model/User.h @@ -50,6 +50,9 @@ public: // existing user User(const char* email); + // existing user by public key + User(const unsigned char* pubkey_array); + User(int user_id); // login //User(const std::string& email, const std::string& password); @@ -82,6 +85,7 @@ public: bool isEmptyPassword(); bool setNewPassword(const std::string& newPassword); bool validatePwd(const std::string& pwd, ErrorList* validationErrorsToPrint); + bool validateIdentHash(HASH hash); Poco::Data::BLOB* encrypt(const ObfusArray* data); diff --git a/src/cpp/tasks/ProcessingTransaction.cpp b/src/cpp/tasks/ProcessingTransaction.cpp new file mode 100644 index 000000000..ed911be0d --- /dev/null +++ b/src/cpp/tasks/ProcessingTransaction.cpp @@ -0,0 +1,99 @@ +#include "ProcessingTransaction.h" +#include + +#include "../model/TransactionCreation.h" +#include "../model/TransactionTransfer.h" + +ProcessingTransaction::ProcessingTransaction(std::string proto_message_base64) + : mType(TRANSACTION_NONE), mProtoMessageBase64(proto_message_base64), mTransactionSpecific(nullptr) +{ + mHashMutex.lock(); + mHash = calculateHash(proto_message_base64); + mHashMutex.unlock(); +} + +ProcessingTransaction::~ProcessingTransaction() +{ + lock(); + if (mTransactionSpecific) { + delete mTransactionSpecific; + mTransactionSpecific = nullptr; + } + unlock(); +} + + +HASH ProcessingTransaction::calculateHash(std::string proto_message_base64) +{ + return DRMakeStringHash(proto_message_base64.data(), proto_message_base64.size()); +} + +int ProcessingTransaction::run() +{ + + lock(); + //mTransactionBody.ParseFromString(); + unsigned char* binBuffer = (unsigned char*)malloc(mProtoMessageBase64.size()); + size_t resultingBinSize = 0; + size_t base64_size = mProtoMessageBase64.size(); + 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")); + unlock(); + return -1; + } + std::string binString((char*)binBuffer, resultingBinSize); + free(binBuffer); + if (!mTransactionBody.ParseFromString(binString)) { + addError(new Error("ProcessingTransaction", "error creating Transaction from binary Message")); + unlock(); + return -2; + } + + // check Type + if (mTransactionBody.has_creation()) { + mType = TRANSACTION_CREATION; + mTransactionSpecific = new TransactionCreation(mTransactionBody.creation()); + } + else if (mTransactionBody.has_transfer()) { + mType = TRANSACTION_TRANSFER; + mTransactionSpecific = new TransactionTransfer(mTransactionBody.transfer()); + } + if (mTransactionSpecific) { + if (mTransactionSpecific->prepare()) { + getErrors(mTransactionSpecific); + addError(new Error("ProcessingTransaction", "error preparing")); + unlock(); + return -3; + } + } + unlock(); + return 0; +} + +std::string ProcessingTransaction::getMemo() +{ + lock(); + if (mTransactionBody.IsInitialized()) { + std::string result(mTransactionBody.memo()); + unlock(); + return result; + } + 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/src/cpp/tasks/ProcessingTransaction.h b/src/cpp/tasks/ProcessingTransaction.h new file mode 100644 index 000000000..0b56909b6 --- /dev/null +++ b/src/cpp/tasks/ProcessingTransaction.h @@ -0,0 +1,65 @@ +#ifndef GRADIDO_LOGIN_SERVER_TASKS_PROCESSING_TRANSACTION_INCLUDE +#define GRADIDO_LOGIN_SERVER_TASKS_PROCESSING_TRANSACTION_INCLUDE + +#include "CPUTask.h" + +#include "../model/ErrorList.h" +#include "../model/TransactionBase.h" + +#include "../proto/gradido/TransactionBody.pb.h" + +/* +* @author: Dario Rekowski +* +* @date: 25.10.19 +* @desc: Task for processing Transactions +*/ + +enum TransactionType { + TRANSACTION_NONE, + TRANSACTION_CREATION, + TRANSACTION_TRANSFER +}; + +class TransactionCreation; +class TransactionTransfer; + +class ProcessingTransaction : public UniLib::controller::CPUTask, public ErrorList +{ +public: + ProcessingTransaction(std::string proto_message_base64); + 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(std::string proto_message_base64); + inline HASH getHash() { mHashMutex.lock(); HASH hs = mHash; mHashMutex.unlock(); return hs; } + +protected: + TransactionType mType; + std::string mProtoMessageBase64; + + model::messages::gradido::TransactionBody mTransactionBody; + TransactionBase* mTransactionSpecific; + + HASH mHash; + + Poco::Mutex mHashMutex; +private: + +}; + + +#endif //GRADIDO_LOGIN_SERVER_TASKS_PROCESSING_TRANSACTION_INCLUDE \ No newline at end of file diff --git a/src/cpsp/checkTransaction.cpsp b/src/cpsp/checkTransaction.cpsp new file mode 100644 index 000000000..6a21b6e76 --- /dev/null +++ b/src/cpsp/checkTransaction.cpsp @@ -0,0 +1,48 @@ +<%@ page class="CheckTransactionPage" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%! +#include "../SingletonManager/SessionManager.h" +%> +<%% +%> + + + + + +Gradido Login Server: Überprüfe Transaktion + + + + + +
+ +

Eine Transaktion prüfen

+ <%= getErrorsHtml() %> + +
+
+ <%= mTimeProfiler.string() %> +
+ + \ No newline at end of file