diff --git a/skeema/gradido_login/node_servers.sql b/skeema/gradido_login/node_servers.sql new file mode 100644 index 000000000..88e4d8ac3 --- /dev/null +++ b/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/src/cpp/HTTPInterface/AdminTopicPage.cpp b/src/cpp/HTTPInterface/AdminTopicPage.cpp new file mode 100644 index 000000000..d8926093e --- /dev/null +++ b/src/cpp/HTTPInterface/AdminTopicPage.cpp @@ -0,0 +1,128 @@ +#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" + + +#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 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + + const char* pageName = "Topic"; + + + +#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
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t
"; + // end include header_large.cpsp + responseStream << "\n"; +#line 16 "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 << "
\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/src/cpp/HTTPInterface/AdminTopicPage.h b/src/cpp/HTTPInterface/AdminTopicPage.h new file mode 100644 index 000000000..b02e5856c --- /dev/null +++ b/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/src/cpp/HTTPInterface/PassphrasedTransaction.cpsp b/src/cpp/HTTPInterface/PassphrasedTransaction.cpsp new file mode 100644 index 000000000..debc1f296 --- /dev/null +++ b/src/cpp/HTTPInterface/PassphrasedTransaction.cpsp @@ -0,0 +1,162 @@ +<%@ page class="PassphrasedTransaction" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="PageRequestMessagedHandler" %> +<%@ header include="PageRequestMessagedHandler.h" %> +<%! +#include "../SingletonManager/MemoryManager.h" +#include "../SingletonManager/SessionManager.h" +#include "../Crypto/KeyPair.h" +#include "../ServerConfig.h" + +#include "Poco/JSON/Object.h" +#include "Poco/JSON/Parser.h" +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" + +enum PageState { + PAGE_STATE_INPUT, + PAGE_STATE_SUCCESS +}; +%> +<%% + 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]; + 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); + bool keysGenerated = false; + KeyPair keys; + if(!passphraseValid) + { + addError(new Error("Passphrase", "Fehler beim validieren der Passphrase")); + } + else + { + keysGenerated = keys.generateFromPassphrase(passphrase.data(), wordSource); + if(!keysGenerated) + { + addError(new Error("Passphrase", "Konnte keine Keys aus der Passphrase generieren")); + } + } + if(passphraseValid && keysGenerated) + { + // create session only for transaction + int session_id = 0; + auto session = sm->getNewSession(&session_id); + // create payload + Poco::JSON::Object requestJson; + Poco::JSON::Object pubkeys; + pubkeys.set("sender", keys.getPubkeyHex()); + pubkeys.set("receiver", form.get("recevier", "")); + requestJson.set("method", "moveTransaction"); + requestJson.set("pubkeys", pubkeys); + requestJson.set("memo", form.get("memo", "")); + requestJson.set("session_id", session_id); + + printf("[PassphrasedTransaction] prepare request\n"); + + // send to php server + Poco::Net::HTTPSClientSession httpsClientSession(ServerConfig::g_php_serverHost, 443); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/JsonRequestHandler"); + + request.setChunkedTransferEncoding(true); + std::ostream& requestStream = httpsClientSession.sendRequest(request); + requestJson.stringify(requestStream); + + Poco::Net::HTTPResponse response; + std::istream& request_stream = httpsClientSession.receiveResponse(response); + + 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; + + printf("[PassphrasedTransaction] parse request result\n"); + try { + parsedJson = jsonParser.parse(responseStringStream); + + Poco::JSON::Object object = *parsedJson.extract(); + auto jsonState = object.get("state"); + std::string stateString = jsonState.convert(); + if (stateString == "error") { + addError(new Error("Transfer", "php server return error")); + if (!object.isNull("msg")) { + addError(new ParamError("php server", "msg:", object.get("msg").convert().data())); + } + if (!object.isNull("details")) { + addError(new ParamError("php server", "details:", object.get("details").convert().data())); + } + } else if(stateString == "success") { + printf("[PassphrasedTransaction] request success, wait on transaction ready\n"); + auto currentActiveTransaction = session->getNextReadyTransaction(); + while(currentActiveTransaction.isNull()) { + Poco::Thread::sleep(10); + currentActiveTransaction = session->getNextReadyTransaction(); + } + if(!currentActiveTransaction->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); + printf("[PassphrasedTransaction] cannot sign, implementation missing\n"); + /*if(!signing->run()) { + + } else { + addError(new Error("Transaction", "Fehler beim signieren, bitter erneut versuchen")); + }*/ + // remove transaction from list + //mSession->finalizeTransaction(true, true); + } + } + } + catch (Poco::Exception& ex) { + //printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data()); + addError(new ParamError("Transfer", "Fehler beim erstellen der Transaktion, bitte erneut versuchen", ex.displayText().data())); + errorString = responseStringStream.str(); + sm->releaseSession(session); + session = nullptr; + } + if(session) { + sm->releaseSession(session); + } + } + } + + +%><%@ include file="header_old.cpsp" %> +<% if("" == errorString) { %> + <%= errorString %> +<% } %> +
+ <%= getErrorsHtml() %> + <% if(PAGE_STATE_INPUT == state) { %> + +
+
+

+

+

+

+

+ + "/> +

+

+
+
+ <% } else if(PAGE_STATE_SUCCESS == state) { %> +

Gradidos wurden erfolgreich überwiesen.

+ Weitere Gradidos überweisen + <% } %> +
+<%@ include file="footer.cpsp" %> diff --git a/src/cpp/controller/HederaRequest.cpp b/src/cpp/controller/HederaRequest.cpp new file mode 100644 index 000000000..ec1c6c2a0 --- /dev/null +++ b/src/cpp/controller/HederaRequest.cpp @@ -0,0 +1,39 @@ +#include "HederaRequest.h" +#include "../proto/hedera/CryptoService.grpc.pb.h" + +#include +#include +#include +#include +#include + +HederaRequest::HederaRequest() +{ + +} + +HederaRequest::~HederaRequest() +{ + +} + +HederaRequestReturn HederaRequest::request(model::hedera::Query* query) +{ + 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(100); + context.set_deadline(deadline); + + auto proto_query = query->getProtoQuery(); + proto::Response* response = nullptr; + if (proto_query->has_cryptogetaccountbalance()) { + auto stub = proto::CryptoService::NewStub(channel); + auto connect_string = query->getConnectionString(); + printf("try connection to hedera with: %s\n", connect_string.data()); + auto status = stub->cryptoGetBalance(&context, *proto_query, response); + addError(new ParamError("Hedera Request", "crypto get balance", status.error_message())); + printf("[HederaRequest::request] error details: %s\n", status.error_details().data()); + } + return HEDERA_REQUEST_RETURN_OK; +} \ No newline at end of file diff --git a/src/cpp/controller/HederaRequest.h b/src/cpp/controller/HederaRequest.h new file mode 100644 index 000000000..692215f8d --- /dev/null +++ b/src/cpp/controller/HederaRequest.h @@ -0,0 +1,39 @@ +#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" + +enum HederaRequestReturn +{ + HEDERA_REQUEST_RETURN_OK, + HEDERA_REQUEST_RETURN_PARSE_ERROR, + HEDERA_REQUEST_RETURN_ERROR, + HEDERA_REQUEST_CONNECT_ERROR +}; + +// NodeServerConnection +class HederaRequest : public ErrorList +{ +public: + HederaRequest(); + ~HederaRequest(); + + HederaRequestReturn request(model::hedera::Query* query); + +protected: + +}; + + +#endif //__GRADIDO_LOGIN_SERVER_LIB_HEDERA_REQUEST_ +// \ No newline at end of file diff --git a/src/cpsp/adminHederaAccount.cpsp b/src/cpsp/adminHederaAccount.cpsp new file mode 100644 index 000000000..b4fd1f485 --- /dev/null +++ b/src/cpsp/adminHederaAccount.cpsp @@ -0,0 +1,203 @@ +<%@ 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 "../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(); + + Poco::URI uri(request.getURI()); + auto uri_query = uri.getQueryParameters(); + std::string action = ""; + std::string account_id_from_query; + if(uri_query.size() >= 2) { + if(uri_query[0].first == "action") { + action = uri_query[0].second; + } + if(uri_query[1].first == "account_id") { + account_id_from_query = uri_query[1].second; + } + } + if(action == "updateBalance") { + int account_id = 0; + 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_account = controller::HederaAccount::load("id", account_id); + if(!hedera_account.size() || hedera_account[0].isNull()) { + addError(new Error("Action Update Balance", "hedera id not found")); + } else { + hedera_account[0]->updateBalanceFromHedera(user, this); + } + } + } + // add + else if(!form.empty()) { + // 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 publicKeyString = form.get("account-public-key", ""); + auto networkTypeString = form.get("account-network-type", "0"); + + 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)model::table::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(), ed25519_pubkey_SIZE); + + if(crypto_key.isNull()) { + crypto_key = controller::CryptoKey::create(&key_pair, user); + 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()) { + auto hedera_account = controller::HederaAccount::create( + user->getModel()->getID(), + hedera_id->getModel()->getID(), + crypto_key->getModel()->getID(), + 0, + (model::table::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); + } + + } + + // 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
+
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()); + %> +
+
<%= (*it)->getHederaId()->getModel()->toString() %>
+
<%= hedera_account_model->getBalanceDouble() %> hbar
+
<%= model::table::HederaAccount::hederaNetworkTypeToString(hedera_account_model->getNetworkType()) %>
+
<%= hedera_account_model->getUpdatedString() %>
+
+ +
+ <% } %> +
+
+
+

Einen neuen Account anlegen

+
+
+
+ + + + + + + + + + + "> +
+
+<%@ include file="footer.cpsp" %>