mirror of
https://github.com/luxfi/license.git
synced 2026-10-30 16:21:14 +00:00
- 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.
101 lines
3.6 KiB
C
101 lines
3.6 KiB
C
/*
|
|
* Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
|
|
* See the file LICENSE for licensing terms.
|
|
*
|
|
* test_capi.c — round-trip test for the C ABI of luxfi/license.
|
|
*
|
|
* Build (assumes liblux_license.a + lux_license.h already produced by
|
|
* `go build -buildmode=c-archive`):
|
|
*
|
|
* cc -I. test_capi.c liblux_license.a -o test_capi -lpthread \
|
|
* $(pkg-config --libs libssl 2>/dev/null)
|
|
*
|
|
* Run with $LUX_LICENSE set to a base64 token signed by the dev key.
|
|
*/
|
|
|
|
#include "lux_license.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static void must(int cond, const char* msg) {
|
|
if (!cond) {
|
|
fprintf(stderr, "FAIL: %s\n", msg);
|
|
const char* e = lux_license_last_error();
|
|
if (e != NULL && e[0] != '\0') {
|
|
fprintf(stderr, " last error: %s\n", e);
|
|
}
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
const char* env_token = getenv("LUX_LICENSE");
|
|
if (env_token == NULL) {
|
|
fprintf(stderr, "FAIL: $LUX_LICENSE must be set for this test\n");
|
|
return 2;
|
|
}
|
|
|
|
/* 1. verify directly via lux_license_verify_base64 */
|
|
LuxLicenseClaims* c = lux_license_verify_base64(env_token);
|
|
must(c != NULL, "verify_base64 returned NULL");
|
|
|
|
const char* cust = lux_license_customer_id(c);
|
|
must(cust != NULL && strcmp(cust, "Acme Inc") == 0, "customer_id mismatch");
|
|
|
|
const char* lid = lux_license_license_id(c);
|
|
must(lid != NULL && strncmp(lid, "lic_", 4) == 0, "license_id missing prefix");
|
|
|
|
must(lux_license_has_feature(c, "gpu") == 1, "expected gpu feature");
|
|
must(lux_license_has_feature(c, "dex") == 1, "expected dex feature");
|
|
must(lux_license_has_feature(c, "fpga") == 1, "expected fpga feature");
|
|
must(lux_license_has_feature(c, "missing") == 0, "unexpected feature");
|
|
|
|
int n = lux_license_scope_count(c);
|
|
must(n == 3, "expected 3 scopes");
|
|
|
|
/* Scopes are sorted: dex, fpga, gpu */
|
|
const char* s0 = lux_license_scope(c, 0);
|
|
const char* s1 = lux_license_scope(c, 1);
|
|
const char* s2 = lux_license_scope(c, 2);
|
|
must(s0 != NULL && strcmp(s0, "dex") == 0, "scope[0] != dex");
|
|
must(s1 != NULL && strcmp(s1, "fpga") == 0, "scope[1] != fpga");
|
|
must(s2 != NULL && strcmp(s2, "gpu") == 0, "scope[2] != gpu");
|
|
must(lux_license_scope(c, 99) == NULL, "OOB scope should be NULL");
|
|
|
|
int64_t iat = lux_license_issued_at_unix(c);
|
|
int64_t exp = lux_license_expiry_unix(c);
|
|
must(iat > 0, "iat == 0");
|
|
must(exp > iat, "exp <= iat");
|
|
|
|
lux_license_free(c);
|
|
|
|
/* 2. tampered token rejected */
|
|
char* tampered = strdup(env_token);
|
|
/* flip a base64 char in the middle of the payload */
|
|
size_t mid = strlen(tampered) / 2;
|
|
tampered[mid] = (tampered[mid] == 'A') ? 'B' : 'A';
|
|
LuxLicenseClaims* bad = lux_license_verify_base64(tampered);
|
|
must(bad == NULL, "tampered token should fail to verify");
|
|
const char* berr = lux_license_last_error();
|
|
must(berr != NULL && berr[0] != '\0', "expected last_error to be set");
|
|
free(tampered);
|
|
|
|
/* 3. load_from_env path */
|
|
LuxLicenseClaims* env_c = lux_license_load_from_env();
|
|
must(env_c != NULL, "load_from_env returned NULL");
|
|
must(lux_license_has_feature(env_c, "gpu") == 1, "env gpu feature");
|
|
lux_license_free(env_c);
|
|
|
|
/* 4. NULL handling */
|
|
must(lux_license_verify_base64(NULL) == NULL, "NULL token should fail");
|
|
must(lux_license_has_feature(NULL, "gpu") == 0, "NULL handle has_feature");
|
|
must(lux_license_customer_id(NULL) == NULL, "NULL handle customer_id");
|
|
lux_license_free(NULL); /* must not crash */
|
|
|
|
fprintf(stdout, "PASS: lux_license C ABI round-trip\n");
|
|
return 0;
|
|
}
|