UNPKG

admina

Version:

Detect root/admin/sudo and execute commands as it if available

89 lines 9.78 kB
import which from "which"; import { execa, execaCommand, execaCommandSync, execaSync, } from "execa"; /** Detect if sudo is available */ export function hasSudo() { return which.sync("sudo", { nothrow: true }) !== null; } /** * Detect if the process has root privilege on Posix. * * @example * * ```js * import { isRoot } from "admina" * * console.log(isRoot()) * //=> false * ``` * * @returns Whether the process is running as root. */ export function isRoot() { // TODO not all CI systems are root return process.getuid?.() === 0 || Boolean(process.env.CI); } /** Detect if sudo is available and the user has root privileges */ export function isSudo() { return isRoot() && hasSudo(); } /** Prepend `sudo` to the command if sudo is available */ export function prependSudo(command) { if (isSudo()) { return `sudo ${command}`; } return command; } /** Default exec options `{ stdio: "inherit", shell: true }` */ export const defaultExecOptions = { stdio: "inherit", shell: true, }; /** * Execute a command as root if sudo is available. Otherwise executes the command normally without sudo. * * @param program The program to spawn * @param args The command arguments * @param execOptions The options passed to `execa`. Defaults to `{ stdio: "inherit", shell: true }` * @returns The execution result */ export function execRootSync(program, args = [], execOptions = defaultExecOptions) { if (isSudo()) { const command = getSudoCommand(program, args); return execaCommandSync(command, execOptions); } else { return execaSync(program, args, execOptions); } } /** * Asynchronously execute a command as root if sudo is available. Otherwise executes the command normally without sudo. * * @param program The program to spawn * @param args The command arguments * @param execOptions The options passed to `execa`. Defaults to `{ stdio: "inherit", shell: true }` * @returns A promise to the execution result */ export function execRoot(program, args = [], execOptions = defaultExecOptions) { if (isSudo()) { const command = getSudoCommand(program, args); return execaCommand(command, execOptions); } else { return execa(program, args, execOptions); } } function getSudoCommand(program, args) { return `sudo ${quote([program, ...args]).join(" ")}`; } function quote(strings) { return strings.map((str) => (isQuoted(str) ? str : `'${str}'`)); } function isQuoted(str) { if (str.length < 2) { return false; } const first = str[0]; const last = str[str.length - 1]; return (first === "'" && last === "'") || (first === '"' && last === '"'); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9vdC5tanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcm9vdC5tdHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFBO0FBQ3pCLE9BQU8sRUFDTCxLQUFLLEVBQ0wsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixTQUFTLEdBS1YsTUFBTSxPQUFPLENBQUE7QUFFZCxrQ0FBa0M7QUFDbEMsTUFBTSxVQUFVLE9BQU87SUFDckIsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxLQUFLLElBQUksQ0FBQTtBQUN2RCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxNQUFNO0lBQ3BCLG1DQUFtQztJQUNuQyxPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUM1RCxDQUFDO0FBRUQsbUVBQW1FO0FBQ25FLE1BQU0sVUFBVSxNQUFNO0lBQ3BCLE9BQU8sTUFBTSxFQUFFLElBQUksT0FBTyxFQUFFLENBQUE7QUFDOUIsQ0FBQztBQUVELHlEQUF5RDtBQUN6RCxNQUFNLFVBQVUsV0FBVyxDQUFDLE9BQWU7SUFDekMsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ2IsT0FBTyxRQUFRLE9BQU8sRUFBRSxDQUFBO0lBQzFCLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQTtBQUNoQixDQUFDO0FBRUQsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFxQjtJQUNsRCxLQUFLLEVBQUUsU0FBUztJQUNoQixLQUFLLEVBQUUsSUFBSTtDQUNaLENBQUE7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FDMUIsT0FBZSxFQUNmLE9BQWlCLEVBQUUsRUFDbkIsY0FBZ0Msa0JBQWtCO0lBRWxELElBQUksTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUNiLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDN0MsT0FBTyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDL0MsQ0FBQztTQUFNLENBQUM7UUFDTixPQUFPLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBQzlDLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxRQUFRLENBQ3RCLE9BQWUsRUFDZixPQUFpQixFQUFFLEVBQ25CLGNBQTRCLGtCQUFrQjtJQUU5QyxJQUFJLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDYixNQUFNLE9BQU8sR0FBRyxjQUFjLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzdDLE9BQU8sWUFBWSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQTtJQUMzQyxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sS0FBSyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDMUMsQ0FBQztBQUNILENBQUM7QUFFRCxTQUFTLGNBQWMsQ0FBQyxPQUFlLEVBQUUsSUFBYztJQUNyRCxPQUFPLFFBQVEsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQTtBQUN0RCxDQUFDO0FBRUQsU0FBUyxLQUFLLENBQUMsT0FBaUI7SUFDOUIsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQTtBQUNqRSxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsR0FBVztJQUMzQixJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDbkIsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ3BCLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFBO0lBQ2hDLE9BQU8sQ0FBQyxLQUFLLEtBQUssR0FBRyxJQUFJLElBQUksS0FBSyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxHQUFHLElBQUksSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFBO0FBQzNFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgd2hpY2ggZnJvbSBcIndoaWNoXCJcbmltcG9ydCB7XG4gIGV4ZWNhLFxuICBleGVjYUNvbW1hbmQsXG4gIGV4ZWNhQ29tbWFuZFN5bmMsXG4gIGV4ZWNhU3luYyxcbiAgdHlwZSBTeW5jT3B0aW9ucyBhcyBFeGVjYVN5bmNPcHRpb25zLFxuICB0eXBlIEV4ZWNhU3luY1JldHVyblZhbHVlLFxuICB0eXBlIE9wdGlvbnMgYXMgRXhlY2FPcHRpb25zLFxuICB0eXBlIEV4ZWNhQ2hpbGRQcm9jZXNzLFxufSBmcm9tIFwiZXhlY2FcIlxuXG4vKiogRGV0ZWN0IGlmIHN1ZG8gaXMgYXZhaWxhYmxlICovXG5leHBvcnQgZnVuY3Rpb24gaGFzU3VkbygpOiBib29sZWFuIHtcbiAgcmV0dXJuIHdoaWNoLnN5bmMoXCJzdWRvXCIsIHsgbm90aHJvdzogdHJ1ZSB9KSAhPT0gbnVsbFxufVxuXG4vKipcbiAqIERldGVjdCBpZiB0aGUgcHJvY2VzcyBoYXMgcm9vdCBwcml2aWxlZ2Ugb24gUG9zaXguXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogaW1wb3J0IHsgaXNSb290IH0gZnJvbSBcImFkbWluYVwiXG4gKlxuICogY29uc29sZS5sb2coaXNSb290KCkpXG4gKiAvLz0+IGZhbHNlXG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJucyBXaGV0aGVyIHRoZSBwcm9jZXNzIGlzIHJ1bm5pbmcgYXMgcm9vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUm9vdCgpOiBib29sZWFuIHtcbiAgLy8gVE9ETyBub3QgYWxsIENJIHN5c3RlbXMgYXJlIHJvb3RcbiAgcmV0dXJuIHByb2Nlc3MuZ2V0dWlkPy4oKSA9PT0gMCB8fCBCb29sZWFuKHByb2Nlc3MuZW52LkNJKVxufVxuXG4vKiogRGV0ZWN0IGlmIHN1ZG8gaXMgYXZhaWxhYmxlIGFuZCB0aGUgdXNlciBoYXMgcm9vdCBwcml2aWxlZ2VzICovXG5leHBvcnQgZnVuY3Rpb24gaXNTdWRvKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gaXNSb290KCkgJiYgaGFzU3VkbygpXG59XG5cbi8qKiBQcmVwZW5kIGBzdWRvYCB0byB0aGUgY29tbWFuZCBpZiBzdWRvIGlzIGF2YWlsYWJsZSAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZXBlbmRTdWRvKGNvbW1hbmQ6IHN0cmluZykge1xuICBpZiAoaXNTdWRvKCkpIHtcbiAgICByZXR1cm4gYHN1ZG8gJHtjb21tYW5kfWBcbiAgfVxuICByZXR1cm4gY29tbWFuZFxufVxuXG4vKiogRGVmYXVsdCBleGVjIG9wdGlvbnMgYHsgc3RkaW86IFwiaW5oZXJpdFwiLCBzaGVsbDogdHJ1ZSB9YCAqL1xuZXhwb3J0IGNvbnN0IGRlZmF1bHRFeGVjT3B0aW9uczogRXhlY2FTeW5jT3B0aW9ucyA9IHtcbiAgc3RkaW86IFwiaW5oZXJpdFwiLFxuICBzaGVsbDogdHJ1ZSxcbn1cblxuLyoqXG4gKiBFeGVjdXRlIGEgY29tbWFuZCBhcyByb290IGlmIHN1ZG8gaXMgYXZhaWxhYmxlLiBPdGhlcndpc2UgZXhlY3V0ZXMgdGhlIGNvbW1hbmQgbm9ybWFsbHkgd2l0aG91dCBzdWRvLlxuICpcbiAqIEBwYXJhbSBwcm9ncmFtIFRoZSBwcm9ncmFtIHRvIHNwYXduXG4gKiBAcGFyYW0gYXJncyBUaGUgY29tbWFuZCBhcmd1bWVudHNcbiAqIEBwYXJhbSBleGVjT3B0aW9ucyBUaGUgb3B0aW9ucyBwYXNzZWQgdG8gYGV4ZWNhYC4gRGVmYXVsdHMgdG8gYHsgc3RkaW86IFwiaW5oZXJpdFwiLCBzaGVsbDogdHJ1ZSB9YFxuICogQHJldHVybnMgVGhlIGV4ZWN1dGlvbiByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4ZWNSb290U3luYyhcbiAgcHJvZ3JhbTogc3RyaW5nLFxuICBhcmdzOiBzdHJpbmdbXSA9IFtdLFxuICBleGVjT3B0aW9uczogRXhlY2FTeW5jT3B0aW9ucyA9IGRlZmF1bHRFeGVjT3B0aW9ucyxcbik6IEV4ZWNhU3luY1JldHVyblZhbHVlPHN0cmluZz4ge1xuICBpZiAoaXNTdWRvKCkpIHtcbiAgICBjb25zdCBjb21tYW5kID0gZ2V0U3Vkb0NvbW1hbmQocHJvZ3JhbSwgYXJncylcbiAgICByZXR1cm4gZXhlY2FDb21tYW5kU3luYyhjb21tYW5kLCBleGVjT3B0aW9ucylcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZXhlY2FTeW5jKHByb2dyYW0sIGFyZ3MsIGV4ZWNPcHRpb25zKVxuICB9XG59XG5cbi8qKlxuICogQXN5bmNocm9ub3VzbHkgZXhlY3V0ZSBhIGNvbW1hbmQgYXMgcm9vdCBpZiBzdWRvIGlzIGF2YWlsYWJsZS4gT3RoZXJ3aXNlIGV4ZWN1dGVzIHRoZSBjb21tYW5kIG5vcm1hbGx5IHdpdGhvdXQgc3Vkby5cbiAqXG4gKiBAcGFyYW0gcHJvZ3JhbSBUaGUgcHJvZ3JhbSB0byBzcGF3blxuICogQHBhcmFtIGFyZ3MgVGhlIGNvbW1hbmQgYXJndW1lbnRzXG4gKiBAcGFyYW0gZXhlY09wdGlvbnMgVGhlIG9wdGlvbnMgcGFzc2VkIHRvIGBleGVjYWAuIERlZmF1bHRzIHRvIGB7IHN0ZGlvOiBcImluaGVyaXRcIiwgc2hlbGw6IHRydWUgfWBcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0byB0aGUgZXhlY3V0aW9uIHJlc3VsdFxuICovXG5leHBvcnQgZnVuY3Rpb24gZXhlY1Jvb3QoXG4gIHByb2dyYW06IHN0cmluZyxcbiAgYXJnczogc3RyaW5nW10gPSBbXSxcbiAgZXhlY09wdGlvbnM6IEV4ZWNhT3B0aW9ucyA9IGRlZmF1bHRFeGVjT3B0aW9ucyxcbik6IEV4ZWNhQ2hpbGRQcm9jZXNzPHN0cmluZz4ge1xuICBpZiAoaXNTdWRvKCkpIHtcbiAgICBjb25zdCBjb21tYW5kID0gZ2V0U3Vkb0NvbW1hbmQocHJvZ3JhbSwgYXJncylcbiAgICByZXR1cm4gZXhlY2FDb21tYW5kKGNvbW1hbmQsIGV4ZWNPcHRpb25zKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBleGVjYShwcm9ncmFtLCBhcmdzLCBleGVjT3B0aW9ucylcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRTdWRvQ29tbWFuZChwcm9ncmFtOiBzdHJpbmcsIGFyZ3M6IHN0cmluZ1tdKSB7XG4gIHJldHVybiBgc3VkbyAke3F1b3RlKFtwcm9ncmFtLCAuLi5hcmdzXSkuam9pbihcIiBcIil9YFxufVxuXG5mdW5jdGlvbiBxdW90ZShzdHJpbmdzOiBzdHJpbmdbXSkge1xuICByZXR1cm4gc3RyaW5ncy5tYXAoKHN0cikgPT4gKGlzUXVvdGVkKHN0cikgPyBzdHIgOiBgJyR7c3RyfSdgKSlcbn1cblxuZnVuY3Rpb24gaXNRdW90ZWQoc3RyOiBzdHJpbmcpIHtcbiAgaWYgKHN0ci5sZW5ndGggPCAyKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbiAgY29uc3QgZmlyc3QgPSBzdHJbMF1cbiAgY29uc3QgbGFzdCA9IHN0cltzdHIubGVuZ3RoIC0gMV1cbiAgcmV0dXJuIChmaXJzdCA9PT0gXCInXCIgJiYgbGFzdCA9PT0gXCInXCIpIHx8IChmaXJzdCA9PT0gJ1wiJyAmJiBsYXN0ID09PSAnXCInKVxufVxuIl19