mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
101 lines
2.4 KiB
JavaScript
101 lines
2.4 KiB
JavaScript
import { auditChanges } from "./audit/index.js";
|
|
import { getScanTimeout } from "../config/configFile.js";
|
|
import { setTimeout } from "timers/promises";
|
|
import chalk from "chalk";
|
|
import { getPackageManager } from "../packagemanager/currentPackageManager.js";
|
|
import { ui } from "../environment/userInteraction.js";
|
|
|
|
/**
|
|
* @param {string[]} args
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
export function shouldScanCommand(args) {
|
|
if (!args || args.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
return getPackageManager().isSupportedCommand(args);
|
|
}
|
|
|
|
/**
|
|
* @param {string[]} args
|
|
*
|
|
* @returns {Promise<number | never[]>}
|
|
*/
|
|
export async function scanCommand(args) {
|
|
if (!shouldScanCommand(args)) {
|
|
return [];
|
|
}
|
|
|
|
let timedOut = false;
|
|
|
|
const spinner = ui.startProcess(
|
|
"Safe-chain: Scanning for malicious packages..."
|
|
);
|
|
/** @type {import("./audit/index.js").AuditResult | undefined} */
|
|
let audit;
|
|
|
|
await Promise.race([
|
|
(async () => {
|
|
try {
|
|
const packageManager = getPackageManager();
|
|
const changes = await packageManager.getDependencyUpdatesForCommand(
|
|
args
|
|
);
|
|
|
|
if (timedOut) {
|
|
return;
|
|
}
|
|
|
|
if (changes.length > 0) {
|
|
spinner.setText(
|
|
`Safe-chain: Scanning ${changes.length} package(s)...`
|
|
);
|
|
}
|
|
|
|
audit = await auditChanges(changes);
|
|
} catch (/** @type any */ error) {
|
|
spinner.fail(`Safe-chain: Error while scanning.`);
|
|
throw error;
|
|
}
|
|
})(),
|
|
setTimeout(getScanTimeout()).then(() => {
|
|
timedOut = true;
|
|
}),
|
|
]);
|
|
|
|
if (timedOut) {
|
|
spinner.fail("Safe-chain: Timeout exceeded while scanning.");
|
|
throw new Error("Timeout exceeded while scanning npm install command.");
|
|
}
|
|
|
|
if (!audit || audit.isAllowed) {
|
|
spinner.stop();
|
|
return 0;
|
|
} else {
|
|
printMaliciousChanges(audit.disallowedChanges, spinner);
|
|
onMalwareFound();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {import("./audit/index.js").PackageChange[]} changes
|
|
* @param spinner {import("../environment/userInteraction.js").Spinner}
|
|
*
|
|
* @return {void}
|
|
*/
|
|
function printMaliciousChanges(changes, spinner) {
|
|
spinner.fail("Safe-chain: " + chalk.bold("Malicious changes detected:"));
|
|
|
|
for (const change of changes) {
|
|
ui.writeInformation(` - ${change.name}@${change.version}`);
|
|
}
|
|
}
|
|
|
|
function onMalwareFound() {
|
|
ui.emptyLine();
|
|
ui.writeExitWithoutInstallingMaliciousPackages();
|
|
ui.emptyLine();
|
|
}
|