From d99708838f90123ff6b3c986b2bf9fa8d146d08f 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: Tue, 1 Nov 2022 00:57:06 +0300 Subject: [PATCH] Added token update. --- src/app/Common.cpp | 106 ++++++++++++++++-- src/app/Common.hpp | 4 +- src/modules/Workers/WebService/WebService.cpp | 34 ++++-- 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/app/Common.cpp b/src/app/Common.cpp index ef22fe2..aa8cb1b 100644 --- a/src/app/Common.cpp +++ b/src/app/Common.cpp @@ -107,7 +107,7 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CCustomModule::JsonStringToKey(const CString &String, CString& Key) { + void CCustomModule::JsonStringToKey(const CString &String, CString &Code, CString& Key) { const CJSON Json(String); if (Json.HasOwnProperty("error")) { @@ -116,6 +116,10 @@ namespace Apostol { throw Delphi::Exception::Exception(error["message"].AsString().c_str()); } + if (Json.HasOwnProperty("code")) { + Code = Json["code"].AsString(); + } + if (Json.HasOwnProperty("data")) { Key = Json["data"].AsString(); } @@ -349,10 +353,15 @@ namespace Apostol { Context.Session() = Json["session"].AsString(); Context.Secret() = Json["secret"].AsString(); - Context.Tokens().Values("access_token", Json["access_token"].AsString()); + const auto expires_in = Json["expires_in"].AsInteger(); + + Context.Tokens().Values("module_token", Json["access_token"].AsString()); Provider.KeyStatus(ksSuccess); + Context.SetFixedDate(0); + Context.SetCheckDate(Now() + (CDateTime) (expires_in - 300) / SecsPerDay); + ModuleStatus(Context); } else { Provider.KeyStatus(ksFailed); @@ -391,6 +400,68 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- + void CCustomModule::UpdateAccessToken(CContext &Context, CProvider &Provider, const CString &Application) { + + auto OnDone = [this, &Context, &Provider](CTCPConnection *Sender) { + + auto pConnection = dynamic_cast (Sender); + auto pReply = pConnection->Reply(); + + DebugReply(pReply); + + if (pReply->Status == CHTTPReply::ok) { + const CJSON Json(pReply->Content); + + Context.Session() = Json["session"].AsString(); + Context.Secret() = Json["secret"].AsString(); + + const auto expires_in = Json["expires_in"].AsInteger(); + + Context.Tokens().Values("module_token", Json["access_token"].AsString()); + + Provider.KeyStatus(ksSuccess); + + Context.SetFixedDate(0); + Context.SetCheckDate(Now() + (CDateTime) (expires_in - 300) / SecsPerDay); + + ModuleStatus(Context); + } else { + Provider.KeyStatus(ksFailed); + } + + return true; + }; + + auto OnFail = [&Context, &Provider](CTCPConnection *Sender, const Delphi::Exception::Exception &E) { + Context.SetStatus(csInitialized); + + auto pConnection = dynamic_cast (Sender); + auto pClient = dynamic_cast (pConnection->Client()); + + Provider.KeyStatus(ksFailed); + + DebugReply(pConnection->Reply()); + + Log()->Error(APP_LOG_ERR, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); + }; + + auto OnHTTPClient = [this](const CLocation &URI) { + return GetClient(URI.hostname, URI.port); + }; + //---------------------------------------------------------------------------------------------------------- + + CString server_uri(Context.URL().Origin()); + + const auto &client_id = Provider.ClientId(Application); + const auto &secret = Provider.Secret(Application); + const auto &token_uri = Provider.TokenURI(Application); + + if (!token_uri.IsEmpty()) { + CToken::ExchangeAccessToken(token_uri.front() == '/' ? server_uri + token_uri : token_uri, client_id, secret, Context.Tokens()["module_token"], OnHTTPClient, OnDone, OnFail); + } + } + //-------------------------------------------------------------------------------------------------------------- + void CCustomModule::CheckProviders(CContext &Context, CDateTime Now) { for (int i = 0; i < Context.Providers().Count(); i++) { auto &Provider = Context.Providers()[i].Value(); @@ -400,7 +471,12 @@ namespace Apostol { if (Provider.KeyStatus() != ksFetching) { Provider.KeyStatusTime(Now); Provider.KeyStatus(ksFetching); - CreateAccessToken(Context, Provider, caApplication.String()); + const auto &module_token = Context.Tokens()["module_token"]; + if (module_token.empty()) { + CreateAccessToken(Context, Provider, caApplication.String()); + } else { + UpdateAccessToken(Context, Provider, caApplication.String()); + } } } } @@ -787,7 +863,7 @@ namespace Apostol { CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/status"); - ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]); + ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["module_token"]); if (!caModuleAddress.IsEmpty()) ARequest->AddHeader("Module-Address", caModuleAddress); @@ -866,7 +942,7 @@ namespace Apostol { CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/client/new"); - ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]); + ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["module_token"]); if (!caModuleAddress.IsEmpty()) ARequest->AddHeader("Module-Address", caModuleAddress); @@ -952,7 +1028,11 @@ namespace Apostol { CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/dm/authorize"); - ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["access_token"]); + ARequest->AddHeader("Authorization", "Bearer " + Context.Tokens()["module_token"]); + + const auto &access_token = Context.Tokens()["access_token"]; + if (!access_token.IsEmpty()) + ARequest->AddHeader("Subject-Token", access_token); const auto &caModuleAddress = m_Module["address"]; if (!caModuleAddress.IsEmpty()) @@ -972,20 +1052,24 @@ namespace Apostol { DebugReply(pReply); - if (pReply->Status == CHTTPReply::ok) { - const CJSON Json(pReply->Content); + const CJSON Json(pReply->Content); + if (pReply->Status == CHTTPReply::ok) { Context.Session() = Json["session"].AsString(); Context.Secret() = Json["secret"].AsString(); Context.Tokens().Values("access_token", Json["access_token"].AsString()); - Context.SetFixedDate(0); - Context.SetCheckDate(Now() + (CDateTime) 55 / MinsPerDay); // 55 min - Context.SetStatus(csAuthorized); } else { Context.SetCheckDate(Now() + (CDateTime) 5 / MinsPerDay); // 5 min + if (Json.HasOwnProperty("error")) { + const auto &error = Json["error"]; + if (error.HasOwnProperty("message")) { + Log()->Error(APP_LOG_EMERG, 0, "[%s] [%s] %s", Context.Name().c_str(), + Context.URL().Origin().c_str(), error["message"].AsString().c_str()); + } + } } pConnection->CloseConnection(true); diff --git a/src/app/Common.hpp b/src/app/Common.hpp index 826d8af..549ffc4 100644 --- a/src/app/Common.hpp +++ b/src/app/Common.hpp @@ -98,6 +98,8 @@ namespace Apostol { void CheckProviders(CContext &Context, CDateTime Now); void CreateAccessToken(CContext &Context, CProvider &Provider, const CString &Application); + void UpdateAccessToken(CContext &Context, CProvider &Provider, const CString &Application); + void ParsePGPKey(const CString &Key, CStringPairs &ServerList, CStringList &BTCKeys); void ModuleService(CContext &Context); @@ -129,7 +131,7 @@ namespace Apostol { virtual void Reload() abstract; static CString ToString(unsigned long Value); - static void JsonStringToKey(const CString &String, CString &Key); + static void JsonStringToKey(const CString &String, CString &Code, CString &Key); static void CheckKeyForNull(LPCTSTR Key, LPCTSTR Value); diff --git a/src/modules/Workers/WebService/WebService.cpp b/src/modules/Workers/WebService/WebService.cpp index cc9867f..0a85985 100644 --- a/src/modules/Workers/WebService/WebService.cpp +++ b/src/modules/Workers/WebService/WebService.cpp @@ -127,6 +127,16 @@ namespace Apostol { } pProxyConnection->SendReply(pProxyReply->Status, nullptr, true); } else { + if (pProxyReply->Status == CHTTPReply::forbidden) { + const auto &caServerParam = pServerRequest->Params["server"]; + const auto index = CurrentContextIndex(caServerParam); + + auto &Context = index == -1 ? m_CurrentServer : m_Servers[index].Value(); + + Context.SetCheckDate(0); + Context.SetStatus(Context::csInitialized); + } + pServerReply->Content = pProxyReply->Content; pProxyConnection->SendStockReply(pProxyReply->Status, true); } @@ -1079,15 +1089,17 @@ namespace Apostol { DebugReply(pReply); - CString Content; + CString Code; + CString Key; try { - JsonStringToKey(pReply->Content, Content); + JsonStringToKey(pReply->Content, Code, Key); - if (Content.IsEmpty()) + if (Key.IsEmpty()) throw Delphi::Exception::Exception("Not found."); const auto &name = pClient->Data()["name"]; + auto &Keys = Context.PGP(); int index = 0; @@ -1096,17 +1108,19 @@ namespace Apostol { } if (index < Keys.Count()) { - auto &Key = Keys[index]; + auto &PGP = Keys[index]; - Key.Status = CKeyContext::ksSuccess; - Key.StatusTime = Now(); - Key.Key = Content; + PGP.Status = CKeyContext::ksSuccess; + PGP.StatusTime = Now(); + PGP.Key = Key; - UpdateServerList(m_Servers, Content); + if (Code == "PUBLIC") { + UpdateServerList(m_Servers, Key); + Context.SetStatus(csRunning); + } } - - Context.SetStatus(csRunning); } catch (Delphi::Exception::Exception &e) { + Context.SetStatus(Context::csAuthorized); Log()->Error(APP_LOG_INFO, 0, "[FetchPGP] %s", e.what()); }