@vigilbase/cli
Version:
Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.
113 lines (112 loc) • 4.07 kB
JavaScript
import { spawn, spawnSync } from 'node:child_process';
import { validateOneOrigin } from './config.js';
/** Stripe Customer Portal uses this exact host; never trust a returned URL by type alone. */
export function validateStripePortalUrl(raw) {
if (typeof raw !== 'string' || /[\u0000-\u0020\u007f-\u009f]/.test(raw)) {
throw new Error('Billing portal returned an invalid Stripe URL.');
}
let url;
try {
url = new URL(raw);
}
catch {
throw new Error('Billing portal returned an invalid Stripe URL.');
}
if (url.protocol !== 'https:' || url.hostname !== 'billing.stripe.com' || url.port || url.username || url.password || url.hash) {
throw new Error('Billing portal URL must be an approved HTTPS Stripe URL.');
}
return url.href;
}
/**
* Detect environments where opening a GUI browser is impossible/undesirable.
*/
export function isHeadlessEnvironment(env = process.env) {
if (env.VIGILBASE_CLI_NO_OPEN === '1')
return true;
if (env.CI === '1' || env.CI === 'true')
return true;
if (env.GITHUB_ACTIONS === 'true')
return true;
if (process.platform === 'linux' && !env.DISPLAY && !env.WAYLAND_DISPLAY) {
return true;
}
return false;
}
function commandExists(command) {
if (process.platform === 'win32') {
const result = spawnSync('where', [command], { encoding: 'utf8' });
return result.status === 0;
}
const result = spawnSync('sh', ['-c', `command -v ${JSON.stringify(command)}`], {
encoding: 'utf8',
});
return result.status === 0;
}
function launch(command, args) {
if (!commandExists(command))
return false;
try {
const child = spawn(command, args, { detached: true, stdio: 'ignore' });
child.on('error', () => undefined);
child.unref();
return true;
}
catch {
return false;
}
}
/**
* Best-effort open of a URL in the user's default browser.
*/
export function openUrlInBrowser(url, env = process.env) {
if (env.VIGILBASE_CLI_NO_OPEN === '1') {
return { isOpened: false, reason: 'disabled' };
}
if (isHeadlessEnvironment(env)) {
return { isOpened: false, reason: 'headless' };
}
const platform = process.platform;
if (platform === 'darwin') {
return launch('open', [url])
? { isOpened: true }
: { isOpened: false, reason: 'failed' };
}
if (platform === 'win32') {
// Shell URL launchers interpret metacharacters. Print the URL for manual opening.
return { isOpened: false, reason: 'unsupported' };
}
if (platform === 'linux') {
for (const [cmd, args] of [
['xdg-open', [url]],
['gio', ['open', url]],
['sensible-browser', [url]],
['wslview', [url]],
]) {
if (launch(cmd, [...args]))
return { isOpened: true };
}
return { isOpened: false, reason: 'failed' };
}
return { isOpened: false, reason: 'unsupported' };
}
/**
* Build the device-auth verification URL on the configured One origin.
* Ignores a mis-reported host so `vigilbase login` always opens Vigilbase One.
*/
/** Format user codes like ABCD-EFGH for easier reading aloud. */
export function formatUserCode(code) {
const compact = code.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
if (compact.length === 8) {
return `${compact.slice(0, 4)}-${compact.slice(4)}`;
}
return compact || code;
}
export function resolveDeviceVerificationUrl(oneBaseUrl, device) {
const base = validateOneOrigin(oneBaseUrl);
// Always pass the hyphenated code so the One UI can show ABCD-EFGH.
const prettyCode = formatUserCode(device.user_code);
const fallback = `${base}/device?user_code=${encodeURIComponent(prettyCode)}`;
// One's verification page is fixed. Never print/open server-controlled userinfo,
// redirect parameters, fragments, or paths, even when they share One's origin.
return fallback;
}