Make sure we use a different version.txt to prevent having to redownload DB

This commit is contained in:
Reinier Criel 2025-10-24 09:59:53 -07:00
parent b5988e19c1
commit 15785fad73
4 changed files with 28 additions and 22 deletions

View file

@ -3,22 +3,13 @@ import { getEcoSystem } from "../config/settings.js";
const malwareDatabaseUrls = { const malwareDatabaseUrls = {
js: "https://malware-list.aikido.dev/malware_predictions.json", js: "https://malware-list.aikido.dev/malware_predictions.json",
py: "https://malware-list.aikido.dev/malware_predictions_python.json", py: "https://malware-list.aikido.dev/malware_pypi.json",
}; };
export async function fetchMalwareDatabase() { export async function fetchMalwareDatabase() {
const ecosystem = getEcoSystem() || "js"; const ecosystem = getEcoSystem() || "js";
const malwareDatabaseUrl = malwareDatabaseUrls[ecosystem]; const malwareDatabaseUrl = malwareDatabaseUrls[ecosystem];
const response = await fetch(malwareDatabaseUrl); const response = await fetch(malwareDatabaseUrl);
// Python malware database doesn't exist yet, return empty database
if (!response.ok && ecosystem === "py" && response.status === 403) {
return {
malwareDatabase: [],
version: undefined,
};
}
if (!response.ok) { if (!response.ok) {
throw new Error(`Error fetching ${ecosystem} malware database: ${response.statusText}`); throw new Error(`Error fetching ${ecosystem} malware database: ${response.statusText}`);
} }
@ -41,12 +32,7 @@ export async function fetchMalwareDatabaseVersion() {
const response = await fetch(malwareDatabaseUrl, { const response = await fetch(malwareDatabaseUrl, {
method: "HEAD", method: "HEAD",
}); });
// Python malware database doesn't exist yet, return undefined
if (!response.ok && ecosystem === "py" && response.status === 403) {
return undefined;
}
if (!response.ok) { if (!response.ok) {
throw new Error( throw new Error(
`Error fetching ${ecosystem} malware database version: ${response.statusText}` `Error fetching ${ecosystem} malware database version: ${response.statusText}`

View file

@ -2,6 +2,7 @@ import fs from "fs";
import path from "path"; import path from "path";
import os from "os"; import os from "os";
import { ui } from "../environment/userInteraction.js"; import { ui } from "../environment/userInteraction.js";
import { getEcoSystem } from "./settings.js";
export function getScanTimeout() { export function getScanTimeout() {
const config = readConfigFile(); const config = readConfigFile();
@ -68,12 +69,14 @@ function readConfigFile() {
function getDatabasePath() { function getDatabasePath() {
const aikidoDir = getAikidoDirectory(); const aikidoDir = getAikidoDirectory();
return path.join(aikidoDir, "malwareDatabase.json"); const ecosystem = getEcoSystem() || "js";
return path.join(aikidoDir, `malwareDatabase_${ecosystem}.json`);
} }
function getDatabaseVersionPath() { function getDatabaseVersionPath() {
const aikidoDir = getAikidoDirectory(); const aikidoDir = getAikidoDirectory();
return path.join(aikidoDir, "version.txt"); const ecosystem = getEcoSystem() || "js";
return path.join(aikidoDir, `version_${ecosystem}.txt`);
} }
function getConfigFilePath() { function getConfigFilePath() {

View file

@ -111,7 +111,6 @@ function handleConnect(req, clientSocket, head) {
// CONNECT method is used for HTTPS requests // CONNECT method is used for HTTPS requests
// It establishes a tunnel to the server identified by the request URL // It establishes a tunnel to the server identified by the request URL
console.log("**registryProxy.js** Handling CONNECT request for:", req.url);
if ((knownJsRegistries.some((reg) => req.url.includes(reg))) if ((knownJsRegistries.some((reg) => req.url.includes(reg)))
|| (knownPipRegistries.some((reg) => req.url.includes(reg)))) { || (knownPipRegistries.some((reg) => req.url.includes(reg)))) {
mitmConnect(req, clientSocket, isAllowedUrl); mitmConnect(req, clientSocket, isAllowedUrl);

View file

@ -7,9 +7,24 @@ import {
writeDatabaseToLocalCache, writeDatabaseToLocalCache,
} from "../config/configFile.js"; } from "../config/configFile.js";
import { ui } from "../environment/userInteraction.js"; import { ui } from "../environment/userInteraction.js";
import { getEcoSystem } from "../config/settings.js";
let cachedMalwareDatabase = null; let cachedMalwareDatabase = null;
/**
* Normalize package name for comparison.
* For Python packages (PEP-503): lowercase and replace _, -, . with -
* For js packages: keep as-is (case-sensitive)
*/
function normalizePackageName(name) {
const ecosystem = getEcoSystem();
if (ecosystem === "py") {
return name.toLowerCase().replace(/[-_.]+/g, "-");
}
return name;
}
export async function openMalwareDatabase() { export async function openMalwareDatabase() {
if (cachedMalwareDatabase) { if (cachedMalwareDatabase) {
return cachedMalwareDatabase; return cachedMalwareDatabase;
@ -18,10 +33,13 @@ export async function openMalwareDatabase() {
const malwareDatabase = await getMalwareDatabase(); const malwareDatabase = await getMalwareDatabase();
function getPackageStatus(name, version) { function getPackageStatus(name, version) {
const normalizedName = normalizePackageName(name);
const packageData = malwareDatabase.find( const packageData = malwareDatabase.find(
(pkg) => (pkg) => {
pkg.package_name === name && const normalizedPkgName = normalizePackageName(pkg.package_name);
(pkg.version === version || pkg.version === "*") return normalizedPkgName === normalizedName &&
(pkg.version === version || pkg.version === "*");
}
); );
if (!packageData) { if (!packageData) {