recker 1.0.29 → 1.0.31
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 +28 -1
- package/dist/ai/client-ai.d.ts +41 -0
- package/dist/ai/client-ai.js +391 -0
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.js +2 -0
- package/dist/ai/memory.d.ts +35 -0
- package/dist/ai/memory.js +136 -0
- package/dist/browser/ai/client-ai.d.ts +41 -0
- package/dist/browser/ai/client-ai.js +391 -0
- package/dist/browser/ai/memory.d.ts +35 -0
- package/dist/browser/ai/memory.js +136 -0
- package/dist/browser/core/client.d.ts +6 -1
- package/dist/browser/core/client.js +18 -0
- package/dist/browser/transport/undici.js +11 -2
- package/dist/browser/types/ai-client.d.ts +32 -0
- package/dist/browser/types/ai-client.js +1 -0
- package/dist/browser/types/ai.d.ts +1 -1
- package/dist/cli/index.js +402 -1
- package/dist/cli/tui/scroll-buffer.js +4 -4
- package/dist/cli/tui/shell.d.ts +3 -0
- package/dist/cli/tui/shell.js +166 -19
- package/dist/core/client.d.ts +6 -1
- package/dist/core/client.js +18 -0
- package/dist/mcp/server.js +15 -0
- package/dist/mcp/tools/scrape.d.ts +3 -0
- package/dist/mcp/tools/scrape.js +156 -0
- package/dist/mcp/tools/security.d.ts +3 -0
- package/dist/mcp/tools/security.js +471 -0
- package/dist/mcp/tools/seo.d.ts +3 -0
- package/dist/mcp/tools/seo.js +427 -0
- package/dist/presets/anthropic.d.ts +3 -1
- package/dist/presets/anthropic.js +11 -1
- package/dist/presets/azure-openai.d.ts +3 -1
- package/dist/presets/azure-openai.js +11 -1
- package/dist/presets/cohere.d.ts +3 -1
- package/dist/presets/cohere.js +8 -2
- package/dist/presets/deepseek.d.ts +3 -1
- package/dist/presets/deepseek.js +8 -2
- package/dist/presets/fireworks.d.ts +3 -1
- package/dist/presets/fireworks.js +8 -2
- package/dist/presets/gemini.d.ts +3 -1
- package/dist/presets/gemini.js +8 -1
- package/dist/presets/groq.d.ts +3 -1
- package/dist/presets/groq.js +8 -2
- package/dist/presets/huggingface.d.ts +3 -1
- package/dist/presets/huggingface.js +8 -1
- package/dist/presets/mistral.d.ts +3 -1
- package/dist/presets/mistral.js +8 -2
- package/dist/presets/openai.d.ts +3 -1
- package/dist/presets/openai.js +9 -2
- package/dist/presets/perplexity.d.ts +3 -1
- package/dist/presets/perplexity.js +8 -2
- package/dist/presets/registry.d.ts +4 -0
- package/dist/presets/registry.js +48 -0
- package/dist/presets/replicate.d.ts +3 -1
- package/dist/presets/replicate.js +8 -1
- package/dist/presets/together.d.ts +3 -1
- package/dist/presets/together.js +8 -2
- package/dist/presets/xai.d.ts +3 -1
- package/dist/presets/xai.js +8 -2
- package/dist/scrape/spider.js +1 -1
- package/dist/transport/undici.js +11 -2
- package/dist/types/ai-client.d.ts +32 -0
- package/dist/types/ai-client.js +1 -0
- package/dist/types/ai.d.ts +1 -1
- package/dist/utils/colors.d.ts +2 -0
- package/dist/utils/colors.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { createClient } from '../../core/client.js';
|
|
2
|
+
import { inspectTLS } from '../../utils/tls-inspector.js';
|
|
3
|
+
import { rdap, supportsRDAP } from '../../utils/rdap.js';
|
|
4
|
+
import { getIpInfo, isValidIP } from '../ip-intel.js';
|
|
5
|
+
import { analyzeSecurityHeaders, quickSecurityCheck } from '../../utils/security-grader.js';
|
|
6
|
+
import { validateSpf, validateDmarc, checkDkim, checkDnsHealth, getSecurityRecords, } from '../../utils/dns-toolkit.js';
|
|
7
|
+
async function tlsInspect(args) {
|
|
8
|
+
const host = String(args.host || '');
|
|
9
|
+
const port = Number(args.port) || 443;
|
|
10
|
+
if (!host) {
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: 'Error: host is required' }],
|
|
13
|
+
isError: true,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const info = await inspectTLS(host, port);
|
|
18
|
+
const output = {
|
|
19
|
+
host,
|
|
20
|
+
port,
|
|
21
|
+
valid: info.valid,
|
|
22
|
+
authorized: info.authorized,
|
|
23
|
+
certificate: {
|
|
24
|
+
subject: info.subject,
|
|
25
|
+
issuer: info.issuer,
|
|
26
|
+
validFrom: info.validFrom.toISOString(),
|
|
27
|
+
validTo: info.validTo.toISOString(),
|
|
28
|
+
daysRemaining: info.daysRemaining,
|
|
29
|
+
serialNumber: info.serialNumber,
|
|
30
|
+
fingerprint256: info.fingerprint256,
|
|
31
|
+
},
|
|
32
|
+
connection: {
|
|
33
|
+
protocol: info.protocol,
|
|
34
|
+
cipher: info.cipher,
|
|
35
|
+
},
|
|
36
|
+
subjectAltNames: info.altNames,
|
|
37
|
+
publicKey: info.pubkey,
|
|
38
|
+
extendedKeyUsage: info.extKeyUsage,
|
|
39
|
+
warnings: [],
|
|
40
|
+
};
|
|
41
|
+
if (info.daysRemaining <= 30) {
|
|
42
|
+
output.warnings.push(`Certificate expires in ${info.daysRemaining} days!`);
|
|
43
|
+
}
|
|
44
|
+
if (!info.authorized) {
|
|
45
|
+
output.warnings.push(`Certificate not trusted: ${info.authorizationError?.message || 'unknown reason'}`);
|
|
46
|
+
}
|
|
47
|
+
if (info.pubkey && info.pubkey.algo === 'rsa' && info.pubkey.size < 2048) {
|
|
48
|
+
output.warnings.push(`RSA key size ${info.pubkey.size} bits is considered weak`);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: 'text', text: `TLS inspection failed: ${error.message}` }],
|
|
57
|
+
isError: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function rdapLookup(args) {
|
|
62
|
+
const query = String(args.query || '');
|
|
63
|
+
if (!query) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: 'text', text: 'Error: query (domain or IP) is required' }],
|
|
66
|
+
isError: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!query.includes(':') && !/^\d+\.\d+\.\d+\.\d+$/.test(query)) {
|
|
70
|
+
const tld = query.split('.').pop()?.toLowerCase() || '';
|
|
71
|
+
if (!supportsRDAP(tld)) {
|
|
72
|
+
return {
|
|
73
|
+
content: [{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: `RDAP is not available for .${tld} domains. Use rek_whois_lookup instead for traditional WHOIS data.`,
|
|
76
|
+
}],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const client = createClient({ timeout: 15000 });
|
|
83
|
+
const result = await rdap(client, query);
|
|
84
|
+
const output = {
|
|
85
|
+
query,
|
|
86
|
+
ldhName: result.ldhName,
|
|
87
|
+
handle: result.handle,
|
|
88
|
+
status: result.status,
|
|
89
|
+
};
|
|
90
|
+
if (result.events) {
|
|
91
|
+
output.events = {};
|
|
92
|
+
for (const event of result.events) {
|
|
93
|
+
output.events[event.eventAction] = event.eventDate;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (result.nameservers) {
|
|
97
|
+
output.nameservers = result.nameservers.map(ns => ns.ldhName);
|
|
98
|
+
}
|
|
99
|
+
if (result.entities) {
|
|
100
|
+
output.entities = result.entities.map(entity => ({
|
|
101
|
+
handle: entity.handle,
|
|
102
|
+
roles: entity.roles,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
if (result.secureDNS) {
|
|
106
|
+
output.dnssec = result.secureDNS.delegationSigned ? 'signed' : 'unsigned';
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: 'text', text: `RDAP lookup failed: ${error.message}` }],
|
|
115
|
+
isError: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function geoipLookup(args) {
|
|
120
|
+
const ip = String(args.ip || '');
|
|
121
|
+
if (!ip) {
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: 'text', text: 'Error: ip address is required' }],
|
|
124
|
+
isError: true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (!isValidIP(ip)) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: 'text', text: `Invalid IP address: ${ip}` }],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const info = await getIpInfo(ip);
|
|
135
|
+
const output = {
|
|
136
|
+
ip: info.ip,
|
|
137
|
+
isIPv6: info.isIPv6,
|
|
138
|
+
};
|
|
139
|
+
if (info.bogon) {
|
|
140
|
+
output.bogon = true;
|
|
141
|
+
output.bogonType = info.bogonType;
|
|
142
|
+
output.note = 'This is a private/reserved IP address. No geolocation available.';
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
output.location = {
|
|
146
|
+
city: info.city,
|
|
147
|
+
region: info.region,
|
|
148
|
+
country: info.country,
|
|
149
|
+
countryCode: info.countryCode,
|
|
150
|
+
continent: info.continent,
|
|
151
|
+
coordinates: info.loc,
|
|
152
|
+
timezone: info.timezone,
|
|
153
|
+
postalCode: info.postal,
|
|
154
|
+
accuracyRadius: info.accuracy ? `${info.accuracy} km` : undefined,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: 'text', text: `GeoIP lookup failed: ${error.message}` }],
|
|
164
|
+
isError: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function securityHeadersAnalyze(args) {
|
|
169
|
+
const url = String(args.url || '');
|
|
170
|
+
const quick = Boolean(args.quick);
|
|
171
|
+
if (!url) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: 'text', text: 'Error: url is required' }],
|
|
174
|
+
isError: true,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const client = createClient({ timeout: 15000 });
|
|
179
|
+
const response = await client.head(url);
|
|
180
|
+
if (quick) {
|
|
181
|
+
const result = quickSecurityCheck(response.headers);
|
|
182
|
+
return {
|
|
183
|
+
content: [{
|
|
184
|
+
type: 'text',
|
|
185
|
+
text: JSON.stringify({
|
|
186
|
+
url,
|
|
187
|
+
secure: result.secure,
|
|
188
|
+
criticalIssues: result.criticalIssues,
|
|
189
|
+
}, null, 2),
|
|
190
|
+
}],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const report = analyzeSecurityHeaders(response.headers);
|
|
194
|
+
const output = {
|
|
195
|
+
url,
|
|
196
|
+
grade: report.grade,
|
|
197
|
+
score: report.score,
|
|
198
|
+
summary: report.summary,
|
|
199
|
+
};
|
|
200
|
+
const failed = report.details.filter(d => d.status === 'fail');
|
|
201
|
+
const warnings = report.details.filter(d => d.status === 'warn');
|
|
202
|
+
const passed = report.details.filter(d => d.status === 'pass');
|
|
203
|
+
if (failed.length > 0) {
|
|
204
|
+
output.failed = failed.map(d => ({
|
|
205
|
+
header: d.header,
|
|
206
|
+
message: d.message,
|
|
207
|
+
recommendation: d.recommendation,
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
if (warnings.length > 0) {
|
|
211
|
+
output.warnings = warnings.map(d => ({
|
|
212
|
+
header: d.header,
|
|
213
|
+
message: d.message,
|
|
214
|
+
recommendation: d.recommendation,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
output.passed = passed.map(d => d.header);
|
|
218
|
+
if (report.csp) {
|
|
219
|
+
output.csp = {
|
|
220
|
+
score: report.csp.score,
|
|
221
|
+
issues: report.csp.issues,
|
|
222
|
+
missingDirectives: report.csp.missingDirectives,
|
|
223
|
+
hasUnsafeInline: report.csp.hasUnsafeInline,
|
|
224
|
+
hasUnsafeEval: report.csp.hasUnsafeEval,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
return {
|
|
233
|
+
content: [{ type: 'text', text: `Security headers analysis failed: ${error.message}` }],
|
|
234
|
+
isError: true,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function dnsToolkit(args) {
|
|
239
|
+
const domain = String(args.domain || '');
|
|
240
|
+
const check = String(args.check || 'all');
|
|
241
|
+
const dkimSelector = args.dkimSelector;
|
|
242
|
+
if (!domain) {
|
|
243
|
+
return {
|
|
244
|
+
content: [{ type: 'text', text: 'Error: domain is required' }],
|
|
245
|
+
isError: true,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const output = { domain };
|
|
250
|
+
if (check === 'all' || check === 'health') {
|
|
251
|
+
const healthReport = await checkDnsHealth(domain);
|
|
252
|
+
output.health = {
|
|
253
|
+
score: healthReport.score,
|
|
254
|
+
grade: healthReport.grade,
|
|
255
|
+
checks: healthReport.checks,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (check === 'all' || check === 'spf') {
|
|
259
|
+
const spfResult = await validateSpf(domain);
|
|
260
|
+
output.spf = {
|
|
261
|
+
valid: spfResult.valid,
|
|
262
|
+
record: spfResult.record,
|
|
263
|
+
mechanisms: spfResult.mechanisms,
|
|
264
|
+
lookupCount: spfResult.lookupCount,
|
|
265
|
+
warnings: spfResult.warnings,
|
|
266
|
+
errors: spfResult.errors,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (check === 'all' || check === 'dmarc') {
|
|
270
|
+
const dmarcResult = await validateDmarc(domain);
|
|
271
|
+
output.dmarc = {
|
|
272
|
+
valid: dmarcResult.valid,
|
|
273
|
+
record: dmarcResult.record,
|
|
274
|
+
policy: dmarcResult.policy,
|
|
275
|
+
subdomainPolicy: dmarcResult.subdomainPolicy,
|
|
276
|
+
percentage: dmarcResult.percentage,
|
|
277
|
+
reportingUris: dmarcResult.rua,
|
|
278
|
+
warnings: dmarcResult.warnings,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (check === 'all' || check === 'dkim') {
|
|
282
|
+
const selectors = dkimSelector
|
|
283
|
+
? [dkimSelector]
|
|
284
|
+
: ['default', 'google', 'selector1', 'selector2', 'k1', 's1', 'dkim'];
|
|
285
|
+
const dkimResults = [];
|
|
286
|
+
for (const sel of selectors) {
|
|
287
|
+
const result = await checkDkim(domain, sel);
|
|
288
|
+
if (result.found) {
|
|
289
|
+
dkimResults.push({
|
|
290
|
+
selector: sel,
|
|
291
|
+
found: true,
|
|
292
|
+
publicKey: result.publicKey?.slice(0, 50) + '...',
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
output.dkim = {
|
|
297
|
+
found: dkimResults.length > 0,
|
|
298
|
+
selectors: dkimResults,
|
|
299
|
+
note: dkimResults.length === 0
|
|
300
|
+
? 'No DKIM records found with common selectors. Specify dkimSelector parameter if you know the selector.'
|
|
301
|
+
: undefined,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (check === 'all' || check === 'records') {
|
|
305
|
+
const records = await getSecurityRecords(domain);
|
|
306
|
+
output.securityRecords = {
|
|
307
|
+
spf: records.spf,
|
|
308
|
+
dmarc: records.dmarc,
|
|
309
|
+
caa: records.caa,
|
|
310
|
+
mx: records.mx,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
return {
|
|
319
|
+
content: [{ type: 'text', text: `DNS toolkit failed: ${error.message}` }],
|
|
320
|
+
isError: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
export const securityTools = [
|
|
325
|
+
{
|
|
326
|
+
name: 'rek_tls_inspect',
|
|
327
|
+
description: `Inspect SSL/TLS certificate and connection details for a host.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
- Certificate validity and expiration
|
|
331
|
+
- Subject and issuer details
|
|
332
|
+
- Subject Alternative Names (SANs)
|
|
333
|
+
- TLS protocol version and cipher suite
|
|
334
|
+
- Public key algorithm and size
|
|
335
|
+
- Warnings for expiring certs, weak keys, or trust issues
|
|
336
|
+
|
|
337
|
+
Use this to check certificate health, debug TLS issues, or audit HTTPS configuration.`,
|
|
338
|
+
inputSchema: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
properties: {
|
|
341
|
+
host: {
|
|
342
|
+
type: 'string',
|
|
343
|
+
description: 'Hostname to inspect (e.g., "example.com")',
|
|
344
|
+
},
|
|
345
|
+
port: {
|
|
346
|
+
type: 'number',
|
|
347
|
+
description: 'Port number (default: 443)',
|
|
348
|
+
default: 443,
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
required: ['host'],
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
name: 'rek_rdap_lookup',
|
|
356
|
+
description: `Perform RDAP lookup (modern WHOIS) for a domain or IP address.
|
|
357
|
+
|
|
358
|
+
RDAP provides structured JSON data including:
|
|
359
|
+
- Registration dates (created, updated, expires)
|
|
360
|
+
- Status (active, locked, etc.)
|
|
361
|
+
- Nameservers
|
|
362
|
+
- DNSSEC status
|
|
363
|
+
- Registrar/Registrant info
|
|
364
|
+
|
|
365
|
+
Note: Some TLDs (.io, .ai, etc.) don't support RDAP yet - use rek_whois_lookup for those.`,
|
|
366
|
+
inputSchema: {
|
|
367
|
+
type: 'object',
|
|
368
|
+
properties: {
|
|
369
|
+
query: {
|
|
370
|
+
type: 'string',
|
|
371
|
+
description: 'Domain name or IP address to lookup',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
required: ['query'],
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
name: 'rek_geoip_lookup',
|
|
379
|
+
description: `Get geolocation data for an IP address using MaxMind GeoLite2 database.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
- City, region, country, continent
|
|
383
|
+
- Coordinates (latitude, longitude)
|
|
384
|
+
- Timezone
|
|
385
|
+
- Accuracy radius
|
|
386
|
+
- Bogon detection (identifies private/reserved IPs)
|
|
387
|
+
|
|
388
|
+
Database is cached locally and updated automatically.`,
|
|
389
|
+
inputSchema: {
|
|
390
|
+
type: 'object',
|
|
391
|
+
properties: {
|
|
392
|
+
ip: {
|
|
393
|
+
type: 'string',
|
|
394
|
+
description: 'IPv4 or IPv6 address to lookup',
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
required: ['ip'],
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
name: 'rek_security_headers',
|
|
402
|
+
description: `Analyze HTTP security headers for a URL.
|
|
403
|
+
|
|
404
|
+
Grades (A+ to F) based on:
|
|
405
|
+
- HSTS (Strict-Transport-Security)
|
|
406
|
+
- CSP (Content-Security-Policy) with detailed analysis
|
|
407
|
+
- X-Frame-Options / frame-ancestors
|
|
408
|
+
- X-Content-Type-Options
|
|
409
|
+
- Referrer-Policy
|
|
410
|
+
- Permissions-Policy
|
|
411
|
+
- Cross-Origin policies (COOP, COEP, CORP)
|
|
412
|
+
- Information leakage (Server, X-Powered-By)
|
|
413
|
+
|
|
414
|
+
Use quick=true for a fast critical issues check.`,
|
|
415
|
+
inputSchema: {
|
|
416
|
+
type: 'object',
|
|
417
|
+
properties: {
|
|
418
|
+
url: {
|
|
419
|
+
type: 'string',
|
|
420
|
+
description: 'URL to analyze',
|
|
421
|
+
},
|
|
422
|
+
quick: {
|
|
423
|
+
type: 'boolean',
|
|
424
|
+
description: 'Quick mode - only check critical security issues',
|
|
425
|
+
default: false,
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
required: ['url'],
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
name: 'rek_dns_toolkit',
|
|
433
|
+
description: `Advanced DNS security analysis for email authentication and DNS health.
|
|
434
|
+
|
|
435
|
+
Checks:
|
|
436
|
+
- SPF validation (syntax, lookup count, mechanisms)
|
|
437
|
+
- DMARC validation (policy, reporting, alignment)
|
|
438
|
+
- DKIM discovery (tries common selectors)
|
|
439
|
+
- CAA records (certificate authority authorization)
|
|
440
|
+
- MX records
|
|
441
|
+
- Overall DNS health score
|
|
442
|
+
|
|
443
|
+
Use check parameter to run specific checks: "all", "health", "spf", "dmarc", "dkim", "records"`,
|
|
444
|
+
inputSchema: {
|
|
445
|
+
type: 'object',
|
|
446
|
+
properties: {
|
|
447
|
+
domain: {
|
|
448
|
+
type: 'string',
|
|
449
|
+
description: 'Domain to analyze',
|
|
450
|
+
},
|
|
451
|
+
check: {
|
|
452
|
+
type: 'string',
|
|
453
|
+
description: 'Which check to run: all, health, spf, dmarc, dkim, records',
|
|
454
|
+
default: 'all',
|
|
455
|
+
},
|
|
456
|
+
dkimSelector: {
|
|
457
|
+
type: 'string',
|
|
458
|
+
description: 'Specific DKIM selector to check (if known)',
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
required: ['domain'],
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
];
|
|
465
|
+
export const securityToolHandlers = {
|
|
466
|
+
rek_tls_inspect: tlsInspect,
|
|
467
|
+
rek_rdap_lookup: rdapLookup,
|
|
468
|
+
rek_geoip_lookup: geoipLookup,
|
|
469
|
+
rek_security_headers: securityHeadersAnalyze,
|
|
470
|
+
rek_dns_toolkit: dnsToolkit,
|
|
471
|
+
};
|