#include "network/license_service.h" #include "db/db_keys.h" #include "network/api_client.h" #include #include namespace radiantwave::license { namespace { long long nowEpochSeconds() { const auto now = std::chrono::system_clock::now(); return std::chrono::duration_cast(now.time_since_epoch()).count(); } } // namespace Result validateStoredLicense(radiantwave::db::DatabaseManager& db, std::string* outErrorMessage) { if (outErrorMessage) outErrorMessage->clear(); const std::string email = db.getKV(radiantwave::db::KV_EMAIL_ADDRESS); const std::string key = db.getKV(radiantwave::db::KV_LICENSE_KEY); if (email.empty() || key.empty()) { return Result::NotConfigured; } const radiantwave::api::LicenseResult result = radiantwave::api::validateLicense(key, email); if (result.status == 0) { if (outErrorMessage) *outErrorMessage = "network error"; return Result::NetworkError; } if (!result.ok()) { if (outErrorMessage) *outErrorMessage = result.error_message; return Result::Invalid; } // A successful validation is the "subscribed" flag: the license is valid // and the subscription is active. Only the "last verified" stamp is stored // (it drives the offline grace window). markLicenseVerified(db); return Result::Ok; } void markLicenseVerified(radiantwave::db::DatabaseManager& db) { db.setKV(radiantwave::db::KV_LICENSE_LAST_VERIFIED, std::to_string(nowEpochSeconds())); } bool isLicenseWithinGracePeriod(const radiantwave::db::DatabaseManager& db) { const std::string raw = db.getKV(radiantwave::db::KV_LICENSE_LAST_VERIFIED); if (raw.empty()) return false; char* end = nullptr; const long long stamp = std::strtoll(raw.c_str(), &end, 10); if (!end || *end != '\0' || stamp <= 0) return false; return nowEpochSeconds() - stamp < GRACE_PERIOD_SECONDS; } } // namespace radiantwave::license