feat: add license loading at startup from env var or file
- LicenseBeanConfig wires LicenseGate bean with startup validation - Supports token from CAMELEER_LICENSE_TOKEN env var or CAMELEER_LICENSE_FILE path - Falls back to open mode when no license or no public key configured - Add license config properties to application.yml
This commit is contained in:
@@ -0,0 +1,68 @@
|
|||||||
|
package com.cameleer3.server.app.config;
|
||||||
|
|
||||||
|
import com.cameleer3.server.core.license.LicenseGate;
|
||||||
|
import com.cameleer3.server.core.license.LicenseInfo;
|
||||||
|
import com.cameleer3.server.core.license.LicenseValidator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class LicenseBeanConfig {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LicenseBeanConfig.class);
|
||||||
|
|
||||||
|
@Value("${license.token:}")
|
||||||
|
private String licenseToken;
|
||||||
|
|
||||||
|
@Value("${license.file:}")
|
||||||
|
private String licenseFile;
|
||||||
|
|
||||||
|
@Value("${license.public-key:}")
|
||||||
|
private String licensePublicKey;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LicenseGate licenseGate() {
|
||||||
|
LicenseGate gate = new LicenseGate();
|
||||||
|
|
||||||
|
String token = resolveLicenseToken();
|
||||||
|
if (token == null || token.isBlank()) {
|
||||||
|
log.info("No license configured — running in open mode (all features enabled)");
|
||||||
|
return gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (licensePublicKey == null || licensePublicKey.isBlank()) {
|
||||||
|
log.warn("License token provided but no public key configured (CAMELEER_LICENSE_PUBLIC_KEY). Running in open mode.");
|
||||||
|
return gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
LicenseValidator validator = new LicenseValidator(licensePublicKey);
|
||||||
|
LicenseInfo info = validator.validate(token);
|
||||||
|
gate.load(info);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to validate license: {}. Running in open mode.", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveLicenseToken() {
|
||||||
|
if (licenseToken != null && !licenseToken.isBlank()) {
|
||||||
|
return licenseToken;
|
||||||
|
}
|
||||||
|
if (licenseFile != null && !licenseFile.isBlank()) {
|
||||||
|
try {
|
||||||
|
return Files.readString(Path.of(licenseFile)).trim();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to read license file {}: {}", licenseFile, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,11 @@ cameleer:
|
|||||||
debounce-ms: ${CAMELEER_INDEXER_DEBOUNCE_MS:2000}
|
debounce-ms: ${CAMELEER_INDEXER_DEBOUNCE_MS:2000}
|
||||||
queue-size: ${CAMELEER_INDEXER_QUEUE_SIZE:10000}
|
queue-size: ${CAMELEER_INDEXER_QUEUE_SIZE:10000}
|
||||||
|
|
||||||
|
license:
|
||||||
|
token: ${CAMELEER_LICENSE_TOKEN:}
|
||||||
|
file: ${CAMELEER_LICENSE_FILE:}
|
||||||
|
public-key: ${CAMELEER_LICENSE_PUBLIC_KEY:}
|
||||||
|
|
||||||
security:
|
security:
|
||||||
access-token-expiry-ms: 3600000
|
access-token-expiry-ms: 3600000
|
||||||
refresh-token-expiry-ms: 604800000
|
refresh-token-expiry-ms: 604800000
|
||||||
|
|||||||
Reference in New Issue
Block a user