Если есть возможность, то нужно регистрировать пользователя МС при запуске МС с указанными в конфиге bitcoin и PGP ключами.
This commit is contained in:
@@ -95,6 +95,9 @@ namespace Apostol {
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef TList<CKeyContext> 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; }
|
||||
|
||||
@@ -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<CHTTPClientConnection *> (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<CHTTPClientConnection *> (AConnection);
|
||||
|
||||
if (pConnection != nullptr) {
|
||||
auto pClient = dynamic_cast<CHTTPClient *> (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<CHTTPClient *> (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);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -582,7 +582,7 @@
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="serverURL">Server</label>
|
||||
<input type="text" class="form-control" id="serverURL" aria-describedby="serverURLHelp" placeholder="Default: http://localhost:4977" value="http://localhost:4977">
|
||||
<input type="text" class="form-control" id="serverURL" aria-describedby="serverURLHelp" placeholder="Default: http://localhost:4977">
|
||||
<small id="serverURLHelp" class="form-text text-muted">BPS server URL.</small>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
|
||||
Reference in New Issue
Block a user