Лицензия, редактор, пульт и сборка
- Main: license service, IPC, router; закрытие окон; yauzl закрытие zip (EMFILE), zipRead тест - Editor: стабильный projectState без мигания, логотип и меню, строки UI, LayoutShell overlay - Control: ластик для всех типов эффектов, затухание/нарастание музыки при смене сцены - Сборка: vite, build/dev scripts, obfuscate-main и build-env скрипты с тестами; package.json Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
||||
|
||||
import { LICENSE_ED25519_SPKI_DER_B64 } from '../../shared/license/bundledPublicKey';
|
||||
import { canonicalJson } from '../../shared/license/canonicalJson';
|
||||
import { isLicensePayloadV1, type LicensePayloadV1 } from '../../shared/license/payloadV1';
|
||||
import { splitSignedLicenseToken } from '../../shared/license/tokenFormat';
|
||||
import type { LicenseVerifyFailure } from '../../shared/license/verifyReasons';
|
||||
|
||||
export type LicenseVerifyResult =
|
||||
| { ok: true; payload: LicensePayloadV1 }
|
||||
| { ok: false; reason: LicenseVerifyFailure };
|
||||
|
||||
let cachedPublicKey: ReturnType<typeof createPublicKey> | null = null;
|
||||
|
||||
function getBundledPublicKey() {
|
||||
cachedPublicKey ??= createPublicKey({
|
||||
key: Buffer.from(LICENSE_ED25519_SPKI_DER_B64, 'base64'),
|
||||
format: 'der',
|
||||
type: 'spki',
|
||||
});
|
||||
return cachedPublicKey;
|
||||
}
|
||||
|
||||
export function verifyLicenseToken(
|
||||
token: string,
|
||||
opts: { nowSec: number; deviceId: string; publicKeyOverrideSpkiDerB64?: string },
|
||||
): LicenseVerifyResult {
|
||||
const parts = splitSignedLicenseToken(token);
|
||||
if (!parts) return { ok: false, reason: 'malformed' };
|
||||
|
||||
let payload: unknown;
|
||||
try {
|
||||
payload = JSON.parse(parts.bodyUtf8) as unknown;
|
||||
} catch {
|
||||
return { ok: false, reason: 'bad_payload' };
|
||||
}
|
||||
if (!isLicensePayloadV1(payload)) return { ok: false, reason: 'bad_payload' };
|
||||
|
||||
const body = canonicalJson(payload);
|
||||
const msg = Buffer.from(body, 'utf8');
|
||||
const publicKey =
|
||||
opts.publicKeyOverrideSpkiDerB64 !== undefined
|
||||
? createPublicKey({
|
||||
key: Buffer.from(opts.publicKeyOverrideSpkiDerB64, 'base64'),
|
||||
format: 'der',
|
||||
type: 'spki',
|
||||
})
|
||||
: getBundledPublicKey();
|
||||
const okSig = cryptoVerify(null, msg, publicKey, Buffer.from(parts.signature));
|
||||
if (!okSig) return { ok: false, reason: 'bad_signature' };
|
||||
|
||||
if (payload.nbf !== undefined && opts.nowSec < payload.nbf) {
|
||||
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' };
|
||||
}
|
||||
|
||||
return { ok: true, payload };
|
||||
}
|
||||
Reference in New Issue
Block a user