feat: add build.rs pubkey embedding and webhook license/v1 endpoints

This commit is contained in:
2026-05-18 22:39:05 +08:00
parent ebb3da2ad6
commit 5d615dd393
3 changed files with 72 additions and 1 deletions
+10 -1
View File
@@ -11,11 +11,20 @@ fn main() {
hash_dir(&src_dir, &mut hasher);
let digest = hasher.finalize();
let hash_hex = format!("{:x}", digest);
println!("cargo:rustc-env=BUILD_SRC_HASH={}", hash_hex);
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out_dir.join("build_hash.txt"), format!("{}\n", hash_hex)).unwrap();
// 嵌入 RSA 公钥(用于 selfhosted 验签)
let pubkey_path = PathBuf::from(&manifest_dir).join("embedded").join("pubkey.pem");
if let Ok(pubkey) = fs::read_to_string(&pubkey_path) {
let trimmed = pubkey.trim();
if !trimmed.is_empty() {
println!("cargo:rustc-env=CRAFTLABS_SELFHOSTED_PUBKEY={}", trimmed);
}
}
println!("cargo:rerun-if-changed=embedded/pubkey.pem");
}
fn hash_dir(dir: &PathBuf, hasher: &mut Sha256) {
+1
View File
@@ -0,0 +1 @@
# Placeholder — replace with production RSA public key (PEM format)
@@ -0,0 +1,61 @@
package cn.craftlabs.platform.webhook.license;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/license/v1")
public class LicenseController {
@PostMapping("/activate")
public ResponseEntity<Map<String, Object>> activate(
@RequestHeader(value = "Authorization", required = false) String auth,
@RequestHeader(value = "X-Craft-Nonce", required = false) String nonce,
@RequestHeader(value = "X-Craft-Timestamp", required = false) String timestamp,
@RequestHeader(value = "X-Craft-Signature", required = false) String signature,
@RequestBody Map<String, Object> request) {
// Phase 1 MVP: accept all activations
String licenseKey = (String) request.getOrDefault("license_key", "unknown");
@SuppressWarnings("unchecked")
Map<String, Object> fp = (Map<String, Object>) request.get("device_fingerprint");
String deviceHash = fp != null ? (String) fp.getOrDefault("composite_hash", "HC-unknown") : "HC-unknown";
Map<String, Object> response = new java.util.HashMap<>();
response.put("status", "activated");
response.put("device_id", deviceHash);
response.put("license_payload", "{\"placeholder\":true,\"note\":\"replace with real license JSON\"}");
return ResponseEntity.ok(response);
}
@PostMapping("/heartbeat")
public ResponseEntity<Map<String, Object>> heartbeat(
@RequestHeader(value = "Authorization", required = false) String auth,
@RequestHeader(value = "X-Craft-Nonce", required = false) String nonce,
@RequestHeader(value = "X-Craft-Timestamp", required = false) String timestamp,
@RequestHeader(value = "X-Craft-Signature", required = false) String signature,
@RequestBody Map<String, Object> request) {
Map<String, Object> response = new java.util.HashMap<>();
response.put("status", "ok");
response.put("lease_renewed_until", java.time.Instant.now().plus(java.time.Duration.ofHours(24)).toString());
response.put("update_available", false);
return ResponseEntity.ok(response);
}
@PostMapping("/check")
public ResponseEntity<Map<String, Object>> check(@RequestBody Map<String, Object> request) {
Map<String, Object> response = new java.util.HashMap<>();
response.put("status", "valid");
response.put("not_after", java.time.Instant.now().plus(java.time.Duration.ofDays(365)).toString());
return ResponseEntity.ok(response);
}
@PostMapping("/release")
public ResponseEntity<Map<String, Object>> release(@RequestBody Map<String, Object> request) {
Map<String, Object> response = new java.util.HashMap<>();
response.put("status", "released");
return ResponseEntity.ok(response);
}
}