admina
Version:
Detect root/admin/sudo and execute commands as it if available
78 lines • 8.68 kB
JavaScript
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