d3ro-voice/scripts/ci/create-desktop-license-keypair.mjs
2026-08-29 18:33:45 +09:00

55 lines
1.8 KiB
JavaScript

import { createHash, generateKeyPairSync, sign, verify } from 'node:crypto'
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
const args = process.argv.slice(2)
const privateKeyPath = resolve(requiredOption('--private-key'))
const publicKeyPath = resolve(requiredOption('--public-key'))
if (privateKeyPath === publicKeyPath) fail('Private and public key paths must differ.')
mkdirSync(dirname(privateKeyPath), { recursive: true })
mkdirSync(dirname(publicKeyPath), { recursive: true })
const { privateKey, publicKey } = generateKeyPairSync('ed25519')
const probe = Buffer.from('d3ro-desktop-license-keypair-v1', 'utf8')
const signature = sign(null, probe, privateKey)
if (!verify(null, probe, publicKey, signature)) fail('Generated keypair self-check failed.')
const privatePem = privateKey.export({ type: 'pkcs8', format: 'pem' })
const publicPem = publicKey.export({ type: 'spki', format: 'pem' })
let privateCreated = false
try {
writeFileSync(privateKeyPath, privatePem, { flag: 'wx', mode: 0o600 })
privateCreated = true
writeFileSync(publicKeyPath, publicPem, { flag: 'wx', mode: 0o644 })
} catch (error) {
if (privateCreated) rmSync(privateKeyPath, { force: true })
throw error
}
const keyId = createHash('sha256')
.update(publicKey.export({ type: 'spki', format: 'der' }))
.digest('hex')
process.stdout.write(`${JSON.stringify({
ok: true,
purpose: 'desktop-license-signing',
algorithm: 'Ed25519',
keyId,
privateKeyPath,
publicKeyPath,
}, null, 2)}\n`)
function requiredOption(name) {
const index = args.indexOf(name)
const value = index === -1 ? undefined : args[index + 1]
if (!value || value.startsWith('--')) fail(`${name} is required.`)
return value
}
function fail(message) {
process.stderr.write(`[desktop-license-keypair] ${message}\n`)
process.exit(1)
}