Code refactoring.
This commit is contained in:
990
src/app/Common.cpp
Normal file
990
src/app/Common.cpp
Normal file
@@ -0,0 +1,990 @@
|
||||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
Common.cpp
|
||||
|
||||
Notices:
|
||||
|
||||
Dial Module common.
|
||||
|
||||
Author:
|
||||
|
||||
Copyright (c) Prepodobny Alen
|
||||
|
||||
mailto: alienufo@inbox.ru
|
||||
mailto: ufocomp@gmail.com
|
||||
|
||||
--*/
|
||||
|
||||
#include "Core.hpp"
|
||||
#include "Common.hpp"
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
#endif // __cplusplus
|
||||
|
||||
namespace Apostol {
|
||||
|
||||
namespace Common {
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//-- CCustomModule ---------------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CCustomModule::CCustomModule(CModuleProcess *AProcess, const CString& ModuleName, const CString& SectionName):
|
||||
CApostolModule(AProcess, ModuleName, SectionName) {
|
||||
|
||||
m_SyncPeriod = BPS_DEFAULT_SYNC_PERIOD;
|
||||
m_Status = psStopped;
|
||||
|
||||
CCustomModule::InitMethods();
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::InitMethods() {
|
||||
#if defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 9)
|
||||
m_pMethods->AddObject(_T("GET") , (CObject *) new CMethodHandler(true , [this](auto && Connection) { DoGet(Connection); }));
|
||||
m_pMethods->AddObject(_T("POST") , (CObject *) new CMethodHandler(true , [this](auto && Connection) { DoPost(Connection); }));
|
||||
m_pMethods->AddObject(_T("HEAD") , (CObject *) new CMethodHandler(true , [this](auto && Connection) { DoHead(Connection); }));
|
||||
m_pMethods->AddObject(_T("OPTIONS"), (CObject *) new CMethodHandler(true , [this](auto && Connection) { DoOptions(Connection); }));
|
||||
m_pMethods->AddObject(_T("PUT") , (CObject *) new CMethodHandler(false, [this](auto && Connection) { MethodNotAllowed(Connection); }));
|
||||
m_pMethods->AddObject(_T("DELETE") , (CObject *) new CMethodHandler(false, [this](auto && Connection) { MethodNotAllowed(Connection); }));
|
||||
m_pMethods->AddObject(_T("TRACE") , (CObject *) new CMethodHandler(false, [this](auto && Connection) { MethodNotAllowed(Connection); }));
|
||||
m_pMethods->AddObject(_T("PATCH") , (CObject *) new CMethodHandler(false, [this](auto && Connection) { MethodNotAllowed(Connection); }));
|
||||
m_pMethods->AddObject(_T("CONNECT"), (CObject *) new CMethodHandler(false, [this](auto && Connection) { MethodNotAllowed(Connection); }));
|
||||
#else
|
||||
m_pMethods->AddObject(_T("GET"), (CObject *) new CMethodHandler(true, std::bind(&CCustomModule::DoGet, this, _1)));
|
||||
m_pMethods->AddObject(_T("POST"), (CObject *) new CMethodHandler(true, std::bind(&CCustomModule::DoPost, this, _1)));
|
||||
m_pMethods->AddObject(_T("HEAD"), (CObject *) new CMethodHandler(true, std::bind(&CCustomModule::DoHead, this, _1)));
|
||||
m_pMethods->AddObject(_T("OPTIONS"), (CObject *) new CMethodHandler(true, std::bind(&CCustomModule::DoOptions, this, _1)));
|
||||
m_pMethods->AddObject(_T("PUT"), (CObject *) new CMethodHandler(false, std::bind(&CCustomModule::MethodNotAllowed, this, _1)));
|
||||
m_pMethods->AddObject(_T("DELETE"), (CObject *) new CMethodHandler(false, std::bind(&CCustomModule::MethodNotAllowed, this, _1)));
|
||||
m_pMethods->AddObject(_T("TRACE"), (CObject *) new CMethodHandler(false, std::bind(&CCustomModule::MethodNotAllowed, this, _1)));
|
||||
m_pMethods->AddObject(_T("PATCH"), (CObject *) new CMethodHandler(false, std::bind(&CCustomModule::MethodNotAllowed, this, _1)));
|
||||
m_pMethods->AddObject(_T("CONNECT"), (CObject *) new CMethodHandler(false, std::bind(&CCustomModule::MethodNotAllowed, this, _1)));
|
||||
#endif
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::Initialization(CModuleProcess *AProcess) {
|
||||
CApostolModule::Initialization(AProcess);
|
||||
|
||||
if (Enabled()) {
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CCustomModule::Enabled() {
|
||||
if (m_ModuleStatus == msUnknown)
|
||||
m_ModuleStatus = Config()->IniFile().ReadBool(SectionName().c_str(), "enable", true) ? msEnabled : msDisabled;
|
||||
return m_ModuleStatus == msEnabled;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
CString CCustomModule::ToString(unsigned long Value) {
|
||||
TCHAR szString[_INT_T_LEN + 1] = {0};
|
||||
sprintf(szString, "%lu", Value);
|
||||
return { szString };
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::JsonStringToKey(const CString &String, CString& Key) {
|
||||
const CJSON Json(String);
|
||||
|
||||
if (Json.HasOwnProperty("error")) {
|
||||
const auto &error = Json["error"];
|
||||
if (error.ValueType() == jvtObject)
|
||||
throw Delphi::Exception::Exception(error["message"].AsString().c_str());
|
||||
}
|
||||
|
||||
if (Json.HasOwnProperty("data")) {
|
||||
Key = Json["data"].AsString();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::CheckKeyForNull(LPCTSTR Key, LPCTSTR Value) {
|
||||
if (Value == nullptr)
|
||||
throw ExceptionFrm("Invalid format: key \"%s\" cannot be empty.", Key);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CCustomModule::FindURLInLine(const CString &Line, CStringList &List) {
|
||||
CString URL;
|
||||
|
||||
TCHAR ch;
|
||||
int length = 0;
|
||||
size_t startPos, pos;
|
||||
|
||||
pos = 0;
|
||||
while ((startPos = Line.Find(HTTP_PREFIX, pos)) != CString::npos) {
|
||||
|
||||
URL.Clear();
|
||||
|
||||
pos = startPos + HTTP_PREFIX_SIZE;
|
||||
if (Line.Length() < 5)
|
||||
return false;
|
||||
|
||||
URL.Append(HTTP_PREFIX);
|
||||
ch = Line.at(pos);
|
||||
if (ch == 's') {
|
||||
URL.Append(ch);
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (Line.Length() < 7 || Line.at(pos++) != ':' || Line.at(pos++) != '/' || Line.at(pos++) != '/')
|
||||
return false;
|
||||
|
||||
URL.Append("://");
|
||||
|
||||
length = 0;
|
||||
ch = Line.at(pos);
|
||||
while (ch != 0 && (IsChar(ch) || IsNumeral(ch) || ch == ':' || ch == '.' || ch == '-')) {
|
||||
URL.Append(ch);
|
||||
length++;
|
||||
ch = Line.at(++pos);
|
||||
}
|
||||
|
||||
if (length < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startPos == 0) {
|
||||
List.Add(URL);
|
||||
} else {
|
||||
ch = Line.at(startPos - 1);
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
case ',':
|
||||
case ';':
|
||||
List.Add(URL);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
int CCustomModule::CheckFee(const CString &Fee) {
|
||||
if (!Fee.IsEmpty()) {
|
||||
|
||||
if (Fee.Length() >= 10)
|
||||
return -1;
|
||||
|
||||
size_t numbers = 0;
|
||||
size_t delimiter = 0;
|
||||
size_t percent = 0;
|
||||
|
||||
size_t pos = 0;
|
||||
TCHAR ch;
|
||||
|
||||
ch = Fee.at(pos);
|
||||
while (ch != 0) {
|
||||
if (IsNumeral(ch))
|
||||
numbers++;
|
||||
if (ch == '.')
|
||||
delimiter++;
|
||||
if (ch == '%')
|
||||
percent++;
|
||||
ch = Fee.at(++pos);
|
||||
}
|
||||
|
||||
if (numbers == 0 || delimiter > 1 || percent > 1 || ((numbers + percent + delimiter) != Fee.Length()))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool CCustomModule::CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message) {
|
||||
if (VerifyPGPSignature == -2) {
|
||||
Message = "PGP public key is not meaningful.";
|
||||
} else if (VerifyPGPSignature == -1) {
|
||||
Message = "PGP signature not valid.";
|
||||
} else if (VerifyPGPSignature == 0) {
|
||||
Message = "PGP signature not found.";
|
||||
} else if (VerifyPGPSignature > 1) {
|
||||
Message = "PGP signature status: Unknown.";
|
||||
}
|
||||
return VerifyPGPSignature == 1;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
int CCustomModule::VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message) {
|
||||
const OpenPGP::Key signer(Key.c_str());
|
||||
const OpenPGP::CleartextSignature cleartext(ClearText.c_str());
|
||||
|
||||
if (!cleartext.meaningful())
|
||||
return -2;
|
||||
|
||||
const int verified = OpenPGP::Verify::cleartext_signature(signer, cleartext);
|
||||
|
||||
if (verified == 1) {
|
||||
Message = cleartext.get_message().c_str();
|
||||
}
|
||||
|
||||
return verified;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::ParsePGPKey(const CString &Key, CStringPairs& ServerList, CStringList& BTCKeys) {
|
||||
if (Key.IsEmpty())
|
||||
return;
|
||||
|
||||
const Apostol::PGP::Key pgp(Key.c_str());
|
||||
if (!pgp.meaningful())
|
||||
return;
|
||||
|
||||
CStringList Data;
|
||||
CPGPUserIdList List;
|
||||
CStringList KeyList;
|
||||
|
||||
pgp.ExportUID(List);
|
||||
|
||||
for (int i = 0; i < List.Count(); i++) {
|
||||
|
||||
const auto &uid = List[i];
|
||||
|
||||
DebugMessage("%s (%s)\n", uid.Name.c_str(), uid.Desc.c_str());
|
||||
|
||||
const auto &name = uid.Name.Lower();
|
||||
const auto &data = uid.Desc.Lower();
|
||||
|
||||
if (name == "technical_data") {
|
||||
SplitColumns(data, Data, ';');
|
||||
|
||||
if (Data.Count() == 3) {
|
||||
m_SyncPeriod = StrToIntDef(Data[1].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD);
|
||||
} else if (Data.Count() == 2) {
|
||||
m_SyncPeriod = StrToIntDef(Data[0].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD);
|
||||
} else if (Data.Count() == 1) {
|
||||
m_SyncPeriod = StrToIntDef(Data[0].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD);
|
||||
}
|
||||
} if (uid.Name.Length() >= 35 && uid.Name.SubString(0, 3) == BM_PREFIX) {
|
||||
CStringList urlList;
|
||||
if (FindURLInLine(uid.Desc, urlList)) {
|
||||
for (int l = 0; l < urlList.Count(); l++) {
|
||||
ServerList.AddPair(uid.Name, urlList[l]);
|
||||
}
|
||||
}
|
||||
} else if (name.Find("bitcoin_key") != CString::npos) {
|
||||
const auto &key = wallet::ec_public(data.c_str());
|
||||
if (verify(key))
|
||||
KeyList.AddPair(name, key.encoded());
|
||||
}
|
||||
}
|
||||
|
||||
CString Name;
|
||||
for (int i = 1; i <= KeyList.Count(); i++) {
|
||||
Name = "bitcoin_key";
|
||||
Name << i;
|
||||
const auto &key = KeyList[Name];
|
||||
if (!key.IsEmpty()) {
|
||||
BTCKeys.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2) {
|
||||
if (OAuth2["type"].AsString() == "service_account") {
|
||||
UpdateProviders(Context.Providers(), OAuth2);
|
||||
|
||||
Context.SetCheckDate(0);
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::UpdateProviders(CProviders &Providers, const CJSONObject &Data) {
|
||||
const auto &caProviderName = CString(SYSTEM_PROVIDER_NAME);
|
||||
const auto &caApplicationName = CString(SERVICE_APPLICATION_NAME);
|
||||
|
||||
int index = Providers.IndexOfName(caProviderName);
|
||||
if (index == -1)
|
||||
index = Providers.AddPair(caProviderName, CProvider(caProviderName));
|
||||
auto& Provider = Providers[index].Value();
|
||||
Provider.Applications().AddPair(caApplicationName, Data);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context) {
|
||||
|
||||
auto OnDone = [this, &Context](CTCPConnection *Sender) {
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (Sender);
|
||||
auto pReply = pConnection->Reply();
|
||||
|
||||
DebugReply(pReply);
|
||||
|
||||
if (pReply->Status == CHTTPReply::ok) {
|
||||
const CJSON Json(pReply->Content);
|
||||
|
||||
Context.Session() = Json["session"].AsString();
|
||||
Context.Secret() = Json["secret"].AsString();
|
||||
|
||||
Context.Tokens().Values("access_token", Json["access_token"].AsString());
|
||||
|
||||
ModuleStatus(Context);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto OnFail = [&Context](CTCPConnection *Sender, const Delphi::Exception::Exception &E) {
|
||||
Context.SetStatus(csInitialized);
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (Sender);
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (pConnection->Client());
|
||||
|
||||
DebugReply(pConnection->Reply());
|
||||
|
||||
Log()->Error(APP_LOG_ERR, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what());
|
||||
};
|
||||
|
||||
auto OnHTTPClient = [this](const CLocation &URI) {
|
||||
return GetClient(URI.hostname, URI.port);
|
||||
};
|
||||
|
||||
CString server_uri(Context.URL().Origin());
|
||||
|
||||
const auto &token_uri = Provider.TokenURI(Application);
|
||||
const auto &service_token = CToken::CreateToken(Provider, Application);
|
||||
|
||||
Context.Tokens().Values("service_token", service_token);
|
||||
|
||||
if (!token_uri.IsEmpty()) {
|
||||
CToken::FetchAccessToken(token_uri.front() == '/' ? server_uri + token_uri : token_uri, service_token, OnHTTPClient, OnDone, OnFail);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::FetchProviders(CDateTime Now, CContext &Context) {
|
||||
for (int i = 0; i < Context.Providers().Count(); i++) {
|
||||
auto &Provider = Context.Providers()[i].Value();
|
||||
for (int j = 0; j < Provider.Applications().Count(); ++j) {
|
||||
const auto &app = Provider.Applications().Members(j);
|
||||
if (app["type"].AsString() == "service_account") {
|
||||
if (Provider.KeyStatus() == ksUnknown) {
|
||||
CreateAccessToken(Provider, app.String(), Context);
|
||||
Provider.KeyStatusTime(Now);
|
||||
Provider.KeyStatus(ksSuccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::CheckProviders(CDateTime Now, CContext &Context) {
|
||||
for (int i = 0; i < Context.Providers().Count(); i++) {
|
||||
auto& Provider = Context.Providers()[i].Value();
|
||||
if (Provider.KeyStatus() != ksUnknown) {
|
||||
Provider.KeyStatusTime(Now);
|
||||
Provider.KeyStatus(ksUnknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::CheckDeal(const CDeal &Deal) {
|
||||
|
||||
const auto &Data = Deal.Data();
|
||||
|
||||
const auto DateTime = UTC();
|
||||
const auto Date = StringToDate(Data.Date);
|
||||
const auto Sum = BTCToDouble(Data.Payment.Sum);
|
||||
|
||||
if (Data.Order == doCreate) {
|
||||
if (DateTime < Date)
|
||||
throw ExceptionFrm("Invalid deal date.");
|
||||
|
||||
if ((DateTime - Date) > (CDateTime) 180 / SecsPerDay)
|
||||
throw ExceptionFrm("Deal date expired.");
|
||||
}
|
||||
|
||||
if (Data.Order == doComplete) {
|
||||
const CDateTime LeaveBefore = StringToDate(Data.FeedBack.LeaveBefore);
|
||||
if (DateTime > LeaveBefore)
|
||||
throw ExceptionFrm("Date feedback expired.");
|
||||
}
|
||||
|
||||
if (Odd(int(Data.Order)) || Data.Order == doExecute || Data.Order == doDelete)
|
||||
throw ExceptionFrm("Invalid \"order\" value for deal module.");
|
||||
|
||||
if (Data.Order == doCancel) {
|
||||
const CDateTime Until = StringToDate(Data.Payment.Until);
|
||||
if (DateTime > Until)
|
||||
throw ExceptionFrm("Deal cancellation expired.");
|
||||
|
||||
CString message(Data.Payment.Address);
|
||||
if (!Data.FeedBack.Comments.IsEmpty()) {
|
||||
message += LINEFEED;
|
||||
message += Data.FeedBack.Comments;
|
||||
}
|
||||
|
||||
if (Data.Seller.Signature.IsEmpty() || !VerifyMessage(message, Data.Seller.Address, Data.Seller.Signature))
|
||||
throw ExceptionFrm("The deal is not signed by the seller.");
|
||||
}
|
||||
|
||||
if (Data.Order == doFeedback) {
|
||||
CString message(Data.Payment.Address);
|
||||
if (!Data.FeedBack.Comments.IsEmpty()) {
|
||||
message += LINEFEED;
|
||||
message += Data.FeedBack.Comments;
|
||||
}
|
||||
|
||||
if (Data.Customer.Signature.IsEmpty() || !VerifyMessage(message, Data.Customer.Address, Data.Customer.Signature))
|
||||
throw ExceptionFrm("The deal is not signed by the customer.");
|
||||
}
|
||||
|
||||
if (!valid_address(Data.Seller.Address))
|
||||
throw ExceptionFrm("Invalid Seller address: %s.", Data.Seller.Address.c_str());
|
||||
|
||||
if (!valid_address(Data.Customer.Address))
|
||||
throw ExceptionFrm("Invalid Customer address: %s.", Data.Customer.Address.c_str());
|
||||
|
||||
if (!valid_address(Data.Payment.Address))
|
||||
throw ExceptionFrm("Invalid Payment address: %s.", Data.Payment.Address.c_str());
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::DoGet(CHTTPServerConnection *AConnection) {
|
||||
|
||||
auto pRequest = AConnection->Request();
|
||||
|
||||
CString sPath(pRequest->Location.pathname);
|
||||
|
||||
// Request sPath must be absolute and not contain "..".
|
||||
if (sPath.empty() || sPath.front() != '/' || sPath.find(_T("..")) != CString::npos) {
|
||||
AConnection->SendStockReply(CHTTPReply::bad_request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sPath.SubString(0, 5) == "/api/") {
|
||||
DoAPI(AConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
SendResource(AConnection, sPath);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::DoPost(CHTTPServerConnection *AConnection) {
|
||||
|
||||
auto pRequest = AConnection->Request();
|
||||
auto pReply = AConnection->Reply();
|
||||
|
||||
pReply->ContentType = CHTTPReply::json;
|
||||
|
||||
CStringList slRouts;
|
||||
SplitColumns(pRequest->Location.pathname, slRouts, '/');
|
||||
|
||||
if (slRouts.Count() < 3) {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &caService = slRouts[0].Lower();
|
||||
const auto &caVersion = slRouts[1].Lower();
|
||||
const auto &caCommand = slRouts[2].Lower();
|
||||
const auto &caAction = slRouts.Count() == 4 ? slRouts[3].Lower() : "";
|
||||
|
||||
if (caService != "api") {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
if (caVersion != "v1") {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
CString sRoute;
|
||||
for (int i = 0; i < slRouts.Count(); ++i) {
|
||||
sRoute.Append('/');
|
||||
sRoute.Append(slRouts[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
if (caCommand == "account") {
|
||||
DoAccount(AConnection, "POST", sRoute);
|
||||
} else if (caCommand == "deal") {
|
||||
DoDeal(AConnection, "POST", sRoute, caAction);
|
||||
} else if (caCommand == "signature") {
|
||||
DoSignature(AConnection);
|
||||
} else {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
ReplyError(AConnection, CHTTPReply::bad_request, e.what());
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::DoAPI(CHTTPServerConnection *AConnection) {
|
||||
|
||||
auto pRequest = AConnection->Request();
|
||||
auto pReply = AConnection->Reply();
|
||||
|
||||
pReply->ContentType = CHTTPReply::json;
|
||||
|
||||
CStringList slRouts;
|
||||
SplitColumns(pRequest->Location.pathname, slRouts, '/');
|
||||
|
||||
if (slRouts.Count() < 3) {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &caService = slRouts[0].Lower();
|
||||
const auto &caVersion = slRouts[1].Lower();
|
||||
const auto &caCommand = slRouts[2].Lower();
|
||||
const auto &caAction = slRouts.Count() == 4 ? slRouts[3].Lower() : "";
|
||||
|
||||
if (caService != "api") {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
if (caVersion != "v1") {
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
CString sRoute;
|
||||
for (int i = 0; i < slRouts.Count(); ++i) {
|
||||
sRoute.Append('/');
|
||||
sRoute.Append(slRouts[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
if (caCommand == "ping") {
|
||||
|
||||
AConnection->SendStockReply(CHTTPReply::ok);
|
||||
|
||||
} else if (caCommand == "time") {
|
||||
|
||||
pReply->Content << "{\"serverTime\": " << ToString(MsEpoch()) << "}";
|
||||
|
||||
AConnection->SendReply(CHTTPReply::ok);
|
||||
|
||||
} else if (caCommand == "help") {
|
||||
|
||||
pRequest->Content.Clear();
|
||||
|
||||
DoAccount(AConnection, "GET", sRoute);
|
||||
|
||||
} else if (caCommand == "account" && caAction == "status") {
|
||||
|
||||
pRequest->Content.Clear();
|
||||
|
||||
DoAccount(AConnection, "GET", sRoute);
|
||||
|
||||
} else if (caCommand == "deal" && caAction == "status") {
|
||||
|
||||
pRequest->Content.Clear();
|
||||
|
||||
DoDeal(AConnection, "GET", sRoute, caAction);
|
||||
|
||||
} else if (caCommand == "bc" && caAction == "history") {
|
||||
|
||||
const auto &caAccount = pRequest->Params["account"];
|
||||
|
||||
if (caAccount.IsEmpty()) {
|
||||
AConnection->SendStockReply(CHTTPReply::bad_request);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const wallet::payment_address address(std::string(caAccount.c_str()));
|
||||
|
||||
CJSON history;
|
||||
fetch_history(address, history);
|
||||
|
||||
pReply->Content = history.ToString();
|
||||
} catch (Delphi::Exception::Exception &E) {
|
||||
ExceptionToJson(CHTTPReply::bad_request, E, pReply->Content);
|
||||
Log()->Error(APP_LOG_EMERG, 0, E.what());
|
||||
}
|
||||
|
||||
AConnection->SendReply(CHTTPReply::ok, nullptr, true);
|
||||
|
||||
} else if (caCommand == "bc" && caAction == "header") {
|
||||
|
||||
const auto &caHeight = pRequest->Params["height"];
|
||||
const auto &caHash = pRequest->Params["hash"];
|
||||
|
||||
if (caHeight.IsEmpty() && caHash.IsEmpty()) {
|
||||
AConnection->SendStockReply(CHTTPReply::bad_request);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CJSON header;
|
||||
|
||||
if (!caHash.IsEmpty()) {
|
||||
fetch_header(hash256(std::string(caHash.c_str())), header);
|
||||
} else {
|
||||
uint32_t height = StrToInt(caHeight.c_str());
|
||||
fetch_header(height, header);
|
||||
}
|
||||
|
||||
pReply->Content = header.ToString();
|
||||
} catch (Delphi::Exception::Exception &E) {
|
||||
ExceptionToJson(CHTTPReply::bad_request, E, pReply->Content);
|
||||
Log()->Error(APP_LOG_EMERG, 0, E.what());
|
||||
}
|
||||
|
||||
AConnection->SendReply(CHTTPReply::ok, nullptr, true);
|
||||
|
||||
} else {
|
||||
|
||||
AConnection->SendStockReply(CHTTPReply::not_found);
|
||||
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
ReplyError(AConnection, CHTTPReply::bad_request, e.what());
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::ModuleService(CContext &Context) {
|
||||
|
||||
Log()->Notice("[%s] [%s] Trying to fetch a OAuth2 configuration file.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||
|
||||
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||
|
||||
Context.SetStatus(Context::csPreparing);
|
||||
|
||||
ARequest->ContentType = CHTTPRequest::text;
|
||||
|
||||
Apostol::PGP::CleartextSignature(
|
||||
m_pgpModuleKey,
|
||||
m_pgpPassphrase,
|
||||
BPS_PGP_HASH,
|
||||
Context.Name(),
|
||||
ARequest->Content);
|
||||
|
||||
CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/service");
|
||||
|
||||
const auto &caModuleAddress = m_Module["address"];
|
||||
if (!caModuleAddress.IsEmpty())
|
||||
ARequest->AddHeader("Module-Address", caModuleAddress);
|
||||
|
||||
DebugRequest(ARequest);
|
||||
};
|
||||
|
||||
auto OnExecute = [&Context](CTCPConnection *AConnection) {
|
||||
|
||||
Context.SetStatus(Context::csInitialization);
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
|
||||
if (pConnection != nullptr) {
|
||||
auto pReply = pConnection->Reply();
|
||||
|
||||
DebugReply(pReply);
|
||||
|
||||
if (pReply->Status == CHTTPReply::ok) {
|
||||
const CJSON OAuth2(pReply->Content);
|
||||
UpdateOAuth2(Context, OAuth2.Object());
|
||||
}
|
||||
|
||||
pConnection->CloseConnection(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto OnException = [&Context](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) {
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
if (pConnection != nullptr) {
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (pConnection->Client());
|
||||
if (pClient != nullptr) {
|
||||
Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what());
|
||||
}
|
||||
DebugReply(pConnection->Reply());
|
||||
}
|
||||
|
||||
Context.SetStatus(Context::csInitialization);
|
||||
};
|
||||
|
||||
auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port);
|
||||
|
||||
pClient->OnRequest(OnRequest);
|
||||
pClient->OnExecute(OnExecute);
|
||||
pClient->OnException(OnException);
|
||||
|
||||
pClient->AutoFree(true);
|
||||
pClient->Active(true);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::ModuleStatus(CContext &Context) {
|
||||
|
||||
Log()->Notice("[%s] [%s] Trying get module status.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||
|
||||
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||
|
||||
Context.SetStatus(Context::csInProgress);
|
||||
|
||||
const auto &caModuleAddress = m_Module["address"];
|
||||
|
||||
ARequest->ContentType = CHTTPRequest::text;
|
||||
|
||||
ARequest->Content.Format(R"({"address": "%s"})", caModuleAddress.c_str());
|
||||
|
||||
CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/status");
|
||||
|
||||
ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]);
|
||||
|
||||
if (!caModuleAddress.IsEmpty())
|
||||
ARequest->AddHeader("Module-Address", caModuleAddress);
|
||||
|
||||
DebugRequest(ARequest);
|
||||
};
|
||||
|
||||
auto OnExecute = [this, &Context](CTCPConnection *AConnection) {
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
|
||||
if (pConnection != nullptr) {
|
||||
auto pReply = pConnection->Reply();
|
||||
|
||||
DebugReply(pReply);
|
||||
|
||||
if (pReply->Status == CHTTPReply::ok) {
|
||||
ModuleAuthorize(Context);
|
||||
} else {
|
||||
ModuleNew(Context);
|
||||
}
|
||||
|
||||
pConnection->CloseConnection(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto OnException = [&Context](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) {
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
if (pConnection != nullptr) {
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (pConnection->Client());
|
||||
if (pClient != nullptr) {
|
||||
Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what());
|
||||
}
|
||||
DebugReply(pConnection->Reply());
|
||||
}
|
||||
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
};
|
||||
|
||||
auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port);
|
||||
|
||||
pClient->OnRequest(OnRequest);
|
||||
pClient->OnExecute(OnExecute);
|
||||
pClient->OnException(OnException);
|
||||
|
||||
pClient->AutoFree(true);
|
||||
pClient->Active(true);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::ModuleNew(CContext &Context) {
|
||||
|
||||
Log()->Notice("[%s] [%s] Trying create new module.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||
|
||||
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||
|
||||
Context.SetStatus(Context::csInProgress);
|
||||
|
||||
ARequest->ContentType = CHTTPRequest::json;
|
||||
|
||||
const auto &caModuleAddress = m_Module["address"];
|
||||
|
||||
CJSON Json(jvtObject);
|
||||
|
||||
Json.Object().AddPair("address", caModuleAddress);
|
||||
Json.Object().AddPair("bitmessage", Context.Name());
|
||||
|
||||
const OpenPGP::SecretKey pgpSecret(m_pgpModuleKey.c_str());
|
||||
const auto &public_key = pgpSecret.get_public();
|
||||
|
||||
Json.Object().AddPair("pgp", public_key.write(OpenPGP::PGP::Armored::YES));
|
||||
|
||||
ARequest->Content = Json.ToString();
|
||||
|
||||
CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/client/new");
|
||||
|
||||
ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]);
|
||||
|
||||
if (!caModuleAddress.IsEmpty())
|
||||
ARequest->AddHeader("Module-Address", caModuleAddress);
|
||||
|
||||
DebugRequest(ARequest);
|
||||
};
|
||||
|
||||
auto OnExecute = [this, &Context](CTCPConnection *AConnection) {
|
||||
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
|
||||
if (pConnection != nullptr) {
|
||||
auto pReply = pConnection->Reply();
|
||||
|
||||
DebugReply(pReply);
|
||||
|
||||
if (pReply->Status == CHTTPReply::ok) {
|
||||
const CJSON Json(pReply->Content);
|
||||
|
||||
if (Json.HasOwnProperty("result")) {
|
||||
const auto &caResult = Json["result"];
|
||||
if (caResult.HasOwnProperty("success")) {
|
||||
if (caResult["success"].AsBoolean()) {
|
||||
ModuleAuthorize(Context);
|
||||
} else {
|
||||
if (caResult.HasOwnProperty("message")) {
|
||||
Log()->Error(APP_LOG_EMERG, 0, "[%s] [%s] %s", Context.Name().c_str(),
|
||||
Context.URL().Origin().c_str(), caResult["message"].AsString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pConnection->CloseConnection(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto OnException = [&Context](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) {
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
if (pConnection != nullptr) {
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (pConnection->Client());
|
||||
if (pClient != nullptr) {
|
||||
Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what());
|
||||
}
|
||||
DebugReply(pConnection->Reply());
|
||||
}
|
||||
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
};
|
||||
|
||||
auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port);
|
||||
|
||||
pClient->OnRequest(OnRequest);
|
||||
pClient->OnExecute(OnExecute);
|
||||
pClient->OnException(OnException);
|
||||
|
||||
pClient->AutoFree(true);
|
||||
pClient->Active(true);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CCustomModule::ModuleAuthorize(CContext &Context) {
|
||||
|
||||
Log()->Notice("[%s] [%s] Trying authorize module.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||
|
||||
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||
|
||||
Context.SetStatus(Context::csAuthorization);
|
||||
|
||||
ARequest->ContentType = CHTTPRequest::text;
|
||||
|
||||
Apostol::PGP::CleartextSignature(
|
||||
m_pgpModuleKey,
|
||||
m_pgpPassphrase,
|
||||
BPS_PGP_HASH,
|
||||
Context.Name(),
|
||||
ARequest->Content);
|
||||
|
||||
CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/authorize");
|
||||
|
||||
ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]);
|
||||
|
||||
const auto &caModuleAddress = m_Module["address"];
|
||||
if (!caModuleAddress.IsEmpty())
|
||||
ARequest->AddHeader("Module-Address", caModuleAddress);
|
||||
|
||||
DebugRequest(ARequest);
|
||||
};
|
||||
|
||||
auto OnExecute = [&Context](CTCPConnection *AConnection) {
|
||||
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
|
||||
if (pConnection != nullptr) {
|
||||
auto pReply = pConnection->Reply();
|
||||
|
||||
DebugReply(pReply);
|
||||
|
||||
if (pReply->Status == CHTTPReply::ok) {
|
||||
const CJSON Json(pReply->Content);
|
||||
|
||||
Context.Session() = Json["session"].AsString();
|
||||
Context.Secret() = Json["secret"].AsString();
|
||||
|
||||
Context.Tokens().Values("access_token", Json["access_token"].AsString());
|
||||
|
||||
Context.SetFixedDate(0);
|
||||
Context.SetCheckDate(Now() + (CDateTime) 55 / MinsPerDay); // 55 min
|
||||
|
||||
Context.SetStatus(csAuthorized);
|
||||
} else {
|
||||
Context.SetCheckDate(Now() + (CDateTime) 5 / MinsPerDay); // 5 min
|
||||
}
|
||||
|
||||
pConnection->CloseConnection(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto OnException = [&Context](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) {
|
||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
||||
if (pConnection != nullptr) {
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (pConnection->Client());
|
||||
if (pClient != nullptr) {
|
||||
Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what());
|
||||
}
|
||||
DebugReply(pConnection->Reply());
|
||||
}
|
||||
|
||||
Context.SetStatus(Context::csInitialized);
|
||||
};
|
||||
|
||||
auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port);
|
||||
|
||||
pClient->OnRequest(OnRequest);
|
||||
pClient->OnExecute(OnExecute);
|
||||
pClient->OnException(OnException);
|
||||
|
||||
pClient->AutoFree(true);
|
||||
pClient->Active(true);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
} // namespace Common
|
||||
|
||||
} // namespace Apostol
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
154
src/app/Common.hpp
Normal file
154
src/app/Common.hpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
Common.hpp
|
||||
|
||||
Notices:
|
||||
|
||||
Dial Module common.
|
||||
|
||||
Author:
|
||||
|
||||
Copyright (c) Prepodobny Alen
|
||||
|
||||
mailto: alienufo@inbox.ru
|
||||
mailto: ufocomp@gmail.com
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef APOSTOL_DM_COMMON_HPP
|
||||
#define APOSTOL_DM_COMMON_HPP
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define BPS_PGP_HASH "SHA512"
|
||||
#define BM_PREFIX "BM-"
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
#endif // __cplusplus
|
||||
|
||||
namespace Apostol {
|
||||
|
||||
namespace Common {
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//-- CCustomModule ---------------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class CCustomModule: public CApostolModule {
|
||||
protected:
|
||||
|
||||
CStringList m_Module;
|
||||
|
||||
CJSON m_OAuth2;
|
||||
|
||||
CString m_pgpModuleKey;
|
||||
CString m_pgpPublicKey;
|
||||
CString m_pgpPassphrase;
|
||||
|
||||
CProcessStatus m_Status;
|
||||
|
||||
int m_SyncPeriod;
|
||||
|
||||
void InitMethods() override;
|
||||
|
||||
template<class ClassName>
|
||||
void UpdateServerList(TPairs<ClassName> &ClassList, const CString &Key) {
|
||||
CStringPairs ServerList;
|
||||
CStringList Keys;
|
||||
int index;
|
||||
|
||||
ParsePGPKey(Key, ServerList, Keys);
|
||||
|
||||
if (ServerList.Count() != 0) {
|
||||
CStringPairs::ConstEnumerator em(ServerList);
|
||||
while (em.MoveNext()) {
|
||||
const auto &caCurrent = em.Current();
|
||||
#ifndef _DEBUG
|
||||
if (caCurrent.Name() == BPS_BM_DEBUG_ADDRESS)
|
||||
continue;
|
||||
#endif
|
||||
index = ClassList.IndexOfName(caCurrent.Name());
|
||||
if (index == -1) {
|
||||
index = ClassList.AddPair(caCurrent.Name(), ClassName(caCurrent.Name(), CLocation(caCurrent.Value())));
|
||||
auto &Context = ClassList[index].Value();
|
||||
Context.PGP().Add(CKeyContext(CString("PUBLIC"), Key));
|
||||
Context.PGP().Add(CKeyContext(caCurrent.Name(), CString()));
|
||||
} else {
|
||||
auto &Context = ClassList[index].Value();
|
||||
Context.URL() = caCurrent.Value();
|
||||
Context.PGP().First().Key = Key;
|
||||
}
|
||||
|
||||
auto &Context = ClassList[index].Value();
|
||||
Context.BTCKeys() = Keys;
|
||||
|
||||
if (Context.Status() == Context::csInitialization) {
|
||||
UpdateOAuth2(Context, m_OAuth2.Object());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
|
||||
void FetchProviders(CDateTime Now, CContext &Context);
|
||||
static void CheckProviders(CDateTime Now, CContext &Context);
|
||||
|
||||
void CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context);
|
||||
void ParsePGPKey(const CString &Key, CStringPairs &ServerList, CStringList &BTCKeys);
|
||||
|
||||
void ModuleService(CContext &Context);
|
||||
void ModuleStatus(CContext &Context);
|
||||
void ModuleNew(CContext &Context);
|
||||
void ModuleAuthorize(CContext &Context);
|
||||
|
||||
void DoGet(CHTTPServerConnection *AConnection) override;
|
||||
|
||||
virtual void DoPost(CHTTPServerConnection *AConnection);
|
||||
virtual void DoAPI(CHTTPServerConnection *AConnection);
|
||||
|
||||
virtual void DoAccount(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI) abstract;
|
||||
virtual void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action) abstract;
|
||||
virtual void DoSignature(CHTTPServerConnection *AConnection) abstract;
|
||||
|
||||
public:
|
||||
|
||||
explicit CCustomModule(CModuleProcess *AProcess, const CString &ModuleName, const CString &SectionName);
|
||||
|
||||
~CCustomModule() override = default;
|
||||
|
||||
void Initialization(CModuleProcess *AProcess) override;
|
||||
bool Enabled() override;
|
||||
|
||||
virtual void Reload() abstract;
|
||||
|
||||
static CString ToString(unsigned long Value);
|
||||
static void JsonStringToKey(const CString &String, CString &Key);
|
||||
|
||||
static void CheckKeyForNull(LPCTSTR Key, LPCTSTR Value);
|
||||
|
||||
static void CheckDeal(const CDeal &Deal);
|
||||
static int CheckFee(const CString &Fee);
|
||||
|
||||
static bool CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message);
|
||||
static int VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message);
|
||||
|
||||
static bool FindURLInLine(const CString &Line, CStringList &List);
|
||||
static void UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2);
|
||||
static void UpdateProviders(CProviders &Providers, const CJSONObject &Data);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Apostol::Common;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif //APOSTOL_DM_COMMON_HPP
|
||||
@@ -29,9 +29,6 @@ Author:
|
||||
#include <execinfo.h>
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//using namespace std;
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "delphi.hpp"
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,9 @@ Author:
|
||||
#define DM_WEB_SERVICE_MODULE_HPP
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "Common.hpp"
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
extern "C++" {
|
||||
|
||||
namespace Apostol {
|
||||
@@ -37,26 +40,14 @@ namespace Apostol {
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class CWebService: public CApostolModule {
|
||||
class CWebService: public CCustomModule {
|
||||
private:
|
||||
|
||||
CStringList m_Module;
|
||||
|
||||
CJSON m_OAuth2;
|
||||
|
||||
CString m_pgpModuleKey;
|
||||
CString m_pgpPublicKey;
|
||||
CString m_pgpPassphrase;
|
||||
|
||||
CProcessStatus m_Status;
|
||||
|
||||
CContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CContext(BPS_BM_SERVER_ADDRESS, CLocation(BPS_SERVER_URL)) };
|
||||
CContextList m_Servers {};
|
||||
|
||||
CContext m_CurrentServer {};
|
||||
|
||||
int m_SyncPeriod;
|
||||
|
||||
CDateTime m_NexServerTime;
|
||||
|
||||
CHTTPProxyManager m_ProxyManager;
|
||||
@@ -64,39 +55,16 @@ namespace Apostol {
|
||||
void InitMethods() override;
|
||||
|
||||
void InitServerList();
|
||||
void UpdateServerList(const CString &Key);
|
||||
|
||||
void FetchProviders(CDateTime Now, CContext &Context);
|
||||
void CheckProviders(CDateTime Now, CContext &Context);
|
||||
|
||||
void CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context);
|
||||
void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys);
|
||||
void FetchPGP(CContext &Context);
|
||||
|
||||
void ModuleService(CContext &Context);
|
||||
void ModuleStatus(CContext &Context);
|
||||
void ModuleNew(CContext &Context);
|
||||
void ModuleAuthorize(CContext &Context);
|
||||
|
||||
protected:
|
||||
|
||||
CHTTPProxy *GetProxy(CHTTPServerConnection *AConnection);
|
||||
|
||||
const CContext &CurrentServer() const;
|
||||
|
||||
static int CheckFee(const CString& Fee);
|
||||
|
||||
static void CheckKeyForNull(LPCTSTR Key, LPCTSTR Value);
|
||||
|
||||
void DoAccount(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI);
|
||||
void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action);
|
||||
|
||||
void DoSignature(CHTTPServerConnection *AConnection);
|
||||
|
||||
void DoAPI(CHTTPServerConnection *AConnection);
|
||||
|
||||
void DoGet(CHTTPServerConnection *AConnection) override;
|
||||
void DoPost(CHTTPServerConnection *AConnection);
|
||||
void DoAccount(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI) override;
|
||||
void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action) override;
|
||||
void DoSignature(CHTTPServerConnection *AConnection) override;
|
||||
|
||||
bool DoProxyExecute(CTCPConnection *AConnection);
|
||||
void DoProxyException(CTCPConnection *AConnection, const Delphi::Exception::Exception &E);
|
||||
@@ -107,33 +75,17 @@ namespace Apostol {
|
||||
|
||||
public:
|
||||
|
||||
explicit CWebService(CModuleProcess *AProcess);
|
||||
explicit CWebService(CModuleProcess *AProcess, const CString &ModuleName, const CString &SectionName);
|
||||
|
||||
~CWebService() override = default;
|
||||
|
||||
static class CWebService *CreateModule(CModuleProcess *AProcess) {
|
||||
return new CWebService(AProcess);
|
||||
return new CWebService(AProcess, "web service", "module/WebService");
|
||||
}
|
||||
|
||||
void Heartbeat(CDateTime Now) override;
|
||||
|
||||
void Initialization(CModuleProcess *AProcess) override;
|
||||
bool Enabled() override;
|
||||
|
||||
void Reload();
|
||||
|
||||
static CString ToString(unsigned long Value);
|
||||
|
||||
static void JsonStringToKey(const CString& jsonString, CString& Key);
|
||||
|
||||
static void CheckDeal(const CDeal& Deal);
|
||||
|
||||
static bool CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message);
|
||||
static int VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message);
|
||||
|
||||
static bool FindURLInLine(const CString &Line, CStringList &List);
|
||||
static void UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2);
|
||||
static void UpdateProviders(CProviders &Providers, const CJSONObject &Data);
|
||||
void Reload() override;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,9 @@ Author:
|
||||
#define DM_WEB_SOCKET_MODULE_HPP
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "Common.hpp"
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
extern "C++" {
|
||||
|
||||
namespace Apostol {
|
||||
@@ -64,42 +67,18 @@ namespace Apostol {
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class CWebSocketModule: public CApostolModule {
|
||||
class CWebSocketModule: public CCustomModule {
|
||||
private:
|
||||
|
||||
CStringList m_Module;
|
||||
|
||||
CJSON m_OAuth2;
|
||||
|
||||
CString m_pgpModuleKey;
|
||||
CString m_pgpPublicKey;
|
||||
CString m_pgpPassphrase;
|
||||
|
||||
int m_SyncPeriod;
|
||||
|
||||
CClientContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CClientContext(BPS_BM_SERVER_ADDRESS, CLocation(BPS_SERVER_URL)) };
|
||||
|
||||
CClientContextList m_Servers {};
|
||||
|
||||
void InitMethods() override;
|
||||
|
||||
void InitServerList();
|
||||
void UpdateServerList(const CString &Key);
|
||||
|
||||
void FetchProviders(CDateTime Now, CClientContext &Context);
|
||||
void CheckProviders(CDateTime Now, CClientContext &Context);
|
||||
|
||||
void CreateAccessToken(const CProvider &Provider, const CString &Application, CClientContext &Context);
|
||||
void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys);
|
||||
|
||||
CWebSocketClient *GetWebSocketClient(CClientContext &Context);
|
||||
void CreateWebSocketClient(CClientContext &Context);
|
||||
|
||||
void ModuleService(CContext &Context);
|
||||
void ModuleStatus(CContext &Context);
|
||||
void ModuleNew(CContext &Context);
|
||||
void ModuleAuthorize(CContext &Context);
|
||||
|
||||
static CWebSocketClient *GetConnectedClient(const CClientContext &Context);
|
||||
|
||||
int CurrentContextIndex(const CString &Params);
|
||||
@@ -107,17 +86,9 @@ namespace Apostol {
|
||||
|
||||
protected:
|
||||
|
||||
void Heartbeat(CDateTime Now) override;
|
||||
|
||||
void DoAccount(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI);
|
||||
void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action);
|
||||
|
||||
void DoSignature(CHTTPServerConnection *AConnection);
|
||||
|
||||
void DoAPI(CHTTPServerConnection *AConnection);
|
||||
|
||||
void DoGet(CHTTPServerConnection *AConnection) override;
|
||||
void DoPost(CHTTPServerConnection *AConnection);
|
||||
void DoAccount(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI) override;
|
||||
void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action) override;
|
||||
void DoSignature(CHTTPServerConnection *AConnection) override;
|
||||
|
||||
void DoWebSocketError(CTCPConnection *AConnection);
|
||||
void DoClientConnected(CObject *Sender);
|
||||
@@ -137,31 +108,18 @@ namespace Apostol {
|
||||
|
||||
public:
|
||||
|
||||
explicit CWebSocketModule(CModuleProcess *AProcess);
|
||||
explicit CWebSocketModule(CModuleProcess *AProcess, const CString &ModuleName, const CString &SectionName);
|
||||
|
||||
~CWebSocketModule() override = default;
|
||||
|
||||
static class CWebSocketModule *CreateModule(CModuleProcess *AProcess) {
|
||||
return new CWebSocketModule(AProcess);
|
||||
return new CWebSocketModule(AProcess, "web socket", "module/WebSocket");
|
||||
}
|
||||
|
||||
void Initialization(CModuleProcess *AProcess) override;
|
||||
bool Enabled() override;
|
||||
void Heartbeat(CDateTime Now) override;
|
||||
|
||||
void Reload();
|
||||
void Reload() override;
|
||||
|
||||
static CString ToString(unsigned long Value);
|
||||
|
||||
static int CheckFee(const CString& Fee);
|
||||
static void CheckDeal(const CDeal& Deal);
|
||||
static void CheckKeyForNull(LPCTSTR key, const CString& Value);
|
||||
|
||||
static bool CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message);
|
||||
static int VerifyPGPSignature(const CString &Text, const CString &Key, CString &Message);
|
||||
|
||||
static bool FindURLInLine(const CString &Line, CStringList &List);
|
||||
static void UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2);
|
||||
static void UpdateProviders(CProviders &Providers, const CJSONObject &Data);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user