diff --git a/community_server/config/routes.php b/community_server/config/routes.php index 791692e96..20fc1ff62 100644 --- a/community_server/config/routes.php +++ b/community_server/config/routes.php @@ -60,19 +60,21 @@ Router::scope('/', function (RouteBuilder $routes) { $whitelist = ['JsonRequestHandler', 'ElopageWebhook', 'AppRequests']; $ajaxWhitelist = ['TransactionSendCoins', 'TransactionCreations']; + $callerIp = $request->clientIp(); + foreach($whitelist as $entry) { if($request->getParam('controller') === $entry) { if($entry == 'ElopageWebhook' || $entry == 'AppRequests') { return true; } $allowedIpLocalhost = ['127.0.0.1', 'localhost', '', '::1']; - if(in_array($request->clientIp(), $allowedIpLocalhost)) { + if(in_array($callerIp, $allowedIpLocalhost)) { return true; } $allowedCaller = Configure::read('API.allowedCaller'); $ipPerHost = []; if($allowedCaller && count($allowedCaller) > 0) { - $callerIp = $request->clientIp(); + foreach($allowedCaller as $allowed) { $ip = gethostbyname($allowed); $ipPerHost[$allowed] = $ip; diff --git a/community_server/src/Controller/JsonRequestHandlerController.php b/community_server/src/Controller/JsonRequestHandlerController.php index 65bf48440..611984118 100644 --- a/community_server/src/Controller/JsonRequestHandlerController.php +++ b/community_server/src/Controller/JsonRequestHandlerController.php @@ -391,8 +391,12 @@ class JsonRequestHandlerController extends AppController { } if ($transaction->save()) { + $result = ['state' => 'success']; + if($transaction->hasWarnings()) { + $result['warnings'] = $transaction->getWarnings(); + } // success - return $this->returnJson(['state' => 'success']); + return $this->returnJson($result); } else { $this->sendEMailTransactionFailed($transaction, 'save'); diff --git a/community_server/src/Model/Transactions/Transaction.php b/community_server/src/Model/Transactions/Transaction.php index db7ed9e5b..810f20c9d 100644 --- a/community_server/src/Model/Transactions/Transaction.php +++ b/community_server/src/Model/Transactions/Transaction.php @@ -198,8 +198,10 @@ class Transaction extends TransactionBase { $connection->commit(); - $this->mTransactionBody->getSpecificTransaction()->sendNotificationEmail($this->mTransactionBody->getMemo()); + $specificTransaction = $this->mTransactionBody->getSpecificTransaction(); + $specificTransaction->sendNotificationEmail($this->mTransactionBody->getMemo()); + $this->addWarnings($specificTransaction->getWarnings()); return true; } diff --git a/community_server/src/Model/Transactions/TransactionBase.php b/community_server/src/Model/Transactions/TransactionBase.php index 607903d8d..6b3817201 100644 --- a/community_server/src/Model/Transactions/TransactionBase.php +++ b/community_server/src/Model/Transactions/TransactionBase.php @@ -6,29 +6,43 @@ use Cake\ORM\TableRegistry; class TransactionBase { private $errors = []; + private $warnings = []; static $tables = []; public function getErrors() { - return $this->errors; + return $this->errors; + } + + public function getWarnings() { + return $this->warnings; } - public function addError($functionName, $errorName) { - array_push($this->errors, [$functionName => $errorName]); + array_push($this->errors, [$functionName => $errorName]); + } + public function addWarning($functionName, $warningName) { + array_push($this->warnings, [$functionName => $warningName]); } public function addErrors($errors) { - $this->errors = array_merge($this->errors, $errors); + $this->errors = array_merge($this->errors, $errors); + } + + public function addWarnings($warnings) { + $this->warnings = array_merge($this->warnings, $warnings); } public function hasErrors() { - return count($this->errors) > 0; + return count($this->errors) > 0; } + public function hasWarnings() { + return count($this->warnings) > 0; + } public static function getTable($tableName) { - if(!isset(self::$tables[$tableName])) { - self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName); - } - return self::$tables[$tableName]; + if(!isset(self::$tables[$tableName])) { + self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName); + } + return self::$tables[$tableName]; } diff --git a/community_server/src/Model/Transactions/TransactionCreation.php b/community_server/src/Model/Transactions/TransactionCreation.php index f9b3c7657..9150d24eb 100644 --- a/community_server/src/Model/Transactions/TransactionCreation.php +++ b/community_server/src/Model/Transactions/TransactionCreation.php @@ -209,6 +209,7 @@ class TransactionCreation extends TransactionBase { ->send(); } catch(Exception $e) { // $this->addError('TransactionCreation::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); + $this->addWarning('TransactionCreation::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); return false; } return true; diff --git a/community_server/src/Model/Transactions/TransactionTransfer.php b/community_server/src/Model/Transactions/TransactionTransfer.php index c36583c13..dc1606f55 100644 --- a/community_server/src/Model/Transactions/TransactionTransfer.php +++ b/community_server/src/Model/Transactions/TransactionTransfer.php @@ -204,13 +204,14 @@ class TransactionTransfer extends TransactionBase { $this->addError('TransactionCreation::sendNotificationEmail', 'to email is empty for user: ' . $receiverUser->id); return false; } - $email->setFrom([$serverAdminEmail => $senderUser->getNames() . ' via Gradido Community']) + $noReplyEmail = Configure::read('noReplyEmail'); + $email->setFrom([$noReplyEmail => 'Gradido (nicht antworten)']) ->setTo([$receiverUser->email => $receiverUser->getNames()]) - ->setReplyTo($senderUser->email) ->setSubject(__('Gradidos erhalten')) ->send(); } catch(Exception $e) { //$this->addError('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); + $this->addWarning('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); return false; } return true; diff --git a/community_server/src/Template/Email/text/notification_transfer.ctp b/community_server/src/Template/Email/text/notification_transfer.ctp index 2cc692e02..155304c2c 100644 --- a/community_server/src/Template/Email/text/notification_transfer.ctp +++ b/community_server/src/Template/Email/text/notification_transfer.ctp @@ -15,7 +15,7 @@ $senderNames = $senderUser->first_name . ' ' . $senderUser->last_name; - + Gradido Community Server \ No newline at end of file diff --git a/configs/community_server/app.php b/configs/community_server/app.php index 5bbdcdc4c..5acd4ce51 100644 --- a/configs/community_server/app.php +++ b/configs/community_server/app.php @@ -214,9 +214,8 @@ return [ 'timeout' => 30, 'username' => null, 'password' => null, - 'client' => null, - 'tls' => null, - 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + 'className' => 'Smtp', + 'tls' => true ], ], diff --git a/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp index 7fb40913e..5478f78cf 100644 --- a/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp +++ b/login_server/src/cpp/JSONInterface/JsonCreateTransaction.cpp @@ -135,6 +135,7 @@ Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params) else { printf("user hasn't valid key pair set\n"); } + Poco::JSON::Array* json_warnings = nullptr; if (!result) { try { auto transaction = model::gradido::Transaction::createTransfer(sender_user, target_pubkey, mTargetGroup, amount, mMemo, mBlockchainType); @@ -149,6 +150,10 @@ Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params) if (errors.size() > 0) { return stateError("error by signing transaction", errors); } + if (transaction->warningCount() > 0) { + json_warnings = new Poco::JSON::Array; + json_warnings->add(transaction->getWarningsArray()); + } } } catch (Poco::Exception& ex) { @@ -164,6 +169,10 @@ Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params) return stateError("exception"); } result = stateSuccess(); + if (json_warnings) { + result->set("warnings", json_warnings); + delete json_warnings; + } } mm->releaseMemory(target_pubkey); return result; diff --git a/login_server/src/cpp/lib/JsonRequest.cpp b/login_server/src/cpp/lib/JsonRequest.cpp index c20c69898..411ec07a0 100644 --- a/login_server/src/cpp/lib/JsonRequest.cpp +++ b/login_server/src/cpp/lib/JsonRequest.cpp @@ -11,6 +11,7 @@ #include "sodium.h" #include "../SingletonManager/MemoryManager.h" #include "DataTypeConverter.h" +#include "Warning.h" JsonRequest::JsonRequest(const std::string& serverHost, int serverPort) : mServerHost(serverHost), mServerPort(serverPort) @@ -125,11 +126,19 @@ JsonRequestReturn JsonRequest::request(const char* methodName, const Poco::JSON: return JSON_REQUEST_RETURN_ERROR; } else if (stateString == "success") { + auto warnings_obj = object.get("warnings"); + if (!warnings_obj.isEmpty()) { + Poco::JSON::Object warnings = *parsedJson.extract(); + for (auto it = warnings.begin(); it != warnings.end(); it++) { + addWarning(new Warning(it->first, it->second.toString())); + } + } 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()); + + //printf("[JsonRequest] %s: %s\n", index.data(), value.data()); } } } @@ -165,95 +174,5 @@ JsonRequestReturn JsonRequest::request(const char* 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(); - 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())); - } - // send copy of errors as email, to have result also in db - sendErrorsAsEmail("", true); - 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())); - sendErrorsAsEmail(); - return JSON_REQUEST_CONNECT_ERROR; - } - - - - return JSON_REQUEST_RETURN_OK; -} diff --git a/login_server/src/cpp/lib/JsonRequest.h b/login_server/src/cpp/lib/JsonRequest.h index 0def2465d..cfb9055d5 100644 --- a/login_server/src/cpp/lib/JsonRequest.h +++ b/login_server/src/cpp/lib/JsonRequest.h @@ -32,7 +32,6 @@ public: 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; diff --git a/login_server/src/cpp/lib/Notification.cpp b/login_server/src/cpp/lib/Notification.cpp index f2fb628d1..4a79b085f 100644 --- a/login_server/src/cpp/lib/Notification.cpp +++ b/login_server/src/cpp/lib/Notification.cpp @@ -10,4 +10,10 @@ Notification::Notification(const char* functionName, const std::string& message) : mFunctionName(functionName), mMessage(message) { +} + +Notification::Notification(const std::string& functionName, const std::string& 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 index 39a712aa6..07de555ae 100644 --- a/login_server/src/cpp/lib/Notification.h +++ b/login_server/src/cpp/lib/Notification.h @@ -8,6 +8,7 @@ class Notification public: Notification(const char* functionName, const char* message); Notification(const char* functionName, const std::string& message); + Notification(const std::string& functionName, const std::string& message); const char* getFunctionName() { return mFunctionName.data(); } const char* getMessage() { return mMessage.data(); } @@ -16,6 +17,7 @@ public: virtual bool isError() { return false; } virtual bool isSuccess() { return false; } + virtual bool isWarning() { return false; } protected: std::string mFunctionName; diff --git a/login_server/src/cpp/lib/NotificationList.cpp b/login_server/src/cpp/lib/NotificationList.cpp index d29774bce..4d5883367 100644 --- a/login_server/src/cpp/lib/NotificationList.cpp +++ b/login_server/src/cpp/lib/NotificationList.cpp @@ -54,6 +54,11 @@ NotificationList::~NotificationList() delete mErrorStack.top(); mErrorStack.pop(); } + + while (mWarningStack.size() > 0) { + delete mWarningStack.top(); + mWarningStack.pop(); + } } void NotificationList::addError(Notification* error, bool log/* = true */) @@ -61,12 +66,21 @@ 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)); + mLogging.error("%s [NotificationList::addError] %s", dateTimeString, error->getString(false)); } mErrorStack.push(error); } +void NotificationList::addWarning(Warning* warning, bool log/* = true*/) +{ + if (log) { + std::string dateTimeString = Poco::DateTimeFormatter::format(Poco::DateTime(), "%d.%m.%y %H:%M:%S"); + mLogging.warning("%s [NotificationList::addWarning] %s", dateTimeString, warning->getString(false)); + } + mWarningStack.push(warning); +} + void NotificationList::addNotification(Notification* notification) { mErrorStack.push(notification); @@ -86,6 +100,20 @@ Notification* NotificationList::getLastError() return error; } +Warning* NotificationList::getLastWarning() +{ + if (mWarningStack.size() == 0) { + return nullptr; + } + + Warning* warning = mWarningStack.top(); + if (warning) { + mWarningStack.pop(); + } + + return warning; +} + void NotificationList::clearErrors() { while (mErrorStack.size()) { @@ -109,6 +137,17 @@ int NotificationList::getErrors(NotificationList* send) return iCount; } +int NotificationList::getWarnings(NotificationList* send) +{ + Warning* warning = nullptr; + int iCount = 0; + while (warning = send->getLastWarning()) { + addWarning(warning, false); + iCount++; + } + return iCount; +} + void NotificationList::printErrors() { while (mErrorStack.size() > 0) { @@ -134,6 +173,21 @@ std::vector NotificationList::getErrorsArray() return result; } +std::vector NotificationList::getWarningsArray() +{ + std::vector result; + result.reserve(mWarningStack.size()); + + while (mWarningStack.size() > 0) { + auto warning = mWarningStack.top(); + mWarningStack.pop(); + //result->add(error->getString()); + result.push_back(warning->getString()); + delete warning; + } + return result; +} + std::string NotificationList::getErrorsHtml() { std::string res; diff --git a/login_server/src/cpp/lib/NotificationList.h b/login_server/src/cpp/lib/NotificationList.h index 2e04ce708..ecb821ee8 100644 --- a/login_server/src/cpp/lib/NotificationList.h +++ b/login_server/src/cpp/lib/NotificationList.h @@ -11,6 +11,7 @@ #define DR_LUA_WEB_MODULE_ERROR_ERROR_LIST_H #include "Error.h" +#include "Warning.h" #include #include "../tasks/CPUTask.h" @@ -28,11 +29,14 @@ public: // push error, error will be deleted in deconstructor virtual void addError(Notification* error, bool log = true); void addNotification(Notification* notification); + virtual void addWarning(Warning* warning, bool log = true); // return error on top of stack, please delete after using Notification* getLastError(); + Warning* getLastWarning(); inline size_t errorCount() { return mErrorStack.size(); } + inline size_t warningCount() { return mWarningStack.size(); } // delete all errors void clearErrors(); @@ -41,16 +45,19 @@ public: return recv->getErrors(send); } int getErrors(NotificationList* send); + int getWarnings(NotificationList* send); void printErrors(); std::string getErrorsHtml(); std::string getErrorsHtmlNewFormat(); std::vector getErrorsArray(); + std::vector getWarningsArray(); void sendErrorsAsEmail(std::string rawHtml = "", bool copy = false); protected: std::stack mErrorStack; + std::stack mWarningStack; // poco logging Poco::Logger& mLogging; }; diff --git a/login_server/src/cpp/lib/Warning.cpp b/login_server/src/cpp/lib/Warning.cpp new file mode 100644 index 000000000..77bb343cb --- /dev/null +++ b/login_server/src/cpp/lib/Warning.cpp @@ -0,0 +1,58 @@ +#include "Warning.h" +#include + +Warning::Warning(const char* functionName, const char* message) + : Notification(functionName, message) +{ + +} + +Warning::Warning(const std::string& functionName, const std::string& message) + : Notification(functionName, message) +{ + +} + +std::string Warning::getString(bool withNewline/* = true*/) const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage; + if (withNewline) ss << std::endl; + + return ss.str(); +} +std::string Warning::getHtmlString() const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage; + + return ss.str(); +} + +ParamWarning::ParamWarning(const char* functionName, const char* message, std::string param) + : Warning(functionName, message), mParam(param) +{ + +} + +ParamWarning::ParamWarning(const char* functionName, const char* message, int param) + : Warning(functionName, message), mParam(std::to_string(param)) +{ + +} + +std::string ParamWarning::getString(bool withNewline/* = true*/) const +{ + std::stringstream ss; + ss << mFunctionName << ": " << mMessage << " " << mParam; + if (withNewline) ss << std::endl; + + return ss.str(); +} +std::string ParamWarning::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/Warning.h b/login_server/src/cpp/lib/Warning.h new file mode 100644 index 000000000..8b032d8f0 --- /dev/null +++ b/login_server/src/cpp/lib/Warning.h @@ -0,0 +1,31 @@ +#ifndef GRADIDO_LOGIN_SERVER_LIB_WARNING_H +#define GRADIDO_LOGIN_SERVER_LIB_WARNING_H + +#include "Notification.h" + +class Warning : public Notification +{ +public: + Warning(const char* functionName, const char* message); + Warning(const std::string& functionName, const std::string& message); + + std::string getString(bool withNewline = true) const; + std::string getHtmlString() const; + + virtual bool isWarning() { return true; } +}; + +class ParamWarning : public Warning +{ +public: + ParamWarning(const char* functionName, const char* message, std::string param); + ParamWarning(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_WARNING_H \ No newline at end of file diff --git a/login_server/src/cpp/model/gradido/Transaction.cpp b/login_server/src/cpp/model/gradido/Transaction.cpp index 20f47bb83..22ac8937f 100644 --- a/login_server/src/cpp/model/gradido/Transaction.cpp +++ b/login_server/src/cpp/model/gradido/Transaction.cpp @@ -561,17 +561,21 @@ namespace model { Poco::Net::NameValueCollection param; param.set("transaction", base_64_message); auto result = json_request.request("putTransaction", param); - if (JSON_REQUEST_RETURN_OK == result) { + json_request.getWarnings(&json_request); + + if (JSON_REQUEST_RETURN_OK == result) + { if (!json_request.errorCount()) { finishSuccess(); } else { - getErrors(&json_request); + getErrors(&json_request); return -1; } return 1; } + json_request.getWarnings(&json_request); getErrors(&json_request); return -1;