Подписанная PGP ключом ДС Created сделка сначала должна отправляться по bitmessage, затем должна быть отдана МС.
This commit is contained in:
@@ -50,7 +50,6 @@ namespace Apostol {
|
|||||||
|
|
||||||
CWebService::CWebService(CModuleProcess *AProcess): CApostolModule(AProcess, "web service", "module/WebService") {
|
CWebService::CWebService(CModuleProcess *AProcess): CApostolModule(AProcess, "web service", "module/WebService") {
|
||||||
m_NexServerTime = 0;
|
m_NexServerTime = 0;
|
||||||
m_ServerIndex = -1;
|
|
||||||
m_SyncPeriod = BPS_DEFAULT_SYNC_PERIOD;
|
m_SyncPeriod = BPS_DEFAULT_SYNC_PERIOD;
|
||||||
m_Status = psStopped;
|
m_Status = psStopped;
|
||||||
|
|
||||||
@@ -122,125 +121,34 @@ namespace Apostol {
|
|||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void CWebService::FetchOAuth2(CContext &Context) {
|
|
||||||
|
|
||||||
Log()->Debug(APP_LOG_DEBUG_CORE, "Trying to fetch a OAuth2 configuration file for module \"%s\" from: %s", Context.Name().c_str(), Context.URL().Origin().c_str());
|
|
||||||
|
|
||||||
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
|
||||||
|
|
||||||
ARequest->ContentType = CHTTPRequest::text;
|
|
||||||
|
|
||||||
Apostol::PGP::CleartextSignature(
|
|
||||||
m_pgpPrivateKey,
|
|
||||||
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 = [this, &Context](CTCPConnection *AConnection) {
|
|
||||||
|
|
||||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (AConnection);
|
|
||||||
|
|
||||||
if (pConnection != nullptr) {
|
|
||||||
auto pReply = pConnection->Reply();
|
|
||||||
|
|
||||||
DebugReply(pReply);
|
|
||||||
|
|
||||||
if (Context.Status() == Context::csPreparing) {
|
|
||||||
if (pReply->Status == CHTTPReply::ok) {
|
|
||||||
const CJSON Json(pReply->Content);
|
|
||||||
Json.SaveToFile(m_OAuth2.c_str());
|
|
||||||
UpdateOAuth2(m_OAuth2);
|
|
||||||
} else {
|
|
||||||
Context.SetStatus(Context::csInitialization);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
Context.SetStatus(Context::csPreparing);
|
|
||||||
|
|
||||||
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 CWebService::UpdateOAuth2(const CString &FileName) {
|
|
||||||
for (int i = 0; i < m_Servers.Count(); i++) {
|
|
||||||
auto &Context = m_Servers[i].Value();
|
|
||||||
if (Context.Status() == Context::csInitialization || Context.Status() == Context::csPreparing) {
|
|
||||||
if (LoadOAuth2(FileName, Context.Providers())) {
|
|
||||||
Context.SetStatus(Context::csInitialized);
|
|
||||||
Context.SetCheckDate(0);
|
|
||||||
} else {
|
|
||||||
if (Context.Status() != Context::csPreparing) {
|
|
||||||
FetchOAuth2(Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CWebService::LoadOAuth2(const CString &FileName, CProviders &Providers) {
|
|
||||||
const auto &caProviderName = CString(SYSTEM_PROVIDER_NAME);
|
|
||||||
const auto &caApplicationName = CString(SERVICE_APPLICATION_NAME);
|
|
||||||
|
|
||||||
if (FileExists(FileName.c_str())) {
|
|
||||||
CJSONObject Json;
|
|
||||||
Json.LoadFromFile(FileName.c_str());
|
|
||||||
|
|
||||||
int index = Providers.IndexOfName(caProviderName);
|
|
||||||
if (index == -1)
|
|
||||||
index = Providers.AddPair(caProviderName, CProvider(caProviderName));
|
|
||||||
auto& Provider = Providers[index].Value();
|
|
||||||
Provider.Applications().AddPair(caApplicationName, Json);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void CWebService::CheckKeyForNull(LPCTSTR Key, LPCTSTR Value) {
|
void CWebService::CheckKeyForNull(LPCTSTR Key, LPCTSTR Value) {
|
||||||
if (Value == nullptr)
|
if (Value == nullptr)
|
||||||
throw ExceptionFrm("Invalid format: key \"%s\" cannot be empty.", Key);
|
throw ExceptionFrm("Invalid format: key \"%s\" cannot be empty.", Key);
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CWebService::UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2) {
|
||||||
|
if (OAuth2["type"].AsString() == "service_account") {
|
||||||
|
UpdateProviders(Context.Providers(), OAuth2);
|
||||||
|
|
||||||
|
Context.SetCheckDate(0);
|
||||||
|
Context.SetStatus(Context::csInitialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CWebService::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);
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool CWebService::FindURLInLine(const CString &Line, CStringList &List) {
|
bool CWebService::FindURLInLine(const CString &Line, CStringList &List) {
|
||||||
CString URL;
|
CString URL;
|
||||||
|
|
||||||
@@ -726,7 +634,7 @@ namespace Apostol {
|
|||||||
sPayload = caClearText.Text();
|
sPayload = caClearText.Text();
|
||||||
} else {
|
} else {
|
||||||
Apostol::PGP::CleartextSignature(
|
Apostol::PGP::CleartextSignature(
|
||||||
m_pgpPrivateKey,
|
m_pgpModuleKey,
|
||||||
m_pgpPassphrase,
|
m_pgpPassphrase,
|
||||||
BPS_PGP_HASH,
|
BPS_PGP_HASH,
|
||||||
caClearText.Text(),
|
caClearText.Text(),
|
||||||
@@ -1174,7 +1082,7 @@ namespace Apostol {
|
|||||||
sPayload = caClearText;
|
sPayload = caClearText;
|
||||||
} else {
|
} else {
|
||||||
Apostol::PGP::CleartextSignature(
|
Apostol::PGP::CleartextSignature(
|
||||||
m_pgpPrivateKey,
|
m_pgpModuleKey,
|
||||||
m_pgpPassphrase,
|
m_pgpPassphrase,
|
||||||
BPS_PGP_HASH,
|
BPS_PGP_HASH,
|
||||||
caClearText,
|
caClearText,
|
||||||
@@ -1612,7 +1520,7 @@ namespace Apostol {
|
|||||||
|
|
||||||
void CWebService::FetchPGP(CContext &Context) {
|
void CWebService::FetchPGP(CContext &Context) {
|
||||||
|
|
||||||
Log()->Debug(APP_LOG_DEBUG_CORE, "Trying to fetch a PGP key \"%s\" from: %s", Context.Name().c_str(), Context.URL().Origin().c_str());
|
Log()->Notice("[%s] [%s] Trying to fetch a PGP key.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||||
|
|
||||||
auto OnRequest = [&Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
auto OnRequest = [&Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||||
|
|
||||||
@@ -1699,28 +1607,348 @@ namespace Apostol {
|
|||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CWebService::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 CWebService::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 CWebService::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 CWebService::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 CWebService::Reload() {
|
void CWebService::Reload() {
|
||||||
Config()->IniFile().ReadSectionValues("module", &m_Module);
|
Config()->IniFile().ReadSectionValues("module", &m_Module);
|
||||||
|
|
||||||
m_OAuth2 = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json");
|
CString FileName;
|
||||||
if (!path_separator(m_OAuth2.front())) {
|
|
||||||
m_OAuth2 = Config()->Prefix() + m_OAuth2;
|
FileName = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json");
|
||||||
|
if (!path_separator(FileName.front())) {
|
||||||
|
FileName = Config()->Prefix() + FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& caPrivateKey = Config()->IniFile().ReadString("pgp", "private", "module.sec");
|
if (FileExists(FileName.c_str())) {
|
||||||
const auto& caPublicKey = Config()->IniFile().ReadString("pgp", "public", "dm.pub");
|
m_OAuth2.LoadFromFile(FileName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &caPrivateKey = Config()->IniFile().ReadString("pgp", "private", "module.sec");
|
||||||
|
const auto &caPublicKey = Config()->IniFile().ReadString("pgp", "public", "dm.pub");
|
||||||
|
|
||||||
m_pgpPassphrase = Config()->IniFile().ReadString("pgp", "passphrase", "");
|
m_pgpPassphrase = Config()->IniFile().ReadString("pgp", "passphrase", "");
|
||||||
|
|
||||||
if (FileExists(caPrivateKey.c_str())) {
|
if (FileExists(caPrivateKey.c_str())) {
|
||||||
m_pgpPrivateKey.LoadFromFile(caPrivateKey.c_str());
|
m_pgpModuleKey.LoadFromFile(caPrivateKey.c_str());
|
||||||
|
|
||||||
if (FileExists(caPublicKey.c_str())) {
|
if (FileExists(caPublicKey.c_str())) {
|
||||||
CString Key;
|
m_pgpPublicKey.LoadFromFile(caPublicKey.c_str());
|
||||||
Key.LoadFromFile(caPublicKey.c_str());
|
UpdateServerList(m_pgpPublicKey);
|
||||||
|
|
||||||
UpdateServerList(Key);
|
|
||||||
UpdateOAuth2(m_OAuth2);
|
|
||||||
} else {
|
} else {
|
||||||
Log()->Error(APP_LOG_WARN, 0, APP_FILE_NOT_FOUND, caPublicKey.c_str());
|
Log()->Error(APP_LOG_WARN, 0, APP_FILE_NOT_FOUND, caPublicKey.c_str());
|
||||||
}
|
}
|
||||||
@@ -1734,23 +1962,21 @@ namespace Apostol {
|
|||||||
for (int i = 0; i < m_Servers.Count(); i++) {
|
for (int i = 0; i < m_Servers.Count(); i++) {
|
||||||
auto &Context = m_Servers[i].Value();
|
auto &Context = m_Servers[i].Value();
|
||||||
|
|
||||||
if ((Now >= Context.CheckDate()) && (Context.Status() == Context::csInitialization)) {
|
if (Now >= Context.CheckDate()) {
|
||||||
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
|
||||||
FetchOAuth2(Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Now >= Context.CheckDate()) && (Context.Status() >= Context::csInitialized)) {
|
|
||||||
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
||||||
|
|
||||||
if (Context.Status() == Context::csInitialized)
|
if (Context.Status() == Context::csInitialization) {
|
||||||
Context.SetStatus(Context::csAuthorization);
|
ModuleService(Context);
|
||||||
|
}
|
||||||
|
|
||||||
CheckProviders(Now, Context);
|
if (Context.Status() >= Context::csInitialized) {
|
||||||
FetchProviders(Now, Context);
|
CheckProviders(Now, Context);
|
||||||
|
FetchProviders(Now, Context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Context.Status() == Context::csAuthorized) {
|
if (Now >= Context.FixedDate()) {
|
||||||
if (Now >= Context.FixedDate()) {
|
if (Context.Status() == Context::csAuthorized) {
|
||||||
Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
||||||
Context.SetStatus(Context::csInProgress);
|
Context.SetStatus(Context::csInProgress);
|
||||||
|
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ namespace Apostol {
|
|||||||
|
|
||||||
CStringList m_Module;
|
CStringList m_Module;
|
||||||
|
|
||||||
CString m_OAuth2;
|
CJSON m_OAuth2;
|
||||||
CString m_pgpPrivateKey;
|
|
||||||
CString m_pgpPassphrase;
|
|
||||||
|
|
||||||
int m_ServerIndex;
|
CString m_pgpModuleKey;
|
||||||
|
CString m_pgpPublicKey;
|
||||||
|
CString m_pgpPassphrase;
|
||||||
|
|
||||||
CProcessStatus m_Status;
|
CProcessStatus m_Status;
|
||||||
|
|
||||||
@@ -65,17 +65,19 @@ namespace Apostol {
|
|||||||
|
|
||||||
void InitServerList();
|
void InitServerList();
|
||||||
void UpdateServerList(const CString &Key);
|
void UpdateServerList(const CString &Key);
|
||||||
void UpdateOAuth2(const CString &FileName);
|
|
||||||
|
|
||||||
void FetchProviders(CDateTime Now, CContext &Context);
|
void FetchProviders(CDateTime Now, CContext &Context);
|
||||||
void CheckProviders(CDateTime Now, CContext &Context);
|
void CheckProviders(CDateTime Now, CContext &Context);
|
||||||
|
|
||||||
void CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context);
|
void CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context);
|
||||||
void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys);
|
void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys);
|
||||||
|
|
||||||
void FetchOAuth2(CContext &Context);
|
|
||||||
void FetchPGP(CContext &Context);
|
void FetchPGP(CContext &Context);
|
||||||
|
|
||||||
|
void ModuleService(CContext &Context);
|
||||||
|
void ModuleStatus(CContext &Context);
|
||||||
|
void ModuleNew(CContext &Context);
|
||||||
|
void ModuleAuthorize(CContext &Context);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
CHTTPProxy *GetProxy(CHTTPServerConnection *AConnection);
|
CHTTPProxy *GetProxy(CHTTPServerConnection *AConnection);
|
||||||
@@ -130,6 +132,8 @@ namespace Apostol {
|
|||||||
static int VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message);
|
static int VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message);
|
||||||
|
|
||||||
static bool FindURLInLine(const CString &Line, CStringList &List);
|
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);
|
static bool LoadOAuth2(const CString &FileName, CProviders &Providers);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,29 +125,31 @@ namespace Apostol {
|
|||||||
Context.PGP().Name = "PUBLIC";
|
Context.PGP().Name = "PUBLIC";
|
||||||
Context.PGP().Key = Key;
|
Context.PGP().Key = Key;
|
||||||
Context.BTCKeys() = Keys;
|
Context.BTCKeys() = Keys;
|
||||||
|
|
||||||
|
UpdateOAuth2(Context, m_OAuth2.Object());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void CWebSocketModule::FetchOAuth2(CContext &Context) {
|
void CWebSocketModule::ModuleStatus(CContext &Context) {
|
||||||
|
|
||||||
Log()->Debug(APP_LOG_DEBUG_CORE, "Trying to fetch a OAuth2 configuration file for module \"%s\" from: %s", Context.Name().c_str(), Context.URL().Origin().c_str());
|
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) {
|
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||||
|
|
||||||
ARequest->ContentType = CHTTPRequest::text;
|
Context.SetStatus(Context::csInProgress);
|
||||||
|
|
||||||
Apostol::PGP::CleartextSignature(
|
|
||||||
m_pgpPrivateKey,
|
|
||||||
m_pgpPassphrase,
|
|
||||||
BPS_PGP_HASH,
|
|
||||||
Context.Name(),
|
|
||||||
ARequest->Content);
|
|
||||||
|
|
||||||
CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/service");
|
|
||||||
|
|
||||||
const auto &caModuleAddress = m_Module["address"];
|
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())
|
if (!caModuleAddress.IsEmpty())
|
||||||
ARequest->AddHeader("Module-Address", caModuleAddress);
|
ARequest->AddHeader("Module-Address", caModuleAddress);
|
||||||
|
|
||||||
@@ -163,14 +165,82 @@ namespace Apostol {
|
|||||||
|
|
||||||
DebugReply(pReply);
|
DebugReply(pReply);
|
||||||
|
|
||||||
if (Context.Status() == Context::csPreparing) {
|
if (pReply->Status == CHTTPReply::ok) {
|
||||||
if (pReply->Status == CHTTPReply::ok) {
|
ModuleAuthorize(Context);
|
||||||
const CJSON Json(pReply->Content);
|
} else {
|
||||||
Json.SaveToFile(m_OAuth2.c_str());
|
ModuleNew(Context);
|
||||||
UpdateOAuth2(m_OAuth2);
|
}
|
||||||
} else {
|
|
||||||
Context.SetStatus(Context::csInitialization);
|
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 CWebSocketModule::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);
|
pConnection->CloseConnection(true);
|
||||||
@@ -192,7 +262,98 @@ namespace Apostol {
|
|||||||
Context.SetStatus(Context::csInitialization);
|
Context.SetStatus(Context::csInitialization);
|
||||||
};
|
};
|
||||||
|
|
||||||
Context.SetStatus(Context::csPreparing);
|
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 CWebSocketModule::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);
|
auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port);
|
||||||
|
|
||||||
@@ -205,41 +366,108 @@ namespace Apostol {
|
|||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void CWebSocketModule::UpdateOAuth2(const CString &FileName) {
|
void CWebSocketModule::ModuleAuthorize(CContext &Context) {
|
||||||
for (int i = 0; i < m_Servers.Count(); i++) {
|
|
||||||
auto &Context = m_Servers[i].Value();
|
Log()->Notice("[%s] [%s] Trying authorize module.", Context.Name().c_str(), Context.URL().Origin().c_str());
|
||||||
if (Context.Status() == Context::csInitialization || Context.Status() == Context::csPreparing) {
|
|
||||||
if (LoadOAuth2(FileName, Context.Providers())) {
|
auto OnRequest = [this, &Context](CHTTPClient *Sender, CHTTPRequest *ARequest) {
|
||||||
Context.SetStatus(Context::csInitialized);
|
|
||||||
Context.SetCheckDate(0);
|
Context.SetStatus(Context::csAuthorization);
|
||||||
} else {
|
|
||||||
if (Context.Status() != Context::csPreparing) {
|
ARequest->ContentType = CHTTPRequest::text;
|
||||||
FetchOAuth2(Context);
|
|
||||||
}
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 CWebSocketModule::UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2) {
|
||||||
|
if (OAuth2["type"].AsString() == "service_account") {
|
||||||
|
UpdateProviders(Context.Providers(), OAuth2);
|
||||||
|
|
||||||
|
Context.SetCheckDate(0);
|
||||||
|
Context.SetStatus(Context::csInitialized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool CWebSocketModule::LoadOAuth2(const CString &FileName, CProviders &Providers) {
|
void CWebSocketModule::UpdateProviders(CProviders &Providers, const CJSONObject &Data) {
|
||||||
const auto &caProviderName = CString(SYSTEM_PROVIDER_NAME);
|
const auto &caProviderName = CString(SYSTEM_PROVIDER_NAME);
|
||||||
const auto &caApplicationName = CString(SERVICE_APPLICATION_NAME);
|
const auto &caApplicationName = CString(SERVICE_APPLICATION_NAME);
|
||||||
|
|
||||||
if (FileExists(FileName.c_str())) {
|
int index = Providers.IndexOfName(caProviderName);
|
||||||
CJSONObject Json;
|
if (index == -1)
|
||||||
Json.LoadFromFile(FileName.c_str());
|
index = Providers.AddPair(caProviderName, CProvider(caProviderName));
|
||||||
|
auto& Provider = Providers[index].Value();
|
||||||
int index = Providers.IndexOfName(caProviderName);
|
Provider.Applications().AddPair(caApplicationName, Data);
|
||||||
if (index == -1)
|
|
||||||
index = Providers.AddPair(caProviderName, CProvider(caProviderName));
|
|
||||||
auto& Provider = Providers[index].Value();
|
|
||||||
Provider.Applications().AddPair(caApplicationName, Json);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -355,9 +583,7 @@ namespace Apostol {
|
|||||||
pClient->Active(true);
|
pClient->Active(true);
|
||||||
|
|
||||||
Context.SetFixedDate(0);
|
Context.SetFixedDate(0);
|
||||||
|
Context.SetStatus(csRunning);
|
||||||
if (Context.Status() == Context::csInProgress)
|
|
||||||
Context.SetStatus(csRunning);
|
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
Log()->Error(APP_LOG_ERR, 0, e.what());
|
Log()->Error(APP_LOG_ERR, 0, e.what());
|
||||||
}
|
}
|
||||||
@@ -425,7 +651,7 @@ namespace Apostol {
|
|||||||
|
|
||||||
void CWebSocketModule::CreateAccessToken(const CProvider &Provider, const CString &Application, CClientContext &Context) {
|
void CWebSocketModule::CreateAccessToken(const CProvider &Provider, const CString &Application, CClientContext &Context) {
|
||||||
|
|
||||||
auto OnDone = [&Context](CTCPConnection *Sender) {
|
auto OnDone = [this, &Context](CTCPConnection *Sender) {
|
||||||
|
|
||||||
auto pConnection = dynamic_cast<CHTTPClientConnection *> (Sender);
|
auto pConnection = dynamic_cast<CHTTPClientConnection *> (Sender);
|
||||||
auto pReply = pConnection->Reply();
|
auto pReply = pConnection->Reply();
|
||||||
@@ -435,14 +661,12 @@ namespace Apostol {
|
|||||||
if (pReply->Status == CHTTPReply::ok) {
|
if (pReply->Status == CHTTPReply::ok) {
|
||||||
const CJSON Json(pReply->Content);
|
const CJSON Json(pReply->Content);
|
||||||
|
|
||||||
if (Context.Status() == Context::csAuthorization)
|
|
||||||
Context.SetStatus(csAuthorized);
|
|
||||||
|
|
||||||
Context.Session() = Json["session"].AsString();
|
Context.Session() = Json["session"].AsString();
|
||||||
Context.Secret() = Json["secret"].AsString();
|
Context.Secret() = Json["secret"].AsString();
|
||||||
|
|
||||||
Context.SetFixedDate(0);
|
Context.Tokens().Values("access_token", Json["access_token"].AsString());
|
||||||
Context.SetCheckDate(Now() + (CDateTime) 55 / MinsPerDay); // 55 min
|
|
||||||
|
ModuleStatus(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -639,7 +863,6 @@ namespace Apostol {
|
|||||||
|
|
||||||
if (Response.Payload.HasOwnProperty("data")) {
|
if (Response.Payload.HasOwnProperty("data")) {
|
||||||
UpdateServerList(Response.Payload["data"].AsString());
|
UpdateServerList(Response.Payload["data"].AsString());
|
||||||
UpdateOAuth2(m_OAuth2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
@@ -863,7 +1086,7 @@ namespace Apostol {
|
|||||||
sPayload = caClearText.Text();
|
sPayload = caClearText.Text();
|
||||||
} else {
|
} else {
|
||||||
Apostol::PGP::CleartextSignature(
|
Apostol::PGP::CleartextSignature(
|
||||||
m_pgpPrivateKey,
|
m_pgpModuleKey,
|
||||||
m_pgpPassphrase,
|
m_pgpPassphrase,
|
||||||
BPS_PGP_HASH,
|
BPS_PGP_HASH,
|
||||||
caClearText.Text(),
|
caClearText.Text(),
|
||||||
@@ -1260,7 +1483,7 @@ namespace Apostol {
|
|||||||
sPayload = caClearText;
|
sPayload = caClearText;
|
||||||
} else {
|
} else {
|
||||||
Apostol::PGP::CleartextSignature(
|
Apostol::PGP::CleartextSignature(
|
||||||
m_pgpPrivateKey,
|
m_pgpModuleKey,
|
||||||
m_pgpPassphrase,
|
m_pgpPassphrase,
|
||||||
BPS_PGP_HASH,
|
BPS_PGP_HASH,
|
||||||
caClearText,
|
caClearText,
|
||||||
@@ -1517,34 +1740,27 @@ namespace Apostol {
|
|||||||
for (int i = 0; i < m_Servers.Count(); i++) {
|
for (int i = 0; i < m_Servers.Count(); i++) {
|
||||||
auto &Context = m_Servers[i].Value();
|
auto &Context = m_Servers[i].Value();
|
||||||
|
|
||||||
if ((Now >= Context.CheckDate()) && (Context.Status() == Context::csInitialization)) {
|
if (Now >= Context.CheckDate()) {
|
||||||
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
|
||||||
FetchOAuth2(Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Now >= Context.CheckDate()) && (Context.Status() >= Context::csInitialized)) {
|
|
||||||
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
||||||
|
|
||||||
if (Context.Status() == Context::csInitialized)
|
if (Context.Status() == Context::csInitialization) {
|
||||||
Context.SetStatus(Context::csAuthorization);
|
ModuleService(Context);
|
||||||
|
}
|
||||||
|
|
||||||
CheckProviders(Now, Context);
|
if (Context.Status() >= Context::csInitialized) {
|
||||||
FetchProviders(Now, Context);
|
CheckProviders(Now, Context);
|
||||||
}
|
FetchProviders(Now, Context);
|
||||||
|
|
||||||
if (Context.Status() == Context::csAuthorized) {
|
|
||||||
if (Now >= Context.FixedDate()) {
|
|
||||||
Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
|
||||||
Context.SetStatus(Context::csInProgress);
|
|
||||||
|
|
||||||
CreateWebSocketClient(Context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Context.Status() == Context::csRunning) {
|
if (Now >= Context.FixedDate()) {
|
||||||
if (Now >= Context.FixedDate()) {
|
Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
||||||
Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec
|
|
||||||
|
|
||||||
|
if (Context.Status() == Context::csAuthorized) {
|
||||||
|
CreateWebSocketClient(Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Context.Status() == Context::csRunning) {
|
||||||
for (int j = 0; j < Context.ClientManager().Count(); ++j) {
|
for (int j = 0; j < Context.ClientManager().Count(); ++j) {
|
||||||
auto pClient = Context.ClientManager()[j];
|
auto pClient = Context.ClientManager()[j];
|
||||||
|
|
||||||
@@ -1552,7 +1768,10 @@ namespace Apostol {
|
|||||||
pClient->Active(true);
|
pClient->Active(true);
|
||||||
|
|
||||||
if (!pClient->Connected() && !pClient->Session().IsEmpty()) {
|
if (!pClient->Connected() && !pClient->Session().IsEmpty()) {
|
||||||
Log()->Notice(_T("[%s] Trying connect to %s."), pClient->Session().c_str(), pClient->URI().href().c_str());
|
Log()->Notice(_T("[%s] [%s] [%s] Trying to establish a connection."),
|
||||||
|
Context.Name().c_str(),
|
||||||
|
Context.URL().Origin().c_str(),
|
||||||
|
pClient->Session().c_str());
|
||||||
pClient->ConnectStart();
|
pClient->ConnectStart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1565,9 +1784,15 @@ namespace Apostol {
|
|||||||
void CWebSocketModule::Reload() {
|
void CWebSocketModule::Reload() {
|
||||||
Config()->IniFile().ReadSectionValues("module", &m_Module);
|
Config()->IniFile().ReadSectionValues("module", &m_Module);
|
||||||
|
|
||||||
m_OAuth2 = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json");
|
CString FileName;
|
||||||
if (!path_separator(m_OAuth2.front())) {
|
|
||||||
m_OAuth2 = Config()->Prefix() + m_OAuth2;
|
FileName = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json");
|
||||||
|
if (!path_separator(FileName.front())) {
|
||||||
|
FileName = Config()->Prefix() + FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileExists(FileName.c_str())) {
|
||||||
|
m_OAuth2.LoadFromFile(FileName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &caPrivateKey = Config()->IniFile().ReadString("pgp", "private", "module.sec");
|
const auto &caPrivateKey = Config()->IniFile().ReadString("pgp", "private", "module.sec");
|
||||||
@@ -1576,14 +1801,11 @@ namespace Apostol {
|
|||||||
m_pgpPassphrase = Config()->IniFile().ReadString("pgp", "passphrase", "");
|
m_pgpPassphrase = Config()->IniFile().ReadString("pgp", "passphrase", "");
|
||||||
|
|
||||||
if (FileExists(caPrivateKey.c_str())) {
|
if (FileExists(caPrivateKey.c_str())) {
|
||||||
m_pgpPrivateKey.LoadFromFile(caPrivateKey.c_str());
|
m_pgpModuleKey.LoadFromFile(caPrivateKey.c_str());
|
||||||
|
|
||||||
if (FileExists(caPublicKey.c_str())) {
|
if (FileExists(caPublicKey.c_str())) {
|
||||||
CString Key;
|
m_pgpPublicKey.LoadFromFile(caPublicKey.c_str());
|
||||||
Key.LoadFromFile(caPublicKey.c_str());
|
UpdateServerList(m_pgpPublicKey);
|
||||||
|
|
||||||
UpdateServerList(Key);
|
|
||||||
UpdateOAuth2(m_OAuth2);
|
|
||||||
} else {
|
} else {
|
||||||
Log()->Error(APP_LOG_WARN, 0, APP_FILE_NOT_FOUND, caPublicKey.c_str());
|
Log()->Error(APP_LOG_WARN, 0, APP_FILE_NOT_FOUND, caPublicKey.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,10 @@ namespace Apostol {
|
|||||||
|
|
||||||
CStringList m_Module;
|
CStringList m_Module;
|
||||||
|
|
||||||
CString m_OAuth2;
|
CJSON m_OAuth2;
|
||||||
CString m_pgpPrivateKey;
|
|
||||||
|
CString m_pgpModuleKey;
|
||||||
|
CString m_pgpPublicKey;
|
||||||
CString m_pgpPassphrase;
|
CString m_pgpPassphrase;
|
||||||
|
|
||||||
int m_SyncPeriod;
|
int m_SyncPeriod;
|
||||||
@@ -83,7 +85,6 @@ namespace Apostol {
|
|||||||
|
|
||||||
void InitServerList();
|
void InitServerList();
|
||||||
void UpdateServerList(const CString &Key);
|
void UpdateServerList(const CString &Key);
|
||||||
void UpdateOAuth2(const CString &FileName);
|
|
||||||
|
|
||||||
void FetchProviders(CDateTime Now, CClientContext &Context);
|
void FetchProviders(CDateTime Now, CClientContext &Context);
|
||||||
void CheckProviders(CDateTime Now, CClientContext &Context);
|
void CheckProviders(CDateTime Now, CClientContext &Context);
|
||||||
@@ -94,7 +95,10 @@ namespace Apostol {
|
|||||||
CWebSocketClient *GetWebSocketClient(CClientContext &Context);
|
CWebSocketClient *GetWebSocketClient(CClientContext &Context);
|
||||||
void CreateWebSocketClient(CClientContext &Context);
|
void CreateWebSocketClient(CClientContext &Context);
|
||||||
|
|
||||||
void FetchOAuth2(CContext &Context);
|
void ModuleService(CContext &Context);
|
||||||
|
void ModuleStatus(CContext &Context);
|
||||||
|
void ModuleNew(CContext &Context);
|
||||||
|
void ModuleAuthorize(CContext &Context);
|
||||||
|
|
||||||
static CWebSocketClient *GetConnectedClient(const CClientContext &Context);
|
static CWebSocketClient *GetConnectedClient(const CClientContext &Context);
|
||||||
|
|
||||||
@@ -147,12 +151,14 @@ namespace Apostol {
|
|||||||
void Reload();
|
void Reload();
|
||||||
|
|
||||||
static CString ToString(unsigned long Value);
|
static CString ToString(unsigned long Value);
|
||||||
|
|
||||||
static int CheckFee(const CString& Fee);
|
static int CheckFee(const CString& Fee);
|
||||||
static void CheckDeal(const CDeal& Deal);
|
static void CheckDeal(const CDeal& Deal);
|
||||||
static void CheckKeyForNull(LPCTSTR key, const CString& Value);
|
static void CheckKeyForNull(LPCTSTR key, const CString& Value);
|
||||||
|
|
||||||
static bool FindURLInLine(const CString &Line, CStringList &List);
|
static bool FindURLInLine(const CString &Line, CStringList &List);
|
||||||
static bool LoadOAuth2(const CString &FileName, CProviders &Providers);
|
static void UpdateOAuth2(CContext &Context, const CJSONObject &OAuth2);
|
||||||
|
static void UpdateProviders(CProviders &Providers, const CJSONObject &Data);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user