@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
JavaScript
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;
;