UNPKG

@soos-io/api-client

Version:

This is the SOOS API Client for registered clients leveraging the various integrations to the SOOS platform. Register for a free trial today at https://app.soos.io/register

212 lines (211 loc) 9.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isScanDone = exports.StringUtilities = exports.DateUtilities = exports.getEnumOptions = exports.getAnalysisExitCodeWithMessage = exports.generateFileHash = exports.formatBytes = exports.getEnvVariable = exports.convertStringToBase64 = exports.reassembleCommandLine = exports.obfuscateCommandLine = exports.obfuscateProperties = exports.isUrlAvailable = exports.sleep = exports.ensureEnumValue = exports.ensureValue = exports.isNil = exports.generatedScanTypes = void 0; const tslib_1 = require("tslib"); const axios_1 = tslib_1.__importStar(require("axios")); const SOOSLogger_1 = require("./logging/SOOSLogger"); const enums_1 = require("./enums"); const fs_1 = tslib_1.__importDefault(require("fs")); const node_crypto_1 = tslib_1.__importDefault(require("node:crypto")); const generatedScanTypes = [enums_1.ScanType.CSA, enums_1.ScanType.SBOM, enums_1.ScanType.SCA]; exports.generatedScanTypes = generatedScanTypes; const isNil = (value) => value === null || value === undefined; exports.isNil = isNil; const ensureValue = (value, propertyName) => { if (isNil(value)) throw new Error(`'${propertyName}' is required.`); return value; }; exports.ensureValue = ensureValue; const getEnumOptions = (enumObject, excludeDefault) => { const options = Object.entries(enumObject); return excludeDefault === undefined ? options : options.filter((o) => o.at(0) !== excludeDefault); }; exports.getEnumOptions = getEnumOptions; const ensureEnumValue = (enumObject, inputValue, parameterName, excludeDefault, ignoreCase = true) => { if (isNil(inputValue)) { return undefined; } const options = getEnumOptions(enumObject, excludeDefault); const option = options.find(([, value]) => { const stringValue = value.toLocaleString(); return ignoreCase ? stringValue.toLocaleLowerCase() === inputValue.toLocaleLowerCase() : stringValue === inputValue; }); if (isNil(option)) { throw new Error(`Invalid value '${inputValue}' for ${parameterName ? `'${parameterName}'` : "parameter"}. Valid options are: ${options.map(([, value]) => value).join(", ")}.`); } const [key] = option; return enumObject[key]; }; exports.ensureEnumValue = ensureEnumValue; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); exports.sleep = sleep; const isUrlAvailable = async (url) => { const delay = 5000; const maxAttempts = 5; let attempts = 0; while (attempts < maxAttempts) { try { SOOSLogger_1.soosLogger.info(`Attempt ${attempts + 1} of ${maxAttempts}...`); const response = await axios_1.default.get(url); if (response.status >= 200 && response.status < 300) { return true; } } catch (error) { if (error instanceof axios_1.AxiosError) { SOOSLogger_1.soosLogger.info(error); if (error.response && error.response.status < 500) { return true; } } attempts++; if (attempts < maxAttempts) await sleep(delay); } } return false; }; exports.isUrlAvailable = isUrlAvailable; const obfuscateProperties = (dictionary, properties, replacement = "*********") => { return Object.entries(dictionary).reduce((accumulator, [key, value]) => { return { ...accumulator, [key]: properties.includes(key) ? replacement : value, }; }, {}); }; exports.obfuscateProperties = obfuscateProperties; const obfuscateCommandLine = (input, argumentsToObfuscate, replacement = "*********") => { const args = input.match(/(--\w+(?:="[^"]+"|=\S+)?|--\w+|"[^"]+"|\S+)/g) || []; const loweredArgumentsToObfuscate = argumentsToObfuscate.map((a) => a.toLocaleLowerCase()); let obfuscating = false; return args .map((arg) => { if (arg.startsWith("--")) { const [key, value] = arg.includes("=") ? arg.split("=") : [arg, undefined]; if (loweredArgumentsToObfuscate.find((a) => a === key.toLocaleLowerCase())) { return value === undefined ? ((obfuscating = true), key) : `${key}=${replacement}`; } obfuscating = false; } if (obfuscating) { obfuscating = false; return replacement; } return arg; }) .join(" "); }; exports.obfuscateCommandLine = obfuscateCommandLine; const reassembleCommandLine = (argv) => { const escapeQuotes = (s) => s.replace(/"/g, '\\"'); return argv .map((arg) => { const [key, value] = arg.split("=", 2); const needsQuotes = /[\s"']/.test(value ?? arg); if (value !== undefined) { return `${key} ${needsQuotes ? `"${escapeQuotes(value)}"` : value}`; } return needsQuotes ? `"${escapeQuotes(arg)}"` : arg; }) .join(" "); }; exports.reassembleCommandLine = reassembleCommandLine; const convertStringToBase64 = (content) => { const messageBytes = Buffer.from(content, "utf-8"); const base64Message = messageBytes.toString("base64"); return base64Message; }; exports.convertStringToBase64 = convertStringToBase64; const getEnvVariable = (name) => { return process.env[name] || null; }; exports.getEnvVariable = getEnvVariable; const formatBytes = (bytes, decimals = 2) => { if (bytes === 0) return "0 Bytes"; const kilobyte = 1024; const fractionalDigits = decimals < 0 ? 0 : decimals; const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const exponentialValue = Math.floor(Math.log(bytes) / Math.log(kilobyte)); const count = Number.parseFloat((bytes / Math.pow(kilobyte, exponentialValue)).toFixed(fractionalDigits)); const unit = sizes[exponentialValue]; return `${count} ${unit}`; }; exports.formatBytes = formatBytes; const generateFileHash = (hashAlgorithm, encoding, digestEncoding, filePath) => { const bufferEncoding = encoding.toLowerCase(); const binaryToTextEncoding = digestEncoding.toLowerCase(); const fileContent = fs_1.default.readFileSync(filePath, bufferEncoding); return node_crypto_1.default .createHash(hashAlgorithm) .update(fileContent, bufferEncoding) .digest(binaryToTextEncoding); }; exports.generateFileHash = generateFileHash; const isScanDone = (scanStatus) => [enums_1.ScanStatus.Finished, enums_1.ScanStatus.FailedWithIssues, enums_1.ScanStatus.Incomplete, enums_1.ScanStatus.Error].some((s) => s === scanStatus); exports.isScanDone = isScanDone; const getAnalysisExitCodeWithMessage = (scanStatus, integrationName, onFailure) => { if (scanStatus === enums_1.ScanStatus.FailedWithIssues) { return { exitCode: onFailure === enums_1.OnFailure.Fail ? 1 : integrationName === enums_1.IntegrationName.AzureDevOps ? 2 : 0, message: "Analysis Complete. Issues reported.", }; } else if (scanStatus === enums_1.ScanStatus.Incomplete) { return { exitCode: onFailure === enums_1.OnFailure.Fail ? 1 : integrationName === enums_1.IntegrationName.AzureDevOps ? 2 : 0, message: "Analysis Incomplete. It may have been cancelled or superseded by another scan.", }; } else if (scanStatus === enums_1.ScanStatus.Error) { return { exitCode: onFailure === enums_1.OnFailure.Fail ? 1 : 0, message: "Analysis Error. Please check the logs and/or set the logLevel to DEBUG for more information.", }; } return { exitCode: 0, message: "Analysis Complete.", }; }; exports.getAnalysisExitCodeWithMessage = getAnalysisExitCodeWithMessage; const DateUtilities = { getDate: (daysAgo = 0) => { const date = new Date(); date.setDate(date.getDate() - daysAgo); return date; }, getDateFromUnixUTC: (unixUTC) => { return new Date(unixUTC * 1000); }, isWithinDateRange(date, minDate) { return date >= minDate; }, }; exports.DateUtilities = DateUtilities; const StringUtilities = { pluralizeWord: (count, singular, plural = `${singular}s`) => { return count === 1 ? singular : plural; }, pluralizeTemplate: (count, singular, plural = `${singular}s`) => { const word = StringUtilities.pluralizeWord(count, singular, plural); return `${count ?? 0} ${word}`; }, fromCamelToTitleCase: (str) => { const words = str.split(/(?<=[a-z])(?=[A-Z])/g).map((word) => { return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); }); return words.join(" "); }, areEqual: (a, b, options) => { return a.localeCompare(b, options?.locales, options) === 0; }, isEmptyString: (value) => { return value.trim() === ""; }, }; exports.StringUtilities = StringUtilities;