import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as exec from './exec'; export const agentConfig = `default-cache-ttl 1 max-cache-ttl 31536000 allow-preset-passphrase`; export interface Version { gnupg: string; libgcrypt: string; } export interface Dirs { libdir: string; datadir: string; homedir: string; } export const getVersion = async (): Promise => { return await exec.exec('gpg', ['--version'], true).then(res => { if (res.stderr != '') { throw new Error(res.stderr); } let gnupgVersion: string = ''; let libgcryptVersion: string = ''; for (let line of res.stdout.replace(/\r/g, '').trim().split(/\n/g)) { if (line.startsWith('gpg (GnuPG) ')) { gnupgVersion = line.substr('gpg (GnuPG) '.length).trim(); } else if (line.startsWith('gpg (GnuPG/MacGPG2) ')) { gnupgVersion = line.substr('gpg (GnuPG/MacGPG2) '.length).trim(); } else if (line.startsWith('libgcrypt ')) { libgcryptVersion = line.substr('libgcrypt '.length).trim(); } } return { gnupg: gnupgVersion, libgcrypt: libgcryptVersion }; }); }; export const getDirs = async (): Promise => { return await exec.exec('gpgconf', ['--list-dirs'], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } let libdir: string = ''; let datadir: string = ''; let homedir: string = ''; for (let line of res.stdout.replace(/\r/g, '').trim().split(/\n/g)) { if (line.startsWith('libdir:')) { libdir = line.substr('libdir:'.length).replace('%3a', ':').trim(); } else if (line.startsWith('datadir:')) { datadir = line.substr('datadir:'.length).replace('%3a', ':').trim(); } else if (line.startsWith('homedir:')) { homedir = line.substr('homedir:'.length).replace('%3a', ':').trim(); } } return { libdir: path.normalize(libdir), datadir: path.normalize(datadir), homedir: path.normalize(homedir) }; }); }; export const importKey = async (armoredText: string): Promise => { const keyFolder: string = fs.mkdtempSync(path.join(os.tmpdir(), 'ghaction-import-gpg-')); const keyPath: string = `${keyFolder}/key.pgp`; fs.writeFileSync(keyPath, armoredText, {mode: 0o600}); return await exec .exec('gpg', ['--import', '--batch', '--yes', keyPath], true) .then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } if (res.stderr != '') { return res.stderr.trim(); } return res.stdout.trim(); }) .finally(() => { fs.unlinkSync(keyPath); }); }; export const getKeygrip = async (fingerprint: string): Promise => { return await exec .exec('gpg', ['--batch', '--with-colons', '--with-keygrip', '--list-secret-keys', fingerprint], true) .then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } let keygrip: string = ''; for (let line of res.stdout.replace(/\r/g, '').trim().split(/\n/g)) { if (line.startsWith('grp')) { keygrip = line.replace(/(grp|:)/g, '').trim(); } } return keygrip; }); }; export const configureAgent = async (config: string): Promise => { const {homedir: homedir} = await getDirs(); const gpgAgentConf = path.join(homedir, 'gpg-agent.conf'); await fs.writeFile(gpgAgentConf, config, function (err) { if (err) throw err; }); await exec.exec(`gpg-connect-agent "RELOADAGENT" /bye`, [], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } }); }; export const presetPassphrase = async (keygrip: string, passphrase: string): Promise => { await exec .exec('gpg-preset-passphrase', ['--verbose', '--preset', '--passphrase', `"${passphrase}"`, keygrip], true) .then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } }); return await exec.exec(`gpg-connect-agent "KEYINFO ${keygrip}" /bye`, [], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } for (let line of res.stdout.replace(/\r/g, '').trim().split(/\n/g)) { if (line.startsWith('ERR')) { throw new Error(line); } } return res.stdout.trim(); }); }; export const deleteKey = async (fingerprint: string): Promise => { await exec.exec('gpg', ['--batch', '--yes', '--delete-secret-keys', fingerprint], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } }); await exec.exec('gpg', ['--batch', '--yes', '--delete-keys', fingerprint], true).then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); } }); };