From 5e524d7ac65baa57c86916f1b555cac80090a3d1 Mon Sep 17 00:00:00 2001 From: Dario Date: Wed, 14 Oct 2020 17:33:37 +0200 Subject: [PATCH] refactor gradido transaction handling --- src/cpp/Gradido_LoginServer.cpp | 4 + src/cpp/SingletonManager/MemoryManager.cpp | 8 ++ src/cpp/SingletonManager/MemoryManager.h | 2 + .../SingletonManager/PendingTasksManager.cpp | 67 ++++++++++ .../SingletonManager/PendingTasksManager.h | 50 +++++++ src/cpp/controller/PendingTask.cpp | 37 +++++- src/cpp/controller/PendingTask.h | 11 +- src/cpp/lib/DataTypeConverter.cpp | 7 + src/cpp/lib/DataTypeConverter.h | 2 + src/cpp/model/gradido/GroupMemberUpdate.cpp | 62 ++++++++- src/cpp/model/gradido/GroupMemberUpdate.h | 2 + src/cpp/model/gradido/Transaction.cpp | 123 ++++++++++++++++++ src/cpp/model/gradido/Transaction.h | 37 ++++++ src/cpp/model/gradido/TransactionBase.cpp | 90 ++++++++++++- src/cpp/model/gradido/TransactionBase.h | 22 ++++ src/cpp/model/gradido/TransactionBody.cpp | 2 + src/cpp/model/gradido/TransactionBody.h | 2 + src/cpp/model/gradido/TransactionCreation.cpp | 60 ++++++++- src/cpp/model/gradido/TransactionCreation.h | 3 + src/cpp/model/gradido/TransactionTransfer.cpp | 35 +++++ src/cpp/model/gradido/TransactionTransfer.h | 1 + src/cpp/model/table/Group.h | 1 - src/cpp/model/table/ModelBase.h | 35 ++++- src/cpp/model/table/NodeServer.h | 6 +- src/cpp/model/table/PendingTask.cpp | 10 ++ src/cpp/model/table/PendingTask.h | 10 +- src/cpp/model/table/User.h | 5 +- src/cpp/tasks/GradidoGroupAddMemberTask.cpp | 27 ++++ src/cpp/tasks/GradidoGroupAddMemberTask.h | 19 +++ src/cpp/tasks/GradidoTask.cpp | 7 + src/cpp/tasks/GradidoTask.h | 18 +++ src/cpp/tasks/PendingTask.h | 12 ++ src/cpp/tasks/ProcessingTransaction.cpp | 32 +++-- src/cpp/tasks/ProcessingTransaction.h | 1 + 34 files changed, 770 insertions(+), 40 deletions(-) create mode 100644 src/cpp/SingletonManager/PendingTasksManager.cpp create mode 100644 src/cpp/SingletonManager/PendingTasksManager.h create mode 100644 src/cpp/model/gradido/Transaction.cpp create mode 100644 src/cpp/model/gradido/Transaction.h create mode 100644 src/cpp/tasks/GradidoGroupAddMemberTask.cpp create mode 100644 src/cpp/tasks/GradidoGroupAddMemberTask.h create mode 100644 src/cpp/tasks/PendingTask.h diff --git a/src/cpp/Gradido_LoginServer.cpp b/src/cpp/Gradido_LoginServer.cpp index 9ab3dd393..9bb861ff4 100644 --- a/src/cpp/Gradido_LoginServer.cpp +++ b/src/cpp/Gradido_LoginServer.cpp @@ -8,6 +8,7 @@ #include "SingletonManager/ConnectionManager.h" #include "SingletonManager/SessionManager.h" #include "SingletonManager/EmailManager.h" +#include "SingletonManager/PendingTasksManager.h" #include "controller/User.h" @@ -252,6 +253,9 @@ int Gradido_LoginServer::main(const std::vector& args) // start the json server json_srv.start(); + // load pending tasks not finished in last session + PendingTasksManager::getInstance()->load(); + printf("[Gradido_LoginServer::main] started in %s\n", usedTime.string().data()); // wait for CTRL-C or kill waitForTerminationRequest(); diff --git a/src/cpp/SingletonManager/MemoryManager.cpp b/src/cpp/SingletonManager/MemoryManager.cpp index 2c6e98ca7..6f77b2c41 100644 --- a/src/cpp/SingletonManager/MemoryManager.cpp +++ b/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()); +} + // ************************************************************* diff --git a/src/cpp/SingletonManager/MemoryManager.h b/src/cpp/SingletonManager/MemoryManager.h index 591148083..fc723f392 100644 --- a/src/cpp/SingletonManager/MemoryManager.h +++ b/src/cpp/SingletonManager/MemoryManager.h @@ -50,6 +50,8 @@ public: //! -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/src/cpp/SingletonManager/PendingTasksManager.cpp b/src/cpp/SingletonManager/PendingTasksManager.cpp new file mode 100644 index 000000000..54fd18402 --- /dev/null +++ b/src/cpp/SingletonManager/PendingTasksManager.cpp @@ -0,0 +1,67 @@ +#include "PendingTasksManager.h" + +PendingTasksManager::PendingTasksManager() +{ + +} + +PendingTasksManager::~PendingTasksManager() +{ + Poco::ScopedLock _lock(mWorkMutex); + 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() +{ + auto pending_tasks = controller::PendingTask::loadAll(); + for (auto it = pending_tasks.begin(); it != pending_tasks.end(); it++) { + addTask(*it); + } + 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; + +} + +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; +} \ No newline at end of file diff --git a/src/cpp/SingletonManager/PendingTasksManager.h b/src/cpp/SingletonManager/PendingTasksManager.h new file mode 100644 index 000000000..3cfbf1b2a --- /dev/null +++ b/src/cpp/SingletonManager/PendingTasksManager.h @@ -0,0 +1,50 @@ +/*! +* +* \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" + +class PendingTasksManager: public UniLib::lib::MultithreadContainer +{ +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); + + //! 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; + +protected: + PendingTasksManager(); + + + 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/src/cpp/controller/PendingTask.cpp b/src/cpp/controller/PendingTask.cpp index 417813762..78679f5dd 100644 --- a/src/cpp/controller/PendingTask.cpp +++ b/src/cpp/controller/PendingTask.cpp @@ -1,5 +1,8 @@ #include "PendingTask.h" +#include "../tasks/GradidoGroupAddMemberTask.h" + + namespace controller { PendingTask::PendingTask(model::table::PendingTask* dbModel) @@ -15,7 +18,7 @@ namespace controller { 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); } @@ -26,11 +29,41 @@ namespace controller { 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; } + 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; + } + + 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; + } + return nullptr; + } + } \ No newline at end of file diff --git a/src/cpp/controller/PendingTask.h b/src/cpp/controller/PendingTask.h index 821f4a141..7a6cd4fcc 100644 --- a/src/cpp/controller/PendingTask.h +++ b/src/cpp/controller/PendingTask.h @@ -21,13 +21,20 @@ namespace controller { 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(); } + 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; }; protected: + static Poco::AutoPtr loadCorrectDerivedClass(model::table::PendingTask* dbModel); PendingTask(model::table::PendingTask* dbModel); diff --git a/src/cpp/lib/DataTypeConverter.cpp b/src/cpp/lib/DataTypeConverter.cpp index b33d46d4b..a5437da7e 100644 --- a/src/cpp/lib/DataTypeConverter.cpp +++ b/src/cpp/lib/DataTypeConverter.cpp @@ -277,6 +277,13 @@ namespace DataTypeConverter return microseconds; } + 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); diff --git a/src/cpp/lib/DataTypeConverter.h b/src/cpp/lib/DataTypeConverter.h index c778f198a..aceb6ac1e 100644 --- a/src/cpp/lib/DataTypeConverter.h +++ b/src/cpp/lib/DataTypeConverter.h @@ -11,6 +11,7 @@ #include "../proto/hedera/Timestamp.pb.h" #include "../proto/hedera/Duration.pb.h" +#include "../proto/gradido/BasicTypes.pb.h" #include "sodium.h" @@ -50,6 +51,7 @@ namespace DataTypeConverter { std::string convertTimespanToLocalizedString(Poco::Timespan duration, LanguageCatalog* lang); Poco::Timestamp convertFromProtoTimestamp(const proto::Timestamp& timestamp); + Poco::Timestamp convertFromProtoTimestampSeconds(const proto::gradido::TimestampSeconds& timestampSeconds); Poco::Timespan convertFromProtoDuration(const proto::Duration& duration); }; diff --git a/src/cpp/model/gradido/GroupMemberUpdate.cpp b/src/cpp/model/gradido/GroupMemberUpdate.cpp index cf0860082..1d922311f 100644 --- a/src/cpp/model/gradido/GroupMemberUpdate.cpp +++ b/src/cpp/model/gradido/GroupMemberUpdate.cpp @@ -18,15 +18,59 @@ namespace model { int GroupMemberUpdate::prepare() { - const static char functionName[] = { "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 + 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; + }*/ + } + + 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 -1; + 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 1; + return TRANSACTION_VALID_CODE_ERROR; } auto target_group = mProtoMemberUpdate.target_group(); auto sm = SessionManager::getInstance(); @@ -34,15 +78,21 @@ namespace model { 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 -2; + return TRANSACTION_VALID_INVALID_GROUP_ALIAS; } } else { addError(new Error(functionName, "target group isn't valid group alias string ")); - return -3; + return TRANSACTION_VALID_INVALID_GROUP_ALIAS; } - return 0; + return TRANSACTION_VALID_OK; } + /* + GroupMemberUpdate::GroupMemberUpdate(const std::string& memo, Poco::AutoPtr user, Poco::AutoPtr group) + { + + } + */ } } \ No newline at end of file diff --git a/src/cpp/model/gradido/GroupMemberUpdate.h b/src/cpp/model/gradido/GroupMemberUpdate.h index 633e93462..562085ecc 100644 --- a/src/cpp/model/gradido/GroupMemberUpdate.h +++ b/src/cpp/model/gradido/GroupMemberUpdate.h @@ -4,6 +4,7 @@ #include "TransactionBase.h" #include "../../proto/gradido/GroupMemberUpdate.pb.h" + namespace model { namespace gradido { class GroupMemberUpdate : public TransactionBase @@ -12,6 +13,7 @@ namespace model { GroupMemberUpdate(const std::string& memo, const proto::gradido::GroupMemberUpdate &protoGroupMemberUpdate); ~GroupMemberUpdate(); int prepare(); + TransactionValidation validate(); protected: const proto::gradido::GroupMemberUpdate& mProtoMemberUpdate; diff --git a/src/cpp/model/gradido/Transaction.cpp b/src/cpp/model/gradido/Transaction.cpp new file mode 100644 index 000000000..4ca8a705e --- /dev/null +++ b/src/cpp/model/gradido/Transaction.cpp @@ -0,0 +1,123 @@ +#include "Transaction.h" +#include "../../SingletonManager/ErrorManager.h" + +namespace model { + namespace gradido { + Transaction::Transaction(Poco::AutoPtr body) + : mTransactionBody(body), mBodyBytesHash(0) + { + + } + + Transaction::~Transaction() + { + + } + + bool Transaction::addSign(Poco::AutoPtr user) + { + static const char function_name[] = "Transaction::addSign"; + + 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; + } + 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, sign->size()); + mm->releaseMemory(sign); + + return true; + } + TransactionValidation Transaction::validate() + { + auto sig_map = mProtoTransaction.sig_map(); + auto transaction_base = mTransactionBody->getTransactionBase(); + auto result = transaction_base->checkRequiredSignatures(&sig_map); + + if (result == TRANSACTION_VALID_OK) + { + return transaction_base->validate(); + } + return result; + + } + + } +} \ No newline at end of file diff --git a/src/cpp/model/gradido/Transaction.h b/src/cpp/model/gradido/Transaction.h new file mode 100644 index 000000000..8ba557eb9 --- /dev/null +++ b/src/cpp/model/gradido/Transaction.h @@ -0,0 +1,37 @@ +#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 "../../controller/User.h" + + +namespace model { + namespace gradido { + class Transaction : public NotificationList + { + public: + Transaction(Poco::AutoPtr body); + ~Transaction(); + + bool addSign(Poco::AutoPtr user); + TransactionValidation validate(); + + + protected: + Poco::AutoPtr mTransactionBody; + proto::gradido::GradidoTransaction mProtoTransaction; + HASH mBodyBytesHash; + }; + } +} + +#endif //GRADIDO_LOGIN_SERVER_MODEL_GRADIDO_TRANSACTION_H diff --git a/src/cpp/model/gradido/TransactionBase.cpp b/src/cpp/model/gradido/TransactionBase.cpp index ab61b88a5..d7016b15a 100644 --- a/src/cpp/model/gradido/TransactionBase.cpp +++ b/src/cpp/model/gradido/TransactionBase.cpp @@ -1,15 +1,32 @@ #include "TransactionBase.h" +#include "../../Crypto/KeyPairEd25519.h" #include namespace model { namespace gradido { TransactionBase::TransactionBase(const std::string& memo) - : mMemo(memo) + : mMemo(memo), mMinSignatureCount(0) { } + 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; @@ -25,6 +42,77 @@ namespace model { 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; + + } } } diff --git a/src/cpp/model/gradido/TransactionBase.h b/src/cpp/model/gradido/TransactionBase.h index 1d7ade30d..83e0c9157 100644 --- a/src/cpp/model/gradido/TransactionBase.h +++ b/src/cpp/model/gradido/TransactionBase.h @@ -17,18 +17,40 @@ 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 + }; + 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 true if all required signatures are found in signature pairs + TransactionValidation checkRequiredSignatures(const proto::gradido::SignatureMap* sig_map); + protected: std::string mMemo; + Poco::UInt32 mMinSignatureCount; + std::vector mRequiredSignPublicKeys; + std::vector mForbiddenSignPublicKeys; }; } } diff --git a/src/cpp/model/gradido/TransactionBody.cpp b/src/cpp/model/gradido/TransactionBody.cpp index bfc6ad54a..010353315 100644 --- a/src/cpp/model/gradido/TransactionBody.cpp +++ b/src/cpp/model/gradido/TransactionBody.cpp @@ -91,6 +91,8 @@ namespace model { return ""; } + + TransactionCreation* TransactionBody::getCreationTransaction() { return dynamic_cast(mTransactionSpecific); diff --git a/src/cpp/model/gradido/TransactionBody.h b/src/cpp/model/gradido/TransactionBody.h index f97fb4d6e..42641fb66 100644 --- a/src/cpp/model/gradido/TransactionBody.h +++ b/src/cpp/model/gradido/TransactionBody.h @@ -2,6 +2,7 @@ #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" @@ -20,6 +21,7 @@ namespace model { TRANSACTION_GROUP_MEMBER_UPDATE }; + class TransactionBody : public Poco::RefCountedObject, UniLib::lib::MultithreadContainer { diff --git a/src/cpp/model/gradido/TransactionCreation.cpp b/src/cpp/model/gradido/TransactionCreation.cpp index 881a2d88c..6c44d49b2 100644 --- a/src/cpp/model/gradido/TransactionCreation.cpp +++ b/src/cpp/model/gradido/TransactionCreation.cpp @@ -26,8 +26,8 @@ namespace model { auto receiver_amount = mProtoCreation.receiver(); auto receiverPublic = receiver_amount.pubkey(); - if (receiverPublic.size() != 32) { - addError(new Error(functionName, "receiver public invalid (size not 32)")); + if (receiverPublic.size() != KeyPairEd25519::getPublicKeySize()) { + addError(new ParamError(functionName, "receiver public invalid: ", receiverPublic.size())); return -2; } mReceiverUser = controller::User::create(); @@ -49,7 +49,11 @@ namespace model { }*/ } // - + 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); return 0; } @@ -62,6 +66,56 @@ namespace model { 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; + } + } } diff --git a/src/cpp/model/gradido/TransactionCreation.h b/src/cpp/model/gradido/TransactionCreation.h index 5b4dbbb9b..a7c64c250 100644 --- a/src/cpp/model/gradido/TransactionCreation.h +++ b/src/cpp/model/gradido/TransactionCreation.h @@ -25,6 +25,9 @@ namespace model { ~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(); } diff --git a/src/cpp/model/gradido/TransactionTransfer.cpp b/src/cpp/model/gradido/TransactionTransfer.cpp index 775c2b46c..3adf68e33 100644 --- a/src/cpp/model/gradido/TransactionTransfer.cpp +++ b/src/cpp/model/gradido/TransactionTransfer.cpp @@ -97,7 +97,14 @@ namespace model { else { mKontoTable.push_back(KontoTableEntry(sender_user->getModel(), amount, true)); } + 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); } + + // TODO: add version for group transfer @@ -118,6 +125,34 @@ namespace model { return 0; } + TransactionValidation TransactionTransfer::validate() + { + 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; + } + auto amount = mProtoTransfer.local().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 (mProtoTransfer.local().receiver().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "invalid size of receiver pubkey")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + if (mProtoTransfer.local().sender().pubkey().size() != KeyPairEd25519::getPublicKeySize()) { + addError(new Error(function_name, "invalid size of sender pubkey")); + return TRANSCATION_VALID_INVALID_PUBKEY; + } + return TRANSACTION_VALID_OK; + + } + const std::string& TransactionTransfer::getKontoNameCell(int index) { diff --git a/src/cpp/model/gradido/TransactionTransfer.h b/src/cpp/model/gradido/TransactionTransfer.h index 0687f1831..3c4e60a55 100644 --- a/src/cpp/model/gradido/TransactionTransfer.h +++ b/src/cpp/model/gradido/TransactionTransfer.h @@ -26,6 +26,7 @@ namespace model { ~TransactionTransfer(); int prepare(); + TransactionValidation validate(); inline size_t getKontoTableSize() { lock(); size_t s = mKontoTable.size(); unlock(); return s; } const std::string& getKontoNameCell(int index); diff --git a/src/cpp/model/table/Group.h b/src/cpp/model/table/Group.h index 1f6296b92..df57cfc87 100644 --- a/src/cpp/model/table/Group.h +++ b/src/cpp/model/table/Group.h @@ -42,7 +42,6 @@ namespace model { std::string mUrl; std::string mDescription; - mutable std::shared_mutex mSharedMutex; }; } diff --git a/src/cpp/model/table/ModelBase.h b/src/cpp/model/table/ModelBase.h index 8d5664735..df83e4fb4 100644 --- a/src/cpp/model/table/ModelBase.h +++ b/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 { @@ -42,6 +45,9 @@ namespace model { size_t updateIntoDB(std::string fieldNames[3], const T1& fieldValue1, const T2& fieldValue2, const T3& fieldValue3); 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(); @@ -79,7 +85,9 @@ namespace model { int mID; // for poco auto ptr - int mReferenceCount; + int mReferenceCount; + + mutable std::shared_mutex mSharedMutex; }; @@ -103,6 +111,31 @@ 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 id" + ,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) { diff --git a/src/cpp/model/table/NodeServer.h b/src/cpp/model/table/NodeServer.h index 4e592c822..21b26e1c7 100644 --- a/src/cpp/model/table/NodeServer.h +++ b/src/cpp/model/table/NodeServer.h @@ -36,7 +36,7 @@ namespace model { static const char* nodeServerTypeToString(NodeServerType type); - inline void setLastLiveSign(Poco::DateTime lastLiveSign) { std::unique_lock _lock(mSharedMutex); mLastLiveSign = lastLiveSign; } + inline void setLastLiveSign(Poco::DateTime lastLiveSign) { UNIQUE_LOCK; mLastLiveSign = lastLiveSign; } inline std::string getUrl() const { return mUrl; } inline int getPort() const { return mPort; } @@ -46,7 +46,7 @@ namespace model { 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 { std::shared_lock _lock(mSharedMutex); return mLastLiveSign; } + inline Poco::DateTime getLastLiveSign() const { SHARED_LOCK; return mLastLiveSign; } protected: Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); @@ -60,8 +60,6 @@ namespace model { int mServerType; int mNodeHederaId; Poco::DateTime mLastLiveSign; - - mutable std::shared_mutex mSharedMutex; }; diff --git a/src/cpp/model/table/PendingTask.cpp b/src/cpp/model/table/PendingTask.cpp index 6248333f8..e405ffa6a 100644 --- a/src/cpp/model/table/PendingTask.cpp +++ b/src/cpp/model/table/PendingTask.cpp @@ -66,6 +66,16 @@ namespace model return select; } + Poco::Data::Statement PendingTask::_loadAllFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, request, created, finished, result_json, task_type_id FROM " << getTableName(); + + return select; + } + + Poco::Data::Statement PendingTask::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); diff --git a/src/cpp/model/table/PendingTask.h b/src/cpp/model/table/PendingTask.h index bab94448c..565b52eaf 100644 --- a/src/cpp/model/table/PendingTask.h +++ b/src/cpp/model/table/PendingTask.h @@ -4,8 +4,6 @@ #include "ModelBase.h" #include "Poco/Types.h" -#include - namespace model { namespace table { @@ -20,12 +18,13 @@ namespace model { TASK_TYPE_HEDERA_ACCOUNT_CREATE = 25, }; - + typedef Poco::Tuple PendingTaskTuple; class PendingTask : public ModelBase { public: + PendingTask(); PendingTask(int userId, std::string serializedProtoRequest, TaskType type); PendingTask(const PendingTaskTuple& tuple); @@ -36,10 +35,13 @@ namespace model { const char* getTableName() const { return "pending_tasks"; } std::string toString(); + inline int getUserId() const { SHARED_LOCK; return mUserId; } + TaskType getTaskType() const { SHARED_LOCK; return (TaskType)mTaskTypeId; } 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); @@ -50,8 +52,6 @@ namespace model { std::string mResultJsonString; int mTaskTypeId; - std::shared_mutex mSharedMutex; - }; } diff --git a/src/cpp/model/table/User.h b/src/cpp/model/table/User.h index d4fb2ea87..5c4609b02 100644 --- a/src/cpp/model/table/User.h +++ b/src/cpp/model/table/User.h @@ -9,7 +9,6 @@ //#include "Poco/Nullable.h" //#include "Poco/Data/LOB.h" -#include #include "UserRole.h" @@ -34,8 +33,6 @@ namespace model { class User : public ModelBase { public: -#define SHARED_LOCK std::shared_lock _lock(mSharedMutex) -#define UNIQUE_LOCK std::unique_lock _lock(mSharedMutex) User(); User(UserTuple tuple); 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"); @@ -123,7 +120,7 @@ namespace model { // from neighbor tables Poco::Nullable mRole; - mutable std::shared_mutex mSharedMutex; + }; } } diff --git a/src/cpp/tasks/GradidoGroupAddMemberTask.cpp b/src/cpp/tasks/GradidoGroupAddMemberTask.cpp new file mode 100644 index 000000000..7028dd741 --- /dev/null +++ b/src/cpp/tasks/GradidoGroupAddMemberTask.cpp @@ -0,0 +1,27 @@ +#include "GradidoGroupAddMemberTask.h" +#include "../model/gradido/GroupMemberUpdate.h" + +GradidoGroupAddMemberTask::GradidoGroupAddMemberTask(model::table::PendingTask* dbModel, Poco::AutoPtr transactionBody) + : GradidoTask(dbModel, transactionBody) +{ + +} + + +Poco::AutoPtr GradidoGroupAddMemberTask::create(Poco::AutoPtr user, Poco::AutoPtr group, const std::string& memo) +{ + if (user.isNull() || !user->getModel() || group.isNull() || !group->getModel()) { + return nullptr; + } + static const char* function_name = "GradidoGroupAddMemberTask::create"; + auto group_model = group->getModel(); + auto transaction = model::gradido::TransactionBody::create(memo, user, proto::gradido::GroupMemberUpdate_MemberUpdateType_ADD_USER, group_model->getAlias()); + auto user_model = user->getModel(); + auto dbModel = new model::table::PendingTask(user_model->getID(), transaction->getBodyBytes(), model::table::TASK_TYPE_GROUP_ADD_MEMBER); + if (!dbModel->insertIntoDB(true)) { + dbModel->addError(new Error(function_name, "error inserting pending task into db, abort")); + dbModel->sendErrorsAsEmail(); + return nullptr; + } + return new GradidoGroupAddMemberTask(dbModel, transaction); +} \ No newline at end of file diff --git a/src/cpp/tasks/GradidoGroupAddMemberTask.h b/src/cpp/tasks/GradidoGroupAddMemberTask.h new file mode 100644 index 000000000..d532f7913 --- /dev/null +++ b/src/cpp/tasks/GradidoGroupAddMemberTask.h @@ -0,0 +1,19 @@ +#ifndef GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_GROUP_ADD_MEMBER_TASK_H +#define GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_GROUP_ADD_MEMBER_TASK_H + +#include "GradidoTask.h" +#include "../controller/User.h" +#include "../controller/Group.h" + +class GradidoGroupAddMemberTask : public GradidoTask +{ +public: + GradidoGroupAddMemberTask(model::table::PendingTask* dbModel, Poco::AutoPtr transactionBody); + + static Poco::AutoPtr create(Poco::AutoPtr user, Poco::AutoPtr group, const std::string& memo); + +protected: + +}; + +#endif //GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_GROUP_ADD_MEMBER_TASK_H \ No newline at end of file diff --git a/src/cpp/tasks/GradidoTask.cpp b/src/cpp/tasks/GradidoTask.cpp index e69de29bb..6481d9f4a 100644 --- a/src/cpp/tasks/GradidoTask.cpp +++ b/src/cpp/tasks/GradidoTask.cpp @@ -0,0 +1,7 @@ +#include "GradidoTask.h" + +GradidoTask::GradidoTask(model::table::PendingTask* dbModel, Poco::AutoPtr transactionBody) + : controller::PendingTask(dbModel), mGradidoTransactionBody(transactionBody) +{ + +} \ No newline at end of file diff --git a/src/cpp/tasks/GradidoTask.h b/src/cpp/tasks/GradidoTask.h index e69de29bb..dc5a017e4 100644 --- a/src/cpp/tasks/GradidoTask.h +++ b/src/cpp/tasks/GradidoTask.h @@ -0,0 +1,18 @@ +#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(model::table::PendingTask* dbModel, Poco::AutoPtr transactionBody); + bool isTimeoutTask() { return false; } + +protected: + + Poco::AutoPtr mGradidoTransactionBody; +}; + +#endif //GRADIDO_LOGIN_SERVER_TASKS_GRADIDO_TASK \ No newline at end of file diff --git a/src/cpp/tasks/PendingTask.h b/src/cpp/tasks/PendingTask.h new file mode 100644 index 000000000..3e6bd976d --- /dev/null +++ b/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/src/cpp/tasks/ProcessingTransaction.cpp b/src/cpp/tasks/ProcessingTransaction.cpp index 300a8efd6..74fca7e0a 100644 --- a/src/cpp/tasks/ProcessingTransaction.cpp +++ b/src/cpp/tasks/ProcessingTransaction.cpp @@ -24,6 +24,15 @@ 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(); @@ -75,22 +84,23 @@ int ProcessingTransaction::run() { lock(); - auto mm = MemoryManager::getInstance(); - auto protoMessageBin = DataTypeConverter::base64ToBin(mProtoMessageBase64); - auto langM = LanguageManager::getInstance(); auto catalog = langM->getFreeCatalog(mLang); - if (!protoMessageBin) - { - 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; + } + mTransactionBody = model::gradido::TransactionBody::create(protoMessageBin); + mm->releaseMemory(protoMessageBin); } - mTransactionBody = model::gradido::TransactionBody::create(protoMessageBin); - mm->releaseMemory(protoMessageBin); 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"); diff --git a/src/cpp/tasks/ProcessingTransaction.h b/src/cpp/tasks/ProcessingTransaction.h index 6566b838e..5f1dc4507 100644 --- a/src/cpp/tasks/ProcessingTransaction.h +++ b/src/cpp/tasks/ProcessingTransaction.h @@ -33,6 +33,7 @@ class ProcessingTransaction : public UniLib::controller::CPUTask, public Notific public: //! \param lang for error messages in user language 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();