feat: build licensed desktop image processor
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
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 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user