compromising-position 1.0.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/LICENSE +21 -0
- package/README.md +250 -0
- package/bin/compromising-position +29 -0
- package/dist/checks/hibp-email.d.ts +7 -0
- package/dist/checks/hibp-email.d.ts.map +1 -0
- package/dist/checks/hibp-email.js +99 -0
- package/dist/checks/hibp-email.js.map +1 -0
- package/dist/checks/hibp-password.d.ts +13 -0
- package/dist/checks/hibp-password.d.ts.map +1 -0
- package/dist/checks/hibp-password.js +119 -0
- package/dist/checks/hibp-password.js.map +1 -0
- package/dist/checks/local-check.d.ts +9 -0
- package/dist/checks/local-check.d.ts.map +1 -0
- package/dist/checks/local-check.js +36 -0
- package/dist/checks/local-check.js.map +1 -0
- package/dist/checks/plugin.d.ts +29 -0
- package/dist/checks/plugin.d.ts.map +1 -0
- package/dist/checks/plugin.js +2 -0
- package/dist/checks/plugin.js.map +1 -0
- package/dist/checks/plugins/common-secrets-plugin.d.ts +3 -0
- package/dist/checks/plugins/common-secrets-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/common-secrets-plugin.js +130 -0
- package/dist/checks/plugins/common-secrets-plugin.js.map +1 -0
- package/dist/checks/plugins/dehashed-plugin.d.ts +3 -0
- package/dist/checks/plugins/dehashed-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/dehashed-plugin.js +86 -0
- package/dist/checks/plugins/dehashed-plugin.js.map +1 -0
- package/dist/checks/plugins/emailrep-plugin.d.ts +3 -0
- package/dist/checks/plugins/emailrep-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/emailrep-plugin.js +95 -0
- package/dist/checks/plugins/emailrep-plugin.js.map +1 -0
- package/dist/checks/plugins/gitguardian-hsl-plugin.d.ts +3 -0
- package/dist/checks/plugins/gitguardian-hsl-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/gitguardian-hsl-plugin.js +75 -0
- package/dist/checks/plugins/gitguardian-hsl-plugin.js.map +1 -0
- package/dist/checks/plugins/hibp-email-plugin.d.ts +3 -0
- package/dist/checks/plugins/hibp-email-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/hibp-email-plugin.js +73 -0
- package/dist/checks/plugins/hibp-email-plugin.js.map +1 -0
- package/dist/checks/plugins/hibp-password-plugin.d.ts +3 -0
- package/dist/checks/plugins/hibp-password-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/hibp-password-plugin.js +39 -0
- package/dist/checks/plugins/hibp-password-plugin.js.map +1 -0
- package/dist/checks/plugins/intelx-plugin.d.ts +3 -0
- package/dist/checks/plugins/intelx-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/intelx-plugin.js +113 -0
- package/dist/checks/plugins/intelx-plugin.js.map +1 -0
- package/dist/checks/plugins/leakcheck-plugin.d.ts +3 -0
- package/dist/checks/plugins/leakcheck-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/leakcheck-plugin.js +82 -0
- package/dist/checks/plugins/leakcheck-plugin.js.map +1 -0
- package/dist/checks/plugins/local-analysis-plugin.d.ts +3 -0
- package/dist/checks/plugins/local-analysis-plugin.d.ts.map +1 -0
- package/dist/checks/plugins/local-analysis-plugin.js +36 -0
- package/dist/checks/plugins/local-analysis-plugin.js.map +1 -0
- package/dist/checks/registry.d.ts +24 -0
- package/dist/checks/registry.d.ts.map +1 -0
- package/dist/checks/registry.js +53 -0
- package/dist/checks/registry.js.map +1 -0
- package/dist/config/config.d.ts +10 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +56 -0
- package/dist/config/config.js.map +1 -0
- package/dist/core/entropy.d.ts +23 -0
- package/dist/core/entropy.d.ts.map +1 -0
- package/dist/core/entropy.js +180 -0
- package/dist/core/entropy.js.map +1 -0
- package/dist/core/fingerprint.d.ts +7 -0
- package/dist/core/fingerprint.d.ts.map +1 -0
- package/dist/core/fingerprint.js +10 -0
- package/dist/core/fingerprint.js.map +1 -0
- package/dist/core/key-identifier.d.ts +9 -0
- package/dist/core/key-identifier.d.ts.map +1 -0
- package/dist/core/key-identifier.js +310 -0
- package/dist/core/key-identifier.js.map +1 -0
- package/dist/core/sanitize.d.ts +7 -0
- package/dist/core/sanitize.d.ts.map +1 -0
- package/dist/core/sanitize.js +15 -0
- package/dist/core/sanitize.js.map +1 -0
- package/dist/core/secure-buffer.d.ts +61 -0
- package/dist/core/secure-buffer.d.ts.map +1 -0
- package/dist/core/secure-buffer.js +122 -0
- package/dist/core/secure-buffer.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +472 -0
- package/dist/index.js.map +1 -0
- package/dist/input/batch-parser.d.ts +21 -0
- package/dist/input/batch-parser.d.ts.map +1 -0
- package/dist/input/batch-parser.js +65 -0
- package/dist/input/batch-parser.js.map +1 -0
- package/dist/input/secure-prompt.d.ts +11 -0
- package/dist/input/secure-prompt.d.ts.map +1 -0
- package/dist/input/secure-prompt.js +105 -0
- package/dist/input/secure-prompt.js.map +1 -0
- package/dist/output/audit-log.d.ts +11 -0
- package/dist/output/audit-log.d.ts.map +1 -0
- package/dist/output/audit-log.js +50 -0
- package/dist/output/audit-log.js.map +1 -0
- package/dist/output/csv.d.ts +6 -0
- package/dist/output/csv.d.ts.map +1 -0
- package/dist/output/csv.js +28 -0
- package/dist/output/csv.js.map +1 -0
- package/dist/output/formatter.d.ts +12 -0
- package/dist/output/formatter.d.ts.map +1 -0
- package/dist/output/formatter.js +154 -0
- package/dist/output/formatter.js.map +1 -0
- package/dist/output/sarif.d.ts +6 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +52 -0
- package/dist/output/sarif.js.map +1 -0
- package/dist/types/index.d.ts +141 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +45 -0
- package/dist/types/index.js.map +1 -0
- package/dist/verification/anthropic-verifier.d.ts +3 -0
- package/dist/verification/anthropic-verifier.d.ts.map +1 -0
- package/dist/verification/anthropic-verifier.js +56 -0
- package/dist/verification/anthropic-verifier.js.map +1 -0
- package/dist/verification/aws-verifier.d.ts +14 -0
- package/dist/verification/aws-verifier.d.ts.map +1 -0
- package/dist/verification/aws-verifier.js +30 -0
- package/dist/verification/aws-verifier.js.map +1 -0
- package/dist/verification/github-verifier.d.ts +4 -0
- package/dist/verification/github-verifier.d.ts.map +1 -0
- package/dist/verification/github-verifier.js +62 -0
- package/dist/verification/github-verifier.js.map +1 -0
- package/dist/verification/openai-verifier.d.ts +4 -0
- package/dist/verification/openai-verifier.d.ts.map +1 -0
- package/dist/verification/openai-verifier.js +59 -0
- package/dist/verification/openai-verifier.js.map +1 -0
- package/dist/verification/slack-verifier.d.ts +4 -0
- package/dist/verification/slack-verifier.d.ts.map +1 -0
- package/dist/verification/slack-verifier.js +67 -0
- package/dist/verification/slack-verifier.js.map +1 -0
- package/dist/verification/verifier-registry.d.ts +13 -0
- package/dist/verification/verifier-registry.d.ts.map +1 -0
- package/dist/verification/verifier-registry.js +19 -0
- package/dist/verification/verifier-registry.js.map +1 -0
- package/dist/verification/verifier.d.ts +24 -0
- package/dist/verification/verifier.d.ts.map +1 -0
- package/dist/verification/verifier.js +2 -0
- package/dist/verification/verifier.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { sanitizeForTerminal } from "../../core/sanitize.js";
|
|
2
|
+
const INTELX_BASE = "https://2.intelx.io";
|
|
3
|
+
const USER_AGENT = "compromising-position/1.0.0";
|
|
4
|
+
export const intelXPlugin = {
|
|
5
|
+
id: "intelx",
|
|
6
|
+
name: "Intelligence X",
|
|
7
|
+
inputKind: "email",
|
|
8
|
+
requiresNetwork: true,
|
|
9
|
+
requiredConfigKeys: ["INTELX_API_KEY"],
|
|
10
|
+
isFree: false,
|
|
11
|
+
privacySummary: "Full email -> 2.intelx.io (requires paid API key)",
|
|
12
|
+
async check(input, config) {
|
|
13
|
+
const email = input;
|
|
14
|
+
const apiKey = config.pluginApiKeys["INTELX_API_KEY"];
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
return {
|
|
17
|
+
pluginId: "intelx",
|
|
18
|
+
pluginName: "Intelligence X",
|
|
19
|
+
found: false,
|
|
20
|
+
details: "Intelligence X API key not configured",
|
|
21
|
+
severity: "info",
|
|
22
|
+
error: "Missing INTELX_API_KEY",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
// Step 1: Initiate search
|
|
27
|
+
const searchResponse = await fetch(`${INTELX_BASE}/intelligent/search`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
"x-key": apiKey,
|
|
32
|
+
"User-Agent": USER_AGENT,
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify({
|
|
35
|
+
term: email,
|
|
36
|
+
maxresults: 10,
|
|
37
|
+
media: 0,
|
|
38
|
+
sort: 2,
|
|
39
|
+
terminate: [],
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
if (!searchResponse.ok) {
|
|
43
|
+
const statusText = sanitizeForTerminal(searchResponse.statusText);
|
|
44
|
+
return {
|
|
45
|
+
pluginId: "intelx",
|
|
46
|
+
pluginName: "Intelligence X",
|
|
47
|
+
found: false,
|
|
48
|
+
details: `Search API error: ${searchResponse.status} ${statusText}`,
|
|
49
|
+
severity: "info",
|
|
50
|
+
error: `IntelX API returned ${searchResponse.status}: ${statusText}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const searchData = (await searchResponse.json());
|
|
54
|
+
// Step 2: Fetch results
|
|
55
|
+
const resultResponse = await fetch(`${INTELX_BASE}/intelligent/search/result?id=${encodeURIComponent(searchData.id)}&limit=10`, {
|
|
56
|
+
headers: {
|
|
57
|
+
"x-key": apiKey,
|
|
58
|
+
"User-Agent": USER_AGENT,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (!resultResponse.ok) {
|
|
62
|
+
const statusText = sanitizeForTerminal(resultResponse.statusText);
|
|
63
|
+
return {
|
|
64
|
+
pluginId: "intelx",
|
|
65
|
+
pluginName: "Intelligence X",
|
|
66
|
+
found: false,
|
|
67
|
+
details: `Result API error: ${resultResponse.status} ${statusText}`,
|
|
68
|
+
severity: "info",
|
|
69
|
+
error: `IntelX API returned ${resultResponse.status}: ${statusText}`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const resultData = (await resultResponse.json());
|
|
73
|
+
const records = resultData.records ?? [];
|
|
74
|
+
const found = records.length > 0;
|
|
75
|
+
// Categorize sources
|
|
76
|
+
const buckets = new Set(records.map((r) => r.bucket).filter(Boolean));
|
|
77
|
+
let severity = "low";
|
|
78
|
+
if (records.length > 5) {
|
|
79
|
+
severity = "critical";
|
|
80
|
+
}
|
|
81
|
+
else if (records.length > 0) {
|
|
82
|
+
severity = "high";
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
pluginId: "intelx",
|
|
86
|
+
pluginName: "Intelligence X",
|
|
87
|
+
found,
|
|
88
|
+
details: found
|
|
89
|
+
? `Found ${records.length} result(s) across ${buckets.size} source(s) (Tor, I2P, pastes, leaks)`
|
|
90
|
+
: "Not found in Intelligence X",
|
|
91
|
+
severity,
|
|
92
|
+
error: null,
|
|
93
|
+
metadata: {
|
|
94
|
+
resultCount: records.length,
|
|
95
|
+
buckets: Array.from(buckets),
|
|
96
|
+
searchId: searchData.id,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
return {
|
|
103
|
+
pluginId: "intelx",
|
|
104
|
+
pluginName: "Intelligence X",
|
|
105
|
+
found: false,
|
|
106
|
+
details: `Network error: ${sanitizeForTerminal(message)}`,
|
|
107
|
+
severity: "info",
|
|
108
|
+
error: sanitizeForTerminal(message),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=intelx-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intelx-plugin.js","sourceRoot":"","sources":["../../../src/checks/plugins/intelx-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAI7D,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAC1C,MAAM,UAAU,GAAG,6BAA6B,CAAC;AAqBjD,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,gBAAgB;IACtB,SAAS,EAAE,OAAO;IAClB,eAAe,EAAE,IAAI;IACrB,kBAAkB,EAAE,CAAC,gBAAgB,CAAC;IACtC,MAAM,EAAE,KAAK;IACb,cAAc,EAAE,mDAAmD;IAEnE,KAAK,CAAC,KAAK,CACT,KAAc,EACd,MAAiB;QAEjB,MAAM,KAAK,GAAG,KAAe,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAEtD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,gBAAgB;gBAC5B,KAAK,EAAE,KAAK;gBACZ,OAAO,EAAE,uCAAuC;gBAChD,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,wBAAwB;aAChC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,0BAA0B;YAC1B,MAAM,cAAc,GAAG,MAAM,KAAK,CAChC,GAAG,WAAW,qBAAqB,EACnC;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,OAAO,EAAE,MAAM;oBACf,YAAY,EAAE,UAAU;iBACzB;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,IAAI,EAAE,KAAK;oBACX,UAAU,EAAE,EAAE;oBACd,KAAK,EAAE,CAAC;oBACR,IAAI,EAAE,CAAC;oBACP,SAAS,EAAE,EAAE;iBACd,CAAC;aACH,CACF,CAAC;YAEF,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;gBACvB,MAAM,UAAU,GAAG,mBAAmB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;gBAClE,OAAO;oBACL,QAAQ,EAAE,QAAQ;oBAClB,UAAU,EAAE,gBAAgB;oBAC5B,KAAK,EAAE,KAAK;oBACZ,OAAO,EAAE,qBAAqB,cAAc,CAAC,MAAM,IAAI,UAAU,EAAE;oBACnE,QAAQ,EAAE,MAAM;oBAChB,KAAK,EAAE,uBAAuB,cAAc,CAAC,MAAM,KAAK,UAAU,EAAE;iBACrE,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,CAAyB,CAAC;YAEzE,wBAAwB;YACxB,MAAM,cAAc,GAAG,MAAM,KAAK,CAChC,GAAG,WAAW,iCAAiC,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC,WAAW,EAC3F;gBACE,OAAO,EAAE;oBACP,OAAO,EAAE,MAAM;oBACf,YAAY,EAAE,UAAU;iBACzB;aACF,CACF,CAAC;YAEF,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;gBACvB,MAAM,UAAU,GAAG,mBAAmB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;gBAClE,OAAO;oBACL,QAAQ,EAAE,QAAQ;oBAClB,UAAU,EAAE,gBAAgB;oBAC5B,KAAK,EAAE,KAAK;oBACZ,OAAO,EAAE,qBAAqB,cAAc,CAAC,MAAM,IAAI,UAAU,EAAE;oBACnE,QAAQ,EAAE,MAAM;oBAChB,KAAK,EAAE,uBAAuB,cAAc,CAAC,MAAM,KAAK,UAAU,EAAE;iBACrE,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,CAAyB,CAAC;YACzE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YAEjC,qBAAqB;YACrB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAEtE,IAAI,QAAQ,GAAkC,KAAK,CAAC;YACpD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,QAAQ,GAAG,UAAU,CAAC;YACxB,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,QAAQ,GAAG,MAAM,CAAC;YACpB,CAAC;YAED,OAAO;gBACL,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,gBAAgB;gBAC5B,KAAK;gBACL,OAAO,EAAE,KAAK;oBACZ,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,qBAAqB,OAAO,CAAC,IAAI,sCAAsC;oBAChG,CAAC,CAAC,6BAA6B;gBACjC,QAAQ;gBACR,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE;oBACR,WAAW,EAAE,OAAO,CAAC,MAAM;oBAC3B,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;oBAC5B,QAAQ,EAAE,UAAU,CAAC,EAAE;iBACxB;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACL,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,gBAAgB;gBAC5B,KAAK,EAAE,KAAK;gBACZ,OAAO,EAAE,kBAAkB,mBAAmB,CAAC,OAAO,CAAC,EAAE;gBACzD,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC;aACpC,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leakcheck-plugin.d.ts","sourceRoot":"","sources":["../../../src/checks/plugins/leakcheck-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiBhD,eAAO,MAAM,eAAe,EAAE,WAwF7B,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { sanitizeForTerminal } from "../../core/sanitize.js";
|
|
2
|
+
const LEAKCHECK_BASE = "https://leakcheck.io/api/v2/query";
|
|
3
|
+
const USER_AGENT = "compromising-position/1.0.0";
|
|
4
|
+
export const leakCheckPlugin = {
|
|
5
|
+
id: "leakcheck",
|
|
6
|
+
name: "LeakCheck",
|
|
7
|
+
inputKind: "email",
|
|
8
|
+
requiresNetwork: true,
|
|
9
|
+
requiredConfigKeys: ["LEAKCHECK_API_KEY"],
|
|
10
|
+
isFree: false,
|
|
11
|
+
privacySummary: "Full email -> leakcheck.io (requires paid API key)",
|
|
12
|
+
async check(input, config) {
|
|
13
|
+
const email = input;
|
|
14
|
+
const apiKey = config.pluginApiKeys["LEAKCHECK_API_KEY"];
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
return {
|
|
17
|
+
pluginId: "leakcheck",
|
|
18
|
+
pluginName: "LeakCheck",
|
|
19
|
+
found: false,
|
|
20
|
+
details: "LeakCheck API key not configured",
|
|
21
|
+
severity: "info",
|
|
22
|
+
error: "Missing LEAKCHECK_API_KEY",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(`${LEAKCHECK_BASE}/${encodeURIComponent(email)}`, {
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: "application/json",
|
|
29
|
+
"X-API-Key": apiKey,
|
|
30
|
+
"User-Agent": USER_AGENT,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const statusText = sanitizeForTerminal(response.statusText);
|
|
35
|
+
return {
|
|
36
|
+
pluginId: "leakcheck",
|
|
37
|
+
pluginName: "LeakCheck",
|
|
38
|
+
found: false,
|
|
39
|
+
details: `API error: ${response.status} ${statusText}`,
|
|
40
|
+
severity: "info",
|
|
41
|
+
error: `LeakCheck API returned ${response.status}: ${statusText}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const data = (await response.json());
|
|
45
|
+
const found = data.found > 0;
|
|
46
|
+
let severity = "low";
|
|
47
|
+
if (data.found > 10) {
|
|
48
|
+
severity = "critical";
|
|
49
|
+
}
|
|
50
|
+
else if (data.found > 0) {
|
|
51
|
+
severity = "high";
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
pluginId: "leakcheck",
|
|
55
|
+
pluginName: "LeakCheck",
|
|
56
|
+
found,
|
|
57
|
+
details: found
|
|
58
|
+
? `Found in ${data.found} leak(s) from ${data.sources.length} source(s)`
|
|
59
|
+
: "Not found in LeakCheck database",
|
|
60
|
+
severity,
|
|
61
|
+
error: null,
|
|
62
|
+
metadata: {
|
|
63
|
+
found: data.found,
|
|
64
|
+
sourceCount: data.sources.length,
|
|
65
|
+
sources: data.sources.map((s) => s.name),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
71
|
+
return {
|
|
72
|
+
pluginId: "leakcheck",
|
|
73
|
+
pluginName: "LeakCheck",
|
|
74
|
+
found: false,
|
|
75
|
+
details: `Network error: ${sanitizeForTerminal(message)}`,
|
|
76
|
+
severity: "info",
|
|
77
|
+
error: sanitizeForTerminal(message),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=leakcheck-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leakcheck-plugin.js","sourceRoot":"","sources":["../../../src/checks/plugins/leakcheck-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-analysis-plugin.d.ts","sourceRoot":"","sources":["../../../src/checks/plugins/local-analysis-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,eAAO,MAAM,mBAAmB,EAAE,WAwCjC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { performLocalCheck } from "../local-check.js";
|
|
2
|
+
export const localAnalysisPlugin = {
|
|
3
|
+
id: "local-analysis",
|
|
4
|
+
name: "Local Analysis",
|
|
5
|
+
inputKind: "secret",
|
|
6
|
+
requiresNetwork: false,
|
|
7
|
+
requiredConfigKeys: [],
|
|
8
|
+
isFree: true,
|
|
9
|
+
privacySummary: "No data sent (local only)",
|
|
10
|
+
async check(input, _config) {
|
|
11
|
+
const secret = input;
|
|
12
|
+
const result = performLocalCheck(secret);
|
|
13
|
+
const details = [
|
|
14
|
+
`Provider: ${result.identification.provider} (${result.identification.confidence})`,
|
|
15
|
+
`Entropy: ${result.entropy.shannonEntropy} bits/char`,
|
|
16
|
+
];
|
|
17
|
+
if (result.warnings.length > 0) {
|
|
18
|
+
details.push(`Warnings: ${result.warnings.join("; ")}`);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
pluginId: "local-analysis",
|
|
22
|
+
pluginName: "Local Analysis",
|
|
23
|
+
found: false,
|
|
24
|
+
details: details.join(", "),
|
|
25
|
+
severity: result.looksLikeSecret ? "info" : "low",
|
|
26
|
+
error: null,
|
|
27
|
+
metadata: {
|
|
28
|
+
provider: result.identification.provider,
|
|
29
|
+
confidence: result.identification.confidence,
|
|
30
|
+
entropy: result.entropy.shannonEntropy,
|
|
31
|
+
looksLikeSecret: result.looksLikeSecret,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=local-analysis-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-analysis-plugin.js","sourceRoot":"","sources":["../../../src/checks/plugins/local-analysis-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAgB;IAC9C,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,gBAAgB;IACtB,SAAS,EAAE,QAAQ;IACnB,eAAe,EAAE,KAAK;IACtB,kBAAkB,EAAE,EAAE;IACtB,MAAM,EAAE,IAAI;IACZ,cAAc,EAAE,2BAA2B;IAE3C,KAAK,CAAC,KAAK,CACT,KAA4B,EAC5B,OAAkB;QAElB,MAAM,MAAM,GAAG,KAAqB,CAAC;QACrC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAEzC,MAAM,OAAO,GAAG;YACd,aAAa,MAAM,CAAC,cAAc,CAAC,QAAQ,KAAK,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG;YACnF,YAAY,MAAM,CAAC,OAAO,CAAC,cAAc,YAAY;SACtD,CAAC;QAEF,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,gBAAgB;YAC1B,UAAU,EAAE,gBAAgB;YAC5B,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;YACjD,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE;gBACR,QAAQ,EAAE,MAAM,CAAC,cAAc,CAAC,QAAQ;gBACxC,UAAU,EAAE,MAAM,CAAC,cAAc,CAAC,UAAU;gBAC5C,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,cAAc;gBACtC,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CheckPlugin } from "./plugin.js";
|
|
2
|
+
import type { AppConfig, PluginInputKind } from "../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Registry for check plugins. Manages plugin registration and
|
|
5
|
+
* filtering by input kind, network requirements, and config availability.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CheckRegistry {
|
|
8
|
+
#private;
|
|
9
|
+
register(plugin: CheckPlugin): void;
|
|
10
|
+
/** Get all registered plugins. */
|
|
11
|
+
getAll(): readonly CheckPlugin[];
|
|
12
|
+
/** Get plugins filtered by input kind. */
|
|
13
|
+
getByKind(kind: PluginInputKind): CheckPlugin[];
|
|
14
|
+
/**
|
|
15
|
+
* Get plugins that are runnable given the current config.
|
|
16
|
+
* Filters out:
|
|
17
|
+
* - Network plugins when offline
|
|
18
|
+
* - Plugins missing required API keys
|
|
19
|
+
* - Explicitly disabled plugins
|
|
20
|
+
* - Plugins not in the enabled list (if an enabled list is provided)
|
|
21
|
+
*/
|
|
22
|
+
getRunnable(kind: PluginInputKind, config: AppConfig): CheckPlugin[];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/checks/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpE;;;GAGG;AACH,qBAAa,aAAa;;IAGxB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAOnC,kCAAkC;IAClC,MAAM,IAAI,SAAS,WAAW,EAAE;IAIhC,0CAA0C;IAC1C,SAAS,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,EAAE;IAM/C;;;;;;;OAOG;IACH,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,GAAG,WAAW,EAAE;CA2BrE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry for check plugins. Manages plugin registration and
|
|
3
|
+
* filtering by input kind, network requirements, and config availability.
|
|
4
|
+
*/
|
|
5
|
+
export class CheckRegistry {
|
|
6
|
+
#plugins = [];
|
|
7
|
+
register(plugin) {
|
|
8
|
+
if (this.#plugins.some((p) => p.id === plugin.id)) {
|
|
9
|
+
throw new Error(`Plugin already registered: ${plugin.id}`);
|
|
10
|
+
}
|
|
11
|
+
this.#plugins.push(plugin);
|
|
12
|
+
}
|
|
13
|
+
/** Get all registered plugins. */
|
|
14
|
+
getAll() {
|
|
15
|
+
return this.#plugins;
|
|
16
|
+
}
|
|
17
|
+
/** Get plugins filtered by input kind. */
|
|
18
|
+
getByKind(kind) {
|
|
19
|
+
return this.#plugins.filter((p) => p.inputKind === kind || p.inputKind === "both");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get plugins that are runnable given the current config.
|
|
23
|
+
* Filters out:
|
|
24
|
+
* - Network plugins when offline
|
|
25
|
+
* - Plugins missing required API keys
|
|
26
|
+
* - Explicitly disabled plugins
|
|
27
|
+
* - Plugins not in the enabled list (if an enabled list is provided)
|
|
28
|
+
*/
|
|
29
|
+
getRunnable(kind, config) {
|
|
30
|
+
return this.getByKind(kind).filter((p) => {
|
|
31
|
+
// Respect disable list
|
|
32
|
+
if (config.disabledPlugins.length > 0 && config.disabledPlugins.includes(p.id)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
// If an explicit enable list is provided, only include those
|
|
36
|
+
if (config.enabledPlugins.length > 0 && !config.enabledPlugins.includes(p.id)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// Skip network plugins in offline mode
|
|
40
|
+
if (config.offline && p.requiresNetwork) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
// Skip plugins missing required config keys
|
|
44
|
+
for (const key of p.requiredConfigKeys) {
|
|
45
|
+
if (!config.pluginApiKeys[key]) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/checks/registry.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAO,aAAa;IACf,QAAQ,GAAkB,EAAE,CAAC;IAEtC,QAAQ,CAAC,MAAmB;QAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,kCAAkC;IAClC,MAAM;QACJ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,0CAA0C;IAC1C,SAAS,CAAC,IAAqB;QAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM,CACtD,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,WAAW,CAAC,IAAqB,EAAE,MAAiB;QAClD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACvC,uBAAuB;YACvB,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/E,OAAO,KAAK,CAAC;YACf,CAAC;YAED,6DAA6D;YAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC9E,OAAO,KAAK,CAAC;YACf,CAAC;YAED,uCAAuC;YACvC,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;gBACxC,OAAO,KAAK,CAAC;YACf,CAAC;YAED,4CAA4C;YAC5C,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;gBACvC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC/B,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AppConfig } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Load configuration from env vars and CLI options.
|
|
4
|
+
*
|
|
5
|
+
* Only loads .env if --env-file is explicitly provided or the .env file
|
|
6
|
+
* is in the current working directory (with a warning). This prevents
|
|
7
|
+
* a malicious .env in a cloned repo from silently overriding config.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadConfig(cliOptions?: Partial<AppConfig>): AppConfig;
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAanD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,UAAU,GAAE,OAAO,CAAC,SAAS,CAAM,GAAG,SAAS,CAsCzE"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { config as dotenvConfig } from "dotenv";
|
|
4
|
+
/** Known plugin API key env var names. */
|
|
5
|
+
const PLUGIN_API_KEY_VARS = [
|
|
6
|
+
"HIBP_API_KEY",
|
|
7
|
+
"EMAILREP_API_KEY",
|
|
8
|
+
"GITGUARDIAN_API_TOKEN",
|
|
9
|
+
"DEHASHED_EMAIL",
|
|
10
|
+
"DEHASHED_API_KEY",
|
|
11
|
+
"LEAKCHECK_API_KEY",
|
|
12
|
+
"INTELX_API_KEY",
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Load configuration from env vars and CLI options.
|
|
16
|
+
*
|
|
17
|
+
* Only loads .env if --env-file is explicitly provided or the .env file
|
|
18
|
+
* is in the current working directory (with a warning). This prevents
|
|
19
|
+
* a malicious .env in a cloned repo from silently overriding config.
|
|
20
|
+
*/
|
|
21
|
+
export function loadConfig(cliOptions = {}) {
|
|
22
|
+
if (cliOptions.envFile) {
|
|
23
|
+
// Explicit --env-file: load it
|
|
24
|
+
dotenvConfig({ path: resolve(cliOptions.envFile) });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Only auto-load .env from cwd if it exists, with a warning
|
|
28
|
+
const defaultEnv = resolve(".env");
|
|
29
|
+
if (existsSync(defaultEnv)) {
|
|
30
|
+
process.stderr.write(`Note: Loading .env from ${defaultEnv}\n`);
|
|
31
|
+
dotenvConfig({ path: defaultEnv });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Collect plugin API keys from environment
|
|
35
|
+
const pluginApiKeys = {
|
|
36
|
+
...cliOptions.pluginApiKeys,
|
|
37
|
+
};
|
|
38
|
+
for (const varName of PLUGIN_API_KEY_VARS) {
|
|
39
|
+
const val = process.env[varName];
|
|
40
|
+
if (val && !pluginApiKeys[varName]) {
|
|
41
|
+
pluginApiKeys[varName] = val;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
hibpApiKey: cliOptions.hibpApiKey ?? process.env["HIBP_API_KEY"] ?? null,
|
|
46
|
+
auditLogPath: cliOptions.auditLogPath ?? process.env["CP_AUDIT_LOG"] ?? null,
|
|
47
|
+
offline: cliOptions.offline ?? false,
|
|
48
|
+
json: cliOptions.json ?? false,
|
|
49
|
+
verbose: cliOptions.verbose ?? false,
|
|
50
|
+
verify: cliOptions.verify ?? false,
|
|
51
|
+
enabledPlugins: cliOptions.enabledPlugins ?? [],
|
|
52
|
+
disabledPlugins: cliOptions.disabledPlugins ?? [],
|
|
53
|
+
pluginApiKeys,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGhD,0CAA0C;AAC1C,MAAM,mBAAmB,GAAG;IAC1B,cAAc;IACd,kBAAkB;IAClB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,gBAAgB;CACR,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,aAAiC,EAAE;IAC5D,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACvB,+BAA+B;QAC/B,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,4DAA4D;QAC5D,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2BAA2B,UAAU,IAAI,CAC1C,CAAC;YACF,YAAY,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,MAAM,aAAa,GAA2B;QAC5C,GAAG,UAAU,CAAC,aAAa;KAC5B,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,aAAa,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAE,UAAU,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI;QACxE,YAAY,EACV,UAAU,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI;QAChE,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,KAAK;QACpC,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,KAAK;QAC9B,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,KAAK;QACpC,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,KAAK;QAClC,cAAc,EAAE,UAAU,CAAC,cAAc,IAAI,EAAE;QAC/C,eAAe,EAAE,UAAU,CAAC,eAAe,IAAI,EAAE;QACjD,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SecureBuffer } from "./secure-buffer.js";
|
|
2
|
+
import type { Encoding, EntropyResult } from "../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Calculate Shannon entropy (bits per character) from a Buffer.
|
|
5
|
+
* Operates on raw bytes to avoid creating an immutable string.
|
|
6
|
+
*/
|
|
7
|
+
export declare function shannonEntropyFromBuffer(buf: Buffer): number;
|
|
8
|
+
/** Calculate Shannon entropy (bits per character) from a string. */
|
|
9
|
+
export declare function shannonEntropy(data: string): number;
|
|
10
|
+
/**
|
|
11
|
+
* Detect the likely encoding of a buffer by examining byte values.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectEncodingFromBuffer(buf: Buffer): Encoding;
|
|
14
|
+
/** Detect the likely encoding of a string. */
|
|
15
|
+
export declare function detectEncoding(data: string): Encoding;
|
|
16
|
+
/**
|
|
17
|
+
* Analyze entropy of a secret held in a SecureBuffer.
|
|
18
|
+
* Uses Buffer-based operations to avoid creating long-lived strings.
|
|
19
|
+
*/
|
|
20
|
+
export declare function analyzeEntropyFromBuffer(secret: SecureBuffer): EntropyResult;
|
|
21
|
+
/** Analyze entropy of a string. */
|
|
22
|
+
export declare function analyzeEntropy(data: string): EntropyResult;
|
|
23
|
+
//# sourceMappingURL=entropy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../src/core/entropy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiB5D;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBnD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAqC9D;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAQrD;AAsBD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAgC5E;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAuB1D"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate Shannon entropy (bits per character) from a Buffer.
|
|
3
|
+
* Operates on raw bytes to avoid creating an immutable string.
|
|
4
|
+
*/
|
|
5
|
+
export function shannonEntropyFromBuffer(buf) {
|
|
6
|
+
if (buf.length === 0)
|
|
7
|
+
return 0;
|
|
8
|
+
const freq = new Map();
|
|
9
|
+
for (let i = 0; i < buf.length; i++) {
|
|
10
|
+
const byte = buf[i];
|
|
11
|
+
freq.set(byte, (freq.get(byte) ?? 0) + 1);
|
|
12
|
+
}
|
|
13
|
+
let entropy = 0;
|
|
14
|
+
const len = buf.length;
|
|
15
|
+
for (const count of freq.values()) {
|
|
16
|
+
const p = count / len;
|
|
17
|
+
entropy -= p * Math.log2(p);
|
|
18
|
+
}
|
|
19
|
+
return entropy;
|
|
20
|
+
}
|
|
21
|
+
/** Calculate Shannon entropy (bits per character) from a string. */
|
|
22
|
+
export function shannonEntropy(data) {
|
|
23
|
+
if (data.length === 0)
|
|
24
|
+
return 0;
|
|
25
|
+
const freq = new Map();
|
|
26
|
+
for (const ch of data) {
|
|
27
|
+
freq.set(ch, (freq.get(ch) ?? 0) + 1);
|
|
28
|
+
}
|
|
29
|
+
let entropy = 0;
|
|
30
|
+
const len = data.length;
|
|
31
|
+
for (const count of freq.values()) {
|
|
32
|
+
const p = count / len;
|
|
33
|
+
entropy -= p * Math.log2(p);
|
|
34
|
+
}
|
|
35
|
+
return entropy;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Detect the likely encoding of a buffer by examining byte values.
|
|
39
|
+
*/
|
|
40
|
+
export function detectEncodingFromBuffer(buf) {
|
|
41
|
+
let hasPlus = false;
|
|
42
|
+
let hasSlash = false;
|
|
43
|
+
let hasEquals = false;
|
|
44
|
+
let hasUnderscore = false;
|
|
45
|
+
let hasHyphen = false;
|
|
46
|
+
let allHex = true;
|
|
47
|
+
let allAlnum = true;
|
|
48
|
+
let allBase64 = true;
|
|
49
|
+
for (let i = 0; i < buf.length; i++) {
|
|
50
|
+
const b = buf[i];
|
|
51
|
+
const isDigit = b >= 0x30 && b <= 0x39;
|
|
52
|
+
const isUpper = b >= 0x41 && b <= 0x5a;
|
|
53
|
+
const isLower = b >= 0x61 && b <= 0x7a;
|
|
54
|
+
const isHexLower = b >= 0x61 && b <= 0x66;
|
|
55
|
+
const isHexUpper = b >= 0x41 && b <= 0x46;
|
|
56
|
+
const isB64Special = b === 0x2b || b === 0x2f || b === 0x3d; // + / =
|
|
57
|
+
if (b === 0x2b)
|
|
58
|
+
hasPlus = true;
|
|
59
|
+
else if (b === 0x2f)
|
|
60
|
+
hasSlash = true;
|
|
61
|
+
else if (b === 0x3d)
|
|
62
|
+
hasEquals = true;
|
|
63
|
+
else if (b === 0x5f)
|
|
64
|
+
hasUnderscore = true;
|
|
65
|
+
else if (b === 0x2d)
|
|
66
|
+
hasHyphen = true;
|
|
67
|
+
if (!(isDigit || isHexLower || isHexUpper))
|
|
68
|
+
allHex = false;
|
|
69
|
+
if (!(isDigit || isUpper || isLower))
|
|
70
|
+
allAlnum = false;
|
|
71
|
+
if (!(isDigit || isUpper || isLower || isB64Special))
|
|
72
|
+
allBase64 = false;
|
|
73
|
+
}
|
|
74
|
+
if (allHex && !hasPlus && !hasSlash && !hasEquals && !hasUnderscore && !hasHyphen)
|
|
75
|
+
return "hex";
|
|
76
|
+
if (allBase64 && (hasPlus || hasSlash || hasEquals))
|
|
77
|
+
return "base64";
|
|
78
|
+
if (allAlnum && !hasUnderscore && !hasHyphen)
|
|
79
|
+
return "base62";
|
|
80
|
+
if (allAlnum || (!hasPlus && !hasSlash && !hasEquals)) {
|
|
81
|
+
if (hasUnderscore || hasHyphen)
|
|
82
|
+
return "alphanumeric";
|
|
83
|
+
}
|
|
84
|
+
return "mixed";
|
|
85
|
+
}
|
|
86
|
+
/** Detect the likely encoding of a string. */
|
|
87
|
+
export function detectEncoding(data) {
|
|
88
|
+
if (/^[0-9a-fA-F]+$/.test(data))
|
|
89
|
+
return "hex";
|
|
90
|
+
// base64 must contain +, /, or trailing = to distinguish from base62
|
|
91
|
+
if (/^[A-Za-z0-9+/]+=+$/.test(data) || (/^[A-Za-z0-9+/=]+$/.test(data) && /[+/=]/.test(data)))
|
|
92
|
+
return "base64";
|
|
93
|
+
if (/^[A-Za-z0-9]+$/.test(data))
|
|
94
|
+
return "base62";
|
|
95
|
+
if (/^[A-Za-z0-9_-]+$/.test(data))
|
|
96
|
+
return "alphanumeric";
|
|
97
|
+
return "mixed";
|
|
98
|
+
}
|
|
99
|
+
/** Maximum possible Shannon entropy for a given alphabet size. */
|
|
100
|
+
function maxEntropy(alphabetSize) {
|
|
101
|
+
return alphabetSize > 0 ? Math.log2(alphabetSize) : 0;
|
|
102
|
+
}
|
|
103
|
+
function alphabetSizeForEncoding(encoding) {
|
|
104
|
+
switch (encoding) {
|
|
105
|
+
case "hex":
|
|
106
|
+
return 16;
|
|
107
|
+
case "base62":
|
|
108
|
+
return 62;
|
|
109
|
+
case "base64":
|
|
110
|
+
return 64;
|
|
111
|
+
case "alphanumeric":
|
|
112
|
+
return 64; // includes _ and -
|
|
113
|
+
case "mixed":
|
|
114
|
+
return 95; // printable ASCII
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Analyze entropy of a secret held in a SecureBuffer.
|
|
119
|
+
* Uses Buffer-based operations to avoid creating long-lived strings.
|
|
120
|
+
*/
|
|
121
|
+
export function analyzeEntropyFromBuffer(secret) {
|
|
122
|
+
const buf = secret.unsafeGetBuffer();
|
|
123
|
+
// Trim whitespace bytes from the buffer for analysis
|
|
124
|
+
let start = 0;
|
|
125
|
+
let end = buf.length;
|
|
126
|
+
while (start < end && (buf[start] === 0x20 || buf[start] === 0x09 || buf[start] === 0x0a || buf[start] === 0x0d))
|
|
127
|
+
start++;
|
|
128
|
+
while (end > start && (buf[end - 1] === 0x20 || buf[end - 1] === 0x09 || buf[end - 1] === 0x0a || buf[end - 1] === 0x0d))
|
|
129
|
+
end--;
|
|
130
|
+
const trimmed = buf.subarray(start, end);
|
|
131
|
+
const len = trimmed.length;
|
|
132
|
+
const entropy = shannonEntropyFromBuffer(trimmed);
|
|
133
|
+
const encoding = detectEncodingFromBuffer(trimmed);
|
|
134
|
+
const maxEnt = maxEntropy(alphabetSizeForEncoding(encoding));
|
|
135
|
+
const normalized = maxEnt > 0 ? entropy / maxEnt : 0;
|
|
136
|
+
let warning = null;
|
|
137
|
+
if (len < 8) {
|
|
138
|
+
warning = "Very short — likely not a real API key";
|
|
139
|
+
}
|
|
140
|
+
else if (entropy < 2.5) {
|
|
141
|
+
warning = "Very low entropy — may be a placeholder or test value";
|
|
142
|
+
}
|
|
143
|
+
else if (entropy < 3.5 && len < 20) {
|
|
144
|
+
warning = "Low entropy — consider whether this is a real secret";
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
shannonEntropy: Math.round(entropy * 1000) / 1000,
|
|
148
|
+
maxPossibleEntropy: Math.round(maxEnt * 1000) / 1000,
|
|
149
|
+
normalizedEntropy: Math.round(normalized * 1000) / 1000,
|
|
150
|
+
encoding,
|
|
151
|
+
length: len,
|
|
152
|
+
warning,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** Analyze entropy of a string. */
|
|
156
|
+
export function analyzeEntropy(data) {
|
|
157
|
+
const entropy = shannonEntropy(data);
|
|
158
|
+
const encoding = detectEncoding(data);
|
|
159
|
+
const maxEnt = maxEntropy(alphabetSizeForEncoding(encoding));
|
|
160
|
+
const normalized = maxEnt > 0 ? entropy / maxEnt : 0;
|
|
161
|
+
let warning = null;
|
|
162
|
+
if (data.length < 8) {
|
|
163
|
+
warning = "Very short — likely not a real API key";
|
|
164
|
+
}
|
|
165
|
+
else if (entropy < 2.5) {
|
|
166
|
+
warning = "Very low entropy — may be a placeholder or test value";
|
|
167
|
+
}
|
|
168
|
+
else if (entropy < 3.5 && data.length < 20) {
|
|
169
|
+
warning = "Low entropy — consider whether this is a real secret";
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
shannonEntropy: Math.round(entropy * 1000) / 1000,
|
|
173
|
+
maxPossibleEntropy: Math.round(maxEnt * 1000) / 1000,
|
|
174
|
+
normalizedEntropy: Math.round(normalized * 1000) / 1000,
|
|
175
|
+
encoding,
|
|
176
|
+
length: data.length,
|
|
177
|
+
warning,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=entropy.js.map
|