import{n as e}from"./scan-paths-C13EseXp.js";import{a as t}from"./errors-y2V0aFIS.js";import n from"node:path";import r from"node:fs/promises";const i=new Set([`.js`,`.ts`,`.mjs`,`.cjs`,`.mts`,`.cts`,`.jsx`,`.tsx`]),a=new Map,o=new Map;function s(e){return i.has(n.extname(e).toLowerCase())}function c(e){let t=a.get(e.filePath);if(t){if(t.size!==e.size||t.mtimeMs!==e.mtimeMs||t.maxFileBytes!==e.maxFileBytes){a.delete(e.filePath);return}return t}}function l(e,t){if(a.size>=5e3){let e=a.keys().next();e.done||a.delete(e.value)}a.set(e,t)}function u(e,t){if(o.size>=5e3){let e=o.keys().next();e.done||o.delete(e.value)}o.set(e,t)}const d=[{ruleId:`dangerous-exec`,severity:`critical`,message:`Shell command execution detected (child_process)`,pattern:/\b(exec|execSync|spawn|spawnSync|execFile|execFileSync)\s*\(/,requiresContext:/child_process/},{ruleId:`dynamic-code-execution`,severity:`critical`,message:`Dynamic code execution detected`,pattern:/\beval\s*\(|new\s+Function\s*\(/},{ruleId:`crypto-mining`,severity:`critical`,message:`Possible crypto-mining reference detected`,pattern:/stratum\+tcp|stratum\+ssl|coinhive|cryptonight|xmrig/i},{ruleId:`suspicious-network`,severity:`warn`,message:`WebSocket connection to non-standard port`,pattern:/new\s+WebSocket\s*\(\s*["']wss?:\/\/[^"']*:(\d+)/}],f=new Set([80,443,8080,8443,3e3]),p=[{ruleId:`potential-exfiltration`,severity:`warn`,message:`File read combined with network send — possible data exfiltration`,pattern:/readFileSync|readFile/,requiresContext:/\bfetch\b|\bpost\b|http\.request/i},{ruleId:`obfuscated-code`,severity:`warn`,message:`Hex-encoded string sequence detected (possible obfuscation)`,pattern:/(\\x[0-9a-fA-F]{2}){6,}/},{ruleId:`obfuscated-code`,severity:`warn`,message:`Large base64 payload with decode call detected (possible obfuscation)`,pattern:/(?:atob|Buffer\.from)\s*\(\s*["'][A-Za-z0-9+/=]{200,}["']/},{ruleId:`env-harvesting`,severity:`critical`,message:`Environment variable access combined with network send — possible credential harvesting`,pattern:/process\.env/,requiresContext:/\bfetch\b|\bpost\b|http\.request/i}];function m(e,t=120){return e.length<=t?e:`${e.slice(0,t)}…`}function h(e,t){let n=[],r=e.split(`
`),i=new Set;for(let a of d)if(!i.has(a.ruleId)&&!(a.requiresContext&&!a.requiresContext.test(e)))for(let e=0;e<r.length;e++){let o=r[e],s=a.pattern.exec(o);if(s){if(a.ruleId===`suspicious-network`){let e=parseInt(s[1],10);if(f.has(e))continue}n.push({ruleId:a.ruleId,severity:a.severity,file:t,line:e+1,message:a.message,evidence:m(o.trim())}),i.add(a.ruleId);break}}let a=new Set;for(let i of p){let o=`${i.ruleId}::${i.message}`;if(a.has(o)||!i.pattern.test(e)||i.requiresContext&&!i.requiresContext.test(e))continue;let s=0,c=``;for(let e=0;e<r.length;e++)if(i.pattern.test(r[e])){s=e+1,c=r[e].trim();break}s===0&&(s=1,c=e.slice(0,120)),n.push({ruleId:i.ruleId,severity:i.severity,file:t,line:s,message:i.message,evidence:m(c)}),a.add(o)}return n}function g(e){return{includeFiles:e?.includeFiles??[],maxFiles:Math.max(1,e?.maxFiles??500),maxFileBytes:Math.max(1,e?.maxFileBytes??1048576)}}async function _(e,t){let r=[],i=[e];for(;i.length>0&&r.length<t;){let e=i.pop();if(!e)break;let a=await v(e);for(let o of a){if(r.length>=t)break;if(o.name.startsWith(`.`)||o.name===`node_modules`)continue;let a=n.join(e,o.name);o.kind===`dir`?i.push(a):o.kind===`file`&&s(o.name)&&r.push(a)}}return r}async function v(e){let n=null;try{n=await r.stat(e)}catch(e){if(t(e,`ENOENT`))return[];throw e}if(!n?.isDirectory())return[];let i=o.get(e);if(i&&i.mtimeMs===n.mtimeMs)return i.entries;let a=await r.readdir(e,{withFileTypes:!0}),s=[];for(let e of a)e.isDirectory()?s.push({name:e.name,kind:`dir`}):e.isFile()&&s.push({name:e.name,kind:`file`});return u(e,{mtimeMs:n.mtimeMs,entries:s}),s}async function y(i){if(i.includeFiles.length===0)return[];let a=new Set,o=[];for(let c of i.includeFiles){let l=n.resolve(i.rootDir,c);if(!e(i.rootDir,l)||!s(l)||a.has(l))continue;let u=null;try{u=await r.stat(l)}catch(e){if(t(e,`ENOENT`))continue;throw e}u?.isFile()&&(o.push(l),a.add(l))}return o}async function b(e,t){let r=await y({rootDir:e,includeFiles:t.includeFiles});if(r.length>=t.maxFiles)return r.slice(0,t.maxFiles);let i=await _(e,t.maxFiles),a=new Set(r.map(e=>n.resolve(e))),o=[...r];for(let e of i){if(o.length>=t.maxFiles)break;let r=n.resolve(e);a.has(r)||(o.push(e),a.add(r))}return o}async function x(e){let{filePath:n,maxFileBytes:i}=e,a=null;try{a=await r.stat(n)}catch(e){if(t(e,`ENOENT`))return{scanned:!1,findings:[]};throw e}if(!a?.isFile())return{scanned:!1,findings:[]};let o=c({filePath:n,size:a.size,mtimeMs:a.mtimeMs,maxFileBytes:i});if(o)return{scanned:o.scanned,findings:o.findings};if(a.size>i)return l(n,{size:a.size,mtimeMs:a.mtimeMs,maxFileBytes:i,scanned:!1,findings:[]}),{scanned:!1,findings:[]};let s;try{s=await r.readFile(n,`utf-8`)}catch(e){if(t(e,`ENOENT`))return{scanned:!1,findings:[]};throw e}let u=h(s,n);return l(n,{size:a.size,mtimeMs:a.mtimeMs,maxFileBytes:i,scanned:!0,findings:u}),{scanned:!0,findings:u}}async function S(e,t){let n=g(t),r=await b(e,n),i=[],a=0,o=0,s=0,c=0;for(let e of r){let t=await x({filePath:e,maxFileBytes:n.maxFileBytes});if(t.scanned){a+=1;for(let e of t.findings)i.push(e),e.severity===`critical`?o+=1:e.severity===`warn`?s+=1:c+=1}}return{scannedFiles:a,critical:o,warn:s,info:c,findings:i}}export{S as t};
