import { app, safeStorage } from 'electron' import { promises as fs } from 'node:fs' import path from 'node:path' export interface StoredLicense { token: string licenseCodeMask: string deviceMask: string expiresAt?: string maxDevices: number lastVerifiedAt: string } interface StoredLicenseFile { encryptedToken: string licenseCodeMask: string deviceMask: string expiresAt?: string maxDevices: number lastVerifiedAt: string } export class LicenseStore { private get filePath(): string { return path.join(app.getPath('userData'), 'license.json') } async load(): Promise { try { const raw = await fs.readFile(this.filePath, 'utf8') const stored = JSON.parse(raw) as StoredLicenseFile const decrypted = await safeStorage.decryptStringAsync( Buffer.from(stored.encryptedToken, 'base64'), ) return { token: decrypted.result, licenseCodeMask: stored.licenseCodeMask, deviceMask: stored.deviceMask, expiresAt: stored.expiresAt, maxDevices: stored.maxDevices, lastVerifiedAt: stored.lastVerifiedAt, } } catch { return null } } async save(license: StoredLicense): Promise { if (!(await safeStorage.isAsyncEncryptionAvailable())) { throw new Error('系统安全凭据存储不可用') } const encryptedToken = await safeStorage.encryptStringAsync(license.token) const stored: StoredLicenseFile = { encryptedToken: encryptedToken.toString('base64'), licenseCodeMask: license.licenseCodeMask, deviceMask: license.deviceMask, expiresAt: license.expiresAt, maxDevices: license.maxDevices, lastVerifiedAt: license.lastVerifiedAt, } await fs.mkdir(path.dirname(this.filePath), { recursive: true }) const temporaryPath = `${this.filePath}.tmp` await fs.writeFile(temporaryPath, JSON.stringify(stored), { mode: 0o600 }) await fs.rename(temporaryPath, this.filePath) } async clear(): Promise { await fs.rm(this.filePath, { force: true }) } }