Files
image-processing/electron/main/license-store.ts
T

71 lines
2.0 KiB
TypeScript

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<StoredLicense | null> {
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<void> {
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<void> {
await fs.rm(this.filePath, { force: true })
}
}