/** * @file src/provider_scan_protocol.h * @brief Bounded protocol for unprivileged Linux provider discovery. */ #pragma once #include "lutris_integration.h" #include "steam_integration.h" #include #include #include #include #include #include #include namespace platf::provider_scan { inline constexpr std::string_view schema_name = "vibeshine.provider-catalog"; inline constexpr unsigned int schema_version = 1; inline constexpr std::size_t max_games = 4096; inline constexpr std::size_t max_payload_bytes = 16U * 1024U * 1024U; inline constexpr auto command_timeout = std::chrono::seconds {15}; struct steam_catalog_t { bool available = false; std::vector games; }; struct lutris_catalog_t { bool database_available = false; bool executable_available = false; std::vector games; }; // The wire catalog intentionally excludes every user-derived filesystem // path and Steam direct-launch command field. Only an opaque artwork revision // crosses in the catalog; separate ID-only requests return bounded PNG bytes. The machine // host must never open or interpolate desktop-user-controlled provider // content while holding CAP_SYS_ADMIN. std::optional encode_steam_catalog(const steam_catalog_t &catalog); std::optional encode_lutris_catalog(const lutris_catalog_t &catalog); std::optional decode_steam_catalog(std::string_view payload); std::optional decode_lutris_catalog(std::string_view payload); #if defined(__linux__) namespace detail { struct capture_limits_t { std::chrono::milliseconds timeout; std::size_t maximum_bytes; }; // Exposed for focused tests. Production callers use the fixed wrapper // below, never a caller-controlled executable path. std::optional capture_command( const std::filesystem::path &executable, std::string_view verb, capture_limits_t limits ); } // namespace detail std::optional scan_steam_session(); std::optional scan_lutris_session(); #endif } // namespace platf::provider_scan