UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

46 lines (45 loc) • 2.19 kB
import { execFile } from 'node:child_process'; import { userInfo } from 'node:os'; import { promisify } from 'node:util'; import { platform } from '../lib/platform.js'; /** * macOS access control lists. An allow entry grants access whatever the mode bits say, and Node's stat can't see * entries, so on darwin the credentials paths are checked with /bin/ls and cleaned with /bin/chmod. Other platforms * have nothing to do: Linux's chmod 0600 masks a default POSIX ACL. */ const run = promisify(execFile); /** * Directory rights that let another user add, remove or replace an entry, remove the directory, or take over its ACL * or ownership (and then grant themselves the rest). The boundaries keep writeattr and writeextattr from matching. */ const CHANGES_ENTRIES = /\b(?:add_file|add_subdirectory|delete_child|delete|write|append|writesecurity|chown)\b/; /** Remove every entry from a path the CLI just created, so it doesn't keep one inherited from its parent. */ export async function stripAcl(path) { if (platform() !== 'darwin') return; await run('/bin/chmod', ['-N', path]); } /** The ACL entries of each path, in order, like ` 0: group:everyone allow read`. Empty off darwin. */ export async function aclEntries(paths) { if (platform() !== 'darwin' || !paths.length) return paths.map(() => []); // -q prints a newline in a name as ?, -f keeps the operands' order. const { stdout } = await run('/bin/ls', ['-ledqf', '--', ...paths]); const entries = []; for (const line of stdout.split('\n')) { if (/^\s*\d+: /.test(line)) entries.at(-1)?.push(line.trim()); else if (line) entries.push([]); } if (entries.length !== paths.length) throw new Error('Unexpected /bin/ls output.'); return entries; } /** Whether an entry lets someone other than the current user change the directory's entries. */ export function letsOthersChangeEntries(entry) { const match = /^\d+: (.+?) (?:inherited )?(allow|deny) (\S+)/.exec(entry); if (!match || match[2] !== 'allow' || !CHANGES_ENTRIES.test(match[3])) return false; return match[1] !== `user:${userInfo().username}`; }