492 lines
12 KiB
C++
492 lines
12 KiB
C++
#include "Deals.hpp"
|
|
#include <string>
|
|
#include <cstdlib>
|
|
#include "PrintFile.hpp"
|
|
#include "common.hpp"
|
|
#include "ExecCommand.hpp"
|
|
#include "json.hpp"
|
|
#include "base64.h"
|
|
#include <fstream>
|
|
#include "cleanHtml.h"
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <ctime>
|
|
|
|
using namespace std;
|
|
using json = nlohmann::json;
|
|
|
|
string url_encode(const string &value)
|
|
{
|
|
ostringstream escaped;
|
|
escaped.fill('0');
|
|
escaped << hex;
|
|
|
|
for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
|
|
{
|
|
string::value_type c = (*i);
|
|
|
|
// Keep alphanumeric and other accepted characters intact
|
|
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
|
|
{
|
|
escaped << c;
|
|
continue;
|
|
}
|
|
|
|
// Any other characters are percent-encoded
|
|
escaped << uppercase;
|
|
escaped << '%' << setw(2) << int((unsigned char)c);
|
|
escaped << nouppercase;
|
|
}
|
|
|
|
return escaped.str();
|
|
}
|
|
|
|
int Deals::HelpCreate() const
|
|
{
|
|
if (isRussian)
|
|
PrintFile(DEALS_RU);
|
|
else
|
|
PrintFile(DEALS_EN);
|
|
return 0;
|
|
}
|
|
int Deals::HelpDealStatus() const
|
|
{
|
|
if (isRussian)
|
|
PrintFile(DEAL_STATUS_RU);
|
|
else
|
|
PrintFile(DEAL_STATUS_EN);
|
|
return 0;
|
|
}
|
|
int Deals::HelpDealComplete() const
|
|
{
|
|
if (isRussian)
|
|
PrintFile(DEAL_COMPLETE_RU);
|
|
else
|
|
PrintFile(DEAL_COMPLETE_EN);
|
|
return 0;
|
|
}
|
|
int Deals::HelpDealCancel() const
|
|
{
|
|
if (isRussian)
|
|
PrintFile(DEAL_CANCEL_RU);
|
|
else
|
|
PrintFile(DEAL_CANCEL_EN);
|
|
return 0;
|
|
}
|
|
int Deals::HelpDealNegative() const
|
|
{
|
|
if (isRussian)
|
|
PrintFile(DEAL_NEGATIVE_RU);
|
|
else
|
|
PrintFile(DEAL_NEGATIVE_EN);
|
|
return 0;
|
|
}
|
|
Deals::Deals(const InputParser &parser, const bool isRussian, const string address, bool isDebug)
|
|
{
|
|
this->parser = parser;
|
|
this->isRussian = isRussian;
|
|
this->address = address;
|
|
this->isDebug = isDebug;
|
|
}
|
|
|
|
int Deals::Process()
|
|
{
|
|
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("create") && (this->parser.cmdOptionExists("--help") || parser.cmdOptionExists("-h")))
|
|
return this->HelpCreate();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("status") && (this->parser.cmdOptionExists("--help") || parser.cmdOptionExists("-h")))
|
|
return this->HelpDealStatus();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("complete") && (this->parser.cmdOptionExists("--help") || parser.cmdOptionExists("-h")))
|
|
return this->HelpDealComplete();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("cancel") && (this->parser.cmdOptionExists("--help") || parser.cmdOptionExists("-h")))
|
|
return this->HelpDealCancel();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("negative") && (this->parser.cmdOptionExists("--help") || parser.cmdOptionExists("-h")))
|
|
return this->HelpDealNegative();
|
|
|
|
return Update();
|
|
return 0;
|
|
}
|
|
|
|
int Deals::Update()
|
|
{
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("create"))
|
|
return Create();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("status"))
|
|
return Status();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("complete"))
|
|
return Complite();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("cancel"))
|
|
return Cancel();
|
|
if (parser.cmdOptionExists("deal") && this->parser.cmdOptionExists("negative"))
|
|
return Negative();
|
|
return 1;
|
|
}
|
|
|
|
int Deals::Create()
|
|
{
|
|
|
|
string at;
|
|
string seller;
|
|
string customer;
|
|
string type;
|
|
string sum;
|
|
string leave_before;
|
|
string pay;
|
|
|
|
at = GetVal("-a", "--at");
|
|
if (at.length() == 0)
|
|
at = "https://testnet-dm2.bitdeals.org";
|
|
seller = GetVal("-s", "--seller");
|
|
customer = GetVal("-c", "--customer");
|
|
type = GetVal("-t", "--type");
|
|
sum = GetVal("-g", "--sum");
|
|
leave_before = GetVal("-l", "--leave_before");
|
|
pay = GetVal("-p", "--pay");
|
|
|
|
// start curl
|
|
string data("");
|
|
data += ReadFile(DEAL_CREATE_TPL);
|
|
|
|
data = Replace(data, string("{{ADDRESS}}"), address);
|
|
data = Replace(data, string("{{AT}}"), at);
|
|
data = Replace(data, string("{{TYPE}}"), type);
|
|
data = Replace(data, string("{{SELLER}}"), seller);
|
|
data = Replace(data, string("{{CUSTOMER}}"), customer);
|
|
data = Replace(data, string("{{SUM}}"), sum);
|
|
|
|
if (pay.length() == 0)
|
|
{
|
|
//{{UNTIL}}
|
|
data = Replace(data, string("{{UNTIL}}"), "");
|
|
}
|
|
else
|
|
{
|
|
pay = GetDate(pay);
|
|
string untl(",\"until\": \"");
|
|
untl.append(pay);
|
|
untl.append("\"");
|
|
data = Replace(data, string("{{UNTIL}}"), untl);
|
|
}
|
|
|
|
if (leave_before.length() == 0)
|
|
{
|
|
//{{FEETBACK}}
|
|
data = Replace(data, string("{{FEETBACK}}"), "");
|
|
}
|
|
else
|
|
{
|
|
leave_before = GetDate(leave_before);
|
|
string untl(",\"feedback\": {\"leave-before\": \"");
|
|
untl.append(leave_before);
|
|
untl.append("\"}");
|
|
|
|
data = Replace(data, string("{{FEETBACK}}"), untl);
|
|
}
|
|
|
|
string result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
nlohmann::json jsonData = nlohmann::json::parse(result);
|
|
|
|
std::ostringstream stream;
|
|
stream << "success: " << jsonData["result"]["success"] << endl;
|
|
stream << "message: " << jsonData["result"]["message"] << endl;
|
|
string payload = base64_decode(jsonData["payload"]);
|
|
stream << payload << endl;
|
|
string decoded = stream.str();
|
|
cout << decoded << endl;
|
|
if (isDebug)
|
|
ShowDebug(data, result, 1, payload);
|
|
|
|
return 0;
|
|
}
|
|
string Deals::GetDate(const string date)
|
|
{
|
|
string buffer = date;
|
|
/*
|
|
-p|--pay { <yyyy-mm-dd> [hh:mm:ss UTC] | <time>[smhd] }
|
|
Time for make payment; default: 1d
|
|
*/
|
|
std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::toupper);
|
|
if (buffer.length() < 23)
|
|
{
|
|
char letter = buffer[buffer.length() - 1];
|
|
int append = 0;
|
|
string numval = buffer.substr(0, buffer.length() - 1);
|
|
int num = stoi(numval);
|
|
switch (letter)
|
|
{
|
|
case 'S':
|
|
append = num;
|
|
break;
|
|
case 'M':
|
|
append = num * 60;
|
|
break;
|
|
case 'H':
|
|
append = num * 60 * 60;
|
|
break;
|
|
case 'D':
|
|
append = num * 24 * 60 * 60;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
std::time_t utcTimeInSeconds = std::time(nullptr);
|
|
utcTimeInSeconds += append;
|
|
|
|
tm *tmm = gmtime(&utcTimeInSeconds);
|
|
char buff[70];
|
|
strftime(buff, sizeof buff, "%Y-%m-%d %H:%M:%S", tmm);
|
|
string result = buff;
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
string Deals::CommonStatus()
|
|
{
|
|
string payaddress = parser.getLast();
|
|
string data("curl -s -X POST \"");
|
|
data.append(address);
|
|
data.append("/api/v1/deal/status\" -H \"Content-Type: application/json\" ");
|
|
data.append("-d \"{\\\"address\\\":\\\"");
|
|
data.append(payaddress);
|
|
data.append("\\\"}\"");
|
|
return data;
|
|
}
|
|
int Deals::Status()
|
|
{
|
|
string data = CommonStatus();
|
|
string result = ExecCommand(data.c_str());
|
|
if (isDebug)
|
|
{
|
|
cout << "command line" << endl;
|
|
cout << data << endl;
|
|
cout << result << endl;
|
|
}
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
nlohmann::json jsonData = nlohmann::json::parse(result);
|
|
|
|
std::ostringstream stream;
|
|
|
|
bool isPayment = false;
|
|
string payload = base64_decode(jsonData["payload"]);
|
|
stream << payload << endl;
|
|
// order: Paid, order: Completed, order: Executed
|
|
|
|
if ((int)payload.find("Paid") != -1 || (int)payload.find("Completed") != -1 || (int)payload.find("Executed") != -1)
|
|
{
|
|
isPayment = true;
|
|
}
|
|
|
|
string decoded = stream.str();
|
|
cout << decoded << endl;
|
|
|
|
if (isDebug)
|
|
ShowDebug(data, result, 1, decoded);
|
|
if (parser.cmdOptionExists("-i") || parser.cmdOptionExists("--is-paid"))
|
|
{
|
|
return isPayment == true ? 0 : 1;
|
|
}
|
|
return 0;
|
|
}
|
|
int Deals::Complite()
|
|
{
|
|
|
|
string data = CommonStatus();
|
|
string result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
nlohmann::json jsonData = nlohmann::json::parse(result);
|
|
nlohmann::json deal = jsonData["deal"];
|
|
|
|
string positive = "Positive";
|
|
int refund = 0;
|
|
if (parser.cmdOptionExists("-n") || parser.cmdOptionExists("--negative"))
|
|
{
|
|
positive = "Negative";
|
|
}
|
|
if (parser.cmdOptionExists("--refund"))
|
|
{
|
|
refund = stoi(parser.getCmdOption("--refund"));
|
|
}
|
|
if (parser.cmdOptionExists("-r"))
|
|
{
|
|
refund = stoi(parser.getCmdOption("-r"));
|
|
}
|
|
|
|
deal["feedback"]["status"] = positive;
|
|
if (refund > 0)
|
|
deal["feedback"]["refund"] = refund;
|
|
|
|
deal["date"] = Replace(deal["date"], " UTC", "");
|
|
deal["feedback"]["leave_before"] = Replace(deal["feedback"]["leave_before"], " UTC", "");
|
|
deal["payment"]["until"] = Replace(deal["payment"]["until"], " UTC", "");
|
|
|
|
string jsf = deal.dump();
|
|
jsf = ReplaceAll(jsf, "\"", "\\\"");
|
|
data = "curl -s -X POST \"";
|
|
data.append(address);
|
|
data.append("/api/v1/deal/complete\" -H \"Content-Type: application/json\" ");
|
|
data.append("-d \"");
|
|
data.append(jsf);
|
|
data.append("\"");
|
|
|
|
result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
|
|
std::ostringstream stream;
|
|
stream << "success: " << jsonData["result"]["success"] << endl;
|
|
stream << "message: " << jsonData["result"]["message"] << endl;
|
|
|
|
string decoded = stream.str();
|
|
std::cout << decoded << endl;
|
|
|
|
if (isDebug)
|
|
ShowDebug(data, decoded, 0, result);
|
|
return 0;
|
|
}
|
|
int Deals::Cancel()
|
|
{
|
|
string data = CommonStatus();
|
|
string result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
nlohmann::json jsonData = nlohmann::json::parse(result);
|
|
nlohmann::json deal = jsonData["deal"];
|
|
|
|
string message;
|
|
string sign;
|
|
if (parser.cmdOptionExists("-m") || parser.cmdOptionExists("--message"))
|
|
{
|
|
message = GetVal("-m", "--message");
|
|
}
|
|
if (parser.cmdOptionExists("-s") || parser.cmdOptionExists("--signature"))
|
|
{
|
|
sign = GetVal("-s", "--signature");
|
|
}
|
|
|
|
deal["seller"]["signature"] = sign;
|
|
deal["feedback"]["comments"] = message;
|
|
|
|
deal["date"] = Replace(deal["date"], " UTC", "");
|
|
deal["feedback"]["leave_before"] = Replace(deal["feedback"]["leave_before"], " UTC", "");
|
|
deal["payment"]["until"] = Replace(deal["payment"]["until"], " UTC", "");
|
|
|
|
string jsf = deal.dump();
|
|
jsf = ReplaceAll(jsf, "\"", "\\\"");
|
|
data = "curl -s -X POST \"";
|
|
data.append(address);
|
|
data.append("/api/v1/deal/cancel\" -H \"Content-Type: application/json\" ");
|
|
data.append("-d \"");
|
|
data.append(jsf);
|
|
data.append("\"");
|
|
|
|
result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
|
|
std::ostringstream stream;
|
|
stream << "success: " << jsonData["result"]["success"] << endl;
|
|
stream << "message: " << jsonData["result"]["message"] << endl;
|
|
|
|
string decoded = stream.str();
|
|
std::cout << decoded << endl;
|
|
|
|
if (isDebug)
|
|
ShowDebug(data, decoded, 0, result);
|
|
return 0;
|
|
}
|
|
int Deals::Negative()
|
|
{
|
|
string data = CommonStatus();
|
|
string result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
nlohmann::json jsonData = nlohmann::json::parse(result);
|
|
nlohmann::json deal = jsonData["deal"];
|
|
nlohmann::ordered_json deal2;
|
|
string message;
|
|
string sign;
|
|
if (parser.cmdOptionExists("-m") || parser.cmdOptionExists("--message"))
|
|
{
|
|
message = GetVal("-m", "--message");
|
|
}
|
|
if (parser.cmdOptionExists("-s") || parser.cmdOptionExists("--signature"))
|
|
{
|
|
sign = GetVal("-s", "--signature");
|
|
}
|
|
|
|
deal2["order"] = "feedback";
|
|
deal2["type"] = deal["type"];
|
|
deal2["at"] = deal["at"];
|
|
deal2["date"] = deal["date"];
|
|
deal2["salt"] = deal["salt"];
|
|
|
|
// deal2["seller"] = "{}";
|
|
deal2["seller"]["address"] = deal["seller"]["address"];
|
|
|
|
// deal2["customer"] = "{}";
|
|
deal2["customer"]["address"] = deal["customer"]["address"];
|
|
deal2["customer"]["signature"] = sign;
|
|
|
|
deal2["payment"]["address"] = deal["payment"]["address"];
|
|
deal2["payment"]["until"] = deal["payment"]["until"];
|
|
deal2["payment"]["sum"] = deal["payment"]["sum"];
|
|
|
|
// deal2["feedback"] = "{}";
|
|
deal2["feedback"]["leave_before"] = deal["feedback"]["leave_before"];
|
|
deal2["feedback"]["comments"] = message;
|
|
|
|
string jsf = deal2.dump();
|
|
jsf = ReplaceAll(jsf, "leave_before", "leave-before");
|
|
data = "curl --location '";
|
|
data.append(address);
|
|
data.append("/api/v1/deal/feedback?server=");
|
|
data.append(url_encode(address));
|
|
data.append("'");
|
|
data.append(" --header 'Content-Type: application/json' ");
|
|
data.append("--data '");
|
|
data.append(jsf);
|
|
data.append("'");
|
|
|
|
result = ExecCommand(data.c_str());
|
|
if (result.length() == 0)
|
|
return NoResponse("");
|
|
|
|
std::ostringstream stream;
|
|
stream << "success: " << jsonData["result"]["success"] << endl;
|
|
stream << "message: " << jsonData["result"]["message"] << endl;
|
|
|
|
string decoded = stream.str();
|
|
std::cout << decoded << endl;
|
|
|
|
if (isDebug)
|
|
ShowDebug(data, decoded, 0, result);
|
|
return 0;
|
|
}
|
|
|
|
string Deals::GetVal(const string first, const string second)
|
|
{
|
|
string aval;
|
|
string res("");
|
|
if (parser.cmdOptionExists(first))
|
|
{
|
|
aval = parser.getCmdOption(first);
|
|
if (aval.length() > 0)
|
|
res = aval;
|
|
}
|
|
if (parser.cmdOptionExists(second))
|
|
{
|
|
aval = parser.getCmdOption(second);
|
|
if (aval.length() > 0)
|
|
res = aval;
|
|
}
|
|
return res;
|
|
}
|