From f71c727ad90d672cedf9831838489930f33c729b Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Mon, 4 May 2020 19:55:53 +0200 Subject: [PATCH] Use which to determine gpg-preset-passphrase path --- dist/index.js | 308 +++++++++++++++++++++++++++++++++++++++++++++- package-lock.json | 32 ++++- package.json | 4 +- src/gpg.ts | 17 ++- 4 files changed, 351 insertions(+), 10 deletions(-) diff --git a/dist/index.js b/dist/index.js index 33e0ba7..90200ef 100644 --- a/dist/index.js +++ b/dist/index.js @@ -987,6 +987,54 @@ if (!exports.IsPost) { } +/***/ }), + +/***/ 197: +/***/ (function(module, __unusedexports, __webpack_require__) { + +module.exports = isexe +isexe.sync = sync + +var fs = __webpack_require__(747) + +function isexe (path, options, cb) { + fs.stat(path, function (er, stat) { + cb(er, er ? false : checkStat(stat, options)) + }) +} + +function sync (path, options) { + return checkStat(fs.statSync(path), options) +} + +function checkStat (stat, options) { + return stat.isFile() && checkMode(stat, options) +} + +function checkMode (stat, options) { + var mod = stat.mode + var uid = stat.uid + var gid = stat.gid + + var myUid = options.uid !== undefined ? + options.uid : process.getuid && process.getuid() + var myGid = options.gid !== undefined ? + options.gid : process.getgid && process.getgid() + + var u = parseInt('100', 8) + var g = parseInt('010', 8) + var o = parseInt('001', 8) + var ug = u | g + + var ret = (mod & o) || + (mod & g) && gid === myGid || + (mod & u) && uid === myUid || + (mod & ug) && myUid === 0 + + return ret +} + + /***/ }), /***/ 198: @@ -1108,17 +1156,28 @@ var __importStar = (this && this.__importStar) || function (mod) { result["default"] = mod; return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); const fs = __importStar(__webpack_require__(747)); const path = __importStar(__webpack_require__(622)); const os = __importStar(__webpack_require__(87)); const exec = __importStar(__webpack_require__(807)); +const which_1 = __importDefault(__webpack_require__(814)); exports.agentConfig = `default-cache-ttl 7200 max-cache-ttl 31536000 allow-preset-passphrase`; const getGpgPresetPassphrasePath = () => __awaiter(void 0, void 0, void 0, function* () { + let gpgPresetPassphrasePath; + gpgPresetPassphrasePath = yield which_1.default('gpg-preset-passphrase').then(resolvedPath => { + return resolvedPath; + }); + if (gpgPresetPassphrasePath != '') { + return gpgPresetPassphrasePath; + } const { libexecdir: libexecdir } = yield exports.getDirs(); - let gpgPresetPassphrasePath = path.join(libexecdir, 'gpg-preset-passphrase'); + gpgPresetPassphrasePath = path.join(libexecdir, 'gpg-preset-passphrase'); if (yield fs.existsSync(gpgPresetPassphrasePath)) { return gpgPresetPassphrasePath; } @@ -1246,7 +1305,7 @@ exports.configureAgent = (config) => __awaiter(void 0, void 0, void 0, function* }); exports.presetPassphrase = (keygrip, passphrase) => __awaiter(void 0, void 0, void 0, function* () { yield exec - .exec(yield getGpgPresetPassphrasePath(), ['--verbose', '--preset', '--passphrase', `"${passphrase}"`, keygrip], true) + .exec(`"${yield getGpgPresetPassphrasePath()}" --verbose --preset --passphrase "${passphrase}" ${keygrip}`, [], true) .then(res => { if (res.stderr != '' && !res.success) { throw new Error(res.stderr); @@ -45565,6 +45624,70 @@ exports.default = AsyncProxy; }); +/***/ }), + +/***/ 742: +/***/ (function(module, __unusedexports, __webpack_require__) { + +var fs = __webpack_require__(747) +var core +if (process.platform === 'win32' || global.TESTING_WINDOWS) { + core = __webpack_require__(818) +} else { + core = __webpack_require__(197) +} + +module.exports = isexe +isexe.sync = sync + +function isexe (path, options, cb) { + if (typeof options === 'function') { + cb = options + options = {} + } + + if (!cb) { + if (typeof Promise !== 'function') { + throw new TypeError('callback not provided') + } + + return new Promise(function (resolve, reject) { + isexe(path, options || {}, function (er, is) { + if (er) { + reject(er) + } else { + resolve(is) + } + }) + }) + } + + core(path, options || {}, function (er, is) { + // ignore EACCES because that just means we aren't allowed to run it + if (er) { + if (er.code === 'EACCES' || options && options.ignoreErrors) { + er = null + is = false + } + } + cb(er, is) + }) +} + +function sync (path, options) { + // my kingdom for a filtered catch + try { + return core.sync(path, options || {}) + } catch (er) { + if (options && options.ignoreErrors || er.code === 'EACCES') { + return false + } else { + throw er + } + } +} + + /***/ }), /***/ 747: @@ -45676,6 +45799,187 @@ exports.exec = (command, args = [], silent) => __awaiter(void 0, void 0, void 0, }); +/***/ }), + +/***/ 814: +/***/ (function(module, __unusedexports, __webpack_require__) { + +const isWindows = process.platform === 'win32' || + process.env.OSTYPE === 'cygwin' || + process.env.OSTYPE === 'msys' + +const path = __webpack_require__(622) +const COLON = isWindows ? ';' : ':' +const isexe = __webpack_require__(742) + +const getNotFoundError = (cmd) => + Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) + +const getPathInfo = (cmd, opt) => { + const colon = opt.colon || COLON + + // If it has a slash, then we don't bother searching the pathenv. + // just check the file itself, and that's it. + const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [''] + : ( + [ + // windows always checks the cwd first + ...(isWindows ? [process.cwd()] : []), + ...(opt.path || process.env.PATH || + /* istanbul ignore next: very unusual */ '').split(colon), + ] + ) + const pathExtExe = isWindows + ? opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM' + : '' + const pathExt = isWindows ? pathExtExe.split(colon) : [''] + + if (isWindows) { + if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') + pathExt.unshift('') + } + + return { + pathEnv, + pathExt, + pathExtExe, + } +} + +const which = (cmd, opt, cb) => { + if (typeof opt === 'function') { + cb = opt + opt = {} + } + if (!opt) + opt = {} + + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) + const found = [] + + const step = i => new Promise((resolve, reject) => { + if (i === pathEnv.length) + return opt.all && found.length ? resolve(found) + : reject(getNotFoundError(cmd)) + + const ppRaw = pathEnv[i] + const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw + + const pCmd = path.join(pathPart, cmd) + const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd + : pCmd + + resolve(subStep(p, i, 0)) + }) + + const subStep = (p, i, ii) => new Promise((resolve, reject) => { + if (ii === pathExt.length) + return resolve(step(i + 1)) + const ext = pathExt[ii] + isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { + if (!er && is) { + if (opt.all) + found.push(p + ext) + else + return resolve(p + ext) + } + return resolve(subStep(p, i, ii + 1)) + }) + }) + + return cb ? step(0).then(res => cb(null, res), cb) : step(0) +} + +const whichSync = (cmd, opt) => { + opt = opt || {} + + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) + const found = [] + + for (let i = 0; i < pathEnv.length; i ++) { + const ppRaw = pathEnv[i] + const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw + + const pCmd = path.join(pathPart, cmd) + const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd + : pCmd + + for (let j = 0; j < pathExt.length; j ++) { + const cur = p + pathExt[j] + try { + const is = isexe.sync(cur, { pathExt: pathExtExe }) + if (is) { + if (opt.all) + found.push(cur) + else + return cur + } + } catch (ex) {} + } + } + + if (opt.all && found.length) + return found + + if (opt.nothrow) + return null + + throw getNotFoundError(cmd) +} + +module.exports = which +which.sync = whichSync + + +/***/ }), + +/***/ 818: +/***/ (function(module, __unusedexports, __webpack_require__) { + +module.exports = isexe +isexe.sync = sync + +var fs = __webpack_require__(747) + +function checkPathExt (path, options) { + var pathext = options.pathExt !== undefined ? + options.pathExt : process.env.PATHEXT + + if (!pathext) { + return true + } + + pathext = pathext.split(';') + if (pathext.indexOf('') !== -1) { + return true + } + for (var i = 0; i < pathext.length; i++) { + var p = pathext[i].toLowerCase() + if (p && path.substr(-p.length).toLowerCase() === p) { + return true + } + } + return false +} + +function checkStat (stat, path, options) { + if (!stat.isSymbolicLink() && !stat.isFile()) { + return false + } + return checkPathExt(path, options) +} + +function isexe (path, options, cb) { + fs.stat(path, function (er, stat) { + cb(er, er ? false : checkStat(stat, path, options)) + }) +} + +function sync (path, options) { + return checkStat(fs.statSync(path), path, options) +} + + /***/ }), /***/ 986: diff --git a/package-lock.json b/package-lock.json index 86206e2..5f0f827 100644 --- a/package-lock.json +++ b/package-lock.json @@ -916,6 +916,12 @@ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, + "@types/which": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", + "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "dev": true + }, "@types/yargs": { "version": "15.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", @@ -1562,6 +1568,16 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } } }, "cssom": { @@ -3571,6 +3587,16 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "optional": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -5145,9 +5171,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index 7aba938..a53cb15 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,14 @@ "@actions/core": "^1.2.3", "@actions/exec": "^1.0.4", "@actions/github": "^2.1.1", - "openpgp": "^4.10.4" + "openpgp": "^4.10.4", + "which": "^2.0.2" }, "devDependencies": { "@types/jest": "^25.2.1", "@types/node": "^13.13.4", "@types/openpgp": "^4.4.10", + "@types/which": "^1.3.2", "@zeit/ncc": "^0.22.1", "jest": "^25.5.4", "jest-circus": "^25.5.4", diff --git a/src/gpg.ts b/src/gpg.ts index 6398890..71e188a 100644 --- a/src/gpg.ts +++ b/src/gpg.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as exec from './exec'; +import which from 'which'; export const agentConfig = `default-cache-ttl 7200 max-cache-ttl 31536000 @@ -20,9 +21,17 @@ export interface Dirs { } const getGpgPresetPassphrasePath = async (): Promise => { - const {libexecdir: libexecdir} = await getDirs(); + let gpgPresetPassphrasePath: string; - let gpgPresetPassphrasePath = path.join(libexecdir, 'gpg-preset-passphrase'); + gpgPresetPassphrasePath = await which('gpg-preset-passphrase').then(resolvedPath => { + return resolvedPath; + }); + if (gpgPresetPassphrasePath != '') { + return gpgPresetPassphrasePath; + } + + const {libexecdir: libexecdir} = await getDirs(); + gpgPresetPassphrasePath = path.join(libexecdir, 'gpg-preset-passphrase'); if (await fs.existsSync(gpgPresetPassphrasePath)) { return gpgPresetPassphrasePath; } @@ -163,8 +172,8 @@ export const configureAgent = async (config: string): Promise => { export const presetPassphrase = async (keygrip: string, passphrase: string): Promise => { await exec .exec( - await getGpgPresetPassphrasePath(), - ['--verbose', '--preset', '--passphrase', `"${passphrase}"`, keygrip], + `"${await getGpgPresetPassphrasePath()}" --verbose --preset --passphrase "${passphrase}" ${keygrip}`, + [], true ) .then(res => {