@profullstack/threatcrush 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/daemon.js CHANGED
@@ -4362,7 +4362,7 @@ var XXE_GUARD = /FEATURE_SECURE_PROCESSING|setExpandEntityReferences|disallow-do
4362
4362
  var XML_PARSING_FILE = /\b(?:javax\.xml|org\.xml\.sax|org\.w3c\.dom|org\.jdom2?|org\.dom4j|XmlPullParser|DocumentBuilderFactory|DocumentBuilder|SAXParserFactory|SAXParser|XMLInputFactory|XMLReaderFactory|XMLReader|SAXBuilder|SAXReader)\b/;
4363
4363
  var CODE_SINK = /\bglobalThis\s*\[|\bconstructor\b|\beval\b|\bFunction\b|\brun\s*\(|\bvm\s*\.\s*run/;
4364
4364
  var EXFIL_SINK = /\bconsole\s*\.\s*(?:log|debug|info|warn|error)\s*\(|\bfetch\s*\(|\baxios\b|\brequest\s*\(|\.\s*send\s*\(/;
4365
- var SQL_KEYWORDS = "SELECT|INSERT\\s+INTO|INSERT|UPDATE|DELETE\\s+FROM|DELETE|DROP|UNION\\s+SELECT";
4365
+ var SQL_KEYWORDS = "SELECT\\b(?=[^`'\"\\n]*\\bFROM\\b)|INSERT\\s+INTO|UPDATE\\b(?=[^`'\"\\n]*\\bSET\\b)|DELETE\\s+FROM|DROP\\s+(?:TABLE|DATABASE|INDEX|VIEW|SCHEMA)|TRUNCATE\\s+TABLE|UNION\\s+SELECT";
4366
4366
  var SQL_IN_DOUBLE = `"[^"\\n]*(?:${SQL_KEYWORDS})\\b[^"\\n]*"`;
4367
4367
  var SQL_IN_SINGLE = `'[^'\\n]*(?:${SQL_KEYWORDS})\\b[^'\\n]*'`;
4368
4368
  var SQL_STRING = `(?:${SQL_IN_DOUBLE}|${SQL_IN_SINGLE})`;
@@ -5866,6 +5866,81 @@ function scanManifest(relativePath, filename, text) {
5866
5866
  // ../../packages/scan/src/node/walk.ts
5867
5867
  var import_node_fs10 = require("fs");
5868
5868
  var import_node_path5 = require("path");
5869
+ function compileExcludes(patterns) {
5870
+ const matchers = patterns.map((p) => p.trim()).filter((p) => p.length > 0 && !p.startsWith("#")).map(compilePattern);
5871
+ if (matchers.length === 0) return () => false;
5872
+ return (relPath) => {
5873
+ const segs = relPath.split("/");
5874
+ return matchers.some((m) => m(segs));
5875
+ };
5876
+ }
5877
+ var GLOBSTAR = /* @__PURE__ */ Symbol("globstar");
5878
+ function compilePattern(pattern) {
5879
+ const withoutLead = pattern.replace(/^\.?\//, "");
5880
+ let end = withoutLead.length;
5881
+ while (end > 0 && withoutLead[end - 1] === "/") end -= 1;
5882
+ const p = withoutLead.slice(0, end);
5883
+ if (!p.includes("/")) {
5884
+ if (p === "**") return () => true;
5885
+ const rx = segToRegExp(p);
5886
+ return (segs) => segs.some((s) => rx.test(s));
5887
+ }
5888
+ const raw = p.split("/");
5889
+ const trailingGlobstar = raw[raw.length - 1] === "**";
5890
+ const core = trailingGlobstar ? raw.slice(0, -1) : raw;
5891
+ const parts = core.map((s) => s === "**" ? GLOBSTAR : segToRegExp(s));
5892
+ return (segs) => {
5893
+ const end2 = matchPrefix(parts, segs);
5894
+ if (end2 < 0) return false;
5895
+ return trailingGlobstar ? end2 < segs.length : true;
5896
+ };
5897
+ }
5898
+ function segToRegExp(seg) {
5899
+ let body = "";
5900
+ for (let i = 0; i < seg.length; i += 1) {
5901
+ const c = seg[i];
5902
+ if (c === "*") {
5903
+ while (seg[i + 1] === "*") i += 1;
5904
+ body += "[^/]*";
5905
+ } else if (c === "?") {
5906
+ body += "[^/]";
5907
+ } else {
5908
+ body += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
5909
+ }
5910
+ }
5911
+ return new RegExp(`^${body}$`);
5912
+ }
5913
+ function matchPrefix(parts, segs) {
5914
+ let pi = 0;
5915
+ let si = 0;
5916
+ let star = -1;
5917
+ let starSi = -1;
5918
+ while (pi < parts.length) {
5919
+ const part = parts[pi];
5920
+ if (part === GLOBSTAR) {
5921
+ star = pi;
5922
+ starSi = si;
5923
+ pi += 1;
5924
+ } else if (si < segs.length && part.test(segs[si])) {
5925
+ pi += 1;
5926
+ si += 1;
5927
+ } else if (star !== -1 && starSi < segs.length) {
5928
+ starSi += 1;
5929
+ si = starSi;
5930
+ pi = star + 1;
5931
+ } else {
5932
+ return -1;
5933
+ }
5934
+ }
5935
+ return si;
5936
+ }
5937
+ function readIgnoreFile(root) {
5938
+ try {
5939
+ return (0, import_node_fs10.readFileSync)((0, import_node_path5.join)(root, ".threatcrushignore"), "utf-8").split("\n");
5940
+ } catch {
5941
+ return [];
5942
+ }
5943
+ }
5869
5944
  function scanPath(targetPath, options = {}) {
5870
5945
  const maxFileBytes = options.maxFileBytes ?? 1024 * 1024;
5871
5946
  const allowed = options.categories ? new Set(options.categories) : null;
@@ -5873,6 +5948,7 @@ function scanPath(targetPath, options = {}) {
5873
5948
  const unreadable = [];
5874
5949
  let filesScanned = 0;
5875
5950
  let suppressed = 0;
5951
+ let excluded = 0;
5876
5952
  const rootIsDirectory = (() => {
5877
5953
  try {
5878
5954
  return (0, import_node_fs10.statSync)(targetPath).isDirectory();
@@ -5881,6 +5957,7 @@ function scanPath(targetPath, options = {}) {
5881
5957
  }
5882
5958
  })();
5883
5959
  const walkRoot = rootIsDirectory ? targetPath : (0, import_node_path5.dirname)(targetPath);
5960
+ const isExcluded = compileExcludes([...options.exclude ?? [], ...readIgnoreFile(walkRoot)]);
5884
5961
  const scanFile = (fullPath, filename) => {
5885
5962
  const relativePath = toRelative(walkRoot, fullPath);
5886
5963
  const extension = (0, import_node_path5.extname)(filename).toLowerCase();
@@ -5938,17 +6015,28 @@ function scanPath(targetPath, options = {}) {
5938
6015
  }
5939
6016
  for (const entry of entries) {
5940
6017
  const fullPath = (0, import_node_path5.join)(currentPath, entry.name);
6018
+ const relativePath = toRelative(walkRoot, fullPath);
5941
6019
  if (entry.isDirectory()) {
5942
6020
  if (SKIP_DIRS.has(entry.name)) continue;
6021
+ if (isExcluded(relativePath)) {
6022
+ excluded += 1;
6023
+ continue;
6024
+ }
5943
6025
  walk(fullPath);
5944
6026
  continue;
5945
6027
  }
5946
6028
  if (!entry.isFile()) continue;
6029
+ if (isExcluded(relativePath)) {
6030
+ excluded += 1;
6031
+ continue;
6032
+ }
5947
6033
  scanFile(fullPath, entry.name);
5948
6034
  }
5949
6035
  };
5950
6036
  if (rootIsDirectory) {
5951
6037
  walk(targetPath);
6038
+ } else if (isExcluded(toRelative(walkRoot, targetPath))) {
6039
+ excluded += 1;
5952
6040
  } else {
5953
6041
  scanFile(targetPath, (0, import_node_path5.basename)(targetPath));
5954
6042
  }
@@ -5956,7 +6044,7 @@ function scanPath(targetPath, options = {}) {
5956
6044
  filtered.sort(
5957
6045
  (a, b) => severityRank(b.severity) - severityRank(a.severity) || a.file.localeCompare(b.file) || a.line - b.line
5958
6046
  );
5959
- return { findings: filtered, filesScanned, unreadable, suppressed, root: walkRoot };
6047
+ return { findings: filtered, filesScanned, unreadable, suppressed, excluded, root: walkRoot };
5960
6048
  }
5961
6049
  function recordSensitiveFile(filename, relativePath, sink, fileFindings) {
5962
6050
  if (fileFindings.length > 0) return;