const assert = require("node:assert/strict"); const crypto = require("node:crypto"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const { after, before, test } = require("node:test"); const { signLicense } = require("../license-manager"); let privateKeyPath; let publicKey; let temporaryDirectory; before(async () => { temporaryDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), "reinloop-license-")); const pair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); privateKeyPath = path.join(temporaryDirectory, "license_private.pem"); publicKey = pair.publicKey; await fs.promises.writeFile(privateKeyPath, pair.privateKey.export({ type: "pkcs8", format: "pem" })); }); after(async () => { await fs.promises.rm(temporaryDirectory, { recursive: true, force: true }); }); function validPayload(overrides = {}) { return { customer: "示例公司", company_id: "company-1", production_line_id: "line-1", device_id: "sample-co/line-1", issued: "2026-07-25 12:00", expiry: "2027-07-25 12:00", features: "*", ...overrides }; } test("signLicense creates a Python-compatible RSA-PSS license", () => { const signed = signLicense(validPayload(), privateKeyPath); const [payloadBase64, signatureBase64] = signed.content.split("|"); const verified = crypto.verify("sha256", Buffer.from(payloadBase64), { key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO }, Buffer.from(signatureBase64, "base64")); assert.equal(verified, true); assert.deepEqual(JSON.parse(Buffer.from(payloadBase64, "base64").toString("utf8")), signed.payload); assert.match(signed.payload.license_id, /^[0-9a-f-]{36}$/); }); test("signLicense rejects invalid identity and date ranges", () => { assert.throws(() => signLicense(validPayload({ device_id: "line-only" }), privateKeyPath), /device_id/); assert.throws(() => signLicense(validPayload({ company_id: "" }), privateKeyPath), /company_id/); assert.throws(() => signLicense(validPayload({ expiry: "2026-07-24 12:00" }), privateKeyPath), /到期时间/); });