#pragma once #include #include #include #include namespace rublon::method { class PasscodeBasedAuth : public AuthenticationStep< PasscodeBasedAuth > { using base_t = AuthenticationStep< PasscodeBasedAuth >; const char * uri = "/api/transaction/confirmCode"; const char * userMessage{nullptr}; constexpr static bool isdigit(char ch) { return std::isdigit(static_cast< unsigned char >(ch)); } static bool hasDigitsOnly(const std::string & userinput) { return std::all_of(userinput.cbegin(), userinput.cend(), isdigit); } static bool isProperLength(const std::string & userInput) { return userInput.size() == 6; } template < typename PamInfo_t = LinuxPam > tl::expected< std::reference_wrapper< Document >, Error > readPasscode(Document & body, const PamInfo_t & pam) const { auto & alloc = body.GetAllocator(); auto vericode = pam.scan([](const char * userInput) { return std::string{userInput}; }, userMessage); if(isProperLength(vericode) and hasDigitsOnly(vericode)) { body.AddMember("vericode", Value{vericode.c_str(), alloc}, alloc); return body; } return tl::unexpected{Error{WerificationError{WerificationError::WrongCode}}}; } template < typename PamInfo_t = LinuxPam > tl::expected< std::reference_wrapper< Document >, Error > askForPasscodeAgain(Document & body, const PamInfo_t & pam) const { pam.print("passcode has wrong number of digits or illegal characters, please correct"); return readPasscode(body, pam); } tl::expected< AuthenticationStatus, Error > checkAuthenticationStatus(const Document & coreResponse) const { RapidJSONPMRStackAlloc< 1024 > alloc; auto error = JSONPointer{"/result/error", &alloc}.Get(coreResponse); if(error) { return tl::unexpected{Error{WerificationError{WerificationError::WrongCode}}}; } return AuthenticationStatus{AuthenticationStatus::Action::Confirmed}; } public: const char * name; PasscodeBasedAuth(std::string systemToken, std::string tid, const char * name, const char * userMessage) : base_t(std::move(systemToken), std::move(tid)), userMessage{userMessage}, name{name} {} template < typename Hander_t, typename PamInfo_t = LinuxPam > tl::expected< AuthenticationStatus, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler, const PamInfo_t & pam) const { RapidJSONPMRStackAlloc< 1024 > alloc{}; Document body{rapidjson::kObjectType, &alloc}; const auto checkAuthenticationStatus = [this](const auto & coreResponse) { return this->checkAuthenticationStatus(coreResponse); }; const auto requestAuthorization = [&](const auto & body) { return coreHandler.request(uri, body); }; const auto askForPasscodeAgain = [&](const auto & /*error*/) { return this->askForPasscodeAgain(body, pam); }; this->addSystemToken(body); this->addTid(body); return readPasscode(body, pam) // .or_else(askForPasscodeAgain) .and_then(requestAuthorization) .and_then(checkAuthenticationStatus); } }; } // namespace rublon::method