@s-gw/s-gw 0.1.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/.codex-plugin/plugin.json +35 -0
- package/.mcp.json +16 -0
- package/LICENSE +201 -0
- package/NOTICE +7 -0
- package/README.md +197 -0
- package/TRADEMARKS.md +9 -0
- package/assets/icons/aws-ec2.png +0 -0
- package/assets/icons/lucide/bot.svg +8 -0
- package/assets/icons/lucide/monitor.svg +5 -0
- package/assets/icons/lucide/server.svg +6 -0
- package/assets/icons/lucide/terminal.svg +4 -0
- package/assets/icons/s-gw-128.png +0 -0
- package/assets/icons/s-gw-16.png +0 -0
- package/assets/icons/s-gw-180.png +0 -0
- package/assets/icons/s-gw-192.png +0 -0
- package/assets/icons/s-gw-32.png +0 -0
- package/assets/icons/s-gw-64.png +0 -0
- package/assets/icons/s-gw-menu-bar-template.png +0 -0
- package/dist/agent-context.d.ts +17 -0
- package/dist/agent-context.js +207 -0
- package/dist/agents.d.ts +64 -0
- package/dist/agents.js +763 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1385 -0
- package/dist/command-suggest.d.ts +3 -0
- package/dist/command-suggest.js +131 -0
- package/dist/console-server.d.ts +16 -0
- package/dist/console-server.js +978 -0
- package/dist/console-ui/assets/codex-DYTPdPxi.png +0 -0
- package/dist/console-ui/assets/cursor-CBrUTJD-.png +0 -0
- package/dist/console-ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/console-ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/console-ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/console-ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/console-ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/console-ui/assets/hermes-B8hNbJPm.png +0 -0
- package/dist/console-ui/assets/index-BxUf0Sye.js +96 -0
- package/dist/console-ui/assets/index-CmTiBR_w.css +2 -0
- package/dist/console-ui/assets/omnigent-Cxa4p2Mq.png +0 -0
- package/dist/console-ui/assets/openclaw-C5wL4ZVW.png +0 -0
- package/dist/console-ui/assets/opencode-D_wFATSC.png +0 -0
- package/dist/console-ui/assets/openhands-DnrlGgev.svg +9 -0
- package/dist/console-ui/assets/s-gw-64-ByMUGQ3K.png +0 -0
- package/dist/console-ui/assets/vscode-Bdtr9eyf.png +0 -0
- package/dist/console-ui/assets/zeptoclaw-DztQW8Sw.png +0 -0
- package/dist/console-ui/index.html +13 -0
- package/dist/crypto.d.ts +6 -0
- package/dist/crypto.js +53 -0
- package/dist/executor.d.ts +7 -0
- package/dist/executor.js +297 -0
- package/dist/gateway.d.ts +31 -0
- package/dist/gateway.js +114 -0
- package/dist/guard.d.ts +61 -0
- package/dist/guard.js +247 -0
- package/dist/install.d.ts +146 -0
- package/dist/install.js +629 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +119 -0
- package/dist/native/s-gw-core +0 -0
- package/dist/native/s-gw-keychain-helper +0 -0
- package/dist/onepassword.d.ts +48 -0
- package/dist/onepassword.js +412 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +22 -0
- package/dist/s-gw Menu Bar.app/Contents/Info.plist +28 -0
- package/dist/s-gw Menu Bar.app/Contents/MacOS/s-gw-menu-bar-helper +0 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/AwsEc2.png +0 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-bot.svg +8 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-monitor.svg +5 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-server.svg +6 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-terminal.svg +4 -0
- package/dist/s-gw Menu Bar.app/Contents/Resources/MenuBarTemplate.png +0 -0
- package/dist/s-gw Menu Bar.app/Contents/_CodeSignature/CodeResources +194 -0
- package/dist/s-gw.app/Contents/Info.plist +28 -0
- package/dist/s-gw.app/Contents/MacOS/s-gw +0 -0
- package/dist/s-gw.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/s-gw.app/Contents/Resources/MenuBarTemplate.png +0 -0
- package/dist/s-gw.app/Contents/_CodeSignature/CodeResources +139 -0
- package/dist/scanner.d.ts +9 -0
- package/dist/scanner.js +437 -0
- package/dist/ssh.d.ts +31 -0
- package/dist/ssh.js +286 -0
- package/dist/store.d.ts +131 -0
- package/dist/store.js +1611 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.js +2 -0
- package/dist/unlock.d.ts +29 -0
- package/dist/unlock.js +274 -0
- package/dist/windows/VERSION.txt +1 -0
- package/dist/windows/s-gw-client.cmd +4 -0
- package/dist/windows/s-gw-client.ps1 +106 -0
- package/dist/windows/s-gw-credential.cmd +4 -0
- package/dist/windows/s-gw-credential.ps1 +167 -0
- package/dist/windows/s-gw-helper.cmd +4 -0
- package/dist/windows/s-gw-helper.ps1 +180 -0
- package/docs/README.md +23 -0
- package/docs/agents.md +160 -0
- package/docs/architecture.md +72 -0
- package/docs/deployment.md +447 -0
- package/docs/detection.md +44 -0
- package/docs/images/s-gw-overview.png +0 -0
- package/docs/integrations.md +195 -0
- package/docs/keychain.md +39 -0
- package/docs/onepassword.md +84 -0
- package/docs/quickstart.md +104 -0
- package/docs/threat-model.md +100 -0
- package/docs/ui/THIRD_PARTY_NOTICES.md +111 -0
- package/docs/ui/apple-touch-icon.png +0 -0
- package/docs/ui/favicon-32.png +0 -0
- package/docs/ui/local-console.html +4477 -0
- package/docs/ui/vendor/d3-sankey/d3-array.LICENSE.txt +27 -0
- package/docs/ui/vendor/d3-sankey/d3-array.min.js +2 -0
- package/docs/ui/vendor/d3-sankey/d3-path.LICENSE.txt +27 -0
- package/docs/ui/vendor/d3-sankey/d3-path.min.js +2 -0
- package/docs/ui/vendor/d3-sankey/d3-sankey.LICENSE.txt +27 -0
- package/docs/ui/vendor/d3-sankey/d3-sankey.min.js +2 -0
- package/docs/ui/vendor/d3-sankey/d3-shape.LICENSE.txt +27 -0
- package/docs/ui/vendor/d3-sankey/d3-shape.min.js +2 -0
- package/docs/ui/vendor/sankeymatic/LICENSE.txt +17 -0
- package/docs/ui/vendor/sankeymatic/sankey.js +897 -0
- package/package.json +117 -0
- package/skills/s-gw/SKILL.md +19 -0
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
const detectorRules = [
|
|
3
|
+
{
|
|
4
|
+
id: "SEC-PRIVATE-KEY",
|
|
5
|
+
type: "private-key",
|
|
6
|
+
provider: "generic",
|
|
7
|
+
label: "private key block",
|
|
8
|
+
regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]+?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,
|
|
9
|
+
severity: "critical",
|
|
10
|
+
confidence: 0.98
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "SEC-ANTHROPIC",
|
|
14
|
+
type: "api-token",
|
|
15
|
+
provider: "anthropic",
|
|
16
|
+
label: "Anthropic API key",
|
|
17
|
+
regex: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g,
|
|
18
|
+
severity: "critical",
|
|
19
|
+
confidence: 0.98
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "SEC-OPENAI-PROJECT",
|
|
23
|
+
type: "api-token",
|
|
24
|
+
provider: "openai",
|
|
25
|
+
label: "OpenAI project key",
|
|
26
|
+
regex: /\bsk-proj-[A-Za-z0-9_-]{20,}\b/g,
|
|
27
|
+
severity: "critical",
|
|
28
|
+
confidence: 0.95
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "SEC-OPENAI",
|
|
32
|
+
type: "api-token",
|
|
33
|
+
provider: "openai",
|
|
34
|
+
label: "OpenAI API key",
|
|
35
|
+
regex: /\bsk-[A-Za-z0-9]{40,}\b/g,
|
|
36
|
+
severity: "critical",
|
|
37
|
+
confidence: 0.85
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "SEC-AWS-ACCESS-KEY",
|
|
41
|
+
type: "access-key",
|
|
42
|
+
provider: "aws",
|
|
43
|
+
label: "AWS access key id",
|
|
44
|
+
regex: /\b(?:AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[0-9A-Z]{16,}\b/g,
|
|
45
|
+
severity: "critical",
|
|
46
|
+
confidence: 0.95
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "SEC-AWS-SECRET",
|
|
50
|
+
type: "credential",
|
|
51
|
+
provider: "aws",
|
|
52
|
+
label: "AWS secret access key",
|
|
53
|
+
regex: /\b(?:aws_?)?(?:secret_?)?(?:access_?)?key\b\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})["']?/gi,
|
|
54
|
+
group: 1,
|
|
55
|
+
severity: "critical",
|
|
56
|
+
confidence: 0.9
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "SEC-GITHUB-FINE",
|
|
60
|
+
type: "api-token",
|
|
61
|
+
provider: "github",
|
|
62
|
+
label: "GitHub fine-grained PAT",
|
|
63
|
+
regex: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g,
|
|
64
|
+
severity: "critical",
|
|
65
|
+
confidence: 0.95
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "SEC-GITHUB-TOKEN",
|
|
69
|
+
type: "api-token",
|
|
70
|
+
provider: "github",
|
|
71
|
+
label: "GitHub token",
|
|
72
|
+
regex: /\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,
|
|
73
|
+
severity: "critical",
|
|
74
|
+
confidence: 0.95
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "SEC-GITLAB",
|
|
78
|
+
type: "api-token",
|
|
79
|
+
provider: "gitlab",
|
|
80
|
+
label: "GitLab access token",
|
|
81
|
+
regex: /\bgl(?:pat|ptt|soat)-[A-Za-z0-9_-]{20,}\b/g,
|
|
82
|
+
severity: "critical",
|
|
83
|
+
confidence: 0.95
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: "SEC-SLACK-TOKEN",
|
|
87
|
+
type: "api-token",
|
|
88
|
+
provider: "slack",
|
|
89
|
+
label: "Slack token",
|
|
90
|
+
regex: /\bxox[baprs]-[0-9A-Za-z-]{20,}\b/g,
|
|
91
|
+
severity: "critical",
|
|
92
|
+
confidence: 0.9
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "SEC-SLACK-WEBHOOK",
|
|
96
|
+
type: "api-token",
|
|
97
|
+
provider: "slack",
|
|
98
|
+
label: "Slack webhook URL",
|
|
99
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g,
|
|
100
|
+
severity: "critical",
|
|
101
|
+
confidence: 0.95
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: "SEC-DISCORD-WEBHOOK",
|
|
105
|
+
type: "api-token",
|
|
106
|
+
provider: "discord",
|
|
107
|
+
label: "Discord webhook URL",
|
|
108
|
+
regex: /https:\/\/discord(?:app)?\.com\/api\/webhooks\/\d+\/[A-Za-z0-9_-]+/g,
|
|
109
|
+
severity: "critical",
|
|
110
|
+
confidence: 0.95
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: "SEC-STRIPE-SECRET",
|
|
114
|
+
type: "api-token",
|
|
115
|
+
provider: "stripe",
|
|
116
|
+
label: "Stripe secret key",
|
|
117
|
+
regex: /\b(?:sk_live_|sk_test_|rk_live_|rk_test_)[A-Za-z0-9]{20,}\b/g,
|
|
118
|
+
severity: "critical",
|
|
119
|
+
confidence: 0.95
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "SEC-STRIPE-PUBLISHABLE",
|
|
123
|
+
type: "api-token",
|
|
124
|
+
provider: "stripe",
|
|
125
|
+
label: "Stripe publishable key",
|
|
126
|
+
regex: /\bpk_(?:live|test)_[A-Za-z0-9]{20,}\b/g,
|
|
127
|
+
severity: "low",
|
|
128
|
+
confidence: 0.8
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: "SEC-GOOGLE-API",
|
|
132
|
+
type: "api-token",
|
|
133
|
+
provider: "google",
|
|
134
|
+
label: "Google API key",
|
|
135
|
+
regex: /\bAIza[0-9A-Za-z_-]{35}\b/g,
|
|
136
|
+
severity: "high",
|
|
137
|
+
confidence: 0.9
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "SEC-AZURE-STORAGE",
|
|
141
|
+
type: "credential",
|
|
142
|
+
provider: "azure",
|
|
143
|
+
label: "Azure storage account key",
|
|
144
|
+
regex: /\bAccountKey=([A-Za-z0-9+/=]{44,})/gi,
|
|
145
|
+
group: 1,
|
|
146
|
+
severity: "critical",
|
|
147
|
+
confidence: 0.92
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: "SEC-AZURE-SAS",
|
|
151
|
+
type: "api-token",
|
|
152
|
+
provider: "azure",
|
|
153
|
+
label: "Azure SAS signature",
|
|
154
|
+
regex: /[?&]sig=([A-Za-z0-9%+/=]{30,})/gi,
|
|
155
|
+
group: 1,
|
|
156
|
+
severity: "high",
|
|
157
|
+
confidence: 0.85
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "SEC-SENDGRID",
|
|
161
|
+
type: "api-token",
|
|
162
|
+
provider: "sendgrid",
|
|
163
|
+
label: "SendGrid API key",
|
|
164
|
+
regex: /\bSG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{30,}\b/g,
|
|
165
|
+
severity: "critical",
|
|
166
|
+
confidence: 0.95
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "SEC-MAILGUN",
|
|
170
|
+
type: "api-token",
|
|
171
|
+
provider: "mailgun",
|
|
172
|
+
label: "Mailgun API key",
|
|
173
|
+
regex: /\bkey-[A-Za-z0-9]{32}\b/g,
|
|
174
|
+
severity: "critical",
|
|
175
|
+
confidence: 0.9
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "SEC-TWILIO-AUTH",
|
|
179
|
+
type: "api-token",
|
|
180
|
+
provider: "twilio",
|
|
181
|
+
label: "Twilio auth token",
|
|
182
|
+
regex: /\btwilio[\w-]*(?:auth|token)\b\s*[:=]\s*["']?([0-9a-fA-F]{32})["']?/gi,
|
|
183
|
+
group: 1,
|
|
184
|
+
severity: "critical",
|
|
185
|
+
confidence: 0.9
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "SEC-TWILIO-KEY",
|
|
189
|
+
type: "api-token",
|
|
190
|
+
provider: "twilio",
|
|
191
|
+
label: "Twilio API key",
|
|
192
|
+
regex: /\bSK[0-9a-fA-F]{32}\b/g,
|
|
193
|
+
severity: "high",
|
|
194
|
+
confidence: 0.8
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "SEC-NPM",
|
|
198
|
+
type: "api-token",
|
|
199
|
+
provider: "npm",
|
|
200
|
+
label: "npm access token",
|
|
201
|
+
regex: /\bnpm_[A-Za-z0-9]{36,}\b/g,
|
|
202
|
+
severity: "critical",
|
|
203
|
+
confidence: 0.95
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "SEC-PYPI",
|
|
207
|
+
type: "api-token",
|
|
208
|
+
provider: "pypi",
|
|
209
|
+
label: "PyPI API token",
|
|
210
|
+
regex: /\bpypi-[A-Za-z0-9_-]{50,}\b/g,
|
|
211
|
+
severity: "critical",
|
|
212
|
+
confidence: 0.95
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "SEC-JWT",
|
|
216
|
+
type: "api-token",
|
|
217
|
+
provider: "jwt",
|
|
218
|
+
label: "JWT token",
|
|
219
|
+
regex: /\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_.+/=-]+\b/g,
|
|
220
|
+
severity: "medium",
|
|
221
|
+
confidence: 0.7,
|
|
222
|
+
validator: looksLikeJwt
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: "SEC-CONNECTION-STRING",
|
|
226
|
+
type: "credential",
|
|
227
|
+
provider: "database",
|
|
228
|
+
label: "connection string credentials",
|
|
229
|
+
regex: /\b(?:mongodb(?:\+srv)?|postgres(?:ql)?|mysql|redis|amqp):\/\/([^:\s/@]+:[^@\s]+)@/gi,
|
|
230
|
+
group: 1,
|
|
231
|
+
severity: "critical",
|
|
232
|
+
confidence: 0.9
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
id: "SEC-BASIC-AUTH",
|
|
236
|
+
type: "credential",
|
|
237
|
+
provider: "http",
|
|
238
|
+
label: "Basic auth header",
|
|
239
|
+
regex: /\b(?:authorization|auth)\b\s*[:=]\s*["']?Basic\s+([A-Za-z0-9+/=]{10,})["']?/gi,
|
|
240
|
+
group: 1,
|
|
241
|
+
severity: "high",
|
|
242
|
+
confidence: 0.82
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: "SEC-BEARER",
|
|
246
|
+
type: "api-token",
|
|
247
|
+
provider: "http",
|
|
248
|
+
label: "Bearer token",
|
|
249
|
+
regex: /\b(?:authorization|auth|bearer)\b\s*[:=]\s*["']?Bearer\s+([A-Za-z0-9_.~+/=-]{20,})["']?/gi,
|
|
250
|
+
group: 1,
|
|
251
|
+
severity: "high",
|
|
252
|
+
confidence: 0.82
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: "SEC-HEX-ASSIGNMENT",
|
|
256
|
+
type: "credential",
|
|
257
|
+
provider: "generic",
|
|
258
|
+
label: "hex-encoded secret assignment",
|
|
259
|
+
regex: /\b[A-Z0-9_.-]*(?:SECRET(?:_KEY)?|API[_-]?KEY|ACCESS[_-]?TOKEN|AUTH[_-]?TOKEN)[A-Z0-9_.-]*\s*[:=]\s*["']([a-f0-9]{32,})["']/gi,
|
|
260
|
+
group: 1,
|
|
261
|
+
severity: "high",
|
|
262
|
+
confidence: 0.72
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: "SEC-GENERIC-ASSIGNMENT",
|
|
266
|
+
type: "credential",
|
|
267
|
+
provider: "generic",
|
|
268
|
+
label: "credential assignment",
|
|
269
|
+
regex: /\b[A-Z0-9_.-]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|CLIENT[_-]?SECRET)[A-Z0-9_.-]*\s*[:=]\s*["']?([A-Za-z0-9][A-Za-z0-9_\-./+=:@]{15,})["']?/gim,
|
|
270
|
+
group: 1,
|
|
271
|
+
severity: "high",
|
|
272
|
+
confidence: 0.68
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: "SEC-PASSWORD-ASSIGNMENT",
|
|
276
|
+
type: "password",
|
|
277
|
+
provider: "generic",
|
|
278
|
+
label: "password assignment",
|
|
279
|
+
regex: /\b(?:password|passwd|pwd)\b\s*[:=]\s*["']?([^\s;,'"]{12,})["']?/gi,
|
|
280
|
+
group: 1,
|
|
281
|
+
severity: "high",
|
|
282
|
+
confidence: 0.66
|
|
283
|
+
}
|
|
284
|
+
];
|
|
285
|
+
export async function scanText(text, getHandle) {
|
|
286
|
+
const candidates = collectCandidates(text);
|
|
287
|
+
const findings = [];
|
|
288
|
+
const chunks = [];
|
|
289
|
+
let cursor = 0;
|
|
290
|
+
for (const candidate of candidates) {
|
|
291
|
+
if (candidate.start < cursor) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const handle = await getHandle(candidate);
|
|
295
|
+
const token = tokenForHandle(handle);
|
|
296
|
+
findings.push({
|
|
297
|
+
type: candidate.type,
|
|
298
|
+
label: candidate.label,
|
|
299
|
+
provider: candidate.provider,
|
|
300
|
+
ruleId: candidate.ruleId,
|
|
301
|
+
severity: candidate.severity,
|
|
302
|
+
confidence: candidate.confidence,
|
|
303
|
+
handle,
|
|
304
|
+
token,
|
|
305
|
+
start: candidate.start,
|
|
306
|
+
end: candidate.end
|
|
307
|
+
});
|
|
308
|
+
chunks.push(text.slice(cursor, candidate.start));
|
|
309
|
+
chunks.push(token);
|
|
310
|
+
cursor = candidate.end;
|
|
311
|
+
}
|
|
312
|
+
chunks.push(text.slice(cursor));
|
|
313
|
+
return {
|
|
314
|
+
tokenizedText: chunks.join(""),
|
|
315
|
+
findings
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
export function previewHandle(candidate) {
|
|
319
|
+
return `s-gw:preview:${candidate.type}:${randomBytes(9).toString("base64url")}`;
|
|
320
|
+
}
|
|
321
|
+
export function tokenForHandle(handle) {
|
|
322
|
+
return `<<SGW_SECRET:${handle}>>`;
|
|
323
|
+
}
|
|
324
|
+
export function sanitizeKnownSecrets(text, pairs) {
|
|
325
|
+
let out = text;
|
|
326
|
+
const ordered = [...pairs].sort((left, right) => right.value.length - left.value.length);
|
|
327
|
+
for (const pair of ordered) {
|
|
328
|
+
if (!pair.value) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
out = out.split(pair.value).join(tokenForHandle(pair.handle));
|
|
332
|
+
}
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
function collectCandidates(text) {
|
|
336
|
+
const found = [];
|
|
337
|
+
for (const rule of detectorRules) {
|
|
338
|
+
rule.regex.lastIndex = 0;
|
|
339
|
+
let match = rule.regex.exec(text);
|
|
340
|
+
while (match) {
|
|
341
|
+
const value = rule.group ? match[rule.group] : match[0];
|
|
342
|
+
if (value && shouldKeepCandidate(value, rule)) {
|
|
343
|
+
const baseIndex = match.index;
|
|
344
|
+
const offset = rule.group ? match[0].indexOf(value) : 0;
|
|
345
|
+
const start = baseIndex + offset;
|
|
346
|
+
found.push({
|
|
347
|
+
type: rule.type,
|
|
348
|
+
label: rule.label,
|
|
349
|
+
provider: rule.provider,
|
|
350
|
+
ruleId: rule.id,
|
|
351
|
+
severity: rule.severity,
|
|
352
|
+
confidence: rule.confidence,
|
|
353
|
+
value,
|
|
354
|
+
start,
|
|
355
|
+
end: start + value.length
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
match = rule.regex.exec(text);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
found.sort((a, b) => {
|
|
362
|
+
if (a.start === b.start) {
|
|
363
|
+
return b.end - a.end;
|
|
364
|
+
}
|
|
365
|
+
return a.start - b.start;
|
|
366
|
+
});
|
|
367
|
+
const out = [];
|
|
368
|
+
let occupiedUntil = -1;
|
|
369
|
+
for (const item of found) {
|
|
370
|
+
if (item.start < occupiedUntil) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
out.push(item);
|
|
374
|
+
occupiedUntil = item.end;
|
|
375
|
+
}
|
|
376
|
+
return out;
|
|
377
|
+
}
|
|
378
|
+
function shouldKeepCandidate(value, rule) {
|
|
379
|
+
if (!likelySecret(value)) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
if (looksLikePlaceholder(value)) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
if (rule.validator && !rule.validator(value)) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
function likelySecret(value) {
|
|
391
|
+
if (value.length < 16) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
const uniqueChars = new Set(value).size;
|
|
395
|
+
if (uniqueChars < 8) {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
if (/^(true|false|null|undefined)$/i.test(value)) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
function looksLikePlaceholder(value) {
|
|
404
|
+
const compact = value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
405
|
+
if (!compact) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
if (/^(x+|0+|1+|a+|z+)$/.test(compact)) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
return (compact.includes("example") ||
|
|
412
|
+
compact.includes("placeholder") ||
|
|
413
|
+
compact.includes("changeme") ||
|
|
414
|
+
compact.includes("replacewith") ||
|
|
415
|
+
compact.includes("yourtoken") ||
|
|
416
|
+
compact.includes("yourkey") ||
|
|
417
|
+
compact.includes("yourapikey"));
|
|
418
|
+
}
|
|
419
|
+
function looksLikeJwt(value) {
|
|
420
|
+
const parts = value.split(".");
|
|
421
|
+
if (parts.length !== 3) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
for (const part of parts.slice(0, 2)) {
|
|
425
|
+
try {
|
|
426
|
+
const normalized = part.replace(/-/g, "+").replace(/_/g, "/");
|
|
427
|
+
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
|
|
428
|
+
const decoded = Buffer.from(padded, "base64").toString("utf8");
|
|
429
|
+
JSON.parse(decoded);
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=scanner.js.map
|
package/dist/ssh.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CommandAction, ExecutionSummary, RequestRecord, SecretRecord } from "./types.js";
|
|
2
|
+
export declare const SGW_SSH_SESSION_COMMAND = "s-gw:ssh-session";
|
|
3
|
+
export interface SshSessionInput {
|
|
4
|
+
target: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
args?: string[];
|
|
7
|
+
injectEnv?: string;
|
|
8
|
+
workingDir?: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
interface ProcessResult {
|
|
12
|
+
exitCode: number | null;
|
|
13
|
+
signal: NodeJS.Signals | null;
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
timedOut: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildSshSessionAction(input: SshSessionInput): CommandAction;
|
|
20
|
+
export declare function defaultSshInjectEnv(secret: SecretRecord): string;
|
|
21
|
+
export declare function normalizeSshTarget(target: string): string;
|
|
22
|
+
export declare function normalizeSshPort(port?: number): number;
|
|
23
|
+
export declare function sshSessionIdentity(action: CommandAction): string;
|
|
24
|
+
export declare function runOwnedSshSession(request: RequestRecord, secretRecord: SecretRecord, secretValue: string, home?: string): Promise<ExecutionSummary>;
|
|
25
|
+
export declare function closeOwnedSshSession(input: {
|
|
26
|
+
handle: string;
|
|
27
|
+
target: string;
|
|
28
|
+
port?: number;
|
|
29
|
+
home?: string;
|
|
30
|
+
}): Promise<ProcessResult>;
|
|
31
|
+
export {};
|