Files
zeekay f77da86cda Initial luxfi/license — Ed25519-signed offline license tokens for commercial Lux features.
- Stdlib-only deterministic binary token format (no JWT / CBOR dep).
- Go API: VerifyToken, LoadFromEnv, HasFeature, HasFeatureOrDie.
- Stable C ABI + C++17 RAII wrapper for non-Go commercial binaries (luxcpp/cevm).
- cmd/lux-license: keygen / issue / inspect / verify.
- Embedded development key; warns once at runtime until production key swap.
- 22 Go tests + 1 cgo round-trip test, all passing.
2026-05-15 17:08:32 -07:00

113 lines
3.0 KiB
C++

/*
* Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
* See the file LICENSE for licensing terms.
*
* lux_license.hpp — thin RAII wrapper around lux_license.h for C++17+.
*/
#ifndef LUX_LICENSE_HPP
#define LUX_LICENSE_HPP
#include "lux_license.h"
#include <cstdint>
#include <stdexcept>
#include <string>
#include <string_view>
namespace lux {
class license_error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
class License {
public:
/* Load and verify a license from the environment. Throws license_error
* on failure; check::has_feature is the non-throwing alternative. */
static License load_from_env() {
auto* c = lux_license_load_from_env();
if (c == nullptr) {
throw license_error(lux_license_last_error());
}
return License(c);
}
/* Verify a base64-encoded token directly. */
static License verify_base64(std::string_view token) {
std::string s(token); // NUL-terminate
auto* c = lux_license_verify_base64(s.c_str());
if (c == nullptr) {
throw license_error(lux_license_last_error());
}
return License(c);
}
/* Abort the process if the named feature is not licensed. Mirrors
* Go's HasFeatureOrDie. */
static void require_feature_or_die(std::string_view scope) {
std::string s(scope);
lux_license_require_feature_or_die(s.c_str());
}
License(const License&) = delete;
License& operator=(const License&) = delete;
License(License&& other) noexcept : claims_(other.claims_) {
other.claims_ = nullptr;
}
License& operator=(License&& other) noexcept {
if (this != &other) {
reset();
claims_ = other.claims_;
other.claims_ = nullptr;
}
return *this;
}
~License() { reset(); }
bool has_feature(std::string_view scope) const {
std::string s(scope);
return lux_license_has_feature(claims_, s.c_str()) != 0;
}
std::string customer_id() const {
const char* p = lux_license_customer_id(claims_);
return p == nullptr ? std::string{} : std::string(p);
}
std::string license_id() const {
const char* p = lux_license_license_id(claims_);
return p == nullptr ? std::string{} : std::string(p);
}
int64_t issued_at_unix() const { return lux_license_issued_at_unix(claims_); }
int64_t expiry_unix() const { return lux_license_expiry_unix(claims_); }
int scope_count() const { return lux_license_scope_count(claims_); }
std::string scope(int i) const {
const char* p = lux_license_scope(claims_, i);
return p == nullptr ? std::string{} : std::string(p);
}
private:
explicit License(LuxLicenseClaims* c) : claims_(c) {}
void reset() {
if (claims_ != nullptr) {
lux_license_free(claims_);
claims_ = nullptr;
}
}
LuxLicenseClaims* claims_;
};
} /* namespace lux */
#endif /* LUX_LICENSE_HPP */