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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +250 -0
  3. package/bin/compromising-position +29 -0
  4. package/dist/checks/hibp-email.d.ts +7 -0
  5. package/dist/checks/hibp-email.d.ts.map +1 -0
  6. package/dist/checks/hibp-email.js +99 -0
  7. package/dist/checks/hibp-email.js.map +1 -0
  8. package/dist/checks/hibp-password.d.ts +13 -0
  9. package/dist/checks/hibp-password.d.ts.map +1 -0
  10. package/dist/checks/hibp-password.js +119 -0
  11. package/dist/checks/hibp-password.js.map +1 -0
  12. package/dist/checks/local-check.d.ts +9 -0
  13. package/dist/checks/local-check.d.ts.map +1 -0
  14. package/dist/checks/local-check.js +36 -0
  15. package/dist/checks/local-check.js.map +1 -0
  16. package/dist/checks/plugin.d.ts +29 -0
  17. package/dist/checks/plugin.d.ts.map +1 -0
  18. package/dist/checks/plugin.js +2 -0
  19. package/dist/checks/plugin.js.map +1 -0
  20. package/dist/checks/plugins/common-secrets-plugin.d.ts +3 -0
  21. package/dist/checks/plugins/common-secrets-plugin.d.ts.map +1 -0
  22. package/dist/checks/plugins/common-secrets-plugin.js +130 -0
  23. package/dist/checks/plugins/common-secrets-plugin.js.map +1 -0
  24. package/dist/checks/plugins/dehashed-plugin.d.ts +3 -0
  25. package/dist/checks/plugins/dehashed-plugin.d.ts.map +1 -0
  26. package/dist/checks/plugins/dehashed-plugin.js +86 -0
  27. package/dist/checks/plugins/dehashed-plugin.js.map +1 -0
  28. package/dist/checks/plugins/emailrep-plugin.d.ts +3 -0
  29. package/dist/checks/plugins/emailrep-plugin.d.ts.map +1 -0
  30. package/dist/checks/plugins/emailrep-plugin.js +95 -0
  31. package/dist/checks/plugins/emailrep-plugin.js.map +1 -0
  32. package/dist/checks/plugins/gitguardian-hsl-plugin.d.ts +3 -0
  33. package/dist/checks/plugins/gitguardian-hsl-plugin.d.ts.map +1 -0
  34. package/dist/checks/plugins/gitguardian-hsl-plugin.js +75 -0
  35. package/dist/checks/plugins/gitguardian-hsl-plugin.js.map +1 -0
  36. package/dist/checks/plugins/hibp-email-plugin.d.ts +3 -0
  37. package/dist/checks/plugins/hibp-email-plugin.d.ts.map +1 -0
  38. package/dist/checks/plugins/hibp-email-plugin.js +73 -0
  39. package/dist/checks/plugins/hibp-email-plugin.js.map +1 -0
  40. package/dist/checks/plugins/hibp-password-plugin.d.ts +3 -0
  41. package/dist/checks/plugins/hibp-password-plugin.d.ts.map +1 -0
  42. package/dist/checks/plugins/hibp-password-plugin.js +39 -0
  43. package/dist/checks/plugins/hibp-password-plugin.js.map +1 -0
  44. package/dist/checks/plugins/intelx-plugin.d.ts +3 -0
  45. package/dist/checks/plugins/intelx-plugin.d.ts.map +1 -0
  46. package/dist/checks/plugins/intelx-plugin.js +113 -0
  47. package/dist/checks/plugins/intelx-plugin.js.map +1 -0
  48. package/dist/checks/plugins/leakcheck-plugin.d.ts +3 -0
  49. package/dist/checks/plugins/leakcheck-plugin.d.ts.map +1 -0
  50. package/dist/checks/plugins/leakcheck-plugin.js +82 -0
  51. package/dist/checks/plugins/leakcheck-plugin.js.map +1 -0
  52. package/dist/checks/plugins/local-analysis-plugin.d.ts +3 -0
  53. package/dist/checks/plugins/local-analysis-plugin.d.ts.map +1 -0
  54. package/dist/checks/plugins/local-analysis-plugin.js +36 -0
  55. package/dist/checks/plugins/local-analysis-plugin.js.map +1 -0
  56. package/dist/checks/registry.d.ts +24 -0
  57. package/dist/checks/registry.d.ts.map +1 -0
  58. package/dist/checks/registry.js +53 -0
  59. package/dist/checks/registry.js.map +1 -0
  60. package/dist/config/config.d.ts +10 -0
  61. package/dist/config/config.d.ts.map +1 -0
  62. package/dist/config/config.js +56 -0
  63. package/dist/config/config.js.map +1 -0
  64. package/dist/core/entropy.d.ts +23 -0
  65. package/dist/core/entropy.d.ts.map +1 -0
  66. package/dist/core/entropy.js +180 -0
  67. package/dist/core/entropy.js.map +1 -0
  68. package/dist/core/fingerprint.d.ts +7 -0
  69. package/dist/core/fingerprint.d.ts.map +1 -0
  70. package/dist/core/fingerprint.js +10 -0
  71. package/dist/core/fingerprint.js.map +1 -0
  72. package/dist/core/key-identifier.d.ts +9 -0
  73. package/dist/core/key-identifier.d.ts.map +1 -0
  74. package/dist/core/key-identifier.js +310 -0
  75. package/dist/core/key-identifier.js.map +1 -0
  76. package/dist/core/sanitize.d.ts +7 -0
  77. package/dist/core/sanitize.d.ts.map +1 -0
  78. package/dist/core/sanitize.js +15 -0
  79. package/dist/core/sanitize.js.map +1 -0
  80. package/dist/core/secure-buffer.d.ts +61 -0
  81. package/dist/core/secure-buffer.d.ts.map +1 -0
  82. package/dist/core/secure-buffer.js +122 -0
  83. package/dist/core/secure-buffer.js.map +1 -0
  84. package/dist/index.d.ts +4 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +472 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/input/batch-parser.d.ts +21 -0
  89. package/dist/input/batch-parser.d.ts.map +1 -0
  90. package/dist/input/batch-parser.js +65 -0
  91. package/dist/input/batch-parser.js.map +1 -0
  92. package/dist/input/secure-prompt.d.ts +11 -0
  93. package/dist/input/secure-prompt.d.ts.map +1 -0
  94. package/dist/input/secure-prompt.js +105 -0
  95. package/dist/input/secure-prompt.js.map +1 -0
  96. package/dist/output/audit-log.d.ts +11 -0
  97. package/dist/output/audit-log.d.ts.map +1 -0
  98. package/dist/output/audit-log.js +50 -0
  99. package/dist/output/audit-log.js.map +1 -0
  100. package/dist/output/csv.d.ts +6 -0
  101. package/dist/output/csv.d.ts.map +1 -0
  102. package/dist/output/csv.js +28 -0
  103. package/dist/output/csv.js.map +1 -0
  104. package/dist/output/formatter.d.ts +12 -0
  105. package/dist/output/formatter.d.ts.map +1 -0
  106. package/dist/output/formatter.js +154 -0
  107. package/dist/output/formatter.js.map +1 -0
  108. package/dist/output/sarif.d.ts +6 -0
  109. package/dist/output/sarif.d.ts.map +1 -0
  110. package/dist/output/sarif.js +52 -0
  111. package/dist/output/sarif.js.map +1 -0
  112. package/dist/types/index.d.ts +141 -0
  113. package/dist/types/index.d.ts.map +1 -0
  114. package/dist/types/index.js +45 -0
  115. package/dist/types/index.js.map +1 -0
  116. package/dist/verification/anthropic-verifier.d.ts +3 -0
  117. package/dist/verification/anthropic-verifier.d.ts.map +1 -0
  118. package/dist/verification/anthropic-verifier.js +56 -0
  119. package/dist/verification/anthropic-verifier.js.map +1 -0
  120. package/dist/verification/aws-verifier.d.ts +14 -0
  121. package/dist/verification/aws-verifier.d.ts.map +1 -0
  122. package/dist/verification/aws-verifier.js +30 -0
  123. package/dist/verification/aws-verifier.js.map +1 -0
  124. package/dist/verification/github-verifier.d.ts +4 -0
  125. package/dist/verification/github-verifier.d.ts.map +1 -0
  126. package/dist/verification/github-verifier.js +62 -0
  127. package/dist/verification/github-verifier.js.map +1 -0
  128. package/dist/verification/openai-verifier.d.ts +4 -0
  129. package/dist/verification/openai-verifier.d.ts.map +1 -0
  130. package/dist/verification/openai-verifier.js +59 -0
  131. package/dist/verification/openai-verifier.js.map +1 -0
  132. package/dist/verification/slack-verifier.d.ts +4 -0
  133. package/dist/verification/slack-verifier.d.ts.map +1 -0
  134. package/dist/verification/slack-verifier.js +67 -0
  135. package/dist/verification/slack-verifier.js.map +1 -0
  136. package/dist/verification/verifier-registry.d.ts +13 -0
  137. package/dist/verification/verifier-registry.d.ts.map +1 -0
  138. package/dist/verification/verifier-registry.js +19 -0
  139. package/dist/verification/verifier-registry.js.map +1 -0
  140. package/dist/verification/verifier.d.ts +24 -0
  141. package/dist/verification/verifier.d.ts.map +1 -0
  142. package/dist/verification/verifier.js +2 -0
  143. package/dist/verification/verifier.js.map +1 -0
  144. 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,3 @@
1
+ import type { CheckPlugin } from "../plugin.js";
2
+ export declare const leakCheckPlugin: CheckPlugin;
3
+ //# sourceMappingURL=leakcheck-plugin.d.ts.map
@@ -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,3 @@
1
+ import type { CheckPlugin } from "../plugin.js";
2
+ export declare const localAnalysisPlugin: CheckPlugin;
3
+ //# sourceMappingURL=local-analysis-plugin.d.ts.map
@@ -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