#pragma once #include #include #include #include #include namespace svapi { enum class KeyOp { Read, List, Search, Insert, Update, Delete }; std::optional keyOpFromString(const std::string& s); std::string keyOpToString(KeyOp op); struct KeyScopeRule { std::string collection; // exact ("presets") or prefix glob ("catalog_*") std::set ops; bool requireHumanToken = false; }; struct KeyScope { std::vector rules; std::vector origins; // empty = any origin allowed uint32_t rateLimitPerMin = 0; // 0 = unlimited uint64_t expiresAt = 0; // epoch seconds; 0 = never const KeyScopeRule* findRule(const std::string& collection, KeyOp op) const; bool originAllowed(const std::string& origin) const; bool expired(uint64_t nowEpochSec) const; static KeyScope fromJson(const nlohmann::json& j); nlohmann::json toJson() const; }; /// An API key with per-project grants and optional admin privilege. struct ApiKey { std::string id; // stable non-secret identifier (used as DB doc id) std::string key; // secret value (used for authentication only) std::string label; std::vector projects; // may contain "*" (all projects) bool admin = false; uint64_t createdAt = 0; std::optional scope; static ApiKey fromJson(const nlohmann::json& j); nlohmann::json toJson() const; // full (includes key) — for DB storage nlohmann::json toPublicJson() const; // masked: label, projects, admin, created_at, key_prefix /// Returns true if admin, or projects contains "*", or projects contains project. bool canAccess(const std::string& project) const; }; /// Generate a 48-character lowercase hex key (24 random bytes via OpenSSL RAND_bytes). std::string generateApiKey(); } // namespace svapi