@id-wispera/core 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/README.md +268 -0
- package/dist/audit.d.ts +68 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +252 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/keychainProvider.d.ts +40 -0
- package/dist/auth/keychainProvider.d.ts.map +1 -0
- package/dist/auth/keychainProvider.js +98 -0
- package/dist/auth/keychainProvider.js.map +1 -0
- package/dist/auth/passphraseProvider.d.ts +80 -0
- package/dist/auth/passphraseProvider.d.ts.map +1 -0
- package/dist/auth/passphraseProvider.js +188 -0
- package/dist/auth/passphraseProvider.js.map +1 -0
- package/dist/auth/sessionTokenManager.d.ts +106 -0
- package/dist/auth/sessionTokenManager.d.ts.map +1 -0
- package/dist/auth/sessionTokenManager.js +263 -0
- package/dist/auth/sessionTokenManager.js.map +1 -0
- package/dist/delegation.d.ts +81 -0
- package/dist/delegation.d.ts.map +1 -0
- package/dist/delegation.js +299 -0
- package/dist/delegation.js.map +1 -0
- package/dist/detection.d.ts +35 -0
- package/dist/detection.d.ts.map +1 -0
- package/dist/detection.js +474 -0
- package/dist/detection.js.map +1 -0
- package/dist/exec/execManager.d.ts +60 -0
- package/dist/exec/execManager.d.ts.map +1 -0
- package/dist/exec/execManager.js +226 -0
- package/dist/exec/execManager.js.map +1 -0
- package/dist/exec/index.d.ts +6 -0
- package/dist/exec/index.d.ts.map +1 -0
- package/dist/exec/index.js +5 -0
- package/dist/exec/index.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/base.d.ts +64 -0
- package/dist/integrations/base.d.ts.map +1 -0
- package/dist/integrations/base.js +173 -0
- package/dist/integrations/base.js.map +1 -0
- package/dist/integrations/envMapping.d.ts +47 -0
- package/dist/integrations/envMapping.d.ts.map +1 -0
- package/dist/integrations/envMapping.js +174 -0
- package/dist/integrations/envMapping.js.map +1 -0
- package/dist/integrations/google-a2a.d.ts +48 -0
- package/dist/integrations/google-a2a.d.ts.map +1 -0
- package/dist/integrations/google-a2a.js +108 -0
- package/dist/integrations/google-a2a.js.map +1 -0
- package/dist/integrations/index.d.ts +14 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +14 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/langchain.d.ts +38 -0
- package/dist/integrations/langchain.d.ts.map +1 -0
- package/dist/integrations/langchain.js +45 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/integrations/openai-agents.d.ts +76 -0
- package/dist/integrations/openai-agents.d.ts.map +1 -0
- package/dist/integrations/openai-agents.js +95 -0
- package/dist/integrations/openai-agents.js.map +1 -0
- package/dist/integrations/slack.d.ts +59 -0
- package/dist/integrations/slack.d.ts.map +1 -0
- package/dist/integrations/slack.js +113 -0
- package/dist/integrations/slack.js.map +1 -0
- package/dist/integrations/types.d.ts +107 -0
- package/dist/integrations/types.d.ts.map +1 -0
- package/dist/integrations/types.js +6 -0
- package/dist/integrations/types.js.map +1 -0
- package/dist/locations.d.ts +157 -0
- package/dist/locations.d.ts.map +1 -0
- package/dist/locations.js +733 -0
- package/dist/locations.js.map +1 -0
- package/dist/passport.d.ts +70 -0
- package/dist/passport.d.ts.map +1 -0
- package/dist/passport.js +429 -0
- package/dist/passport.js.map +1 -0
- package/dist/policy.d.ts +80 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +392 -0
- package/dist/policy.js.map +1 -0
- package/dist/providers/openclaw.d.ts +80 -0
- package/dist/providers/openclaw.d.ts.map +1 -0
- package/dist/providers/openclaw.js +712 -0
- package/dist/providers/openclaw.js.map +1 -0
- package/dist/provisioning/adminPassport.d.ts +51 -0
- package/dist/provisioning/adminPassport.d.ts.map +1 -0
- package/dist/provisioning/adminPassport.js +101 -0
- package/dist/provisioning/adminPassport.js.map +1 -0
- package/dist/provisioning/index.d.ts +81 -0
- package/dist/provisioning/index.d.ts.map +1 -0
- package/dist/provisioning/index.js +141 -0
- package/dist/provisioning/index.js.map +1 -0
- package/dist/provisioning/provider.d.ts +59 -0
- package/dist/provisioning/provider.d.ts.map +1 -0
- package/dist/provisioning/provider.js +52 -0
- package/dist/provisioning/provider.js.map +1 -0
- package/dist/provisioning/providers/anthropic.d.ts +32 -0
- package/dist/provisioning/providers/anthropic.d.ts.map +1 -0
- package/dist/provisioning/providers/anthropic.js +116 -0
- package/dist/provisioning/providers/anthropic.js.map +1 -0
- package/dist/provisioning/providers/aws.d.ts +29 -0
- package/dist/provisioning/providers/aws.d.ts.map +1 -0
- package/dist/provisioning/providers/aws.js +455 -0
- package/dist/provisioning/providers/aws.js.map +1 -0
- package/dist/provisioning/providers/azure-entra.d.ts +32 -0
- package/dist/provisioning/providers/azure-entra.d.ts.map +1 -0
- package/dist/provisioning/providers/azure-entra.js +312 -0
- package/dist/provisioning/providers/azure-entra.js.map +1 -0
- package/dist/provisioning/providers/github.d.ts +24 -0
- package/dist/provisioning/providers/github.d.ts.map +1 -0
- package/dist/provisioning/providers/github.js +219 -0
- package/dist/provisioning/providers/github.js.map +1 -0
- package/dist/provisioning/providers/google-cloud.d.ts +34 -0
- package/dist/provisioning/providers/google-cloud.d.ts.map +1 -0
- package/dist/provisioning/providers/google-cloud.js +366 -0
- package/dist/provisioning/providers/google-cloud.js.map +1 -0
- package/dist/provisioning/providers/openai.d.ts +29 -0
- package/dist/provisioning/providers/openai.d.ts.map +1 -0
- package/dist/provisioning/providers/openai.js +263 -0
- package/dist/provisioning/providers/openai.js.map +1 -0
- package/dist/provisioning/providers/sendgrid.d.ts +27 -0
- package/dist/provisioning/providers/sendgrid.d.ts.map +1 -0
- package/dist/provisioning/providers/sendgrid.js +186 -0
- package/dist/provisioning/providers/sendgrid.js.map +1 -0
- package/dist/provisioning/providers/twilio.d.ts +27 -0
- package/dist/provisioning/providers/twilio.d.ts.map +1 -0
- package/dist/provisioning/providers/twilio.js +194 -0
- package/dist/provisioning/providers/twilio.js.map +1 -0
- package/dist/provisioning/types.d.ts +274 -0
- package/dist/provisioning/types.d.ts.map +1 -0
- package/dist/provisioning/types.js +6 -0
- package/dist/provisioning/types.js.map +1 -0
- package/dist/sharing.d.ts +60 -0
- package/dist/sharing.d.ts.map +1 -0
- package/dist/sharing.js +305 -0
- package/dist/sharing.js.map +1 -0
- package/dist/types.d.ts +396 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +88 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +45 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +110 -0
- package/dist/utils.js.map +1 -0
- package/dist/vault.d.ts +151 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +499 -0
- package/dist/vault.js.map +1 -0
- package/package.json +117 -0
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID Wispera Credential Locations Registry
|
|
3
|
+
* Defines well-known credential storage paths for various providers
|
|
4
|
+
*/
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Path Helpers
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Expand path patterns like {home} to actual paths
|
|
12
|
+
*/
|
|
13
|
+
export function expandPath(pattern, vars = {}) {
|
|
14
|
+
let result = pattern;
|
|
15
|
+
result = result.replace('{home}', homedir());
|
|
16
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
17
|
+
result = result.replace(`{${key}}`, value);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the home directory
|
|
23
|
+
*/
|
|
24
|
+
export function getHomeDir() {
|
|
25
|
+
return homedir();
|
|
26
|
+
}
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// OpenClaw Provider
|
|
29
|
+
// ============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Parse WhatsApp credentials from creds.json
|
|
32
|
+
*/
|
|
33
|
+
function parseWhatsAppCreds(filePath, content) {
|
|
34
|
+
try {
|
|
35
|
+
const data = JSON.parse(content);
|
|
36
|
+
const credentials = [];
|
|
37
|
+
// Extract account ID from path or me.id
|
|
38
|
+
const pathMatch = filePath.match(/whatsapp\/([^/]+)\/creds\.json$/);
|
|
39
|
+
const accountId = pathMatch?.[1] || data.me?.id?.split(':')[0] || 'unknown';
|
|
40
|
+
const phoneNumber = data.me?.id?.split(':')[0] || accountId;
|
|
41
|
+
// The entire creds.json is a sensitive session credential
|
|
42
|
+
credentials.push({
|
|
43
|
+
provider: 'openclaw',
|
|
44
|
+
filePath,
|
|
45
|
+
classification: {
|
|
46
|
+
name: `WhatsApp Session (${accountId})`,
|
|
47
|
+
credentialType: 'session-keys',
|
|
48
|
+
visaType: 'access',
|
|
49
|
+
riskLevel: 'high',
|
|
50
|
+
platforms: ['openclaw', 'whatsapp'],
|
|
51
|
+
tags: ['openclaw', 'whatsapp', 'session', 'imported'],
|
|
52
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
53
|
+
},
|
|
54
|
+
rawValue: content,
|
|
55
|
+
metadata: {
|
|
56
|
+
accountId,
|
|
57
|
+
phoneNumber,
|
|
58
|
+
botName: data.me?.name,
|
|
59
|
+
registrationId: data.registrationId,
|
|
60
|
+
hasNoiseKey: !!data.noiseKey,
|
|
61
|
+
hasSignedIdentityKey: !!data.signedIdentityKey,
|
|
62
|
+
hasSignedPreKey: !!data.signedPreKey,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return credentials;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse channel allowlist files
|
|
73
|
+
*/
|
|
74
|
+
function parseAllowlist(filePath, content) {
|
|
75
|
+
try {
|
|
76
|
+
const data = JSON.parse(content);
|
|
77
|
+
const credentials = [];
|
|
78
|
+
// Extract channel name from filename
|
|
79
|
+
const fileMatch = filePath.match(/([^/]+)-allowFrom\.json$/);
|
|
80
|
+
const channel = fileMatch?.[1] || 'unknown';
|
|
81
|
+
const pairedCount = Object.keys(data).length;
|
|
82
|
+
credentials.push({
|
|
83
|
+
provider: 'openclaw',
|
|
84
|
+
filePath,
|
|
85
|
+
classification: {
|
|
86
|
+
name: `Pairing Allowlist: ${channel} (${pairedCount} users)`,
|
|
87
|
+
credentialType: 'custom',
|
|
88
|
+
visaType: 'access',
|
|
89
|
+
riskLevel: 'low',
|
|
90
|
+
platforms: ['openclaw', channel],
|
|
91
|
+
tags: ['openclaw', channel, 'allowlist', 'imported'],
|
|
92
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
93
|
+
},
|
|
94
|
+
rawValue: content,
|
|
95
|
+
metadata: {
|
|
96
|
+
channel,
|
|
97
|
+
pairedUsers: Object.entries(data).map(([id, info]) => ({
|
|
98
|
+
id,
|
|
99
|
+
name: info.name,
|
|
100
|
+
pairedAt: info.pairedAt,
|
|
101
|
+
})),
|
|
102
|
+
pairedCount,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
return credentials;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse auth-profiles.json for LLM API keys
|
|
113
|
+
*/
|
|
114
|
+
function parseAuthProfiles(filePath, content) {
|
|
115
|
+
try {
|
|
116
|
+
const data = JSON.parse(content);
|
|
117
|
+
const credentials = [];
|
|
118
|
+
// Extract agent ID from path
|
|
119
|
+
const pathMatch = filePath.match(/agents\/([^/]+)\/agent\/auth-profiles\.json$/);
|
|
120
|
+
const agentId = pathMatch?.[1] || 'unknown';
|
|
121
|
+
for (const [provider, profile] of Object.entries(data)) {
|
|
122
|
+
if (profile.type === 'api-key' && profile.key) {
|
|
123
|
+
const keyPreview = profile.key.substring(0, 10) + '...' +
|
|
124
|
+
profile.key.substring(profile.key.length - 4);
|
|
125
|
+
credentials.push({
|
|
126
|
+
provider: 'openclaw',
|
|
127
|
+
filePath,
|
|
128
|
+
classification: {
|
|
129
|
+
name: `${capitalizeFirst(provider)} API Key (${keyPreview})`,
|
|
130
|
+
credentialType: 'api-key',
|
|
131
|
+
visaType: 'privilege',
|
|
132
|
+
riskLevel: 'critical',
|
|
133
|
+
platforms: ['openclaw', 'mcp', provider],
|
|
134
|
+
tags: ['openclaw', provider, 'api-key', 'llm', 'imported'],
|
|
135
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
136
|
+
context: { agentId, model: profile.model },
|
|
137
|
+
},
|
|
138
|
+
rawValue: profile.key,
|
|
139
|
+
metadata: {
|
|
140
|
+
agentId,
|
|
141
|
+
provider,
|
|
142
|
+
model: profile.model,
|
|
143
|
+
keyType: profile.type,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return credentials;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Parse oauth.json for OAuth tokens
|
|
156
|
+
*/
|
|
157
|
+
function parseOAuthTokens(filePath, content) {
|
|
158
|
+
try {
|
|
159
|
+
const data = JSON.parse(content);
|
|
160
|
+
const credentials = [];
|
|
161
|
+
for (const [provider, tokens] of Object.entries(data)) {
|
|
162
|
+
if (tokens.access_token) {
|
|
163
|
+
const tokenPreview = tokens.access_token.substring(0, 10) + '...';
|
|
164
|
+
const expiresAt = tokens.expires_at ? new Date(tokens.expires_at * 1000) : undefined;
|
|
165
|
+
const isExpired = expiresAt && expiresAt < new Date();
|
|
166
|
+
credentials.push({
|
|
167
|
+
provider: 'openclaw',
|
|
168
|
+
filePath,
|
|
169
|
+
classification: {
|
|
170
|
+
name: `${capitalizeFirst(provider)} OAuth Token (${tokenPreview})`,
|
|
171
|
+
credentialType: 'oauth-token',
|
|
172
|
+
visaType: 'access',
|
|
173
|
+
riskLevel: 'medium',
|
|
174
|
+
platforms: ['openclaw', provider],
|
|
175
|
+
tags: ['openclaw', provider, 'oauth', 'imported', ...(isExpired ? ['expired'] : [])],
|
|
176
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
177
|
+
},
|
|
178
|
+
rawValue: tokens.access_token,
|
|
179
|
+
metadata: {
|
|
180
|
+
provider,
|
|
181
|
+
hasRefreshToken: !!tokens.refresh_token,
|
|
182
|
+
tokenType: tokens.token_type,
|
|
183
|
+
expiresAt: expiresAt?.toISOString(),
|
|
184
|
+
isExpired,
|
|
185
|
+
},
|
|
186
|
+
expiresAt,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return credentials;
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Parse openclaw.json for channel tokens and gateway config
|
|
198
|
+
*/
|
|
199
|
+
function parseOpenClawConfig(filePath, content) {
|
|
200
|
+
try {
|
|
201
|
+
const data = JSON.parse(content);
|
|
202
|
+
const credentials = [];
|
|
203
|
+
// Parse channel tokens
|
|
204
|
+
if (data.channels) {
|
|
205
|
+
for (const [channel, config] of Object.entries(data.channels)) {
|
|
206
|
+
// Telegram bot token
|
|
207
|
+
if (channel === 'telegram' && config.token) {
|
|
208
|
+
const tokenPreview = config.token.substring(0, 7) + '...' +
|
|
209
|
+
config.token.substring(config.token.length - 4);
|
|
210
|
+
credentials.push({
|
|
211
|
+
provider: 'openclaw',
|
|
212
|
+
filePath,
|
|
213
|
+
classification: {
|
|
214
|
+
name: `Telegram Bot Token (${tokenPreview})`,
|
|
215
|
+
credentialType: 'api-key',
|
|
216
|
+
visaType: 'access',
|
|
217
|
+
riskLevel: 'high',
|
|
218
|
+
platforms: ['openclaw', 'telegram'],
|
|
219
|
+
tags: ['openclaw', 'telegram', 'bot-token', 'imported'],
|
|
220
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
221
|
+
},
|
|
222
|
+
rawValue: config.token,
|
|
223
|
+
metadata: { channel: 'telegram' },
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
// Slack tokens
|
|
227
|
+
if (channel === 'slack') {
|
|
228
|
+
if (config.botToken) {
|
|
229
|
+
const tokenPreview = config.botToken.substring(0, 10) + '...' +
|
|
230
|
+
config.botToken.substring(config.botToken.length - 4);
|
|
231
|
+
credentials.push({
|
|
232
|
+
provider: 'openclaw',
|
|
233
|
+
filePath,
|
|
234
|
+
classification: {
|
|
235
|
+
name: `Slack Bot Token (${tokenPreview})`,
|
|
236
|
+
credentialType: 'api-key',
|
|
237
|
+
visaType: 'access',
|
|
238
|
+
riskLevel: 'high',
|
|
239
|
+
platforms: ['openclaw', 'slack'],
|
|
240
|
+
tags: ['openclaw', 'slack', 'bot-token', 'imported'],
|
|
241
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
242
|
+
},
|
|
243
|
+
rawValue: config.botToken,
|
|
244
|
+
metadata: { channel: 'slack', tokenType: 'bot' },
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (config.appToken) {
|
|
248
|
+
const tokenPreview = config.appToken.substring(0, 10) + '...' +
|
|
249
|
+
config.appToken.substring(config.appToken.length - 4);
|
|
250
|
+
credentials.push({
|
|
251
|
+
provider: 'openclaw',
|
|
252
|
+
filePath,
|
|
253
|
+
classification: {
|
|
254
|
+
name: `Slack App Token (${tokenPreview})`,
|
|
255
|
+
credentialType: 'api-key',
|
|
256
|
+
visaType: 'access',
|
|
257
|
+
riskLevel: 'high',
|
|
258
|
+
platforms: ['openclaw', 'slack'],
|
|
259
|
+
tags: ['openclaw', 'slack', 'app-token', 'imported'],
|
|
260
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
261
|
+
},
|
|
262
|
+
rawValue: config.appToken,
|
|
263
|
+
metadata: { channel: 'slack', tokenType: 'app' },
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Discord token
|
|
268
|
+
if (channel === 'discord' && config.token) {
|
|
269
|
+
const tokenPreview = config.token.substring(0, 10) + '...' +
|
|
270
|
+
config.token.substring(config.token.length - 4);
|
|
271
|
+
credentials.push({
|
|
272
|
+
provider: 'openclaw',
|
|
273
|
+
filePath,
|
|
274
|
+
classification: {
|
|
275
|
+
name: `Discord Bot Token (${tokenPreview})`,
|
|
276
|
+
credentialType: 'api-key',
|
|
277
|
+
visaType: 'access',
|
|
278
|
+
riskLevel: 'high',
|
|
279
|
+
platforms: ['openclaw', 'discord'],
|
|
280
|
+
tags: ['openclaw', 'discord', 'bot-token', 'imported'],
|
|
281
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
282
|
+
},
|
|
283
|
+
rawValue: config.token,
|
|
284
|
+
metadata: { channel: 'discord' },
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Parse gateway token
|
|
290
|
+
if (data.gateway?.token) {
|
|
291
|
+
const tokenPreview = data.gateway.token.substring(0, 6) + '...' +
|
|
292
|
+
data.gateway.token.substring(data.gateway.token.length - 4);
|
|
293
|
+
credentials.push({
|
|
294
|
+
provider: 'openclaw',
|
|
295
|
+
filePath,
|
|
296
|
+
classification: {
|
|
297
|
+
name: `Gateway Token (${tokenPreview})`,
|
|
298
|
+
credentialType: 'api-key',
|
|
299
|
+
visaType: 'privilege',
|
|
300
|
+
riskLevel: 'high',
|
|
301
|
+
platforms: ['openclaw'],
|
|
302
|
+
tags: ['openclaw', 'gateway', 'admin', 'imported'],
|
|
303
|
+
issuingAuthority: 'OpenClaw (self-managed)',
|
|
304
|
+
},
|
|
305
|
+
rawValue: data.gateway.token,
|
|
306
|
+
metadata: {
|
|
307
|
+
gatewayPort: data.gateway.port,
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return credentials;
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Helper to capitalize first letter
|
|
319
|
+
*/
|
|
320
|
+
function capitalizeFirst(str) {
|
|
321
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* OpenClaw provider definition
|
|
325
|
+
*/
|
|
326
|
+
export const openclawProvider = {
|
|
327
|
+
id: 'openclaw',
|
|
328
|
+
name: 'OpenClaw',
|
|
329
|
+
description: 'OpenClaw AI agent framework credentials',
|
|
330
|
+
detect: async () => {
|
|
331
|
+
const fs = await import('fs/promises');
|
|
332
|
+
const openclawPath = join(homedir(), '.openclaw');
|
|
333
|
+
try {
|
|
334
|
+
await fs.access(openclawPath);
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
locations: [
|
|
342
|
+
{
|
|
343
|
+
id: 'whatsapp-creds',
|
|
344
|
+
name: 'WhatsApp Credentials',
|
|
345
|
+
pathPattern: '{home}/.openclaw/credentials/whatsapp',
|
|
346
|
+
filePattern: '**/creds.json',
|
|
347
|
+
parse: parseWhatsAppCreds,
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: 'channel-allowlists',
|
|
351
|
+
name: 'Channel Allowlists',
|
|
352
|
+
pathPattern: '{home}/.openclaw/credentials',
|
|
353
|
+
filePattern: '*-allowFrom.json',
|
|
354
|
+
parse: parseAllowlist,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 'auth-profiles',
|
|
358
|
+
name: 'LLM Auth Profiles',
|
|
359
|
+
pathPattern: '{home}/.openclaw/agents',
|
|
360
|
+
filePattern: '**/agent/auth-profiles.json',
|
|
361
|
+
parse: parseAuthProfiles,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: 'oauth-tokens',
|
|
365
|
+
name: 'OAuth Tokens',
|
|
366
|
+
pathPattern: '{home}/.openclaw/credentials',
|
|
367
|
+
filePattern: 'oauth.json',
|
|
368
|
+
parse: parseOAuthTokens,
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
id: 'config',
|
|
372
|
+
name: 'OpenClaw Config',
|
|
373
|
+
pathPattern: '{home}/.openclaw',
|
|
374
|
+
filePattern: 'openclaw.json',
|
|
375
|
+
parse: parseOpenClawConfig,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
};
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// Other Common Providers
|
|
381
|
+
// ============================================================================
|
|
382
|
+
/**
|
|
383
|
+
* AWS provider definition
|
|
384
|
+
*/
|
|
385
|
+
export const awsProvider = {
|
|
386
|
+
id: 'aws',
|
|
387
|
+
name: 'AWS',
|
|
388
|
+
description: 'Amazon Web Services credentials',
|
|
389
|
+
detect: async () => {
|
|
390
|
+
const fs = await import('fs/promises');
|
|
391
|
+
try {
|
|
392
|
+
await fs.access(join(homedir(), '.aws'));
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
locations: [
|
|
400
|
+
{
|
|
401
|
+
id: 'credentials',
|
|
402
|
+
name: 'AWS Credentials',
|
|
403
|
+
pathPattern: '{home}/.aws',
|
|
404
|
+
filePattern: 'credentials',
|
|
405
|
+
parse: (filePath, content) => {
|
|
406
|
+
const credentials = [];
|
|
407
|
+
const profileRegex = /\[([^\]]+)\]\s*\n((?:[^[]*(?:\n|$))*)/g;
|
|
408
|
+
let match;
|
|
409
|
+
while ((match = profileRegex.exec(content)) !== null) {
|
|
410
|
+
const profileName = match[1] ?? 'default';
|
|
411
|
+
const profileContent = match[2] ?? '';
|
|
412
|
+
const accessKeyMatch = profileContent.match(/aws_access_key_id\s*=\s*(\S+)/);
|
|
413
|
+
const secretKeyMatch = profileContent.match(/aws_secret_access_key\s*=\s*(\S+)/);
|
|
414
|
+
if (accessKeyMatch?.[1] && secretKeyMatch?.[1]) {
|
|
415
|
+
const keyPreview = accessKeyMatch[1].substring(0, 8) + '...';
|
|
416
|
+
credentials.push({
|
|
417
|
+
provider: 'aws',
|
|
418
|
+
filePath,
|
|
419
|
+
classification: {
|
|
420
|
+
name: `AWS Access Key [${profileName}] (${keyPreview})`,
|
|
421
|
+
credentialType: 'api-key',
|
|
422
|
+
visaType: 'privilege',
|
|
423
|
+
riskLevel: 'critical',
|
|
424
|
+
platforms: ['aws'],
|
|
425
|
+
tags: ['aws', profileName, 'imported'],
|
|
426
|
+
issuingAuthority: 'AWS IAM',
|
|
427
|
+
},
|
|
428
|
+
rawValue: `${accessKeyMatch[1]}:${secretKeyMatch[1]}`,
|
|
429
|
+
metadata: {
|
|
430
|
+
profile: profileName,
|
|
431
|
+
accessKeyId: accessKeyMatch[1],
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return credentials;
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* SSH provider definition
|
|
443
|
+
*/
|
|
444
|
+
export const sshProvider = {
|
|
445
|
+
id: 'ssh',
|
|
446
|
+
name: 'SSH',
|
|
447
|
+
description: 'SSH private keys',
|
|
448
|
+
detect: async () => {
|
|
449
|
+
const fs = await import('fs/promises');
|
|
450
|
+
try {
|
|
451
|
+
await fs.access(join(homedir(), '.ssh'));
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
locations: [
|
|
459
|
+
{
|
|
460
|
+
id: 'private-keys',
|
|
461
|
+
name: 'SSH Private Keys',
|
|
462
|
+
pathPattern: '{home}/.ssh',
|
|
463
|
+
filePattern: 'id_*',
|
|
464
|
+
parse: (filePath, content) => {
|
|
465
|
+
const credentials = [];
|
|
466
|
+
// Only process private keys (not .pub files)
|
|
467
|
+
if (filePath.endsWith('.pub'))
|
|
468
|
+
return credentials;
|
|
469
|
+
// Check if it's a private key
|
|
470
|
+
if (content.includes('PRIVATE KEY')) {
|
|
471
|
+
const keyType = content.includes('RSA') ? 'RSA' :
|
|
472
|
+
content.includes('EC') ? 'EC' :
|
|
473
|
+
content.includes('OPENSSH') ? 'OpenSSH' : 'Unknown';
|
|
474
|
+
const fileName = filePath.split('/').pop() || 'unknown';
|
|
475
|
+
credentials.push({
|
|
476
|
+
provider: 'ssh',
|
|
477
|
+
filePath,
|
|
478
|
+
classification: {
|
|
479
|
+
name: `SSH Private Key (${fileName})`,
|
|
480
|
+
credentialType: 'private-key',
|
|
481
|
+
visaType: 'access',
|
|
482
|
+
riskLevel: 'high',
|
|
483
|
+
platforms: ['ssh'],
|
|
484
|
+
tags: ['ssh', keyType.toLowerCase(), 'imported'],
|
|
485
|
+
issuingAuthority: 'Self-generated',
|
|
486
|
+
},
|
|
487
|
+
rawValue: content,
|
|
488
|
+
metadata: {
|
|
489
|
+
keyType,
|
|
490
|
+
fileName,
|
|
491
|
+
},
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return credentials;
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
],
|
|
498
|
+
};
|
|
499
|
+
/**
|
|
500
|
+
* Docker provider definition
|
|
501
|
+
*/
|
|
502
|
+
export const dockerProvider = {
|
|
503
|
+
id: 'docker',
|
|
504
|
+
name: 'Docker',
|
|
505
|
+
description: 'Docker registry credentials',
|
|
506
|
+
detect: async () => {
|
|
507
|
+
const fs = await import('fs/promises');
|
|
508
|
+
try {
|
|
509
|
+
await fs.access(join(homedir(), '.docker', 'config.json'));
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
locations: [
|
|
517
|
+
{
|
|
518
|
+
id: 'config',
|
|
519
|
+
name: 'Docker Config',
|
|
520
|
+
pathPattern: '{home}/.docker',
|
|
521
|
+
filePattern: 'config.json',
|
|
522
|
+
parse: (filePath, content) => {
|
|
523
|
+
const credentials = [];
|
|
524
|
+
try {
|
|
525
|
+
const data = JSON.parse(content);
|
|
526
|
+
if (data.auths) {
|
|
527
|
+
for (const [registry, auth] of Object.entries(data.auths)) {
|
|
528
|
+
if (auth.auth) {
|
|
529
|
+
credentials.push({
|
|
530
|
+
provider: 'docker',
|
|
531
|
+
filePath,
|
|
532
|
+
classification: {
|
|
533
|
+
name: `Docker Registry (${registry})`,
|
|
534
|
+
credentialType: 'api-key',
|
|
535
|
+
visaType: 'access',
|
|
536
|
+
riskLevel: 'medium',
|
|
537
|
+
platforms: ['docker'],
|
|
538
|
+
tags: ['docker', 'registry', 'imported'],
|
|
539
|
+
issuingAuthority: registry,
|
|
540
|
+
},
|
|
541
|
+
rawValue: auth.auth,
|
|
542
|
+
metadata: {
|
|
543
|
+
registry,
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
catch {
|
|
551
|
+
// Invalid JSON
|
|
552
|
+
}
|
|
553
|
+
return credentials;
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
};
|
|
558
|
+
/**
|
|
559
|
+
* npm provider definition
|
|
560
|
+
*/
|
|
561
|
+
export const npmProvider = {
|
|
562
|
+
id: 'npm',
|
|
563
|
+
name: 'npm',
|
|
564
|
+
description: 'npm registry tokens',
|
|
565
|
+
detect: async () => {
|
|
566
|
+
const fs = await import('fs/promises');
|
|
567
|
+
try {
|
|
568
|
+
await fs.access(join(homedir(), '.npmrc'));
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
locations: [
|
|
576
|
+
{
|
|
577
|
+
id: 'npmrc',
|
|
578
|
+
name: 'npm Config',
|
|
579
|
+
pathPattern: '{home}',
|
|
580
|
+
filePattern: '.npmrc',
|
|
581
|
+
parse: (filePath, content) => {
|
|
582
|
+
const credentials = [];
|
|
583
|
+
// Match auth tokens
|
|
584
|
+
const tokenMatch = content.match(/_authToken=([^\s\n]+)/);
|
|
585
|
+
if (tokenMatch?.[1]) {
|
|
586
|
+
const tokenPreview = tokenMatch[1].substring(0, 8) + '...';
|
|
587
|
+
credentials.push({
|
|
588
|
+
provider: 'npm',
|
|
589
|
+
filePath,
|
|
590
|
+
classification: {
|
|
591
|
+
name: `npm Auth Token (${tokenPreview})`,
|
|
592
|
+
credentialType: 'api-key',
|
|
593
|
+
visaType: 'access',
|
|
594
|
+
riskLevel: 'medium',
|
|
595
|
+
platforms: ['npm'],
|
|
596
|
+
tags: ['npm', 'registry', 'imported'],
|
|
597
|
+
issuingAuthority: 'npm Registry',
|
|
598
|
+
},
|
|
599
|
+
rawValue: tokenMatch[1],
|
|
600
|
+
metadata: {},
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return credentials;
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
};
|
|
608
|
+
/**
|
|
609
|
+
* Kubernetes provider definition
|
|
610
|
+
*/
|
|
611
|
+
export const kubernetesProvider = {
|
|
612
|
+
id: 'kubernetes',
|
|
613
|
+
name: 'Kubernetes',
|
|
614
|
+
description: 'Kubernetes cluster credentials',
|
|
615
|
+
detect: async () => {
|
|
616
|
+
const fs = await import('fs/promises');
|
|
617
|
+
try {
|
|
618
|
+
await fs.access(join(homedir(), '.kube', 'config'));
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
catch {
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
locations: [
|
|
626
|
+
{
|
|
627
|
+
id: 'kubeconfig',
|
|
628
|
+
name: 'Kubeconfig',
|
|
629
|
+
pathPattern: '{home}/.kube',
|
|
630
|
+
filePattern: 'config',
|
|
631
|
+
parse: (filePath, content) => {
|
|
632
|
+
const credentials = [];
|
|
633
|
+
// Simple YAML parsing for kubeconfig
|
|
634
|
+
const clusterMatches = content.match(/- name:\s*([^\n]+)/g);
|
|
635
|
+
if (clusterMatches) {
|
|
636
|
+
for (const match of clusterMatches) {
|
|
637
|
+
const name = match.replace('- name:', '').trim();
|
|
638
|
+
credentials.push({
|
|
639
|
+
provider: 'kubernetes',
|
|
640
|
+
filePath,
|
|
641
|
+
classification: {
|
|
642
|
+
name: `Kubernetes Cluster (${name})`,
|
|
643
|
+
credentialType: 'custom',
|
|
644
|
+
visaType: 'privilege',
|
|
645
|
+
riskLevel: 'high',
|
|
646
|
+
platforms: ['kubernetes'],
|
|
647
|
+
tags: ['kubernetes', 'cluster', 'imported'],
|
|
648
|
+
issuingAuthority: 'Kubernetes',
|
|
649
|
+
},
|
|
650
|
+
rawValue: content,
|
|
651
|
+
metadata: {
|
|
652
|
+
clusterName: name,
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
break; // Just capture the first cluster as the main credential
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return credentials;
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
],
|
|
662
|
+
};
|
|
663
|
+
// ============================================================================
|
|
664
|
+
// Provider Registry
|
|
665
|
+
// ============================================================================
|
|
666
|
+
/**
|
|
667
|
+
* All registered providers
|
|
668
|
+
*/
|
|
669
|
+
export const providers = [
|
|
670
|
+
openclawProvider,
|
|
671
|
+
awsProvider,
|
|
672
|
+
sshProvider,
|
|
673
|
+
dockerProvider,
|
|
674
|
+
npmProvider,
|
|
675
|
+
kubernetesProvider,
|
|
676
|
+
];
|
|
677
|
+
/**
|
|
678
|
+
* Get provider by ID
|
|
679
|
+
*/
|
|
680
|
+
export function getProvider(id) {
|
|
681
|
+
return providers.find(p => p.id === id);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get all provider IDs
|
|
685
|
+
*/
|
|
686
|
+
export function getProviderIds() {
|
|
687
|
+
return providers.map(p => p.id);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Detect which providers are installed
|
|
691
|
+
*/
|
|
692
|
+
export async function detectInstalledProviders() {
|
|
693
|
+
const installed = [];
|
|
694
|
+
for (const provider of providers) {
|
|
695
|
+
if (await provider.detect()) {
|
|
696
|
+
installed.push(provider);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return installed;
|
|
700
|
+
}
|
|
701
|
+
// ============================================================================
|
|
702
|
+
// Risk Level Helpers
|
|
703
|
+
// ============================================================================
|
|
704
|
+
/**
|
|
705
|
+
* Get risk level emoji
|
|
706
|
+
*/
|
|
707
|
+
export function getRiskEmoji(level) {
|
|
708
|
+
switch (level) {
|
|
709
|
+
case 'critical': return '🔴';
|
|
710
|
+
case 'high': return '⚠️ ';
|
|
711
|
+
case 'medium': return '⚠️ ';
|
|
712
|
+
case 'low': return 'ℹ️ ';
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Get risk level label
|
|
717
|
+
*/
|
|
718
|
+
export function getRiskLabel(level) {
|
|
719
|
+
return level.toUpperCase();
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Sort credentials by risk level (critical first)
|
|
723
|
+
*/
|
|
724
|
+
export function sortByRisk(credentials) {
|
|
725
|
+
const order = {
|
|
726
|
+
critical: 0,
|
|
727
|
+
high: 1,
|
|
728
|
+
medium: 2,
|
|
729
|
+
low: 3,
|
|
730
|
+
};
|
|
731
|
+
return [...credentials].sort((a, b) => order[a.classification.riskLevel] - order[b.classification.riskLevel]);
|
|
732
|
+
}
|
|
733
|
+
//# sourceMappingURL=locations.js.map
|