From fe4d665e8c34ea985eded6dea04f6f7bdd54c62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=BF=D0=BE=D0=B4=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=90=D0=BB=D0=B5=D0=BD?= Date: Sun, 18 Sep 2022 00:42:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=95=D1=81=D0=BB=D0=B8=20=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C,=20=D1=82=D0=BE=20=D0=BD=D1=83=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F=20=D0=9C=D0=A1=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B5=20?= =?UTF-8?q?=D0=9C=D0=A1=20=D1=81=20=D1=83=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=BC=D0=B8=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=84?= =?UTF-8?q?=D0=B8=D0=B3=D0=B5=20bitcoin=20=D0=B8=20PGP=20=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/Context.hpp | 23 +- src/modules/Workers/WebService/WebService.cpp | 221 +++++++++++++----- src/modules/Workers/WebService/WebService.hpp | 4 +- src/modules/Workers/WebSocket/WebSocket.cpp | 155 ++++++++++-- src/modules/Workers/WebSocket/WebSocket.hpp | 7 +- .../Workers/WebSocket/WebSocketClient.cpp | 20 +- www/dashboard/index.html | 2 +- 7 files changed, 338 insertions(+), 94 deletions(-) diff --git a/src/app/Context.hpp b/src/app/Context.hpp index 879c449..856892f 100644 --- a/src/app/Context.hpp +++ b/src/app/Context.hpp @@ -95,6 +95,9 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- + typedef TList CKeys; + //-------------------------------------------------------------------------------------------------------------- + enum CContextStatus { csInitialization = 0, csPreparing, csInitialized, csAuthorization, csAuthorized, csInProgress, csRunning }; //-------------------------------------------------------------------------------------------------------------- @@ -113,8 +116,8 @@ namespace Apostol { CString m_Session {}; CString m_Secret {}; - CKeyContext m_PGP {}; - CKeyContext m_BTC {}; + CKeys m_PGP {}; + CKeys m_BTC {}; CStringList m_BTCKeys {}; CStringList m_Tokens {}; @@ -129,7 +132,12 @@ namespace Apostol { Assign(Context); } - explicit CContext(const CLocation &URL): CContext() { + explicit CContext(const CString &Name): CContext() { + m_Name = Name; + } + + explicit CContext(const CString &Name, const CLocation &URL): CContext() { + m_Name = Name; m_URL = URL; } @@ -165,6 +173,7 @@ namespace Apostol { m_Providers.Clear(); }; + CLocation& URL() { return m_URL; } const CLocation& URL() const { return m_URL; } CContextStatus Status() const { return m_Status; } @@ -185,11 +194,11 @@ namespace Apostol { CString& Secret() { return m_Secret; } const CString& Secret() const { return m_Secret; } - CKeyContext& PGP() { return m_PGP; } - const CKeyContext& PGP() const { return m_PGP; } + CKeys& PGP() { return m_PGP; } + const CKeys& PGP() const { return m_PGP; } - CKeyContext& BTC() { return m_BTC; } - const CKeyContext& BTC() const { return m_BTC; } + CKeys& BTC() { return m_BTC; } + const CKeys& BTC() const { return m_BTC; } CStringList& BTCKeys() { return m_BTCKeys; } const CStringList& BTCKeys() const { return m_BTCKeys; } diff --git a/src/modules/Workers/WebService/WebService.cpp b/src/modules/Workers/WebService/WebService.cpp index 9b816c4..16d0ce1 100644 --- a/src/modules/Workers/WebService/WebService.cpp +++ b/src/modules/Workers/WebService/WebService.cpp @@ -54,6 +54,8 @@ namespace Apostol { m_Status = psStopped; CWebService::InitMethods(); + + InitServerList(); } //-------------------------------------------------------------------------------------------------------------- @@ -83,14 +85,15 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- void CWebService::InitServerList() { - m_DefaultServer.Value().Name() = m_DefaultServer.Name(); - m_DefaultServer.Value().PGP().Name = "PUBLIC"; + m_DefaultServer.Value().PGP().Add(CKeyContext(CString("PUBLIC"), CString())); + m_DefaultServer.Value().PGP().Add(CKeyContext(m_DefaultServer.Name(), CString())); if (m_Servers.Count() == 0) { #ifdef _DEBUG - int index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CContext(CLocation(BPS_SERVER_URL))); - m_Servers[index].Value().Name() = m_Servers[index].Name(); - m_Servers[index].Value().PGP().Name = "PUBLIC"; + int index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CClientContext(BPS_BM_DEBUG_ADDRESS, CLocation(BPS_SERVER_URL))); + auto &Keys = m_Servers[index].Value().PGP(); + Keys.Add(CKeyContext(CString("PUBLIC"), CString())); + Keys.Add(CKeyContext(CString(BPS_BM_DEBUG_ADDRESS), CString())); #else m_Servers.Add(m_DefaultServer); #endif @@ -101,21 +104,34 @@ namespace Apostol { void CWebService::UpdateServerList(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 ¤t = em.Current(); - if (m_Servers.IndexOfName(current.Name()) == -1 && !current.Value().IsEmpty()) { - m_Servers.AddPair(current.Name(), CContext(CLocation(current.Value()))); - auto &Context = m_Servers.Last().Value(); - Context.Name() = current.Name(); - Context.PGP().Name = "PUBLIC"; - Context.PGP().Key = Key; - Context.BTCKeys() = Keys; + const auto &caCurrent = em.Current(); +#ifndef _DEBUG + if (caCurrent.Name() == BPS_BM_DEBUG_ADDRESS) + continue; +#endif + index = m_Servers.IndexOfName(caCurrent.Name()); + if (index == -1) { + index = m_Servers.AddPair(caCurrent.Name(), CClientContext(caCurrent.Name(), CLocation(caCurrent.Value()))); + auto &Context = m_Servers[index].Value(); + Context.PGP().Add(CKeyContext(CString("PUBLIC"), Key)); + Context.PGP().Add(CKeyContext(caCurrent.Name(), CString())); + } else { + auto &Context = m_Servers[index].Value(); + Context.URL() = caCurrent.Value(); + Context.PGP().First().Key = Key; } + + auto &Context = m_Servers[index].Value(); + Context.BTCKeys() = Keys; + + UpdateOAuth2(Context, m_OAuth2.Object()); } } } @@ -245,7 +261,7 @@ namespace Apostol { void CWebService::CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context) { - auto OnDone = [&Context](CTCPConnection *Sender) { + auto OnDone = [this, &Context](CTCPConnection *Sender) { auto pConnection = dynamic_cast (Sender); auto pReply = pConnection->Reply(); @@ -255,15 +271,12 @@ namespace Apostol { if (pReply->Status == CHTTPReply::ok) { const CJSON Json(pReply->Content); - Context.SetStatus(csAuthorized); - 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) 50 / MinsPerDay); // 50 min + ModuleStatus(Context); } return true; @@ -465,14 +478,14 @@ namespace Apostol { auto pServerRequest = AConnection->Request(); auto pProxyRequest = pProxy->Request(); - const auto& caModuleAddress = m_Module["address"]; + const auto &caModuleAddress = m_Module["address"]; + const auto &caHost = pServerRequest->Headers["host"]; + const auto &caOrigin = pServerRequest->Headers["origin"]; + const auto &caUserAddress = pServerRequest->Params["address"]; - const auto& caOrigin = pServerRequest->Headers["origin"]; - const auto& caUserAddress = pServerRequest->Params["address"]; + const auto &pgpValue = pServerRequest->Params["pgp"]; + const auto &caServerParam = pServerRequest->Params["server"]; - const auto& pgpValue = pServerRequest->Params["pgp"]; - - const auto& caServerParam = pServerRequest->Params["server"]; const auto& caServer = caServerParam.IsEmpty() ? m_CurrentServer.URL().Origin() : caServerParam; CLocation Location(caServer); @@ -646,8 +659,18 @@ namespace Apostol { //DebugMessage("[DoAccount] sPayload:\n%s\n", sPayload.c_str()); CJSON Json(jvtObject); + CJSONValue Module(jvtObject); - Json.Object().AddPair("id", ApostolUID()); + Module.Object().AddPair("address", caModuleAddress); + + Json.Object().AddPair("id", GetUID(16).Lower()); + Json.Object().AddPair("host", caHost); + + if (!caOrigin.IsEmpty()) { + Json.Object().AddPair("origin", caOrigin); + } + + Json.Object().AddPair("module", Module); Json.Object().AddPair("address", caUserAddress.IsEmpty() ? caModuleAddress : caUserAddress); if (!sPayload.IsEmpty()) @@ -743,19 +766,25 @@ namespace Apostol { auto pServerRequest = AConnection->Request(); auto pProxyRequest = pProxy->Request(); - const auto& caModuleAddress = m_Module["address"]; - const auto& caModuleFee = m_Module["fee"]; + const auto &caModuleAddress = m_Module["address"]; + const auto &caModuleFee = m_Module["fee"]; const auto checkFee = CheckFee(caModuleFee); if (checkFee == -1) throw ExceptionFrm("Invalid module fee value: %s", caModuleFee.c_str()); - const auto& caOrigin = pServerRequest->Headers["origin"]; - const auto& caUserAddress = pServerRequest->Params["address"]; + const auto &caHost = pServerRequest->Headers["host"]; + const auto &caOrigin = pServerRequest->Headers["origin"]; - const auto& pgpValue = pServerRequest->Params["pgp"]; + const auto &address = pServerRequest->Params["address"]; + const auto &code = pServerRequest->Params["code"]; + + const auto &caUserAddress = address.length() == 40 ? CString() : address; + const auto &caDealCode = !code.empty() ? code : address.length() == 40 ? address : CString(); + + const auto &pgpValue = pServerRequest->Params["pgp"]; + const auto &caServerParam = pServerRequest->Params["server"]; - const auto& caServerParam = pServerRequest->Params["server"]; const auto& caServer = caServerParam.IsEmpty() ? m_CurrentServer.URL().Origin() : caServerParam; CLocation Location(caServer); @@ -1091,10 +1120,26 @@ namespace Apostol { } CJSON Json(jvtObject); + CJSONValue Module(jvtObject); - Json.Object().AddPair("id", ApostolUID()); - if (!caUserAddress.IsEmpty()) - Json.Object().AddPair("address", caUserAddress.IsEmpty() ? caModuleAddress : caUserAddress); + Module.Object().AddPair("address", caModuleAddress); + Module.Object().AddPair("fee", caModuleFee); + + Json.Object().AddPair("id", GetUID(16).Lower()); + Json.Object().AddPair("host", caHost); + + if (!caOrigin.IsEmpty()) { + Json.Object().AddPair("origin", caOrigin); + } + + Json.Object().AddPair("module", Module); + Json.Object().AddPair("address", caUserAddress.IsEmpty() ? caModuleAddress : caUserAddress); + + if (!caDealCode.IsEmpty()) { + CJSONValue Deal(jvtObject); + Deal.Object().AddPair("code", caDealCode); + Json.Object().AddPair("deal", Deal); + } if (!sPayload.IsEmpty()) Json.Object().AddPair("payload", base64_encode(sPayload)); @@ -1129,7 +1174,6 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- void CWebService::DoSignature(CHTTPServerConnection *AConnection) { - auto pRequest = AConnection->Request(); auto pReply = AConnection->Reply(); @@ -1138,10 +1182,20 @@ namespace Apostol { return; } - const auto& caServerKey = m_CurrentServer.PGP().Key; + auto &Keys = m_CurrentServer.PGP(); + + int index = 0; + while (index < Keys.Count() && Keys[index].Name != m_CurrentServer.Name()) { + index++; + } + + if (index == Keys.Count()) + throw ExceptionFrm("PGP key not found."); + + const auto& caServerKey = Keys[index].Key; if (caServerKey.IsEmpty()) - throw ExceptionFrm("Server PGP key not added."); + throw ExceptionFrm("PGP key not added."); CString message; CJSON Json(jvtObject); @@ -1426,16 +1480,16 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - int CWebService::VerifyPGPSignature(const CString &caClearText, const CString &Key, CString &Message) { + int CWebService::VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message) { const OpenPGP::Key signer(Key.c_str()); - const OpenPGP::CleartextSignature cleartext(caClearText.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) { + if (verified == 1) { Message = cleartext.get_message().c_str(); } @@ -1524,11 +1578,23 @@ namespace Apostol { auto OnRequest = [&Context](CHTTPClient *Sender, CHTTPRequest *ARequest) { - Context.PGP().Status = CKeyContext::ksFetching; - Context.PGP().StatusTime = Now(); + const auto &name = Sender->Data()["name"]; + auto &Keys = Context.PGP(); + + int index = 0; + while (index < Keys.Count() && Keys[index].Name != name) { + index++; + } ARequest->ContentType = CHTTPRequest::json; - ARequest->Content = CString().Format(R"({"type": "pgp", "account": "%s", "code": "%s", "fields": ["data"]})", Context.Name().c_str(), Context.PGP().Name.c_str()); + + if (index < Keys.Count()) { + auto &Key = Keys[index]; + Key.Status = CKeyContext::ksFetching; + Key.StatusTime = Now(); + } + + ARequest->Content = CString().Format(R"({"type": "pgp", "account": "%s", "code": "%s", "fields": ["code", "data"]})", Context.Name().c_str(), name.c_str()); CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/key/public"); @@ -1546,24 +1612,36 @@ namespace Apostol { auto pConnection = dynamic_cast (AConnection); if (pConnection != nullptr) { + auto pClient = dynamic_cast (pConnection->Client()); auto pReply = pConnection->Reply(); DebugReply(pReply); - CString Key; + CString Content; try { - JsonStringToKey(pReply->Content, Key); + JsonStringToKey(pReply->Content, Content); - if (Key.IsEmpty()) + if (Content.IsEmpty()) throw Delphi::Exception::Exception("Not found."); - Context.PGP().Status = CKeyContext::ksSuccess; - Context.PGP().StatusTime = Now(); + const auto &name = pClient->Data()["name"]; + auto &Keys = Context.PGP(); - Context.PGP().Key = Key; + int index = 0; + while (index < Keys.Count() && Keys[index].Name != name) { + index++; + } - UpdateServerList(Key); + if (index < Keys.Count()) { + auto &Key = Keys[index]; + + Key.Status = CKeyContext::ksSuccess; + Key.StatusTime = Now(); + Key.Key = Content; + + UpdateServerList(Content); + } Context.SetStatus(csRunning); } catch (Delphi::Exception::Exception &e) { @@ -1581,29 +1659,48 @@ namespace Apostol { if (pConnection != nullptr) { auto pClient = dynamic_cast (pConnection->Client()); if (pClient != nullptr) { + const auto &name = pClient->Data()["name"]; + auto &Keys = Context.PGP(); + + int index = 0; + while (index < Keys.Count() && Keys[index].Name != name) { + index++; + } + + if (index < Keys.Count()) { + auto &Key = Keys[index]; + Key.Status = CKeyContext::ksError; + Key.StatusTime = Now(); + } + Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); } DebugReply(pConnection->Reply()); } Context.SetStatus(Context::csAuthorized); - - Context.PGP().Status = CKeyContext::ksError; - Context.PGP().StatusTime = Now(); }; - Context.PGP().Status = CKeyContext::ksUnknown; - Context.PGP().StatusTime = Now(); - Context.PGP().RunTime = Context.PGP().StatusTime; + auto &Keys = Context.PGP(); - auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port); + for (int i = 0; i < Keys.Count(); i++ ) { + auto &Key = Keys[i]; - pClient->OnRequest(OnRequest); - pClient->OnExecute(OnExecute); - pClient->OnException(OnException); + Key.Status = CKeyContext::ksUnknown; + Key.StatusTime = Now(); + Key.RunTime = Key.StatusTime; - pClient->AutoFree(true); - pClient->Active(true); + auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port); + + pClient->Data().AddPair("name", Key.Name); + + pClient->OnRequest(OnRequest); + pClient->OnExecute(OnExecute); + pClient->OnException(OnException); + + pClient->AutoFree(true); + pClient->Active(true); + } } //-------------------------------------------------------------------------------------------------------------- diff --git a/src/modules/Workers/WebService/WebService.hpp b/src/modules/Workers/WebService/WebService.hpp index 65edbcd..d8110f8 100644 --- a/src/modules/Workers/WebService/WebService.hpp +++ b/src/modules/Workers/WebService/WebService.hpp @@ -50,7 +50,7 @@ namespace Apostol { CProcessStatus m_Status; - CContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CContext(CLocation(BPS_SERVER_URL)) }; + CContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CContext(BPS_BM_SERVER_ADDRESS, CLocation(BPS_SERVER_URL)) }; CContextList m_Servers {}; CContext m_CurrentServer {}; @@ -134,7 +134,7 @@ namespace Apostol { static bool FindURLInLine(const CString &Line, CStringList &List); static void UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2); static void UpdateProviders(CProviders &Providers, const CJSONObject &Data); - static bool LoadOAuth2(const CString &FileName, CProviders &Providers); + }; } } diff --git a/src/modules/Workers/WebSocket/WebSocket.cpp b/src/modules/Workers/WebSocket/WebSocket.cpp index 3fa27bf..07140d1 100644 --- a/src/modules/Workers/WebSocket/WebSocket.cpp +++ b/src/modules/Workers/WebSocket/WebSocket.cpp @@ -90,14 +90,15 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- void CWebSocketModule::InitServerList() { - m_DefaultServer.Value().Name() = m_DefaultServer.Name(); - m_DefaultServer.Value().PGP().Name = "PUBLIC"; + m_DefaultServer.Value().PGP().Add(CKeyContext(CString("PUBLIC"), CString())); + m_DefaultServer.Value().PGP().Add(CKeyContext(m_DefaultServer.Name(), CString())); if (m_Servers.Count() == 0) { #ifdef _DEBUG - int index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CClientContext(CLocation(BPS_SERVER_URL))); - m_Servers[index].Value().Name() = m_Servers[index].Name(); - m_Servers[index].Value().PGP().Name = "PUBLIC"; + int index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CClientContext(BPS_BM_DEBUG_ADDRESS, CLocation(BPS_SERVER_URL))); + auto &Keys = m_Servers[index].Value().PGP(); + Keys.Add(CKeyContext(CString("PUBLIC"), CString())); + Keys.Add(CKeyContext(CString(BPS_BM_DEBUG_ADDRESS), CString())); #else m_Servers.Add(m_DefaultServer); #endif @@ -116,14 +117,23 @@ namespace Apostol { CStringPairs::ConstEnumerator em(ServerList); while (em.MoveNext()) { const auto &caCurrent = em.Current(); +#ifndef _DEBUG + if (caCurrent.Name() == BPS_BM_DEBUG_ADDRESS) + continue; +#endif index = m_Servers.IndexOfName(caCurrent.Name()); if (index == -1) { - index = m_Servers.AddPair(caCurrent.Name(), CClientContext(CLocation(caCurrent.Value()))); + index = m_Servers.AddPair(caCurrent.Name(), CClientContext(caCurrent.Name(), CLocation(caCurrent.Value()))); + auto &Context = m_Servers[index].Value(); + Context.PGP().Add(CKeyContext(CString("PUBLIC"), Key)); + Context.PGP().Add(CKeyContext(caCurrent.Name(), CString())); + } else { + auto &Context = m_Servers[index].Value(); + Context.URL() = caCurrent.Value(); + Context.PGP().First().Key = Key; } + auto &Context = m_Servers[index].Value(); - Context.Name() = caCurrent.Name(); - Context.PGP().Name = "PUBLIC"; - Context.PGP().Key = Key; Context.BTCKeys() = Keys; UpdateOAuth2(Context, m_OAuth2.Object()); @@ -471,6 +481,37 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- + bool CWebSocketModule::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 CWebSocketModule::VerifyPGPSignature(const CString &Text, const CString &Key, CString &Message) { + const OpenPGP::Key signer(Key.c_str()); + const OpenPGP::CleartextSignature cleartext(Text.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; + } + //-------------------------------------------------------------------------------------------------------------- + bool CWebSocketModule::FindURLInLine(const CString &Line, CStringList &List) { CString URL; @@ -857,12 +898,26 @@ namespace Apostol { auto pContext = pClient->Context(); chASSERT(pContext); - pContext->PGP().StatusTime = Now(); - pContext->PGP().Status = CKeyContext::ksSuccess; - pContext->PGP().RunTime = GetRandomDate(10 * 60, m_SyncPeriod * 60, pContext->PGP().StatusTime); // 10..m_SyncPeriod min + auto &Keys = pContext->PGP(); - if (Response.Payload.HasOwnProperty("data")) { - UpdateServerList(Response.Payload["data"].AsString()); + for (int i = 0; i < Keys.Count(); i++ ) { + auto &Key = Keys[i]; + + Key.StatusTime = Now(); + Key.Status = CKeyContext::ksSuccess; + Key.RunTime = GetRandomDate(10 * 60, m_SyncPeriod * 60, Key.StatusTime); // 10..m_SyncPeriod min + + if (Response.Payload.HasOwnProperty("data")) { + if (Response.Payload.HasOwnProperty("code")) { + if (Response.Payload["code"].AsString() == Key.Name) { + if (Key.Name == "PUBLIC") { + UpdateServerList(Response.Payload["data"].AsString()); + } else { + Key.Key = Response.Payload["data"].AsString(); + } + } + } + } } } //-------------------------------------------------------------------------------------------------------------- @@ -1527,7 +1582,79 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- void CWebSocketModule::DoSignature(CHTTPServerConnection *AConnection) { + auto pRequest = AConnection->Request(); + auto pReply = AConnection->Reply(); + if (pRequest->Content.IsEmpty()) { + AConnection->SendStockReply(CHTTPReply::no_content); + return; + } + + const auto &caServerParam = pRequest->Params["server"]; + + int index = CurrentContextIndex(caServerParam); + if (index == -1) { + throw Delphi::Exception::Exception(NOT_FOUND_ACTIVE_CONNECTION); + } + + const auto &caContext = m_Servers[index].Value(); + auto &Keys = caContext.PGP(); + + index = 0; + while (index < Keys.Count() && Keys[index].Name != caContext.Name()) { + index++; + } + + if (index == Keys.Count()) + throw ExceptionFrm("PGP key not found."); + + const auto& caServerKey = Keys[index].Key; + + if (caServerKey.IsEmpty()) + throw ExceptionFrm("Server PGP key not added."); + + CString message; + CJSON Json(jvtObject); + + const auto& caContentType = pRequest->Headers["content-type"]; + + if (caContentType.Find("application/x-www-form-urlencoded") == 0) { + const CStringList &FormData = pRequest->FormData; + + const auto& caClearText = FormData["message"]; + CheckKeyForNull("message", caClearText.c_str()); + + const auto bVerified = CheckVerifyPGPSignature(VerifyPGPSignature(caClearText, caServerKey, message), message); + Json.Object().AddPair("verified", bVerified); + } else if (caContentType.Find("multipart/form-data") == 0) { + CFormData FormData; + CHTTPRequestParser::ParseFormData(pRequest, FormData); + + const auto& caClearText = FormData.Data("message"); + CheckKeyForNull("message", caClearText.c_str()); + + const auto bVerified = CheckVerifyPGPSignature(VerifyPGPSignature(caClearText, caServerKey, message), message); + Json.Object().AddPair("verified", bVerified); + } else if (caContentType.Find("application/json") == 0) { + const CJSON jsonData(pRequest->Content); + + const auto& caClearText = jsonData["message"].AsString(); + CheckKeyForNull("message", caClearText.c_str()); + + const auto bVerified = CheckVerifyPGPSignature(VerifyPGPSignature(caClearText, caServerKey, message), message); + Json.Object().AddPair("verified", bVerified); + } else { + const auto& caClearText = pRequest->Content; + const auto bVerified = CheckVerifyPGPSignature(VerifyPGPSignature(caClearText, caServerKey, message), message); + Json.Object().AddPair("verified", bVerified); + } + + Json.Object().AddPair("message", message); + + AConnection->CloseConnection(true); + pReply->Content << Json; + + AConnection->SendReply(CHTTPReply::ok); } //-------------------------------------------------------------------------------------------------------------- diff --git a/src/modules/Workers/WebSocket/WebSocket.hpp b/src/modules/Workers/WebSocket/WebSocket.hpp index 999d04c..b667ac0 100644 --- a/src/modules/Workers/WebSocket/WebSocket.hpp +++ b/src/modules/Workers/WebSocket/WebSocket.hpp @@ -44,7 +44,7 @@ namespace Apostol { Assign(Context); } - explicit CClientContext(const CLocation &URI): CContext(URI) { + explicit CClientContext(const CString &Name, const CLocation &URI): CContext(Name, URI) { } @@ -77,7 +77,7 @@ namespace Apostol { int m_SyncPeriod; - CClientContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CClientContext(CLocation(BPS_SERVER_URL)) }; + CClientContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CClientContext(BPS_BM_SERVER_ADDRESS, CLocation(BPS_SERVER_URL)) }; CClientContextList m_Servers {}; @@ -156,6 +156,9 @@ namespace Apostol { 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); diff --git a/src/modules/Workers/WebSocket/WebSocketClient.cpp b/src/modules/Workers/WebSocket/WebSocketClient.cpp index 4315c77..262c3cd 100644 --- a/src/modules/Workers/WebSocket/WebSocketClient.cpp +++ b/src/modules/Workers/WebSocket/WebSocketClient.cpp @@ -159,14 +159,22 @@ namespace Apostol { } }; - CWSMessage Message; + const auto &Keys = m_pContext->PGP(); - Message.MessageTypeId = WSProtocol::mtCall; - Message.UniqueId = GenUniqueId(); - Message.Action = "/key/public"; - Message.Payload = CString().Format(R"({"type": "pgp", "account": "%s", "code": "%s", "fields": ["data"]})", m_pContext->Name().c_str(), m_pContext->PGP().Name.c_str()); + for (int i = 0; i < Keys.Count(); i++ ) { + const auto &Key = Keys[i]; - SendMessage(Message, OnRequest); + CWSMessage Message; + + Message.MessageTypeId = WSProtocol::mtCall; + Message.UniqueId = GenUniqueId(); + Message.Action = "/key/public"; + Message.Payload = CString().Format( + R"({"type": "pgp", "account": "%s", "code": "%s", "fields": ["code", "data"]})", + m_pContext->Name().c_str(), Key.Name.c_str()); + + SendMessage(Message, OnRequest); + } } //-------------------------------------------------------------------------------------------------------------- diff --git a/www/dashboard/index.html b/www/dashboard/index.html index 6fe4548..abc4a7f 100644 --- a/www/dashboard/index.html +++ b/www/dashboard/index.html @@ -582,7 +582,7 @@
- + BPS server URL.