@kya-os/agentshield-nextjs 0.1.18 → 0.1.19
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/EDGE_RUNTIME_WASM_SETUP.md +348 -0
- package/bin/setup-edge-wasm.js +525 -0
- package/dist/edge-runtime-loader.d.mts +49 -0
- package/dist/edge-runtime-loader.d.ts +49 -0
- package/dist/edge-runtime-loader.js +198 -0
- package/dist/edge-runtime-loader.js.map +1 -0
- package/dist/edge-runtime-loader.mjs +192 -0
- package/dist/edge-runtime-loader.mjs.map +1 -0
- package/package.json +14 -4
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AgentShield Edge Runtime WASM Setup Script
|
|
5
|
+
*
|
|
6
|
+
* This script helps Next.js users set up WASM support for Edge Runtime (middleware).
|
|
7
|
+
* It copies necessary files and creates the required configuration.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
|
|
14
|
+
// Colors for console output
|
|
15
|
+
const colors = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
bright: '\x1b[1m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
red: '\x1b[31m',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function log(message, color = colors.reset) {
|
|
25
|
+
console.log(`${color}${message}${colors.reset}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function error(message) {
|
|
29
|
+
console.error(`${colors.red}❌ ${message}${colors.reset}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function success(message) {
|
|
33
|
+
log(`✅ ${message}`, colors.green);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function info(message) {
|
|
37
|
+
log(`ℹ️ ${message}`, colors.blue);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function warning(message) {
|
|
41
|
+
log(`⚠️ ${message}`, colors.yellow);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function main() {
|
|
45
|
+
log('\n🚀 AgentShield Edge Runtime WASM Setup\n', colors.bright);
|
|
46
|
+
|
|
47
|
+
// Step 1: Check if we're in a Next.js project
|
|
48
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
49
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
50
|
+
error(
|
|
51
|
+
'No package.json found. Please run this command from your Next.js project root.'
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
57
|
+
const hasNext =
|
|
58
|
+
packageJson.dependencies?.next || packageJson.devDependencies?.next;
|
|
59
|
+
|
|
60
|
+
if (!hasNext) {
|
|
61
|
+
warning('Next.js not detected in package.json. Continuing anyway...');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Step 2: Check if AgentShield is installed
|
|
65
|
+
const agentShieldPath = path.join(
|
|
66
|
+
process.cwd(),
|
|
67
|
+
'node_modules',
|
|
68
|
+
'@kya-os',
|
|
69
|
+
'agentshield-nextjs'
|
|
70
|
+
);
|
|
71
|
+
if (!fs.existsSync(agentShieldPath)) {
|
|
72
|
+
error('@kya-os/agentshield-nextjs not found in node_modules.');
|
|
73
|
+
info('Please install it first:');
|
|
74
|
+
console.log(' npm install @kya-os/agentshield-nextjs');
|
|
75
|
+
console.log(' # or');
|
|
76
|
+
console.log(' pnpm add @kya-os/agentshield-nextjs');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Step 3: Create wasm directory
|
|
81
|
+
const wasmDir = path.join(process.cwd(), 'wasm');
|
|
82
|
+
if (!fs.existsSync(wasmDir)) {
|
|
83
|
+
fs.mkdirSync(wasmDir, { recursive: true });
|
|
84
|
+
success('Created wasm/ directory');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Step 4: Copy WASM file
|
|
88
|
+
const sourceWasm = path.join(
|
|
89
|
+
agentShieldPath,
|
|
90
|
+
'dist',
|
|
91
|
+
'wasm',
|
|
92
|
+
'agentshield_wasm_bg.wasm'
|
|
93
|
+
);
|
|
94
|
+
const destWasm = path.join(wasmDir, 'agentshield_wasm_bg.wasm');
|
|
95
|
+
|
|
96
|
+
if (fs.existsSync(sourceWasm)) {
|
|
97
|
+
fs.copyFileSync(sourceWasm, destWasm);
|
|
98
|
+
const sizeKB = (fs.statSync(destWasm).size / 1024).toFixed(1);
|
|
99
|
+
const sizeMB = (fs.statSync(destWasm).size / 1024 / 1024).toFixed(2);
|
|
100
|
+
const sizeStr = sizeKB < 1024 ? `${sizeKB}KB` : `${sizeMB}MB`;
|
|
101
|
+
success(`Copied WASM file to wasm/ (${sizeStr})`);
|
|
102
|
+
} else {
|
|
103
|
+
// Try alternative location
|
|
104
|
+
const altSourceWasm = path.join(
|
|
105
|
+
agentShieldPath,
|
|
106
|
+
'wasm',
|
|
107
|
+
'agentshield_wasm_bg.wasm'
|
|
108
|
+
);
|
|
109
|
+
if (fs.existsSync(altSourceWasm)) {
|
|
110
|
+
fs.copyFileSync(altSourceWasm, destWasm);
|
|
111
|
+
const sizeKB = (fs.statSync(destWasm).size / 1024).toFixed(1);
|
|
112
|
+
const sizeMB = (fs.statSync(destWasm).size / 1024 / 1024).toFixed(2);
|
|
113
|
+
const sizeStr = sizeKB < 1024 ? `${sizeKB}KB` : `${sizeMB}MB`;
|
|
114
|
+
success(`Copied WASM file to wasm/ (${sizeStr})`);
|
|
115
|
+
} else {
|
|
116
|
+
error(
|
|
117
|
+
'WASM file not found in the package. The package may be corrupted.'
|
|
118
|
+
);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Step 5: Create TypeScript definitions
|
|
124
|
+
const dtsContent = `// Auto-generated by agentshield-setup-edge
|
|
125
|
+
// TypeScript definitions for AgentShield WASM in Edge Runtime
|
|
126
|
+
|
|
127
|
+
declare module '*.wasm?module' {
|
|
128
|
+
const wasmModule: WebAssembly.Module;
|
|
129
|
+
export default wasmModule;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface AgentShieldWasm {
|
|
133
|
+
detect_agent(metadata: string): string;
|
|
134
|
+
get_version(): string;
|
|
135
|
+
memory: WebAssembly.Memory;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface DetectionResult {
|
|
139
|
+
isAgent: boolean;
|
|
140
|
+
confidence: number;
|
|
141
|
+
agent?: string;
|
|
142
|
+
verificationMethod: 'cryptographic' | 'pattern';
|
|
143
|
+
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
144
|
+
timestamp: string;
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const dtsPath = path.join(wasmDir, 'agentshield.d.ts');
|
|
149
|
+
fs.writeFileSync(dtsPath, dtsContent);
|
|
150
|
+
success('Created TypeScript definitions');
|
|
151
|
+
|
|
152
|
+
// Step 6: Create lib directory and Edge loader
|
|
153
|
+
const libDir = path.join(process.cwd(), 'lib');
|
|
154
|
+
if (!fs.existsSync(libDir)) {
|
|
155
|
+
fs.mkdirSync(libDir, { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const edgeLoaderContent = `/**
|
|
159
|
+
* AgentShield Edge Runtime Loader
|
|
160
|
+
* Auto-generated by agentshield-setup-edge
|
|
161
|
+
*
|
|
162
|
+
* This module provides WASM-based AI agent detection for Next.js Edge Runtime.
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
import type { NextRequest } from 'next/server';
|
|
166
|
+
import wasmModule from '../wasm/agentshield_wasm_bg.wasm?module';
|
|
167
|
+
|
|
168
|
+
let wasmInstance: WebAssembly.Instance | null = null;
|
|
169
|
+
let wasmMemory: WebAssembly.Memory | null = null;
|
|
170
|
+
|
|
171
|
+
interface WasmExports {
|
|
172
|
+
detect_agent(metadataPtr: number, metadataLen: number): number;
|
|
173
|
+
get_version(): number;
|
|
174
|
+
__wbindgen_malloc(size: number): number;
|
|
175
|
+
__wbindgen_free(ptr: number, size: number): void;
|
|
176
|
+
__wbindgen_realloc(ptr: number, oldSize: number, newSize: number): number;
|
|
177
|
+
memory: WebAssembly.Memory;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function initWasm(): Promise<void> {
|
|
181
|
+
if (wasmInstance) return;
|
|
182
|
+
|
|
183
|
+
wasmMemory = new WebAssembly.Memory({ initial: 17, maximum: 256 });
|
|
184
|
+
|
|
185
|
+
const imports = {
|
|
186
|
+
wbg: {
|
|
187
|
+
__wbindgen_throw: (ptr: number, len: number) => {
|
|
188
|
+
throw new Error(readString(ptr, len));
|
|
189
|
+
},
|
|
190
|
+
__wbg_log_: (ptr: number, len: number) => {
|
|
191
|
+
console.log(readString(ptr, len));
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
env: {
|
|
195
|
+
memory: wasmMemory,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
wasmInstance = await WebAssembly.instantiate(wasmModule, imports);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function readString(ptr: number, len: number): string {
|
|
203
|
+
if (!wasmInstance || !wasmMemory) throw new Error('WASM not initialized');
|
|
204
|
+
const memory = new Uint8Array(wasmMemory.buffer);
|
|
205
|
+
const bytes = memory.slice(ptr, ptr + len);
|
|
206
|
+
return new TextDecoder().decode(bytes);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function writeString(str: string): [number, number] {
|
|
210
|
+
if (!wasmInstance) throw new Error('WASM not initialized');
|
|
211
|
+
const exports = wasmInstance.exports as unknown as WasmExports;
|
|
212
|
+
|
|
213
|
+
const encoded = new TextEncoder().encode(str);
|
|
214
|
+
const ptr = exports.__wbindgen_malloc(encoded.length);
|
|
215
|
+
|
|
216
|
+
const memory = new Uint8Array(exports.memory.buffer);
|
|
217
|
+
memory.set(encoded, ptr);
|
|
218
|
+
|
|
219
|
+
return [ptr, encoded.length];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface DetectionResult {
|
|
223
|
+
isAgent: boolean;
|
|
224
|
+
confidence: number;
|
|
225
|
+
agent?: string;
|
|
226
|
+
verificationMethod: 'cryptographic' | 'pattern';
|
|
227
|
+
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
228
|
+
timestamp?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface AgentShieldOptions {
|
|
232
|
+
enableWasm?: boolean;
|
|
233
|
+
onAgentDetected?: (result: DetectionResult) => void;
|
|
234
|
+
blockAgents?: boolean;
|
|
235
|
+
allowedAgents?: string[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create an AgentShield middleware instance
|
|
240
|
+
*/
|
|
241
|
+
export function createAgentShieldMiddleware(options: AgentShieldOptions = {}) {
|
|
242
|
+
let initialized = false;
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
async init(): Promise<void> {
|
|
246
|
+
if (initialized) return;
|
|
247
|
+
|
|
248
|
+
if (options.enableWasm !== false) {
|
|
249
|
+
try {
|
|
250
|
+
await initWasm();
|
|
251
|
+
initialized = true;
|
|
252
|
+
console.log('✅ AgentShield WASM initialized in Edge Runtime');
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.warn('⚠️ WASM initialization failed, using pattern detection:', error);
|
|
255
|
+
initialized = true;
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
initialized = true;
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
async detect(request: NextRequest): Promise<DetectionResult> {
|
|
263
|
+
const metadata = {
|
|
264
|
+
userAgent: request.headers.get('user-agent') || '',
|
|
265
|
+
ipAddress: request.ip || request.headers.get('x-forwarded-for')?.split(',')[0] || '',
|
|
266
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Try WASM detection first
|
|
270
|
+
if (wasmInstance && options.enableWasm !== false) {
|
|
271
|
+
try {
|
|
272
|
+
const exports = wasmInstance.exports as unknown as WasmExports;
|
|
273
|
+
const [ptr, len] = writeString(JSON.stringify(metadata));
|
|
274
|
+
|
|
275
|
+
const resultPtr = exports.detect_agent(ptr, len);
|
|
276
|
+
const resultLen = 1024; // Assume max result size
|
|
277
|
+
const resultStr = readString(resultPtr, resultLen);
|
|
278
|
+
|
|
279
|
+
exports.__wbindgen_free(ptr, len);
|
|
280
|
+
exports.__wbindgen_free(resultPtr, resultLen);
|
|
281
|
+
|
|
282
|
+
const result = JSON.parse(resultStr);
|
|
283
|
+
|
|
284
|
+
const detection: DetectionResult = {
|
|
285
|
+
...result,
|
|
286
|
+
verificationMethod: 'cryptographic',
|
|
287
|
+
timestamp: new Date().toISOString(),
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (options.onAgentDetected && detection.isAgent) {
|
|
291
|
+
options.onAgentDetected(detection);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return detection;
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.error('WASM detection failed:', error);
|
|
297
|
+
// Fall through to pattern detection
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Fallback: Pattern-based detection
|
|
302
|
+
return patternDetection(metadata, options);
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
isInitialized(): boolean {
|
|
306
|
+
return initialized;
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
getVerificationMethod(): 'cryptographic' | 'pattern' {
|
|
310
|
+
return wasmInstance ? 'cryptographic' : 'pattern';
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Pattern-based detection fallback
|
|
317
|
+
*/
|
|
318
|
+
function patternDetection(
|
|
319
|
+
metadata: { userAgent: string; ipAddress: string; headers: Record<string, string> },
|
|
320
|
+
options: AgentShieldOptions
|
|
321
|
+
): DetectionResult {
|
|
322
|
+
const userAgent = metadata.userAgent.toLowerCase();
|
|
323
|
+
|
|
324
|
+
// Known AI agent patterns with confidence scores
|
|
325
|
+
const aiAgentPatterns = [
|
|
326
|
+
{ pattern: /chatgpt-user/i, name: 'ChatGPT', confidence: 0.95 },
|
|
327
|
+
{ pattern: /claude-web/i, name: 'Claude', confidence: 0.95 },
|
|
328
|
+
{ pattern: /anthropic/i, name: 'Anthropic', confidence: 0.90 },
|
|
329
|
+
{ pattern: /openai/i, name: 'OpenAI', confidence: 0.90 },
|
|
330
|
+
{ pattern: /gpt-crawler/i, name: 'GPT Crawler', confidence: 0.95 },
|
|
331
|
+
{ pattern: /copilot/i, name: 'GitHub Copilot', confidence: 0.85 },
|
|
332
|
+
{ pattern: /bard/i, name: 'Google Bard', confidence: 0.85 },
|
|
333
|
+
{ pattern: /gemini/i, name: 'Google Gemini', confidence: 0.85 },
|
|
334
|
+
{ pattern: /perplexity/i, name: 'Perplexity', confidence: 0.85 },
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
// Check headers for AI-specific patterns
|
|
338
|
+
const suspiciousHeaders = [
|
|
339
|
+
'x-openai-',
|
|
340
|
+
'x-anthropic-',
|
|
341
|
+
'x-ai-',
|
|
342
|
+
'x-llm-',
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
let headerBoost = 0;
|
|
346
|
+
for (const [key, value] of Object.entries(metadata.headers)) {
|
|
347
|
+
if (suspiciousHeaders.some(prefix => key.toLowerCase().startsWith(prefix))) {
|
|
348
|
+
headerBoost = 0.1;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Check user agent patterns
|
|
354
|
+
for (const { pattern, name, confidence } of aiAgentPatterns) {
|
|
355
|
+
if (pattern.test(userAgent)) {
|
|
356
|
+
const finalConfidence = Math.min(confidence + headerBoost, 1.0);
|
|
357
|
+
|
|
358
|
+
const result: DetectionResult = {
|
|
359
|
+
isAgent: true,
|
|
360
|
+
confidence: finalConfidence,
|
|
361
|
+
agent: name,
|
|
362
|
+
verificationMethod: 'pattern',
|
|
363
|
+
riskLevel: finalConfidence > 0.9 ? 'high' : 'medium',
|
|
364
|
+
timestamp: new Date().toISOString(),
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
if (options.onAgentDetected) {
|
|
368
|
+
options.onAgentDetected(result);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Not detected as AI agent
|
|
376
|
+
return {
|
|
377
|
+
isAgent: false,
|
|
378
|
+
confidence: 0.85,
|
|
379
|
+
verificationMethod: 'pattern',
|
|
380
|
+
timestamp: new Date().toISOString(),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export default createAgentShieldMiddleware;
|
|
385
|
+
`;
|
|
386
|
+
|
|
387
|
+
const edgeLoaderPath = path.join(libDir, 'agentshield-edge.ts');
|
|
388
|
+
fs.writeFileSync(edgeLoaderPath, edgeLoaderContent);
|
|
389
|
+
success('Created Edge Runtime loader at lib/agentshield-edge.ts');
|
|
390
|
+
|
|
391
|
+
// Step 7: Create example middleware if it doesn't exist
|
|
392
|
+
const middlewarePath = path.join(process.cwd(), 'middleware.ts');
|
|
393
|
+
if (!fs.existsSync(middlewarePath)) {
|
|
394
|
+
const middlewareContent = `import { NextResponse } from 'next/server';
|
|
395
|
+
import type { NextRequest } from 'next/server';
|
|
396
|
+
import { createAgentShieldMiddleware } from './lib/agentshield-edge';
|
|
397
|
+
|
|
398
|
+
// Initialize AgentShield
|
|
399
|
+
const agentShield = createAgentShieldMiddleware({
|
|
400
|
+
enableWasm: true,
|
|
401
|
+
onAgentDetected: (result) => {
|
|
402
|
+
console.log(\`🤖 AI Agent detected: \${result.agent} (confidence: \${(result.confidence * 100).toFixed(1)}%)\`);
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
export async function middleware(request: NextRequest) {
|
|
407
|
+
// Initialize WASM on first request
|
|
408
|
+
await agentShield.init();
|
|
409
|
+
|
|
410
|
+
// Detect AI agents
|
|
411
|
+
const detection = await agentShield.detect(request);
|
|
412
|
+
|
|
413
|
+
// Log detection results
|
|
414
|
+
if (detection.isAgent) {
|
|
415
|
+
console.log(\`AI Agent detected on \${request.url}:\`, detection);
|
|
416
|
+
|
|
417
|
+
// Optional: Add headers to track AI agent traffic
|
|
418
|
+
const response = NextResponse.next();
|
|
419
|
+
response.headers.set('X-Agent-Detected', detection.agent || 'unknown');
|
|
420
|
+
response.headers.set('X-Agent-Confidence', detection.confidence.toString());
|
|
421
|
+
return response;
|
|
422
|
+
|
|
423
|
+
// Optional: Block AI agents
|
|
424
|
+
// if (detection.confidence > 0.9) {
|
|
425
|
+
// return NextResponse.json(
|
|
426
|
+
// { error: 'AI agent access denied' },
|
|
427
|
+
// { status: 403 }
|
|
428
|
+
// );
|
|
429
|
+
// }
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return NextResponse.next();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export const config = {
|
|
436
|
+
matcher: [
|
|
437
|
+
/*
|
|
438
|
+
* Match all request paths except for the ones starting with:
|
|
439
|
+
* - api/admin (protect admin APIs)
|
|
440
|
+
* - _next/static (static files)
|
|
441
|
+
* - _next/image (image optimization files)
|
|
442
|
+
* - favicon.ico (favicon file)
|
|
443
|
+
*/
|
|
444
|
+
'/((?!_next/static|_next/image|favicon.ico).*)',
|
|
445
|
+
],
|
|
446
|
+
};
|
|
447
|
+
`;
|
|
448
|
+
|
|
449
|
+
fs.writeFileSync(middlewarePath, middlewareContent);
|
|
450
|
+
success('Created example middleware.ts');
|
|
451
|
+
} else {
|
|
452
|
+
info('middleware.ts already exists - skipping creation');
|
|
453
|
+
info('See lib/agentshield-edge.ts for integration instructions');
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Step 8: Update next.config.js if needed
|
|
457
|
+
const nextConfigPath = path.join(process.cwd(), 'next.config.js');
|
|
458
|
+
const nextConfigMjsPath = path.join(process.cwd(), 'next.config.mjs');
|
|
459
|
+
const configPath = fs.existsSync(nextConfigPath)
|
|
460
|
+
? nextConfigPath
|
|
461
|
+
: fs.existsSync(nextConfigMjsPath)
|
|
462
|
+
? nextConfigMjsPath
|
|
463
|
+
: null;
|
|
464
|
+
|
|
465
|
+
if (configPath) {
|
|
466
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
467
|
+
|
|
468
|
+
if (!configContent.includes('wasm')) {
|
|
469
|
+
warning(
|
|
470
|
+
'Your next.config.js may need to be updated to handle WASM files.'
|
|
471
|
+
);
|
|
472
|
+
console.log('\nAdd this to your webpack config:\n');
|
|
473
|
+
console.log(
|
|
474
|
+
colors.yellow +
|
|
475
|
+
` webpack: (config) => {
|
|
476
|
+
config.module.rules.push({
|
|
477
|
+
test: /\\.wasm$/,
|
|
478
|
+
type: 'asset/resource',
|
|
479
|
+
});
|
|
480
|
+
return config;
|
|
481
|
+
},` +
|
|
482
|
+
colors.reset
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Step 9: Final instructions
|
|
488
|
+
console.log('\n' + colors.bright + '🎉 Setup Complete!' + colors.reset);
|
|
489
|
+
console.log(
|
|
490
|
+
'\n' +
|
|
491
|
+
colors.green +
|
|
492
|
+
'AgentShield Edge Runtime WASM is now configured!' +
|
|
493
|
+
colors.reset
|
|
494
|
+
);
|
|
495
|
+
console.log('\nNext steps:');
|
|
496
|
+
console.log('1. Review the generated files:');
|
|
497
|
+
console.log(' - wasm/agentshield_wasm_bg.wasm (WASM binary)');
|
|
498
|
+
console.log(' - lib/agentshield-edge.ts (Edge Runtime loader)');
|
|
499
|
+
console.log(' - middleware.ts (Example implementation)');
|
|
500
|
+
console.log('\n2. Test your setup:');
|
|
501
|
+
console.log(' npm run dev');
|
|
502
|
+
console.log(' # Visit your site and check the console for detection logs');
|
|
503
|
+
console.log('\n3. Deploy to Vercel:');
|
|
504
|
+
console.log(' git add .');
|
|
505
|
+
console.log(' git commit -m "Add AgentShield WASM for Edge Runtime"');
|
|
506
|
+
console.log(' git push');
|
|
507
|
+
console.log(
|
|
508
|
+
'\n' +
|
|
509
|
+
colors.blue +
|
|
510
|
+
'Documentation: https://github.com/kya-os/agentshield#edge-runtime' +
|
|
511
|
+
colors.reset
|
|
512
|
+
);
|
|
513
|
+
console.log(
|
|
514
|
+
colors.blue +
|
|
515
|
+
'Issues: https://github.com/kya-os/agentshield/issues' +
|
|
516
|
+
colors.reset
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Run the setup
|
|
521
|
+
main().catch(err => {
|
|
522
|
+
error('Setup failed: ' + err.message);
|
|
523
|
+
console.error(err);
|
|
524
|
+
process.exit(1);
|
|
525
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge Runtime Compatible WASM Loader for AgentShield
|
|
5
|
+
*
|
|
6
|
+
* This module provides a pre-built solution for loading WASM in Edge Runtime.
|
|
7
|
+
* It requires the WASM file to be manually placed in the project.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface WasmModule {
|
|
11
|
+
default: WebAssembly.Module;
|
|
12
|
+
}
|
|
13
|
+
interface DetectionResult {
|
|
14
|
+
isAgent: boolean;
|
|
15
|
+
confidence: number;
|
|
16
|
+
agent?: string;
|
|
17
|
+
verificationMethod: 'cryptographic' | 'pattern';
|
|
18
|
+
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
19
|
+
timestamp: string;
|
|
20
|
+
}
|
|
21
|
+
interface AgentShieldConfig {
|
|
22
|
+
wasmModule?: WebAssembly.Module;
|
|
23
|
+
enableWasm?: boolean;
|
|
24
|
+
onAgentDetected?: (result: DetectionResult) => void;
|
|
25
|
+
blockAgents?: boolean;
|
|
26
|
+
allowedAgents?: string[];
|
|
27
|
+
debug?: boolean;
|
|
28
|
+
}
|
|
29
|
+
declare class EdgeRuntimeAgentShield {
|
|
30
|
+
private wasmInstance;
|
|
31
|
+
private wasmMemory;
|
|
32
|
+
private config;
|
|
33
|
+
private initialized;
|
|
34
|
+
constructor(config?: AgentShieldConfig);
|
|
35
|
+
init(wasmModule?: WebAssembly.Module): Promise<void>;
|
|
36
|
+
private readString;
|
|
37
|
+
private writeString;
|
|
38
|
+
detect(request: NextRequest): Promise<DetectionResult>;
|
|
39
|
+
private patternDetection;
|
|
40
|
+
isInitialized(): boolean;
|
|
41
|
+
getVerificationMethod(): 'cryptographic' | 'pattern';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Factory function to create an AgentShield instance for Edge Runtime
|
|
45
|
+
*/
|
|
46
|
+
declare function createEdgeAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
|
|
47
|
+
declare function getDefaultAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
|
|
48
|
+
|
|
49
|
+
export { type AgentShieldConfig, type DetectionResult, type WasmModule, createEdgeAgentShield, createEdgeAgentShield as default, getDefaultAgentShield };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge Runtime Compatible WASM Loader for AgentShield
|
|
5
|
+
*
|
|
6
|
+
* This module provides a pre-built solution for loading WASM in Edge Runtime.
|
|
7
|
+
* It requires the WASM file to be manually placed in the project.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface WasmModule {
|
|
11
|
+
default: WebAssembly.Module;
|
|
12
|
+
}
|
|
13
|
+
interface DetectionResult {
|
|
14
|
+
isAgent: boolean;
|
|
15
|
+
confidence: number;
|
|
16
|
+
agent?: string;
|
|
17
|
+
verificationMethod: 'cryptographic' | 'pattern';
|
|
18
|
+
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
19
|
+
timestamp: string;
|
|
20
|
+
}
|
|
21
|
+
interface AgentShieldConfig {
|
|
22
|
+
wasmModule?: WebAssembly.Module;
|
|
23
|
+
enableWasm?: boolean;
|
|
24
|
+
onAgentDetected?: (result: DetectionResult) => void;
|
|
25
|
+
blockAgents?: boolean;
|
|
26
|
+
allowedAgents?: string[];
|
|
27
|
+
debug?: boolean;
|
|
28
|
+
}
|
|
29
|
+
declare class EdgeRuntimeAgentShield {
|
|
30
|
+
private wasmInstance;
|
|
31
|
+
private wasmMemory;
|
|
32
|
+
private config;
|
|
33
|
+
private initialized;
|
|
34
|
+
constructor(config?: AgentShieldConfig);
|
|
35
|
+
init(wasmModule?: WebAssembly.Module): Promise<void>;
|
|
36
|
+
private readString;
|
|
37
|
+
private writeString;
|
|
38
|
+
detect(request: NextRequest): Promise<DetectionResult>;
|
|
39
|
+
private patternDetection;
|
|
40
|
+
isInitialized(): boolean;
|
|
41
|
+
getVerificationMethod(): 'cryptographic' | 'pattern';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Factory function to create an AgentShield instance for Edge Runtime
|
|
45
|
+
*/
|
|
46
|
+
declare function createEdgeAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
|
|
47
|
+
declare function getDefaultAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
|
|
48
|
+
|
|
49
|
+
export { type AgentShieldConfig, type DetectionResult, type WasmModule, createEdgeAgentShield, createEdgeAgentShield as default, getDefaultAgentShield };
|