initial commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#include "network/license_service.h"
|
||||
#include "db/db_keys.h"
|
||||
#include "network/api_client.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
|
||||
namespace radiantwave::license {
|
||||
|
||||
namespace {
|
||||
|
||||
long long nowEpochSeconds() {
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result validateStoredLicense(radiantwave::db::DatabaseManager& db,
|
||||
const std::string& apiKey,
|
||||
std::string* outLevelName,
|
||||
std::string* outErrorMessage) {
|
||||
if (outLevelName) outLevelName->clear();
|
||||
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, apiKey);
|
||||
|
||||
if (result.status == 0) {
|
||||
if (outErrorMessage) *outErrorMessage = "network error";
|
||||
return Result::NetworkError;
|
||||
}
|
||||
if (!result.ok()) {
|
||||
if (outErrorMessage) *outErrorMessage = result.error_message;
|
||||
return Result::Invalid;
|
||||
}
|
||||
|
||||
const auto& level = result.info.subscription_level;
|
||||
int levelId = level.id;
|
||||
if (levelId <= 0) {
|
||||
// The portal may only report the level name (e.g. "Elite"). Derive the
|
||||
// numeric id from the name so the Home footer and proclamation gating
|
||||
// can rank the level even when the response omits the id.
|
||||
levelId = subscriptionLevelIdForName(level.name);
|
||||
}
|
||||
db.setKV(radiantwave::db::KV_SUBSCRIPTION_LEVEL_ID,
|
||||
levelId > 0 ? std::to_string(levelId) : std::string());
|
||||
db.setKV(radiantwave::db::KV_SUBSCRIPTION_LEVEL_NAME, level.name);
|
||||
db.setKV(radiantwave::db::KV_SUBSCRIPTION_LEVEL_DESCRIPTION, level.description);
|
||||
markLicenseVerified(db);
|
||||
|
||||
if (outLevelName) *outLevelName = level.name;
|
||||
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;
|
||||
}
|
||||
|
||||
int subscriptionLevelIdForName(const std::string& name) {
|
||||
std::string lower;
|
||||
lower.reserve(name.size());
|
||||
for (char c : name) {
|
||||
lower.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
|
||||
}
|
||||
if (lower == "basic") return 1;
|
||||
if (lower == "advanced") return 2;
|
||||
if (lower == "elite") return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getStoredSubscriptionLevelId(const radiantwave::db::DatabaseManager& db) {
|
||||
const std::string raw = db.getKV(radiantwave::db::KV_SUBSCRIPTION_LEVEL_ID);
|
||||
if (raw.empty()) return 0;
|
||||
char* end = nullptr;
|
||||
const long id = std::strtol(raw.c_str(), &end, 10);
|
||||
return (end && *end == '\0' && id > 0) ? static_cast<int>(id) : 0;
|
||||
}
|
||||
|
||||
std::string subscriptionLevelName(int levelId) {
|
||||
switch (levelId) {
|
||||
case 1: return "Basic";
|
||||
case 2: return "Advanced";
|
||||
case 3: return "Elite";
|
||||
default: return "Subscription Level " + std::to_string(levelId);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace radiantwave::license
|
||||
Reference in New Issue
Block a user