mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
321 lines
11 KiB
C++
321 lines
11 KiB
C++
#include <inttypes.h>
|
|
|
|
#include "SigningTransaction.h"
|
|
|
|
|
|
#include <google/protobuf/text_format.h>
|
|
|
|
#include "../SingletonManager/ErrorManager.h"
|
|
#include "../SingletonManager/MemoryManager.h"
|
|
#include "../SingletonManager/SingletonTaskObserver.h"
|
|
|
|
#include "../lib/Profiler.h"
|
|
|
|
#include "sodium.h"
|
|
|
|
#include "../ServerConfig.h"
|
|
#include "Poco/JSON/Object.h"
|
|
#include "Poco/JSON/Parser.h"
|
|
#include "Poco/StreamCopier.h"
|
|
#include "Poco/Net/HTTPSClientSession.h"
|
|
#include "Poco/Net/HTTPRequest.h"
|
|
#include "Poco/Net/HTTPResponse.h"
|
|
|
|
// stuff for hedera transaction
|
|
#include "../controller/HederaAccount.h"
|
|
#include "../controller/HederaRequest.h"
|
|
#include "../model/hedera/TransactionBody.h"
|
|
#include "../model/hedera/Transaction.h"
|
|
|
|
SigningTransaction::SigningTransaction(
|
|
Poco::AutoPtr<ProcessingTransaction> processingeTransaction,
|
|
Poco::AutoPtr<controller::User> newUser,
|
|
bool sendErrorsToAdmin/* = true*/)
|
|
: mProcessingeTransaction(processingeTransaction), mNewUser(newUser), mSendErrorsToAdminEmail(sendErrorsToAdmin)
|
|
{
|
|
auto ob = SingletonTaskObserver::getInstance();
|
|
auto email = getUserEmail();
|
|
|
|
if (email != "") {
|
|
ob->addTask(email, TASK_OBSERVER_SIGN_TRANSACTION);
|
|
}
|
|
}
|
|
|
|
SigningTransaction::~SigningTransaction()
|
|
{
|
|
auto ob = SingletonTaskObserver::getInstance();
|
|
auto email = getUserEmail();
|
|
|
|
if (email != "") {
|
|
ob->removeTask(email, TASK_OBSERVER_SIGN_TRANSACTION);
|
|
}
|
|
}
|
|
|
|
std::string SigningTransaction::getUserEmail()
|
|
{
|
|
model::table::User* user_model = nullptr;
|
|
|
|
if (!mNewUser.isNull()) {
|
|
user_model = mNewUser->getModel();
|
|
}
|
|
if (user_model) {
|
|
return user_model->getEmail();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
int SigningTransaction::run() {
|
|
auto mm = MemoryManager::getInstance();
|
|
|
|
Error* transactionError = new Error("SigningTransaction", mProcessingeTransaction->mProtoMessageBase64.data());
|
|
addError(transactionError, false);
|
|
|
|
//= new Error("SigningTransaction start", mProcessingeTransaction->g)
|
|
//if (mUser.isNull() || !mUser->hasCryptoKey()) {
|
|
if(mNewUser.isNull() || !mNewUser->hasPassword()) {
|
|
addError(new Error("SigningTransaction", "user hasn't crypto key or is null"));
|
|
if(mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
return -1;
|
|
}
|
|
|
|
//auto privKey = mUser->getPrivKey();
|
|
//if (!mUser->hasPrivKey()) {
|
|
auto gradido_key_pair = mNewUser->getGradidoKeyPair();
|
|
KeyPairEd25519* recovered_gradido_key_pair = nullptr;
|
|
if(!gradido_key_pair || !gradido_key_pair->hasPrivateKey()) {
|
|
|
|
if (!mNewUser->tryLoadPassphraseUserBackup(&recovered_gradido_key_pair)) {
|
|
if(mNewUser->setGradidoKeyPair(recovered_gradido_key_pair))
|
|
{
|
|
mNewUser->getModel()->updatePrivkey();
|
|
}
|
|
}
|
|
else {
|
|
addError(new Error("SigningTransaction", "user cannot decrypt private key"));
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
return -2;
|
|
}
|
|
}
|
|
// get body bytes
|
|
proto::gradido::GradidoTransaction transaction;
|
|
auto bodyBytes = transaction.mutable_body_bytes();
|
|
*bodyBytes = mProcessingeTransaction->getBodyBytes();
|
|
if (*bodyBytes == "") {
|
|
getErrors(mProcessingeTransaction);
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
return -3;
|
|
}
|
|
// sign
|
|
//auto sign = mUser->sign((const unsigned char*)bodyBytes->data(), bodyBytes->size());
|
|
MemoryBin* sign = nullptr;
|
|
if (gradido_key_pair) {
|
|
sign = gradido_key_pair->sign(*bodyBytes);
|
|
}
|
|
else if (recovered_gradido_key_pair) {
|
|
sign = recovered_gradido_key_pair->sign(*bodyBytes);
|
|
}
|
|
if (!sign) {
|
|
ErrorManager::getInstance()->sendErrorsAsEmail();
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
mm->releaseMemory(sign);
|
|
return -4;
|
|
}
|
|
|
|
// pubkey for signature
|
|
/*auto pubkeyBin = mm->getFreeMemory(ed25519_pubkey_SIZE);
|
|
size_t realBin = 0;
|
|
if (sodium_hex2bin(*pubkeyBin, *pubkeyBin, pubkeyHex.data(), pubkeyHex.size(), nullptr, &realBin, nullptr)) {
|
|
addError(new Error("SigningTransaction", "error in sodium_hex2bin"));
|
|
sendErrorsAsEmail();
|
|
mm->releaseMemory(pubkeyBin);
|
|
mm->releaseMemory(sign);
|
|
return -5;
|
|
}
|
|
*/
|
|
// add to message
|
|
auto sigMap = transaction.mutable_sig_map();
|
|
auto sigPair = sigMap->add_sigpair();
|
|
|
|
auto pubkeyBytes = sigPair->mutable_pubkey();
|
|
auto pubkeyBin = mNewUser->getModel()->getPublicKey();
|
|
*pubkeyBytes = std::string((const char*)pubkeyBin, crypto_sign_PUBLICKEYBYTES);
|
|
|
|
|
|
auto sigBytes = sigPair->mutable_ed25519();
|
|
*sigBytes = std::string((char*)*sign, sign->size());
|
|
mm->releaseMemory(sign);
|
|
|
|
/*std::string protoPrettyPrint;
|
|
google::protobuf::TextFormat::PrintToString(transaction, &protoPrettyPrint);
|
|
printf("transaction pretty: %s\n", protoPrettyPrint.data());
|
|
proto::gradido::TransactionBody transactionBody;
|
|
transactionBody.MergeFromString(transaction.bodybytes());
|
|
google::protobuf::TextFormat::PrintToString(transactionBody, &protoPrettyPrint);
|
|
printf("transaction body pretty: \n%s\n", protoPrettyPrint.data());
|
|
*/
|
|
// finalize
|
|
//printf("sigpair size: %d\n", transaction.sigmap().sigpair_size());
|
|
std::string finalTransactionBin = transaction.SerializeAsString();
|
|
if (finalTransactionBin == "") {
|
|
addError(new Error("SigningTransaction", "error serializing final transaction"));
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
return -6;
|
|
}
|
|
|
|
auto network_type = model::table::HEDERA_TESTNET;
|
|
auto topic_id = controller::HederaId::find(1, network_type);
|
|
auto hedera_operator_account = controller::HederaAccount::pick(network_type, false);
|
|
|
|
if (!topic_id.isNull() && !hedera_operator_account.isNull()) {
|
|
auto crypto_key = hedera_operator_account->getCryptoKey();
|
|
if (!crypto_key.isNull()) {
|
|
model::hedera::ConsensusSubmitMessage consensus_submit_message(topic_id);
|
|
consensus_submit_message.setMessage(finalTransactionBin);
|
|
auto hedera_transaction_body = hedera_operator_account->createTransactionBody();
|
|
hedera_transaction_body->setConsensusSubmitMessage(consensus_submit_message);
|
|
model::hedera::Transaction hedera_transaction;
|
|
hedera_transaction.sign(crypto_key->getKeyPair(), std::move(hedera_transaction_body));
|
|
|
|
HederaRequest hedera_request;
|
|
HederaTask hedera_task;// placeholder
|
|
if (HEDERA_REQUEST_RETURN_OK != hedera_request.request(&hedera_transaction, &hedera_task)) {
|
|
addError(new Error("SigningTransaction", "error send transaction to hedera"));
|
|
getErrors(&hedera_request);
|
|
sendErrorsAsEmail();
|
|
}
|
|
else {
|
|
auto hedera_precheck_code_string = hedera_task.getTransactionResponse()->getPrecheckCodeString();
|
|
auto cost = hedera_task.getTransactionResponse()->getCost();
|
|
printf("hedera response: %s, cost: %" PRIu64 "\n", hedera_precheck_code_string.data(), cost);
|
|
}
|
|
//model::hedera::TransactionBody hedera_transaction_body()
|
|
}
|
|
else {
|
|
printf("[SigningTransaction] crypto key not found\n");
|
|
}
|
|
}
|
|
else {
|
|
printf("[SigningTransaction] hedera topic id or operator account not found\n");
|
|
}
|
|
|
|
// finale to base64
|
|
auto finalBase64Size = sodium_base64_encoded_len(finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
|
|
auto finalBase64Bin = mm->getFreeMemory(finalBase64Size);
|
|
if (!sodium_bin2base64(*finalBase64Bin, finalBase64Size, (const unsigned char*)finalTransactionBin.data(), finalTransactionBin.size(), sodium_base64_VARIANT_URLSAFE_NO_PADDING)) {
|
|
addError(new Error("SigningTransaction", "error convert final transaction to base64"));
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
mm->releaseMemory(finalBase64Bin);
|
|
return -7;
|
|
}
|
|
addError(new Error("Signing transaction final", *finalBase64Bin), false);
|
|
|
|
// create json request
|
|
|
|
Poco::JSON::Object requestJson;
|
|
requestJson.set("method", "putTransaction");
|
|
requestJson.set("transaction", std::string((char*)*finalBase64Bin));
|
|
//printf("\nbase64 transaction: \n%s\n\n", (char*)*finalBase64Bin);
|
|
mm->releaseMemory(finalBase64Bin);
|
|
|
|
|
|
//std::string request = requestJson.stringify();
|
|
|
|
// send post request via https
|
|
// 443 = HTTPS Default
|
|
// or http via port 80 if it is a test server
|
|
// TODO: adding port into ServerConfig
|
|
bool choose_ssl = false;
|
|
try {
|
|
Profiler phpRequestTime;
|
|
Poco::Net::HTTPClientSession* clientSession = nullptr;
|
|
|
|
if (ServerConfig::g_phpServerPort) {
|
|
clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, ServerConfig::g_phpServerPort);
|
|
choose_ssl = true;
|
|
}
|
|
else if (ServerConfig::SERVER_TYPE_PRODUCTION == ServerConfig::g_ServerSetupType ||
|
|
ServerConfig::SERVER_TYPE_STAGING == ServerConfig::g_ServerSetupType) {
|
|
clientSession = new Poco::Net::HTTPSClientSession(ServerConfig::g_php_serverHost, 443);
|
|
choose_ssl = true;
|
|
}
|
|
else {
|
|
clientSession = new Poco::Net::HTTPClientSession(ServerConfig::g_php_serverHost, 80);
|
|
choose_ssl = false;
|
|
}
|
|
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/JsonRequestHandler");
|
|
|
|
request.setChunkedTransferEncoding(true);
|
|
std::ostream& requestStream = clientSession->sendRequest(request);
|
|
requestJson.stringify(requestStream);
|
|
|
|
Poco::Net::HTTPResponse response;
|
|
std::istream& request_stream = clientSession->receiveResponse(response);
|
|
|
|
// debugging answer
|
|
|
|
std::stringstream responseStringStream;
|
|
for (std::string line; std::getline(request_stream, line); ) {
|
|
responseStringStream << line << std::endl;
|
|
}
|
|
Poco::Logger& speedLog= Poco::Logger::get("SpeedLog");
|
|
speedLog.information("[putTransaction] php server time: %s", phpRequestTime.string());
|
|
|
|
// extract parameter from request
|
|
Poco::JSON::Parser jsonParser;
|
|
Poco::Dynamic::Var parsedJson;
|
|
try {
|
|
parsedJson = jsonParser.parse(responseStringStream.str());
|
|
}
|
|
catch (Poco::Exception& ex) {
|
|
//printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data());
|
|
addError(new ParamError("SigningTransaction", "error parsing request answer", ex.displayText().data()));
|
|
|
|
FILE* f = fopen("response.html", "wt");
|
|
if (f) {
|
|
std::string responseString = responseStringStream.str();
|
|
fwrite(responseString.data(), 1, responseString.size(), f);
|
|
fclose(f);
|
|
}
|
|
// */
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail(responseStringStream.str());
|
|
return -9;
|
|
}
|
|
|
|
//sendErrorsAsEmail("<html><head><title>Hallo</title></head><body><font color='red'>Rote Test </font></body>");
|
|
|
|
Poco::JSON::Object object = *parsedJson.extract<Poco::JSON::Object::Ptr>();
|
|
|
|
std::string stateString = "";
|
|
if (!object.isNull("state")) {
|
|
auto state = object.get("state");
|
|
stateString = state.convert<std::string>();
|
|
}
|
|
if (stateString != "success") {
|
|
addError(new Error("SigningTransaction", "php server don't return success"));
|
|
if (!object.isNull("msg")) {
|
|
addError(new ParamError("SigningTransaction", "msg:", object.get("msg").convert<std::string>().data()));
|
|
}
|
|
if (!object.isNull("details")) {
|
|
addError(new ParamError("SigningTransaction", "details:", object.get("details").convert<std::string>().data()));
|
|
}
|
|
if (!object.isNull("user_error")) {
|
|
addError(new ParamError("SigningTransaction", "user_error", object.get("user_error").convert<std::string>().data()));
|
|
}
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail();
|
|
return -10;
|
|
}
|
|
delete clientSession;
|
|
//printf("state: %s\n", stateString.data());
|
|
//int zahl = 1;
|
|
}
|
|
catch (Poco::Exception& e) {
|
|
addError(new ParamError("SigningTransaction", "connect error to php server", e.displayText().data()));
|
|
addError(new ParamError("SigningTransaction", "url", ServerConfig::g_php_serverHost.data()));
|
|
addError(new ParamError("SigningTransaction", "choose_ssl", choose_ssl));
|
|
if (mSendErrorsToAdminEmail) sendErrorsAsEmail(););
|
|
return -8;
|
|
}
|
|
|
|
|
|
return 0;
|
|
} |