#pragma once #include #include #include #include #include #include namespace rublon { class Verify {}; } // namespace rublon namespace rublon { std::pmr::string osName(std::pmr::memory_resource *mr) { memory::MonotonicStackResource< 8 * 1024 > stackResource; std::ifstream file(std::filesystem::path{"/etc/os-release"}); if(not file.good()) return {"unknown", mr}; std::pmr::string line{&stackResource}; line.reserve(100); while(std::getline(file, line)) { std::pmr::string _key{&stackResource}; std::pmr::string _value{&stackResource}; if(!line.length()) continue; if(line[0] == '#' || line[0] == ';') continue; auto posEqual = line.find('='); _key = line.substr(0, posEqual); _value = line.substr(posEqual + 1); if(_key == "PRETTY_NAME"){ return {_value, mr}; } } return {"unknown", mr}; } template < class MethodSelect_t = MethodSelect > class Init : public AuthenticationStep< Init< MethodSelect_t > > { using base_t = AuthenticationStep< Init< MethodSelect_t > >; const char * apiPath = "/api/transaction/init"; tl::expected< MethodSelect_t, Error > createMethod(const Document & coreResponse) const { const auto & rublonResponse = coreResponse["result"]; std::string tid = rublonResponse["tid"].GetString(); return MethodSelect_t{this->_systemToken, tid, rublonResponse["methods"]}; } template < typename PamInfo_t > void addPamInfo(Document & coreRequest, const PamInfo_t & pam) const { auto & alloc = coreRequest.GetAllocator(); coreRequest.AddMember("username", Value{pam.username().get(), alloc}, alloc); } template < typename PamInfo_t > void addParams(Document & coreRequest, const PamInfo_t & pam) const { memory::MonotonicStackResource< 512 > stackResource; std::pmr::string releaseInfo{&stackResource}; auto & alloc = coreRequest.GetAllocator(); const auto os = 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", "v.0.0.1", alloc); /// TODO add version to cmake params.AddMember("os", osNamePretty, alloc); coreRequest.AddMember("params", std::move(params), alloc); } template < typename PamInfo_t > tl::expected< std::reference_wrapper< const Document >, Error > checkEnrolement(const Document & coreResponse, const PamInfo_t & pam) const { using namespace std::string_view_literals; const auto & resp = coreResponse; 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 and resp["result"].HasMember("webURI")) { const auto & weburi = resp["result"]["webURI"].GetString(); pam.print("It seams that your account is not configured properly,\nplease contact your administrator for more information"); pam.print("also, please visit %s", weburi); return tl::unexpected{Error{RublonAuthenticationInterrupt{RublonAuthenticationInterrupt::UserPending}}}; } if(status == "denied"sv) { pam.print("It seams that your account is disabled, please contact your administrator for more information"); return tl::unexpected{Error{RublonAuthenticationInterrupt{RublonAuthenticationInterrupt::UserDenied}}}; } } return coreResponse; } public: const char * name = "Initialization"; Init(const rublon::Configuration & config) : base_t(config.systemToken.data(), "") {} template < typename Hander_t, typename PamInfo_t = LinuxPam > tl::expected< MethodSelect_t, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler, const PamInfo_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