owasp-dependency-check
Version:
A Node.js wrapper for the OWASP dependency-check-cli.
80 lines (79 loc) • 3.49 kB
JavaScript
import { cleanDir, log, unzipFileIntoDirectory } from "./utils.js";
import { Maybe } from "purify-ts";
import path from "path";
import fs from "fs";
import os from "os";
import { fetch, ProxyAgent } from "undici";
import fsp from "node:fs/promises";
const NAME_RE = /^dependency-check-\d+\.\d+\.\d+-release\.zip$/;
const LATEST_RELEASE_URL = "https://api.github.com/repos/dependency-check/DependencyCheck/releases/latest";
const TAG_RELEASE_URL = "https://api.github.com/repos/dependency-check/DependencyCheck/releases/tags/";
const IS_WIN = os.platform() === "win32";
function findOwaspExecutable(installDir) {
const executable = path.resolve(installDir, "dependency-check", "bin", `dependency-check.${IS_WIN ? "bat" : "sh"}`);
return Maybe.fromNullable(fs.existsSync(executable) ? executable : undefined);
}
async function findReleaseInfo(odcVersion, proxyUrl, githubToken) {
const url = odcVersion.mapOrDefault((value) => {
return TAG_RELEASE_URL + value;
}, LATEST_RELEASE_URL);
log(`Fetching release information from ${url}`);
const res = await fetch(url, createRequestInit(proxyUrl, githubToken));
if (!res.ok) {
throw new Error(`Could not fetch release from GitHub: URL: ${url} Status: ${res.statusText}`);
}
return (await res.json());
}
function findDownloadAsset(release) {
const asset = release.assets.find((a) => NAME_RE.test(a.name));
if (!asset) {
throw new Error(`Could not find asset for version ${release.tag_name}`);
}
return asset;
}
async function downloadRelease(url, name, installDir, proxyUrl) {
log(`Downloading dependency check from ${url}...`);
const response = await fetch(url, createRequestInit(proxyUrl, Maybe.empty()));
const filepath = path.resolve(installDir, name);
if (response.body) {
await fsp.writeFile(filepath, response.body);
log("Download done.");
return filepath;
}
else {
throw new Error(`Download failed from ${url}`);
}
}
function createRequestInit(proxyUrl, githubToken) {
const init = {};
proxyUrl.ifJust((proxyUrl) => {
init.dispatcher = new ProxyAgent(proxyUrl.toString());
});
githubToken.ifJust((token) => {
init.headers = {
Authorization: `Bearer ${token}`,
};
});
return init;
}
async function installRelease(release, installDir, proxyUrl) {
log(`Installing dependency check ${release.tag_name}...`);
await cleanDir(installDir);
const asset = findDownloadAsset(release);
const filePath = await downloadRelease(asset.browser_download_url, asset.name, installDir, proxyUrl);
await unzipFileIntoDirectory(filePath, installDir, true);
return findOwaspExecutable(installDir).orDefaultLazy(() => {
throw new Error(`Could not find Dependency-Check Core executable in ${installDir}`);
});
}
export async function installDependencyCheck(binDir, odcVersion, proxyUrl, githubToken, forceInstall) {
const release = await findReleaseInfo(odcVersion, proxyUrl, githubToken);
log(`Found release ${release.tag_name} on GitHub.`);
const installDir = path.resolve(binDir, release.tag_name);
const executable = findOwaspExecutable(installDir).filter(() => !forceInstall);
if (executable.isJust()) {
log(`Using already installed dependency check at "${executable.unsafeCoerce()}".`);
return executable.unsafeCoerce();
}
return await installRelease(release, installDir, proxyUrl);
}