UNPKG

nehonix-uri-processor

Version:

A powerful URI processor for encoding, decoding, and analyzing URI data securely.

481 lines 20.4 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState, useRef } from "react"; import { NSB } from "../../../services/NehonixSecurityBooster.service"; import { NehonixShieldContext } from "../context/REACT.ShieldContext"; import { ncu } from "../../../utils/NehonixCoreUtils"; import NDS from "../../../services/NehonixDec.service"; import { mapConfidenceToNumber } from "./utils/confidence"; // Default configuration const defaultConfig = { enableBackgroundScanning: true, scanInterval: 30000, // 30 seconds interceptRequests: true, enableDeepScan: false, confidenceThreshold: 0.7, // Added for confidence-based filtering enableContextAnalysis: true, // Added for context-aware scanning scanOptions: { analyseOptions: { debug: true, }, global: { ignoreCase: true, checkEncoding: true, maxEncodingLayers: 3, analyzeContext: true, confidence: "medium", }, }, blockMaliciousRequests: true, blockMaliciousResponses: true, urlUtils: { trustedDomains: [], dynamicWhitelist: [], // Added for runtime whitelisting }, blacklistedPatterns: [], }; // Initialize empty analysis results const initialAnalysisResults = { analysisResults: [], lastScanTimestamp: 0, totalScanned: 0, totalBlocked: 0, activeThreats: [], performanceMetrics: { avgScanTime: 0, totalScanTime: 0, scanCount: 0, }, }; /** * Nehonix Shield Provider Component */ export const NehonixShieldProvider = ({ children, initialConfig = {} }) => { // Merge the default config with the provided initialConfig const [config, setConfig] = useState({ ...defaultConfig, ...initialConfig, }); const [analysisResults, setAnalysisResults] = useState(initialAnalysisResults); const [isScanning, setIsScanning] = useState(false); const [isPaused, setIsPaused] = useState(false); // Use refs for values that need to be accessed in effects const configRef = useRef(config); const scanIntervalRef = useRef(null); const urlCache = useRef(new Map()); // Update the config ref when config changes useEffect(() => { configRef.current = config; }, [config]); /** * Update the configuration */ const updateConfig = (newConfig) => { setConfig((prevConfig) => { const updatedConfig = { ...prevConfig, ...newConfig, scanOptions: { ...prevConfig.scanOptions, ...(newConfig.scanOptions || {}), }, urlUtils: { ...prevConfig.urlUtils, ...(newConfig.urlUtils || {}), }, }; return updatedConfig; }); }; /** * Add URL to dynamic whitelist */ const addToDynamicWhitelist = (url) => { setConfig((prev) => ({ ...prev, urlUtils: { ...prev.urlUtils, dynamicWhitelist: [...(prev.urlUtils.dynamicWhitelist || []), url], }, })); }; /** * Pause background scanning */ const pauseScanning = () => { setIsPaused(true); if (scanIntervalRef.current) { clearInterval(scanIntervalRef.current); scanIntervalRef.current = null; } }; /** * Resume background scanning */ const resumeScanning = () => { if (configRef.current.enableBackgroundScanning) { setIsPaused(false); startBackgroundScanning(); } }; /** * Clear analysis results */ const clearResults = () => { setAnalysisResults(initialAnalysisResults); urlCache.current.clear(); }; /** * Start background scanning */ const startBackgroundScanning = () => { if (scanIntervalRef.current) { clearInterval(scanIntervalRef.current); } scanIntervalRef.current = setInterval(() => { if (!isPaused && configRef.current.enableBackgroundScanning) { performScan(); } }, configRef.current.scanInterval); }; /** * Perform a security scan */ const performScan = async () => { setIsScanning(true); const startTime = performance.now(); try { const currentUrl = NDS.decodeAnyToPlaintext(window.location.href).val(); // Check cache first const cached = urlCache.current.get(currentUrl); if (cached && Date.now() - cached.timestamp < 60 * 1000) { return cached.result; } // Context analysis const context = configRef.current.enableContextAnalysis ? { referrer: document.referrer, userAgent: navigator.userAgent, pageTitle: document.title, } : {}; const urlResult = await NSB.analyzeUrl(currentUrl, { ...configRef.current.scanOptions.analyseOptions, /** * TODO: context, * we'll add context later * */ }); // Apply confidence threshold if (urlResult.isMalicious && mapConfidenceToNumber(urlResult.confidence) < configRef.current.confidenceThreshold) { urlResult.isMalicious = false; console.warn("Low-confidence threat detected:", urlResult); } // Update cache urlCache.current.set(currentUrl, { result: urlResult, timestamp: Date.now(), }); // Deep scan if enabled let deepScanResults = []; if (configRef.current.enableDeepScan) { deepScanResults = await performDeepScan(); } // Apply confidence threshold to deep scan results deepScanResults = deepScanResults.map((result) => { if (result.isMalicious && mapConfidenceToNumber(result.confidence) < configRef.current.confidenceThreshold) { return { ...result, isMalicious: false }; } return result; }); // Combine results const allResults = [urlResult, ...deepScanResults]; const newActiveThreats = allResults.flatMap((result) => result.detectedPatterns.filter((threat) => threat.severity === "high" && mapConfidenceToNumber(result.confidence) >= configRef.current.confidenceThreshold)); // Update scan metrics const endTime = performance.now(); const scanTime = endTime - startTime; setAnalysisResults((prev) => { const totalScanTime = prev.performanceMetrics.totalScanTime + scanTime; const scanCount = prev.performanceMetrics.scanCount + 1; return { analysisResults: [...prev.analysisResults, ...allResults], lastScanTimestamp: Date.now(), totalScanned: prev.totalScanned + allResults.length, totalBlocked: prev.totalBlocked + (allResults.some((r) => r.isMalicious && configRef.current.blockMaliciousRequests) ? 1 : 0), activeThreats: newActiveThreats, performanceMetrics: { avgScanTime: totalScanTime / scanCount, totalScanTime, scanCount, }, }; }); // Call onDetection callback if threats were found if (allResults.some((r) => r.isMalicious) && configRef.current.onDetection) { configRef.current.onDetection(urlResult); } } catch (error) { console.error("Nehonix Shield scan error:", error); } finally { setIsScanning(false); } }; /** * Perform a deep scan of the document and resources */ const performDeepScan = async () => { const results = []; try { // Scan all links in the document const links = Array.from(document.querySelectorAll("a")).map((a) => a.href); const current = configRef.current; const opt = { allowLocalhost: true }; const checkOpt = Object.assign(current.urlUtils, opt); const uniqueLinks = [...new Set(links)].filter((link) => { const checkLink = ncu.checkUrl(link, checkOpt); // Filter out links that don't have a valid protocol or are in trusted/dynamic whitelists if (!checkLink.isValid) return false; if (current.urlUtils.trustedDomains?.some((domain) => link.includes(domain)) || current.urlUtils.dynamicWhitelist?.includes(link)) { return false; } return true; }); // Limit the number of links to scan const linksToScan = uniqueLinks.slice(0, 10); // Scan each link for (const link of linksToScan) { try { const norm = await NDS.asyncDecodeAnyToPlainText(link); const url = norm.val(); const result = await NSB.analyzeUrl(url.normalize("NFC"), current.scanOptions.analyseOptions); if (result.isMalicious && mapConfidenceToNumber(result.confidence) < current.confidenceThreshold) { result.isMalicious = false; } results.push(result); } catch (error) { console.error(`Error scanning link ${link}:`, error); } } // Scan script sources const scripts = Array.from(document.querySelectorAll("script")) .map((s) => s.src) .filter(Boolean); const uniqueScripts = [...new Set(scripts)].filter((src) => ncu.checkUrl(src, checkOpt).isValid && !current.urlUtils.trustedDomains?.some((domain) => src.includes(domain)) && !current.urlUtils.dynamicWhitelist?.includes(src)); for (const src of uniqueScripts.slice(0, 5)) { try { const norm = await NDS.asyncDecodeAnyToPlainText(src); const url = norm.val(); const result = await NSB.analyzeUrl(url.normalize("NFC"), current.scanOptions.analyseOptions); if (result.isMalicious && mapConfidenceToNumber(result.confidence) < current.confidenceThreshold) { result.isMalicious = false; } results.push(result); } catch (error) { console.error(`Error scanning script ${src}:`, error); } } // Scan iframes const iframes = Array.from(document.querySelectorAll("iframe")) .map((i) => i.src) .filter(Boolean); const uniqueIframes = [...new Set(iframes)].filter((src) => ncu.checkUrl(src, checkOpt).isValid && !current.urlUtils.trustedDomains?.some((domain) => src.includes(domain)) && !current.urlUtils.dynamicWhitelist?.includes(src)); for (const src of uniqueIframes) { try { const norm = await NDS.asyncDecodeAnyToPlainText(src); const url = norm.val(); const result = await NSB.analyzeUrl(url.normalize("NFC"), current.scanOptions.analyseOptions); if (result.isMalicious && mapConfidenceToNumber(result.confidence) < current.confidenceThreshold) { result.isMalicious = false; } results.push(result); } catch (error) { console.error(`Error scanning iframe ${src}:`, error); } } } catch (error) { console.error("Deep scan error:", error); } return results; }; /** * Force an immediate scan */ const forceScan = async () => { await performScan(); }; // Initialize request interception useEffect(() => { if (config.interceptRequests) { setupRequestInterception(); } return () => { if (scanIntervalRef.current) { clearInterval(scanIntervalRef.current); } }; }, [config.interceptRequests]); // Start background scanning when enabled useEffect(() => { if (config.enableBackgroundScanning && !isPaused) { startBackgroundScanning(); performScan(); } else if (!config.enableBackgroundScanning && scanIntervalRef.current) { clearInterval(scanIntervalRef.current); scanIntervalRef.current = null; } return () => { if (scanIntervalRef.current) { clearInterval(scanIntervalRef.current); } }; }, [config.enableBackgroundScanning, config.scanInterval, isPaused]); /** * Setup request interception using fetch API */ const setupRequestInterception = () => { const originalFetch = window.fetch; window.fetch = async (input, init) => { const url = typeof input === "string" ? input : input?.url ?? ""; if (configRef.current.urlUtils.trustedDomains?.some((domain) => url.includes(domain)) || configRef.current.urlUtils.dynamicWhitelist?.includes(url)) { return originalFetch(input, init); } try { const norm = await NDS.asyncDecodeAnyToPlainText(url); const link = norm.val(); const analysisResult = await NSB.analyzeUrl(link.normalize("NFC"), configRef.current.scanOptions.analyseOptions); if (analysisResult.isMalicious && mapConfidenceToNumber(analysisResult.confidence) >= configRef.current.confidenceThreshold && configRef.current.blockMaliciousRequests) { console.warn("Nehonix Shield blocked malicious request:", url, analysisResult); if (configRef.current.onBlock) { configRef.current.onBlock(analysisResult, new Request(url, init)); } return Promise.reject(new Error("Request blocked by Nehonix Shield: Malicious URL detected")); } const response = await originalFetch(input, init); const responseClone = response.clone(); if (configRef.current.blockMaliciousResponses) { try { const responseText = await responseClone.text(); const contentType = response.headers.get("content-type") || ""; if (contentType.includes("text/") || contentType.includes("application/json")) { const mockUrl = `http://mock.nehonix.space?data=${encodeURIComponent(responseText.substring(0, 2000))}`; const norm = await NDS.asyncDecodeAnyToPlainText(mockUrl); const mockUrlDecoded = norm.val(); const mockUrlNormalized = mockUrlDecoded.normalize("NFC"); const responseAnalysis = await NSB.analyzeUrl(mockUrlNormalized, configRef.current.scanOptions.analyseOptions); if (responseAnalysis.isMalicious && mapConfidenceToNumber(responseAnalysis.confidence) >= configRef.current.confidenceThreshold) { console.warn("Nehonix Shield blocked malicious response:", url, responseAnalysis); if (configRef.current.onBlock) { configRef.current.onBlock(responseAnalysis, new Request(url, init)); } return Promise.reject(new Error("Response blocked by Nehonix Shield: Malicious content detected")); } } return new Response(responseText, { status: response.status, statusText: response.statusText, headers: response.headers, }); } catch (error) { console.error("Error analyzing response:", error); return response; } } return response; } catch (error) { console.error("Error in request interception:", error); return originalFetch(input, init); } }; const originalXHROpen = XMLHttpRequest.prototype.open; const originalXHRSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function (method, url, ...args) { const urlString = url.toString(); this._nehonixUrl = urlString; return originalXHROpen.apply(this, [method, url, ...args]); }; XMLHttpRequest.prototype.send = async function (body) { if (!this._nehonixUrl || configRef.current.urlUtils.trustedDomains?.some((domain) => this._nehonixUrl.includes(domain)) || configRef.current.urlUtils.dynamicWhitelist?.includes(this._nehonixUrl)) { return originalXHRSend.apply(this, [body]); } try { const norm = await NDS.asyncDecodeAnyToPlainText(this._nehonixUrl); const link = norm.val(); const normalisedLink = link.normalize("NFC"); const analysisResult = await NSB.analyzeUrl(normalisedLink, configRef.current.scanOptions.analyseOptions); if (analysisResult.isMalicious && mapConfidenceToNumber(analysisResult.confidence) >= configRef.current.confidenceThreshold && configRef.current.blockMaliciousRequests) { console.warn("Nehonix Shield blocked malicious XHR request:", this._nehonixUrl, analysisResult); if (configRef.current.onBlock) { const request = new Request(this._nehonixUrl); configRef.current.onBlock(analysisResult, request); } this.abort(); const errorEvent = new ErrorEvent("error", { error: new Error("Request blocked by Nehonix Shield: Malicious URL detected"), message: "Request blocked by Nehonix Shield: Malicious URL detected", }); this.dispatchEvent(errorEvent); return; } } catch (error) { console.error("Error in XHR interception:", error); } return originalXHRSend.apply(this, [body]); }; }; const contextValue = { config, updateConfig, analysisResults, isScanning, pauseScanning, resumeScanning, forceScan, clearResults, addToDynamicWhitelist, }; return (_jsx(NehonixShieldContext.Provider, { value: contextValue, children: children })); }; //# sourceMappingURL=REACT.NehonixShield.js.map