#include "endpoint_rpc.hpp" #include namespace llarp::rpc { EndpointAuthRPC::EndpointAuthRPC( std::string url, std::string method, Whitelist_t whitelist_addrs, std::unordered_set whitelist_tokens, LMQ_ptr lmq, Endpoint_ptr endpoint) : m_AuthURL{std::move(url)} , m_AuthMethod{std::move(method)} , m_AuthWhitelist{std::move(whitelist_addrs)} , m_AuthStaticTokens{std::move(whitelist_tokens)} , m_LMQ{std::move(lmq)} , m_Endpoint{std::move(endpoint)} {} void EndpointAuthRPC::Start() { if (m_AuthURL.empty() or m_AuthMethod.empty()) return; m_LMQ->connect_remote( oxenmq::address{m_AuthURL}, [self = shared_from_this()](oxenmq::ConnectionID c) { self->m_Conn = std::move(c); LogInfo("connected to endpoint auth server"); }, [self = shared_from_this()](oxenmq::ConnectionID, std::string_view fail) { LogWarn("failed to connect to endpoint auth server: ", fail); self->m_Endpoint->Loop()->call_later(1s, [self] { self->Start(); }); }); } bool EndpointAuthRPC::AsyncAuthPending(service::ConvoTag tag) const { return m_PendingAuths.count(tag) > 0; } void EndpointAuthRPC::AuthenticateAsync( std::shared_ptr msg, std::function hook) { service::ConvoTag tag = msg->tag; m_PendingAuths.insert(tag); const auto from = msg->sender.Addr(); auto reply = m_Endpoint->Loop()->make_caller([this, tag, hook](service::AuthResult result) { m_PendingAuths.erase(tag); hook(result); }); if (m_AuthWhitelist.count(from)) { // explicitly whitelisted source reply(service::AuthResult{service::AuthResultCode::eAuthAccepted, "explicitly whitelisted"}); return; } if (msg->proto != llarp::service::ProtocolType::Auth) { // not an auth message, reject reply(service::AuthResult{service::AuthResultCode::eAuthRejected, "protocol error"}); return; } std::string payload{(char*)msg->payload.data(), msg->payload.size()}; if (m_AuthStaticTokens.count(payload)) { reply(service::AuthResult{service::AuthResultCode::eAuthAccepted, "explicitly whitelisted"}); return; } if (not m_Conn.has_value()) { if (m_AuthStaticTokens.empty()) { // we don't have a connection to the backend so it's failed reply(service::AuthResult{ service::AuthResultCode::eAuthFailed, "remote has no connection to auth backend"}); } else { // static auth mode reply(service::AuthResult{service::AuthResultCode::eAuthRejected, "access not permitted"}); } return; } const auto authinfo = msg->EncodeAuthInfo(); std::string_view metainfo{authinfo.data(), authinfo.size()}; // call method with 2 parameters: metainfo and userdata m_LMQ->request( *m_Conn, m_AuthMethod, [self = shared_from_this(), reply = std::move(reply)]( bool success, std::vector data) { service::AuthResult result{service::AuthResultCode::eAuthFailed, "no reason given"}; if (success and not data.empty()) { if (const auto maybe = service::ParseAuthResultCode(data[0])) { result.code = *maybe; } if (result.code == service::AuthResultCode::eAuthAccepted) { result.reason = "OK"; } if (data.size() > 1) { result.reason = data[1]; } } reply(result); }, metainfo, payload); } } // namespace llarp::rpc