#pragma once #include "rublon/memory.hpp" #include #include #include #include #include #include #include [[deprecated]] extern std::string g_tid; namespace rublon { template < class MethodSelect_t = MethodSelect > class Init : public AuthenticationStep { using base_t = AuthenticationStep; const char * apiPath = "/api/transaction/init"; tl::expected< MethodSelect_t, Error > createMethod(const Document & coreResponse) const { memory::MonotonicStackResource< 256 > stackResource; RapidJSONPMRAlloc alloc{&stackResource}; const auto & rublonResponse = coreResponse["result"]; // const auto * rublonMethods = JSONPointer{"/result/methods", &alloc}.Get(coreResponse); const auto * rublonTid = JSONPointer{"/result/tid", &alloc}.Get(coreResponse); _session.updateTransactionId(rublonTid); return MethodSelect_t{_session, rublonResponse["methods"], _session.config().prompt, _session.config().autopushPrompt}; } void addPamInfo(Document & coreRequest, const Pam_t & pam) const { auto & alloc = coreRequest.GetAllocator(); coreRequest.AddMember("username", Value{pam.username().get(), alloc}, alloc); } void addParams(Document & coreRequest, const Pam_t & pam) const { memory::MonotonicStackResource< 512 > stackResource; std::pmr::string releaseInfo{&stackResource}; auto & alloc = coreRequest.GetAllocator(); const auto os = details::osName(&stackResource); if(os == "unknown") { log(LogLevel::Warning, "No OS information available"); } Value osNamePretty{os.data(), static_cast< unsigned >(os.size()), alloc}; Value ip{pam.ip().get(), alloc}; Value params{rapidjson::kObjectType}; params.AddMember("userIP", ip, alloc); params.AddMember("appVer", RUBLON_VERSION_STRING, alloc); params.AddMember("os", osNamePretty, alloc); coreRequest.AddMember("params", std::move(params), alloc); } tl::expected< std::reference_wrapper< const Document >, Error > checkEnrolement(const Document & coreResponse, const Pam_t pam) const { using namespace std::string_view_literals; const auto & resp = coreResponse; /// TODO refactor this if(resp.HasMember("result") and resp["result"].IsObject() and resp["result"].HasMember("status")) { const auto & status = resp["result"]["status"].GetString(); log(LogLevel::Warning, "Got enrolement message with stats %s", status); if(status == "pending"sv) { if(resp["result"].HasMember("webURI")) { const auto & weburi = resp["result"]["webURI"].GetString(); pam.print("Visit %s", weburi); } } else if(status == "waiting"sv) { return tl::unexpected{Error{RublonAuthenticationInterrupt{RublonAuthenticationInterrupt::UserWaiting}}}; } else if(status == "denied"sv) { return tl::unexpected{Error{RublonAuthenticationInterrupt{RublonAuthenticationInterrupt::UserDenied}}}; } } return coreResponse; } public: const char * _name = "Initialization"; Init(Session & session) : base_t(session) { log(LogLevel::Debug, "Init"); } template < typename Hander_t > tl::expected< MethodSelect_t, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler, const Pam_t & pam) const { const auto createMethod = [&](const auto & coreResponse) { return this->createMethod(coreResponse); }; const auto checkEnrolement = [&](const auto & coreResponse) { return this->checkEnrolement(coreResponse, pam); }; RapidJSONPMRStackAlloc< 2048 > alloc{}; Document body{rapidjson::kObjectType, &alloc}; this->addSystemToken(body); this->addPamInfo(body, pam); this->addParams(body, pam); return coreHandler .request(alloc, apiPath, body) // .and_then(checkEnrolement) .and_then(createMethod); } }; } // namespace rublon