From 5b6d2269be2440f9322afb52b4dbf000a7d78b2f Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Wed, 6 May 2026 19:20:24 -0400 Subject: [PATCH] wg: DragonRelay registration client header (libcurl) --- src/wg/relayreg.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/wg/relayreg.h diff --git a/src/wg/relayreg.h b/src/wg/relayreg.h new file mode 100644 index 0000000..3e214f6 --- /dev/null +++ b/src/wg/relayreg.h @@ -0,0 +1,89 @@ +#pragma once +// src/wg/relayreg.h — DragonRelay HTTP registration client for Artemis. +// +// Artemis (the Sunshine fork) uses this to: +// 1. Authenticate with the DragonRelay server (POST /api/auth/login) +// 2. Provision a WireGuard peer (POST /api/vpn/peer) +// 3. Register its streaming address (POST /api/host/register) +// 4. Send periodic heartbeats (PUT /api/host/heartbeat) +// 5. Unregister on shutdown (DELETE /api/host/unregister) +// +// Built on libcurl (synchronous, no event loop dependency). +// The caller is responsible for starting heartbeats in a background thread. + +#include +#include + +namespace wg { + +// VPN peer credentials returned by provisionVPN(). +struct VPNConf { + std::string id; // peer UUID (for deleteMyVPNPeer) + std::string name; // username@devicename + std::string publicKey; // server's public key + std::string allowedIP; // assigned WG address (e.g. "10.99.0.3/32") + std::string conf; // full wg-quick .conf text, ready for wg::Config::fromString() +}; + +using LogFn = std::function; + +class RelayReg { +public: + RelayReg(); + ~RelayReg(); + + // Set base URL of the DragonRelay server, e.g. "https://relay.example.com" + void setBaseURL(const std::string &url) { m_base = url; } + + // Optional log callback. + void setLog(LogFn fn) { m_log = std::move(fn); } + + // ── Authentication ──────────────────────────────────────────────────────── + + // Authenticate and store the JWT. Returns false and sets errOut on failure. + bool login(const std::string &username, const std::string &password, + std::string &errOut); + + // Clear stored credentials. + void logout(); + + // ── VPN provisioning ────────────────────────────────────────────────────── + + // Request a new WireGuard peer from DragonRelay. + // deviceName is appended to username: "user@devicename". + // Returns false and sets errOut on failure. + bool provisionVPN(const std::string &deviceName, VPNConf &out, std::string &errOut); + + // Delete a previously provisioned peer (cleanup on re-provision or shutdown). + bool deleteVPNPeer(const std::string &peerId, std::string &errOut); + + // ── Host registration ───────────────────────────────────────────────────── + + // Register this host with DragonRelay so clients can discover it. + // name: friendly display name shown in DragonMoonlight. + // wgIP: the local WireGuard address (e.g. "10.99.0.3"). + // port: streaming port (default 47984). + bool registerHost(const std::string &name, const std::string &wgIP, + int port, std::string &errOut); + + // Must be called every ~60 seconds to keep the host visible (5-min TTL). + bool heartbeat(std::string &errOut); + + // Called on Artemis shutdown. + bool unregisterHost(std::string &errOut); + +private: + std::string m_base; + std::string m_jwt; + LogFn m_log; + + // Perform a JSON HTTP request. method: "GET","POST","PUT","DELETE". + // body: JSON string to send (empty = no body). + // Returns HTTP status code; responseOut is set to the response body. + int request(const std::string &method, + const std::string &path, + const std::string &body, + std::string &responseOut); +}; + +} // namespace wg