import fsp from 'node:fs/promises' import path from 'node:path' import { DEFAULT_PRIVATE_KEY, DEFAULT_PUBLIC_KEY, assertOutsideRepo, generateEd25519KeyPair, parseOptions, publicKeyFingerprint, resolvePath, runProcess, usageError, writeFileAtomic } from './lib.mjs' const usage = `Usage: node scripts/updates/init-key.mjs [--private-key ] [--public-key ] [--force] The private key must remain outside the repository. The default private key is: ${DEFAULT_PRIVATE_KEY} ` function secureWindowsAcl(filename, isDirectory = false) { if (process.platform !== 'win32') return const identity = runProcess('whoami', []).trim() if (!identity) throw new Error('Unable to determine the current Windows identity') const permission = isDirectory ? `${identity}:(OI)(CI)F` : `${identity}:(F)` runProcess('icacls', [filename, '/inheritance:r', '/grant:r', permission]) } async function pathExists(filename) { try { await fsp.access(filename) return true } catch { return false } } async function main() { const options = parseOptions(process.argv.slice(2), { values: ['private-key', 'public-key'], booleans: ['force'] }) const privateKeyPath = await assertOutsideRepo( resolvePath(options['private-key'] || DEFAULT_PRIVATE_KEY), 'Private key' ) const publicKeyPath = resolvePath(options['public-key'] || DEFAULT_PUBLIC_KEY) if (!options.force) { if (await pathExists(privateKeyPath)) throw new Error(`Refusing to overwrite existing private key: ${privateKeyPath}`) if (await pathExists(publicKeyPath)) throw new Error(`Refusing to overwrite existing public key: ${publicKeyPath}`) } const keyPair = generateEd25519KeyPair() const directory = path.dirname(privateKeyPath) await fsp.mkdir(directory, { recursive: true, mode: 0o700 }) try { await fsp.chmod(directory, 0o700) } catch { // Windows ACLs are applied below. } secureWindowsAcl(directory, true) await writeFileAtomic(privateKeyPath, keyPair.privatePem, 0o600) try { await fsp.chmod(privateKeyPath, 0o600) } catch { // Windows ACLs are applied below. } secureWindowsAcl(privateKeyPath) await writeFileAtomic(publicKeyPath, keyPair.publicPem, 0o644) console.log(`Private key: ${privateKeyPath}`) console.log(`Public key: ${publicKeyPath}`) console.log(`Public key SHA-256 fingerprint: ${publicKeyFingerprint(keyPair.publicPem)}`) console.log('Private key material was not printed. Back up the private key separately before rotating it.') } main().catch((error) => usageError(usage, error))