UNPKG

admina

Version:

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

78 lines 8.68 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, quote(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, quote(args), execOptions); } } function getSudoCommand(program, args) { return `sudo ${quote([program, ...args]).join(" ")}`; } function quote(strings) { return strings.map((str) => `'${str}'`); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9vdC5tanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcm9vdC5tdHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFBO0FBQ3pCLE9BQU8sRUFDTCxLQUFLLEVBQ0wsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixTQUFTLEdBS1YsTUFBTSxPQUFPLENBQUE7QUFFZCxrQ0FBa0M7QUFDbEMsTUFBTSxVQUFVLE9BQU87SUFDckIsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxLQUFLLElBQUksQ0FBQTtBQUN2RCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxNQUFNO0lBQ3BCLG1DQUFtQztJQUNuQyxPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUM1RCxDQUFDO0FBRUQsbUVBQW1FO0FBQ25FLE1BQU0sVUFBVSxNQUFNO0lBQ3BCLE9BQU8sTUFBTSxFQUFFLElBQUksT0FBTyxFQUFFLENBQUE7QUFDOUIsQ0FBQztBQUVELHlEQUF5RDtBQUN6RCxNQUFNLFVBQVUsV0FBVyxDQUFDLE9BQWU7SUFDekMsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ2IsT0FBTyxRQUFRLE9BQU8sRUFBRSxDQUFBO0lBQzFCLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQTtBQUNoQixDQUFDO0FBRUQsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFxQixFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFBO0FBRXJGOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUMxQixPQUFlLEVBQ2YsT0FBaUIsRUFBRSxFQUNuQixjQUFnQyxrQkFBa0I7SUFFbEQsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ2IsTUFBTSxPQUFPLEdBQUcsY0FBYyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQTtRQUM3QyxPQUFPLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQTtJQUMvQyxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sU0FBUyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDckQsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FDdEIsT0FBZSxFQUNmLE9BQWlCLEVBQUUsRUFDbkIsY0FBNEIsa0JBQWtCO0lBRTlDLElBQUksTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUNiLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDN0MsT0FBTyxZQUFZLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBQzNDLENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxXQUFXLENBQUMsQ0FBQTtJQUNqRCxDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLE9BQWUsRUFBRSxJQUFjO0lBQ3JELE9BQU8sUUFBUSxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFBO0FBQ3RELENBQUM7QUFFRCxTQUFTLEtBQUssQ0FBQyxPQUFpQjtJQUM5QixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQTtBQUN6QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHdoaWNoIGZyb20gXCJ3aGljaFwiXG5pbXBvcnQge1xuICBleGVjYSxcbiAgZXhlY2FDb21tYW5kLFxuICBleGVjYUNvbW1hbmRTeW5jLFxuICBleGVjYVN5bmMsXG4gIFN5bmNPcHRpb25zIGFzIEV4ZWNhU3luY09wdGlvbnMsXG4gIEV4ZWNhU3luY1JldHVyblZhbHVlLFxuICBPcHRpb25zIGFzIEV4ZWNhT3B0aW9ucyxcbiAgRXhlY2FDaGlsZFByb2Nlc3MsXG59IGZyb20gXCJleGVjYVwiXG5cbi8qKiBEZXRlY3QgaWYgc3VkbyBpcyBhdmFpbGFibGUgKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTdWRvKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gd2hpY2guc3luYyhcInN1ZG9cIiwgeyBub3Rocm93OiB0cnVlIH0pICE9PSBudWxsXG59XG5cbi8qKlxuICogRGV0ZWN0IGlmIHRoZSBwcm9jZXNzIGhhcyByb290IHByaXZpbGVnZSBvbiBQb3NpeC5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYGpzXG4gKiBpbXBvcnQgeyBpc1Jvb3QgfSBmcm9tIFwiYWRtaW5hXCJcbiAqXG4gKiBjb25zb2xlLmxvZyhpc1Jvb3QoKSlcbiAqIC8vPT4gZmFsc2VcbiAqIGBgYFxuICpcbiAqIEByZXR1cm5zIFdoZXRoZXIgdGhlIHByb2Nlc3MgaXMgcnVubmluZyBhcyByb290LlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNSb290KCk6IGJvb2xlYW4ge1xuICAvLyBUT0RPIG5vdCBhbGwgQ0kgc3lzdGVtcyBhcmUgcm9vdFxuICByZXR1cm4gcHJvY2Vzcy5nZXR1aWQ/LigpID09PSAwIHx8IEJvb2xlYW4ocHJvY2Vzcy5lbnYuQ0kpXG59XG5cbi8qKiBEZXRlY3QgaWYgc3VkbyBpcyBhdmFpbGFibGUgYW5kIHRoZSB1c2VyIGhhcyByb290IHByaXZpbGVnZXMgKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1N1ZG8oKTogYm9vbGVhbiB7XG4gIHJldHVybiBpc1Jvb3QoKSAmJiBoYXNTdWRvKClcbn1cblxuLyoqIFByZXBlbmQgYHN1ZG9gIHRvIHRoZSBjb21tYW5kIGlmIHN1ZG8gaXMgYXZhaWxhYmxlICovXG5leHBvcnQgZnVuY3Rpb24gcHJlcGVuZFN1ZG8oY29tbWFuZDogc3RyaW5nKSB7XG4gIGlmIChpc1N1ZG8oKSkge1xuICAgIHJldHVybiBgc3VkbyAke2NvbW1hbmR9YFxuICB9XG4gIHJldHVybiBjb21tYW5kXG59XG5cbi8qKiBEZWZhdWx0IGV4ZWMgb3B0aW9ucyBgeyBzdGRpbzogXCJpbmhlcml0XCIsIHNoZWxsOiB0cnVlIH1gICovXG5leHBvcnQgY29uc3QgZGVmYXVsdEV4ZWNPcHRpb25zOiBFeGVjYVN5bmNPcHRpb25zID0geyBzdGRpbzogXCJpbmhlcml0XCIsIHNoZWxsOiB0cnVlIH1cblxuLyoqXG4gKiBFeGVjdXRlIGEgY29tbWFuZCBhcyByb290IGlmIHN1ZG8gaXMgYXZhaWxhYmxlLiBPdGhlcndpc2UgZXhlY3V0ZXMgdGhlIGNvbW1hbmQgbm9ybWFsbHkgd2l0aG91dCBzdWRvLlxuICpcbiAqIEBwYXJhbSBwcm9ncmFtIFRoZSBwcm9ncmFtIHRvIHNwYXduXG4gKiBAcGFyYW0gYXJncyBUaGUgY29tbWFuZCBhcmd1bWVudHNcbiAqIEBwYXJhbSBleGVjT3B0aW9ucyBUaGUgb3B0aW9ucyBwYXNzZWQgdG8gYGV4ZWNhYC4gRGVmYXVsdHMgdG8gYHsgc3RkaW86IFwiaW5oZXJpdFwiLCBzaGVsbDogdHJ1ZSB9YFxuICogQHJldHVybnMgVGhlIGV4ZWN1dGlvbiByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4ZWNSb290U3luYyhcbiAgcHJvZ3JhbTogc3RyaW5nLFxuICBhcmdzOiBzdHJpbmdbXSA9IFtdLFxuICBleGVjT3B0aW9uczogRXhlY2FTeW5jT3B0aW9ucyA9IGRlZmF1bHRFeGVjT3B0aW9ucyxcbik6IEV4ZWNhU3luY1JldHVyblZhbHVlPHN0cmluZz4ge1xuICBpZiAoaXNTdWRvKCkpIHtcbiAgICBjb25zdCBjb21tYW5kID0gZ2V0U3Vkb0NvbW1hbmQocHJvZ3JhbSwgYXJncylcbiAgICByZXR1cm4gZXhlY2FDb21tYW5kU3luYyhjb21tYW5kLCBleGVjT3B0aW9ucylcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZXhlY2FTeW5jKHByb2dyYW0sIHF1b3RlKGFyZ3MpLCBleGVjT3B0aW9ucylcbiAgfVxufVxuXG4vKipcbiAqIEFzeW5jaHJvbm91c2x5IGV4ZWN1dGUgYSBjb21tYW5kIGFzIHJvb3QgaWYgc3VkbyBpcyBhdmFpbGFibGUuIE90aGVyd2lzZSBleGVjdXRlcyB0aGUgY29tbWFuZCBub3JtYWxseSB3aXRob3V0IHN1ZG8uXG4gKlxuICogQHBhcmFtIHByb2dyYW0gVGhlIHByb2dyYW0gdG8gc3Bhd25cbiAqIEBwYXJhbSBhcmdzIFRoZSBjb21tYW5kIGFyZ3VtZW50c1xuICogQHBhcmFtIGV4ZWNPcHRpb25zIFRoZSBvcHRpb25zIHBhc3NlZCB0byBgZXhlY2FgLiBEZWZhdWx0cyB0byBgeyBzdGRpbzogXCJpbmhlcml0XCIsIHNoZWxsOiB0cnVlIH1gXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdG8gdGhlIGV4ZWN1dGlvbiByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4ZWNSb290KFxuICBwcm9ncmFtOiBzdHJpbmcsXG4gIGFyZ3M6IHN0cmluZ1tdID0gW10sXG4gIGV4ZWNPcHRpb25zOiBFeGVjYU9wdGlvbnMgPSBkZWZhdWx0RXhlY09wdGlvbnMsXG4pOiBFeGVjYUNoaWxkUHJvY2VzczxzdHJpbmc+IHtcbiAgaWYgKGlzU3VkbygpKSB7XG4gICAgY29uc3QgY29tbWFuZCA9IGdldFN1ZG9Db21tYW5kKHByb2dyYW0sIGFyZ3MpXG4gICAgcmV0dXJuIGV4ZWNhQ29tbWFuZChjb21tYW5kLCBleGVjT3B0aW9ucylcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZXhlY2EocHJvZ3JhbSwgcXVvdGUoYXJncyksIGV4ZWNPcHRpb25zKVxuICB9XG59XG5cbmZ1bmN0aW9uIGdldFN1ZG9Db21tYW5kKHByb2dyYW06IHN0cmluZywgYXJnczogc3RyaW5nW10pIHtcbiAgcmV0dXJuIGBzdWRvICR7cXVvdGUoW3Byb2dyYW0sIC4uLmFyZ3NdKS5qb2luKFwiIFwiKX1gXG59XG5cbmZ1bmN0aW9uIHF1b3RlKHN0cmluZ3M6IHN0cmluZ1tdKSB7XG4gIHJldHVybiBzdHJpbmdzLm1hcCgoc3RyKSA9PiBgJyR7c3RyfSdgKVxufVxuIl19