From 8f5b50f9a12e8d41dff34776cd9f8b1075ec029d Mon Sep 17 00:00:00 2001 From: Controgon Date: Thu, 19 Feb 2026 09:23:04 -0700 Subject: [PATCH 1/9] fixed server in the branch --- Server/lib/urlSanitize.js | 81 ++++++++++++++++++ Server/server.js | 171 ++++++++++++++++++++++---------------- 2 files changed, 182 insertions(+), 70 deletions(-) create mode 100644 Server/lib/urlSanitize.js diff --git a/Server/lib/urlSanitize.js b/Server/lib/urlSanitize.js new file mode 100644 index 0000000..991ffb2 --- /dev/null +++ b/Server/lib/urlSanitize.js @@ -0,0 +1,81 @@ +/** + * Normalize and validate a user-provided domain or URL into a scan target. + * + * ── How it works ────────────────────────────────────────────────────────── + * 1. Coerce to string and trim whitespace. + * 2. If the input contains "://", parse it as a URL and extract the hostname. + * Otherwise treat the raw input as a bare hostname. + * 3. Lowercase the hostname for consistent caching and comparison. + * 4. Strip a leading "www." — the scoring engine is domain-oriented + * (MAIL/RDAP/DNS) and "www.example.com" produces different results. + * 5. Strip any trailing dots (valid in DNS, unwanted here). + * + * ── What is blocked (returns { ok: false, reason }) ────────────────────── + * • Empty or whitespace-only input. + * • Input that cannot be parsed into a hostname. + * • "localhost" (and equivalents like "127.0.0.1", "::1", "0.0.0.0"). + * • Plain IP addresses (no letter-based TLD). + * + * See Docs/url-sanitization-policy.md for the full policy. + * + * @param {string} raw - The domain or URL string from the query parameter. + * @returns {{ ok: true, domain: string } | { ok: false, reason: string }} + */ +function normalizeScanTarget(raw) { + let target = String(raw ?? "").trim(); + + // 1. Empty check + if (!target) { + return { ok: false, reason: "No domain or URL provided." }; + } + + // 2. Extract hostname from a full URL (contains "://") + try { + if (target.includes("://")) { + const u = new URL(target); + target = u.hostname; + } + } catch { + return { ok: false, reason: "Malformed URL — could not extract a hostname." }; + } + + // 3. Lowercase + target = target.toLowerCase(); + + // 4. Strip leading "www." + if (target.startsWith("www.")) target = target.slice(4); + + // 5. Strip trailing dots + target = target.replace(/\.+$/, ""); + + // ── Validation ────────────────────────────────────────────────────── + + // Block empty result after normalization + if (!target) { + return { ok: false, reason: "Domain resolved to an empty string after normalization." }; + } + + // Block localhost and loopback equivalents + const LOCALHOST_PATTERNS = ["localhost", "127.0.0.1", "::1", "0.0.0.0"]; + if (LOCALHOST_PATTERNS.includes(target)) { + return { ok: false, reason: "Scanning localhost or loopback addresses is not allowed." }; + } + + // Block plain IP addresses (no letter-based TLD). + // IPv4 pattern: digits and dots only (e.g. "192.168.1.1") + // IPv6 pattern: hex digits, colons, optional brackets (e.g. "::1", "2001:db8::1") + const IPV4_RE = /^\d{1,3}(\.\d{1,3}){3}$/; + const IPV6_RE = /^[\da-f:]+$/i; + if (IPV4_RE.test(target) || IPV6_RE.test(target)) { + return { ok: false, reason: "Plain IP addresses are not supported. Please enter a domain name." }; + } + + // Require at least one dot followed by 2+ letters (letter-based TLD) + if (!/\.[a-z]{2,}$/i.test(target)) { + return { ok: false, reason: "Invalid domain — no recognizable top-level domain (e.g. .com, .org)." }; + } + + return { ok: true, domain: target }; +} + +module.exports = { normalizeScanTarget }; \ No newline at end of file diff --git a/Server/server.js b/Server/server.js index 8acf62b..deeddc3 100644 --- a/Server/server.js +++ b/Server/server.js @@ -2,6 +2,7 @@ const express = require("express"); const { spawn } = require("child_process"); const path = require("path"); const fs = require("fs"); +const { normalizeScanTarget } = require("./lib/urlSanitize"); const app = express(); @@ -21,18 +22,46 @@ function getStatusFromScore(score) { return "poor"; } -// Parse scoring engine stdout: expects a single JSON object { scores, Aggregated_Score }. +// Known top-level score keys from scoring_main.py (excluding aggregatedScore). +const SCORING_ENGINE_KEYS = [ + "Connection_Security", + "Certificate_Health", + "DNS_Record_Health", + "Domain_Reputation", + "WHOIS_Pattern", + "IP_Reputation", + "Credential_Safety", +]; + +// Parse scoring engine stdout. Accepts either: +// - New format: top-level score keys + "aggregatedScore" (from scoring_main.py) +// - Legacy: "scores" object + "Aggregated_Score" function parseScoringOutput(output) { const jsonMatch = output.match(/\{[\s\S]*\}/); if (!jsonMatch) { throw new Error("Scoring engine did not output valid JSON"); } const jsonData = JSON.parse(jsonMatch[0]); - return { - scores: jsonData.scores && typeof jsonData.scores === "object" ? jsonData.scores : {}, - aggregatedScore: - jsonData.Aggregated_Score != null ? Number(jsonData.Aggregated_Score) : null, - }; + + let scores = {}; + if (jsonData.scores && typeof jsonData.scores === "object") { + scores = jsonData.scores; + } else { + for (const key of SCORING_ENGINE_KEYS) { + if (jsonData[key] != null && typeof jsonData[key] === "number") { + scores[key] = jsonData[key]; + } + } + } + + const aggregatedScore = + jsonData.aggregatedScore != null + ? Number(jsonData.aggregatedScore) + : jsonData.Aggregated_Score != null + ? Number(jsonData.Aggregated_Score) + : null; + + return { scores, aggregatedScore }; } // Map scoring engine keys to extension indicator ids/names. @@ -123,38 +152,23 @@ function resolvePythonScript() { // Main endpoint: /scan?domain=example.com OR /scan?url=https://example.com/path app.get("/scan", (req, res) => { - const input = req.query.domain || req.query.url || "netstar.ai"; - - /** - * Normalize user-provided domain/URL into a scan target. - * - * The scoring engine is domain-oriented (MAIL/RDAP/DNS in particular). If we - * pass a common web subdomain like "www.example.com", those endpoints can - * legitimately return very different (often worse) results than "example.com". - * - * For now we canonicalize by stripping a leading "www.". - */ - function normalizeTargetDomain(raw) { - let targetDomain = String(raw ?? "").trim(); - - // Extract hostname from URL if full URL provided - try { - if (targetDomain.includes("://")) { - const u = new URL(targetDomain); - targetDomain = u.hostname; - } - } catch { - // If URL parsing fails, keep as-is - } - - targetDomain = targetDomain.toLowerCase(); - if (targetDomain.startsWith("www.")) targetDomain = targetDomain.slice(4); - // Defensive: strip any trailing dot (rare but valid in DNS) - targetDomain = targetDomain.replace(/\.+$/, ""); - return targetDomain || "netstar.ai"; + const input = req.query.domain || req.query.url || ""; + + // Normalize and validate the scan target. + // Returns 400 for invalid, empty, localhost, or plain-IP inputs. + // See lib/urlSanitize.js and Docs/url-sanitization-policy.md. + const result = normalizeScanTarget(input); + if (!result.ok) { + return res.status(400).json({ + error: true, + message: result.reason, + safetyScore: 0, + aggregatedScore: 0, + indicators: [], + timestamp: Date.now(), + }); } - - const targetDomain = normalizeTargetDomain(input); + const targetDomain = result.domain; const pythonScript = resolvePythonScript(); if (!pythonScript) { @@ -215,9 +229,8 @@ app.get("/scan", (req, res) => { py.stderr.on("data", (data) => { error += data.toString(); }); - } - try { + try { const { scores, aggregatedScore } = parseScoringOutput(output); const response = formatForExtension(scores, aggregatedScore); @@ -350,6 +363,19 @@ app.get("/scan", (req, res) => { }); } }); + } catch (e) { + if (!responded) { + responded = true; + res.status(500).json({ + error: true, + message: e?.message || "Scoring handler error", + safetyScore: 0, + aggregatedScore: 0, + indicators: [], + timestamp: Date.now(), + }); + } + } }) .catch((err) => { return res.status(500).json({ @@ -380,41 +406,46 @@ app.get("/", (req, res) => { }); }); -const PORT = process.env.PORT || 3000; +// Only start listening when this file is run directly (not when required by tests). +if (require.main === module) { + const PORT = process.env.PORT || 3000; -const server = app.listen(PORT, "0.0.0.0", () => { - console.log(`NetSTAR Shield server running on port ${PORT}`); - console.log(`Health check: http://localhost:${PORT}/health`); - console.log(`Scan endpoint: http://localhost:${PORT}/scan?domain=example.com`); -}); + const server = app.listen(PORT, "0.0.0.0", () => { + console.log(`NetSTAR Shield server running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); + console.log(`Scan endpoint: http://localhost:${PORT}/scan?domain=example.com`); + }); -server.on("error", (error) => { - if (error.code === "EACCES") { - console.error(`ERROR: Permission denied. Port ${PORT} may require elevated privileges.`); - } else if (error.code === "EADDRINUSE") { - console.error(`ERROR: Port ${PORT} is already in use.`); - } else { - console.error("Server error:", error); + server.on("error", (error) => { + if (error.code === "EACCES") { + console.error(`ERROR: Permission denied. Port ${PORT} may require elevated privileges.`); + } else if (error.code === "EADDRINUSE") { + console.error(`ERROR: Port ${PORT} is already in use.`); + } else { + console.error("Server error:", error); + } + process.exit(1); + }); + + function shutdown(signal) { + console.log(`${signal} received, shutting down gracefully`); + server.close(() => { + console.log("Server closed"); + process.exit(0); + }); } - process.exit(1); -}); -function shutdown(signal) { - console.log(`${signal} received, shutting down gracefully`); - server.close(() => { - console.log("Server closed"); - process.exit(0); - }); -} + process.on("SIGTERM", () => shutdown("SIGTERM")); + process.on("SIGINT", () => shutdown("SIGINT")); -process.on("SIGTERM", () => shutdown("SIGTERM")); -process.on("SIGINT", () => shutdown("SIGINT")); + process.on("uncaughtException", (error) => { + console.error("Uncaught Exception:", error); + server.close(() => process.exit(1)); + }); -process.on("uncaughtException", (error) => { - console.error("Uncaught Exception:", error); - server.close(() => process.exit(1)); -}); + process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + }); +} -process.on("unhandledRejection", (reason, promise) => { - console.error("Unhandled Rejection at:", promise, "reason:", reason); -}); +module.exports = { app }; \ No newline at end of file From 13ec5a2ab27073c256659713ec24287eed3d7b60 Mon Sep 17 00:00:00 2001 From: Controgon Date: Wed, 4 Mar 2026 08:17:20 -0700 Subject: [PATCH 2/9] Code will now show if the scan failed, but gives the "You should be Confident" Line --- Extension/src/components/tabs/HomeTab.jsx | 61 +++-- Server/package-lock.json | 272 ++++++++-------------- 2 files changed, 136 insertions(+), 197 deletions(-) diff --git a/Extension/src/components/tabs/HomeTab.jsx b/Extension/src/components/tabs/HomeTab.jsx index 771c3af..f0e1e1e 100644 --- a/Extension/src/components/tabs/HomeTab.jsx +++ b/Extension/src/components/tabs/HomeTab.jsx @@ -73,6 +73,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov /** Complete security scan data including indicators and metadata, or null if not loaded */ const [securityData, setSecurityData] = useState(null); + const [scanState, setScanState] = useState("loading"); // "loading" | "success" | "error" + const [scanError, setScanError] = useState(null); /** * State for whether the "What We Checked" indicators section is expanded @@ -134,6 +136,9 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov }; const run = async () => { + setSecurityData(null); // forces loading UI every time a fetch starts + setScanState("loading"); + setScanError(null); // If the popup is showing a manual scan target, prefer that over "current tab". if (overrideUrl) { @@ -142,6 +147,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (overrideSecurityData?.safetyScore !== undefined) { setSafetyScore(overrideSecurityData.safetyScore); setSecurityData(overrideSecurityData); + setScanState("success") return; } @@ -159,6 +165,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { // Ignore and keep defaults; UI still renders. + setScanError(response.message || "Scan failed"); + setScanState("error"); console.error("Error getting manual scan data:", error); } } @@ -241,11 +249,18 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov resolved = true; resolve(null); } - }, 3000); + }, 15000); }); if (!isMounted || !response) return; + if (response.error) { + setSecurityData({ error: true, message: response.message || "Scan failed" }); + setScanError(response.message || "Scan failed"); + setScanState("error"); + return; + } + if (response.url) { setHostnameFromUrl(response.url); @@ -257,6 +272,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { console.error("Error getting current tab:", error); + setScanError(response.message || "Scan failed"); + setScanState("error"); } } else { setCurrentUrl("example.com"); @@ -303,7 +320,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov const SafetyScoreStatus = getStatusFromScore(safetyScore); const SafetyScoreColor = getColorClasses(SafetyScoreStatus); - const SecurityScoreHeaderPhrase = (securityData !== undefined ? ( + const SecurityScoreHeaderPhrase = (securityData ? ( getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase())) : ( "Loading URL Score")); @@ -324,7 +341,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov mode === "dark" ? "text-slate-200" : "text-brand-900" }`} > - {securityData !== undefined ? ( + + {securityData ? ( <> Scanned {currentUrl} @@ -348,24 +366,25 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov
- {securityData == undefined ? ( - - - - ) : ( - - {safetyScore} - - )} + + {scanState === "loading" ? ( + + + + ) : scanState === "error" ? ( +
+ {scanError} +
+ ) : ( + + )} +
=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -58,7 +59,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -71,7 +71,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -84,22 +83,21 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -108,7 +106,6 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -117,7 +114,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", "engines": { "node": ">=6.6.0" } @@ -126,7 +122,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -143,7 +138,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -152,7 +146,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -165,14 +158,12 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -181,7 +172,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -190,7 +180,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -199,7 +188,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -210,31 +198,29 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "license": "MIT", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -265,10 +251,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "license": "MIT", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -278,14 +263,17 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -294,7 +282,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -303,7 +290,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -312,7 +298,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -336,7 +321,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -349,7 +333,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -361,7 +344,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -373,7 +355,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -382,53 +363,48 @@ } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -436,14 +412,12 @@ "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -452,7 +426,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -461,7 +434,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", "engines": { "node": ">=18" }, @@ -473,34 +445,34 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -509,7 +481,6 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -521,7 +492,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -533,7 +503,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -542,7 +511,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -551,7 +519,6 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -561,7 +528,6 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -571,10 +537,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "dependencies": { "side-channel": "^1.1.0" }, @@ -589,47 +554,28 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -641,59 +587,40 @@ "node": ">= 18" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "license": "MIT", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "license": "MIT", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -702,19 +629,21 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -733,7 +662,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -749,7 +677,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -767,7 +694,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -786,7 +712,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -795,7 +720,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -804,7 +728,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -818,7 +741,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -827,7 +749,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -835,8 +756,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" } } } From b2444ea641ea67502aa74e78ef7a6b105d656210 Mon Sep 17 00:00:00 2001 From: Controgon Date: Thu, 5 Mar 2026 08:54:56 -0700 Subject: [PATCH 3/9] The loading now does not last forever. Score shows once the reponse from the server is recieved. --- Extension/src/components/tabs/HomeTab.jsx | 74 ++++++++++++++--------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/Extension/src/components/tabs/HomeTab.jsx b/Extension/src/components/tabs/HomeTab.jsx index f0e1e1e..0bc84f5 100644 --- a/Extension/src/components/tabs/HomeTab.jsx +++ b/Extension/src/components/tabs/HomeTab.jsx @@ -68,8 +68,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov /** Current website URL hostname */ const [currentUrl, setCurrentUrl] = useState(""); - /** Security safety score (0-100), default is 87 */ - const [safetyScore, setSafetyScore] = useState(87); + /** Security safety score (0-100), default is 0 */ + const [safetyScore, setSafetyScore] = useState(0); /** Complete security scan data including indicators and metadata, or null if not loaded */ const [securityData, setSecurityData] = useState(null); @@ -165,8 +165,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { // Ignore and keep defaults; UI still renders. - setScanError(response.message || "Scan failed"); - setScanState("error"); + setScanError({ error: true, message: error?.message || "Scan failed" }); + setScanState(error?.message || "Scan failed"); console.error("Error getting manual scan data:", error); } } @@ -247,7 +247,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (!resolved) { chrome.runtime.onMessage.removeListener(messageListener); resolved = true; - resolve(null); + resolve({ error: true, message: "Timed out waiting for scan result" }); } }, 15000); }); @@ -255,24 +255,36 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (!isMounted || !response) return; if (response.error) { - setSecurityData({ error: true, message: response.message || "Scan failed" }); - setScanError(response.message || "Scan failed"); + const msg = response.error?.message || "Scan failed"; + setSecurityData({ error: true, message: msg }); + setScanError(msg); setScanState("error"); return; } if (response.url) { setHostnameFromUrl(response.url); + } + // Always end loading if we got a response object back: + if (response.securityData) { + setSecurityData(response.securityData); - // Update safety score from background script if available - if (response.securityData?.safetyScore !== undefined) { + if (response.securityData.safetyScore !== undefined) { setSafetyScore(response.securityData.safetyScore); - setSecurityData(response.securityData); } + + setScanState("success"); + return; } + // If the background answered but didn't include data, treat as error: + setSecurityData({ error: true, message: "No security data returned" }); + setScanError("No security data returned"); + setScanState("error"); + return; } catch (error) { console.error("Error getting current tab:", error); - setScanError(response.message || "Scan failed"); + setSecurityData({ error: true, message: error?.message || "Scan failed" }); + setScanError(error?.message || "Scan failed"); setScanState("error"); } } else { @@ -318,11 +330,24 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov setShowIndicators((openState) => !openState); }; - const SafetyScoreStatus = getStatusFromScore(safetyScore); + const isLoading = securityData == null; + const isError = securityData?.error === true; + + const SafetyScoreStatus = safetyScore === 0 ? "unknown" : getStatusFromScore(safetyScore); const SafetyScoreColor = getColorClasses(SafetyScoreStatus); - const SecurityScoreHeaderPhrase = (securityData ? ( - getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase())) : - ( "Loading URL Score")); + + // Header text + const headerTitle = isLoading + ? "Loading URL Score" + : isError + ? "Scan failed" + : getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase()); + + const headerLine = isLoading + ? "Scanning" + : isError + ? (securityData.message || "We couldn't scan this site.") + : "Scanned"; return ( @@ -334,23 +359,14 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov mode === "dark" ? "text-white" : "text-slate-900" }`} > - {SecurityScoreHeaderPhrase} + {headerTitle}

- - {securityData ? ( - <> - Scanned {currentUrl} - - ) : ( - <> - Scanning {currentUrl} - - )} + {headerLine} {currentUrl}

@@ -382,7 +398,11 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov {scanError}
) : ( - + + {Number.isFinite(safetyScore) ? safetyScore : "—"} + )} From e712ca7d1d5fa320d505f3fe9b0140ec8901d52f Mon Sep 17 00:00:00 2001 From: Controgon Date: Thu, 19 Feb 2026 09:23:04 -0700 Subject: [PATCH 4/9] fixed server in the branch --- Server/lib/urlSanitize.js | 2 +- Server/server.js | 143 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/Server/lib/urlSanitize.js b/Server/lib/urlSanitize.js index ce4cb33..991ffb2 100644 --- a/Server/lib/urlSanitize.js +++ b/Server/lib/urlSanitize.js @@ -78,4 +78,4 @@ function normalizeScanTarget(raw) { return { ok: true, domain: target }; } -module.exports = { normalizeScanTarget }; +module.exports = { normalizeScanTarget }; \ No newline at end of file diff --git a/Server/server.js b/Server/server.js index 6ce23fa..756af55 100644 --- a/Server/server.js +++ b/Server/server.js @@ -3,6 +3,7 @@ const { spawn } = require("child_process"); const path = require("path"); const fs = require("fs"); const { normalizeScanTarget } = require("./lib/urlSanitize"); +const { normalizeScanTarget } = require("./lib/urlSanitize"); const app = express(); @@ -33,6 +34,20 @@ const SCORING_ENGINE_KEYS = [ "Credential_Safety", ]; +// Parse scoring engine stdout. Accepts either: +// - New format: top-level score keys + "aggregatedScore" (from scoring_main.py) +// - Legacy: "scores" object + "Aggregated_Score" +// Known top-level score keys from scoring_main.py (excluding aggregatedScore). +const SCORING_ENGINE_KEYS = [ + "Connection_Security", + "Certificate_Health", + "DNS_Record_Health", + "Domain_Reputation", + "WHOIS_Pattern", + "IP_Reputation", + "Credential_Safety", +]; + // Parse scoring engine stdout. Accepts either: // - New format: top-level score keys + "aggregatedScore" (from scoring_main.py) // - Legacy: "scores" object + "Aggregated_Score" @@ -62,6 +77,26 @@ function parseScoringOutput(output) { : null; return { scores, aggregatedScore }; + + let scores = {}; + if (jsonData.scores && typeof jsonData.scores === "object") { + scores = jsonData.scores; + } else { + for (const key of SCORING_ENGINE_KEYS) { + if (jsonData[key] != null && typeof jsonData[key] === "number") { + scores[key] = jsonData[key]; + } + } + } + + const aggregatedScore = + jsonData.aggregatedScore != null + ? Number(jsonData.aggregatedScore) + : jsonData.Aggregated_Score != null + ? Number(jsonData.Aggregated_Score) + : null; + + return { scores, aggregatedScore }; } // Map scoring engine keys to extension indicator ids/names. @@ -153,7 +188,21 @@ function resolvePythonScript() { // Main endpoint: /scan?domain=example.com OR /scan?url=https://example.com/path app.get("/scan", (req, res) => { const input = req.query.domain || req.query.url || ""; + const input = req.query.domain || req.query.url || ""; + // Normalize and validate the scan target. + // Returns 400 for invalid, empty, localhost, or plain-IP inputs. + // See lib/urlSanitize.js and Docs/url-sanitization-policy.md. + const result = normalizeScanTarget(input); + if (!result.ok) { + return res.status(400).json({ + error: true, + message: result.reason, + safetyScore: 0, + aggregatedScore: 0, + indicators: [], + timestamp: Date.now(), + }); // Normalize and validate the scan target. // Returns 400 for invalid, empty, localhost, or plain-IP inputs. // See lib/urlSanitize.js and Docs/url-sanitization-policy.md. @@ -169,6 +218,7 @@ app.get("/scan", (req, res) => { }); } const targetDomain = result.domain; + const targetDomain = result.domain; const pythonScript = resolvePythonScript(); if (!pythonScript) { @@ -237,6 +287,49 @@ app.get("/scan", (req, res) => { }); try { + const { scores, aggregatedScore } = parseScoringOutput(output); + const response = formatForExtension(scores, aggregatedScore); + + // Debug: log the exact score payload we're about to return + try { + const debugPayload = { + request: { + method: req.method, + path: req.path, + originalUrl: req.originalUrl, + query: req.query, + ip: req.ip, + headers: { + "user-agent": req.get("user-agent"), + origin: req.get("origin"), + referer: req.get("referer"), + }, + }, + targetDomain, + input: String(input), + aggregatedScoreParsed: Number.isFinite(aggregatedScore) ? aggregatedScore : null, + response: { + safetyScore: response?.safetyScore, + aggregatedScore: response?.aggregatedScore, + indicatorsCount: Array.isArray(response?.indicators) ? response.indicators.length : 0, + indicators: Array.isArray(response?.indicators) + ? response.indicators.map((i) => ({ + id: i?.id, + name: i?.name, + score: i?.score, + status: i?.status, + })) + : [], + timestamp: response?.timestamp, + }, + }; + console.log( + `[${new Date().toISOString()}] [scan][score-response] ${JSON.stringify(debugPayload, null, 2)}` + ); + } catch { + // Avoid breaking /scan responses due to logging issues + } + // Timeout after 60 seconds const timeout = setTimeout(() => { if (responded) return; @@ -339,6 +432,19 @@ app.get("/scan", (req, res) => { }); } } + } catch (e) { + if (!responded) { + responded = true; + res.status(500).json({ + error: true, + message: e?.message || "Scoring handler error", + safetyScore: 0, + aggregatedScore: 0, + indicators: [], + timestamp: Date.now(), + }); + } + } }) .catch((err) => { return res.status(500).json({ @@ -369,16 +475,34 @@ app.get("/", (req, res) => { }); }); +// Only start listening when this file is run directly (not when required by tests). +if (require.main === module) { + const PORT = process.env.PORT || 3000; // Only start listening when this file is run directly (not when required by tests). if (require.main === module) { const PORT = process.env.PORT || 3000; + const server = app.listen(PORT, "0.0.0.0", () => { + console.log(`NetSTAR Shield server running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); + console.log(`Scan endpoint: http://localhost:${PORT}/scan?domain=example.com`); + }); const server = app.listen(PORT, "0.0.0.0", () => { console.log(`NetSTAR Shield server running on port ${PORT}`); console.log(`Health check: http://localhost:${PORT}/health`); console.log(`Scan endpoint: http://localhost:${PORT}/scan?domain=example.com`); }); + server.on("error", (error) => { + if (error.code === "EACCES") { + console.error(`ERROR: Permission denied. Port ${PORT} may require elevated privileges.`); + } else if (error.code === "EADDRINUSE") { + console.error(`ERROR: Port ${PORT} is already in use.`); + } else { + console.error("Server error:", error); + } + process.exit(1); + }); server.on("error", (error) => { if (error.code === "EACCES") { console.error(`ERROR: Permission denied. Port ${PORT} may require elevated privileges.`); @@ -390,6 +514,13 @@ if (require.main === module) { process.exit(1); }); + function shutdown(signal) { + console.log(`${signal} received, shutting down gracefully`); + server.close(() => { + console.log("Server closed"); + process.exit(0); + }); + } function shutdown(signal) { console.log(`${signal} received, shutting down gracefully`); server.close(() => { @@ -398,9 +529,15 @@ if (require.main === module) { }); } + process.on("SIGTERM", () => shutdown("SIGTERM")); + process.on("SIGINT", () => shutdown("SIGINT")); process.on("SIGTERM", () => shutdown("SIGTERM")); process.on("SIGINT", () => shutdown("SIGINT")); + process.on("uncaughtException", (error) => { + console.error("Uncaught Exception:", error); + server.close(() => process.exit(1)); + }); process.on("uncaughtException", (error) => { console.error("Uncaught Exception:", error); server.close(() => process.exit(1)); @@ -412,3 +549,9 @@ if (require.main === module) { } module.exports = { app }; + process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + }); +} + +module.exports = { app }; \ No newline at end of file From 432623af40d0c9831d406ef6b8321064d5bc328f Mon Sep 17 00:00:00 2001 From: Controgon Date: Wed, 4 Mar 2026 08:17:20 -0700 Subject: [PATCH 5/9] Code will now show if the scan failed, but gives the "You should be Confident" Line --- Extension/src/components/tabs/HomeTab.jsx | 61 ++-- Server/package-lock.json | 397 ++++++---------------- 2 files changed, 136 insertions(+), 322 deletions(-) diff --git a/Extension/src/components/tabs/HomeTab.jsx b/Extension/src/components/tabs/HomeTab.jsx index 771c3af..f0e1e1e 100644 --- a/Extension/src/components/tabs/HomeTab.jsx +++ b/Extension/src/components/tabs/HomeTab.jsx @@ -73,6 +73,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov /** Complete security scan data including indicators and metadata, or null if not loaded */ const [securityData, setSecurityData] = useState(null); + const [scanState, setScanState] = useState("loading"); // "loading" | "success" | "error" + const [scanError, setScanError] = useState(null); /** * State for whether the "What We Checked" indicators section is expanded @@ -134,6 +136,9 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov }; const run = async () => { + setSecurityData(null); // forces loading UI every time a fetch starts + setScanState("loading"); + setScanError(null); // If the popup is showing a manual scan target, prefer that over "current tab". if (overrideUrl) { @@ -142,6 +147,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (overrideSecurityData?.safetyScore !== undefined) { setSafetyScore(overrideSecurityData.safetyScore); setSecurityData(overrideSecurityData); + setScanState("success") return; } @@ -159,6 +165,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { // Ignore and keep defaults; UI still renders. + setScanError(response.message || "Scan failed"); + setScanState("error"); console.error("Error getting manual scan data:", error); } } @@ -241,11 +249,18 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov resolved = true; resolve(null); } - }, 3000); + }, 15000); }); if (!isMounted || !response) return; + if (response.error) { + setSecurityData({ error: true, message: response.message || "Scan failed" }); + setScanError(response.message || "Scan failed"); + setScanState("error"); + return; + } + if (response.url) { setHostnameFromUrl(response.url); @@ -257,6 +272,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { console.error("Error getting current tab:", error); + setScanError(response.message || "Scan failed"); + setScanState("error"); } } else { setCurrentUrl("example.com"); @@ -303,7 +320,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov const SafetyScoreStatus = getStatusFromScore(safetyScore); const SafetyScoreColor = getColorClasses(SafetyScoreStatus); - const SecurityScoreHeaderPhrase = (securityData !== undefined ? ( + const SecurityScoreHeaderPhrase = (securityData ? ( getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase())) : ( "Loading URL Score")); @@ -324,7 +341,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov mode === "dark" ? "text-slate-200" : "text-brand-900" }`} > - {securityData !== undefined ? ( + + {securityData ? ( <> Scanned {currentUrl} @@ -348,24 +366,25 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov
- {securityData == undefined ? ( - - - - ) : ( - - {safetyScore} - - )} + + {scanState === "loading" ? ( + + + + ) : scanState === "error" ? ( +
+ {scanError} +
+ ) : ( + + )} +
=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/brace-expansion": { @@ -1650,7 +1652,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1659,7 +1660,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -1672,7 +1672,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -1902,22 +1901,21 @@ "dev": true }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1932,7 +1930,6 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1941,7 +1938,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", "engines": { "node": ">=6.6.0" } @@ -1970,7 +1966,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2019,7 +2014,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2047,7 +2041,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -2066,8 +2059,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { "version": "1.5.286", @@ -2097,7 +2089,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2115,7 +2106,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2124,7 +2114,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2133,7 +2122,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -2168,8 +2156,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "2.0.0", @@ -2197,7 +2184,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2258,18 +2244,18 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "license": "MIT", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -2333,10 +2319,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "license": "MIT", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -2346,7 +2331,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-up": { @@ -2436,7 +2425,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2445,7 +2433,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2474,7 +2461,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2501,7 +2487,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -2534,7 +2519,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -2580,7 +2564,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2607,7 +2590,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2634,7 +2616,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2649,28 +2630,22 @@ "dev": true }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/human-signals": { @@ -2683,15 +2658,18 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/import-local": { @@ -2736,14 +2714,12 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -2784,8 +2760,7 @@ "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, "node_modules/is-stream": { "version": "2.0.1", @@ -3600,7 +3575,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3609,7 +3583,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3618,7 +3591,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", "engines": { "node": ">=18" }, @@ -3670,21 +3642,23 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-fn": { @@ -3723,8 +3697,7 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/napi-postinstall": { "version": "0.3.4", @@ -3751,7 +3724,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3793,7 +3765,6 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3805,7 +3776,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -3817,7 +3787,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -3916,7 +3885,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3974,7 +3942,6 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -4049,7 +4016,6 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -4075,9 +4041,10 @@ ] }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" }, @@ -4092,21 +4059,19 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" @@ -4128,47 +4093,10 @@ "url": "https://opencollective.com/express" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -4180,31 +4108,10 @@ "node": ">= 18" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { "version": "6.3.1", @@ -4216,32 +4123,34 @@ } }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "license": "MIT", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "license": "MIT", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -4250,13 +4159,16 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -4283,7 +4195,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -4302,7 +4213,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -4318,7 +4228,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -4336,7 +4245,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -4413,7 +4321,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4718,7 +4625,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -4755,7 +4661,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -4775,7 +4680,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4862,7 +4766,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4984,114 +4887,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } From 4282d1098ca1618c97cc74853a719e4cee16c243 Mon Sep 17 00:00:00 2001 From: Controgon Date: Thu, 5 Mar 2026 08:54:56 -0700 Subject: [PATCH 6/9] The loading now does not last forever. Score shows once the reponse from the server is recieved. --- Extension/src/components/tabs/HomeTab.jsx | 74 ++++++++++++++--------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/Extension/src/components/tabs/HomeTab.jsx b/Extension/src/components/tabs/HomeTab.jsx index f0e1e1e..0bc84f5 100644 --- a/Extension/src/components/tabs/HomeTab.jsx +++ b/Extension/src/components/tabs/HomeTab.jsx @@ -68,8 +68,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov /** Current website URL hostname */ const [currentUrl, setCurrentUrl] = useState(""); - /** Security safety score (0-100), default is 87 */ - const [safetyScore, setSafetyScore] = useState(87); + /** Security safety score (0-100), default is 0 */ + const [safetyScore, setSafetyScore] = useState(0); /** Complete security scan data including indicators and metadata, or null if not loaded */ const [securityData, setSecurityData] = useState(null); @@ -165,8 +165,8 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov } } catch (error) { // Ignore and keep defaults; UI still renders. - setScanError(response.message || "Scan failed"); - setScanState("error"); + setScanError({ error: true, message: error?.message || "Scan failed" }); + setScanState(error?.message || "Scan failed"); console.error("Error getting manual scan data:", error); } } @@ -247,7 +247,7 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (!resolved) { chrome.runtime.onMessage.removeListener(messageListener); resolved = true; - resolve(null); + resolve({ error: true, message: "Timed out waiting for scan result" }); } }, 15000); }); @@ -255,24 +255,36 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (!isMounted || !response) return; if (response.error) { - setSecurityData({ error: true, message: response.message || "Scan failed" }); - setScanError(response.message || "Scan failed"); + const msg = response.error?.message || "Scan failed"; + setSecurityData({ error: true, message: msg }); + setScanError(msg); setScanState("error"); return; } if (response.url) { setHostnameFromUrl(response.url); + } + // Always end loading if we got a response object back: + if (response.securityData) { + setSecurityData(response.securityData); - // Update safety score from background script if available - if (response.securityData?.safetyScore !== undefined) { + if (response.securityData.safetyScore !== undefined) { setSafetyScore(response.securityData.safetyScore); - setSecurityData(response.securityData); } + + setScanState("success"); + return; } + // If the background answered but didn't include data, treat as error: + setSecurityData({ error: true, message: "No security data returned" }); + setScanError("No security data returned"); + setScanState("error"); + return; } catch (error) { console.error("Error getting current tab:", error); - setScanError(response.message || "Scan failed"); + setSecurityData({ error: true, message: error?.message || "Scan failed" }); + setScanError(error?.message || "Scan failed"); setScanState("error"); } } else { @@ -318,11 +330,24 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov setShowIndicators((openState) => !openState); }; - const SafetyScoreStatus = getStatusFromScore(safetyScore); + const isLoading = securityData == null; + const isError = securityData?.error === true; + + const SafetyScoreStatus = safetyScore === 0 ? "unknown" : getStatusFromScore(safetyScore); const SafetyScoreColor = getColorClasses(SafetyScoreStatus); - const SecurityScoreHeaderPhrase = (securityData ? ( - getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase())) : - ( "Loading URL Score")); + + // Header text + const headerTitle = isLoading + ? "Loading URL Score" + : isError + ? "Scan failed" + : getDetailedStatusMessage(String(SafetyScoreStatus).toLowerCase()); + + const headerLine = isLoading + ? "Scanning" + : isError + ? (securityData.message || "We couldn't scan this site.") + : "Scanned"; return ( @@ -334,23 +359,14 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov mode === "dark" ? "text-white" : "text-slate-900" }`} > - {SecurityScoreHeaderPhrase} + {headerTitle}

- - {securityData ? ( - <> - Scanned {currentUrl} - - ) : ( - <> - Scanning {currentUrl} - - )} + {headerLine} {currentUrl}

@@ -382,7 +398,11 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov {scanError}
) : ( - + + {Number.isFinite(safetyScore) ? safetyScore : "—"} + )} From 35861a962c59cfe52f4eb057812656f53a63c77b Mon Sep 17 00:00:00 2001 From: Tate McCauley Date: Tue, 10 Mar 2026 08:16:33 -0600 Subject: [PATCH 7/9] sync Serever package-lock --- Server/package-lock.json | 162 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 4 deletions(-) diff --git a/Server/package-lock.json b/Server/package-lock.json index 61f9c14..3d25fe8 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -1574,10 +1574,6 @@ "engines": { "node": ">=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -4084,6 +4080,46 @@ "node": ">= 0.10" } }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -4877,6 +4913,124 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } From 39f84bd3a5897ead000bd5cf061dc71eacde34e0 Mon Sep 17 00:00:00 2001 From: Controgon Date: Tue, 10 Mar 2026 08:55:30 -0600 Subject: [PATCH 8/9] Copied over the server.js from main, hoping that fixes unit test fails. --- Server/server.js | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/Server/server.js b/Server/server.js index ccc8b45..45ed696 100644 --- a/Server/server.js +++ b/Server/server.js @@ -237,49 +237,6 @@ app.get("/scan", (req, res) => { }); try { - const { scores, aggregatedScore } = parseScoringOutput(output); - const response = formatForExtension(scores, aggregatedScore); - - // Debug: log the exact score payload we're about to return - try { - const debugPayload = { - request: { - method: req.method, - path: req.path, - originalUrl: req.originalUrl, - query: req.query, - ip: req.ip, - headers: { - "user-agent": req.get("user-agent"), - origin: req.get("origin"), - referer: req.get("referer"), - }, - }, - targetDomain, - input: String(input), - aggregatedScoreParsed: Number.isFinite(aggregatedScore) ? aggregatedScore : null, - response: { - safetyScore: response?.safetyScore, - aggregatedScore: response?.aggregatedScore, - indicatorsCount: Array.isArray(response?.indicators) ? response.indicators.length : 0, - indicators: Array.isArray(response?.indicators) - ? response.indicators.map((i) => ({ - id: i?.id, - name: i?.name, - score: i?.score, - status: i?.status, - })) - : [], - timestamp: response?.timestamp, - }, - }; - console.log( - `[${new Date().toISOString()}] [scan][score-response] ${JSON.stringify(debugPayload, null, 2)}` - ); - } catch { - // Avoid breaking /scan responses due to logging issues - } - // Timeout after 60 seconds const timeout = setTimeout(() => { if (responded) return; From 5e7a09e99e06dc6af23fab24522113e88637e00e Mon Sep 17 00:00:00 2001 From: Controgon Date: Wed, 11 Mar 2026 09:30:23 -0600 Subject: [PATCH 9/9] Fixed the fail to scan on initial scan and reload fixing it. Now the initial scan should work. --- Extension/src/components/tabs/HomeTab.jsx | 123 ++++++---------------- 1 file changed, 34 insertions(+), 89 deletions(-) diff --git a/Extension/src/components/tabs/HomeTab.jsx b/Extension/src/components/tabs/HomeTab.jsx index 0bc84f5..74978ca 100644 --- a/Extension/src/components/tabs/HomeTab.jsx +++ b/Extension/src/components/tabs/HomeTab.jsx @@ -162,12 +162,21 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov if (result && !result.error && result.safetyScore !== undefined) { setSafetyScore(result.safetyScore); setSecurityData(result); + setScanError(null); + setScanState("success"); + } else { + const msg = result?.message || result?.error || "Scan failed"; + setSecurityData({ error: true, message: msg }); + setScanError(msg); + setScanState("error"); } } catch (error) { - // Ignore and keep defaults; UI still renders. - setScanError({ error: true, message: error?.message || "Scan failed" }); - setScanState(error?.message || "Scan failed"); console.error("Error getting manual scan data:", error); + const msg = error?.message || "Scan failed"; + + setSecurityData({ error: true, message: msg }); + setScanError(msg); + setScanState("error"); } } @@ -177,114 +186,50 @@ export function HomeTab({ mode, onNavigate, forceShowIndicators, overrideUrl, ov // Default behavior: Get current tab URL and security data. if (typeof chrome !== "undefined" && chrome.runtime) { try { - const response = await new Promise((resolve, reject) => { - let resolved = false; - const requestId = `getCurrentTab_${Date.now()}_${Math.random()}`; - - // Set up a one-time message listener for the response - const messageListener = (message) => { - if (message.action === "getCurrentTabResponse" && message.requestId === requestId) { - chrome.runtime.onMessage.removeListener(messageListener); - if (!resolved) { - resolved = true; - resolve(message.data); - } - return true; - } - }; - - chrome.runtime.onMessage.addListener(messageListener); - - // Send the request - chrome.runtime.sendMessage( - { - action: "getCurrentTab", - requestId: requestId, - }, - (response) => { - const callbackError = chrome.runtime.lastError; - - // If we got a response synchronously, use it - if (response && typeof response === "object" && response.url !== undefined) { - chrome.runtime.onMessage.removeListener(messageListener); - if (!resolved) { - resolved = true; - resolve(response); - } - return; - } - - // Check for port closed error - expected in Manifest V3 with async handlers - if (callbackError) { - const errorMsg = callbackError.message || String(callbackError); - if ( - errorMsg.includes("message port closed") || - errorMsg.includes("The message port closed before a response was received") - ) { - // Wait for message listener to receive the response - return; - } - - // Other fatal errors - if ( - errorMsg.includes("Receiving end does not exist") || - errorMsg.includes("Could not establish connection") || - errorMsg.includes("Extension context invalidated") - ) { - chrome.runtime.onMessage.removeListener(messageListener); - if (!resolved) { - resolved = true; - reject(callbackError); - } - return; - } - } - } - ); - - // Timeout fallback - setTimeout(() => { - if (!resolved) { - chrome.runtime.onMessage.removeListener(messageListener); - resolved = true; - resolve({ error: true, message: "Timed out waiting for scan result" }); + const response = await new Promise((resolve) => { + chrome.runtime.sendMessage({ action: "getCurrentTab" }, (resp) => { + const err = chrome.runtime.lastError; + if (err) { + resolve({ error: err.message || String(err) }); + return; } - }, 15000); + resolve(resp); + }); }); if (!isMounted || !response) return; if (response.error) { - const msg = response.error?.message || "Scan failed"; + const msg = typeof response.error === "string" + ? response.error + : (response.message || "Scan failed"); setSecurityData({ error: true, message: msg }); setScanError(msg); setScanState("error"); return; } - if (response.url) { - setHostnameFromUrl(response.url); - } - // Always end loading if we got a response object back: + if (response.url) setHostnameFromUrl(response.url); + if (response.securityData) { setSecurityData(response.securityData); - if (response.securityData.safetyScore !== undefined) { setSafetyScore(response.securityData.safetyScore); } - + setScanError(null); setScanState("success"); return; } - // If the background answered but didn't include data, treat as error: - setSecurityData({ error: true, message: "No security data returned" }); - setScanError("No security data returned"); + + // Background responded but no data — show error instead of spinning forever + const msg = "No security data returned"; + setSecurityData({ error: true, message: msg }); + setScanError(msg); setScanState("error"); - return; } catch (error) { - console.error("Error getting current tab:", error); - setSecurityData({ error: true, message: error?.message || "Scan failed" }); - setScanError(error?.message || "Scan failed"); + const msg = error?.message || "Scan failed"; + setSecurityData({ error: true, message: msg }); + setScanError(msg); setScanState("error"); } } else {