fix(license): bind deviceId to physical machine, not OS user

Use OS machine identifiers (Windows MachineGuid, macOS IOPlatformUUID, Linux machine-id) hashed as deviceId so all accounts on one PC share one license slot. Keep legacy userData/device.id for migration and retire it on re-activation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-07-23 10:39:46 +08:00
parent c1c332364c
commit 32a5479086
11 changed files with 399 additions and 24 deletions
+12 -3
View File
@@ -23,7 +23,13 @@ function getBundledPublicKey() {
export function verifyLicenseToken(
token: string,
opts: { nowSec: number; deviceId: string; publicKeyOverrideSpkiDerB64?: string },
opts: {
nowSec: number;
deviceId: string;
/** Старые deviceId (например UUID из userData) — принимаются до повторной активации. */
alsoAcceptDeviceIds?: readonly string[];
publicKeyOverrideSpkiDerB64?: string;
},
): LicenseVerifyResult {
const parts = splitSignedLicenseToken(token);
if (!parts) return { ok: false, reason: 'malformed' };
@@ -53,8 +59,11 @@ export function verifyLicenseToken(
return { ok: false, reason: 'not_yet_valid' };
}
if (opts.nowSec >= payload.exp) return { ok: false, reason: 'expired' };
if (payload.did !== null && payload.did !== opts.deviceId) {
return { ok: false, reason: 'wrong_device' };
if (payload.did !== null) {
const accepted = new Set<string>([opts.deviceId, ...(opts.alsoAcceptDeviceIds ?? [])]);
if (!accepted.has(payload.did)) {
return { ok: false, reason: 'wrong_device' };
}
}
return { ok: true, payload };