ai-appshield 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/browser/shield.min.js +19 -0
- package/dist/browser/BotDetector.d.ts +9 -0
- package/dist/browser/BotDetector.d.ts.map +1 -0
- package/dist/browser/BotDetector.js +99 -0
- package/dist/browser/BotDetector.js.map +1 -0
- package/dist/browser/ContentProtector.d.ts +27 -0
- package/dist/browser/ContentProtector.d.ts.map +1 -0
- package/dist/browser/ContentProtector.js +136 -0
- package/dist/browser/ContentProtector.js.map +1 -0
- package/dist/browser/DevToolsGuard.d.ts +16 -0
- package/dist/browser/DevToolsGuard.d.ts.map +1 -0
- package/dist/browser/DevToolsGuard.js +89 -0
- package/dist/browser/DevToolsGuard.js.map +1 -0
- package/dist/browser/Fingerprint.d.ts +30 -0
- package/dist/browser/Fingerprint.d.ts.map +1 -0
- package/dist/browser/Fingerprint.js +143 -0
- package/dist/browser/Fingerprint.js.map +1 -0
- package/dist/browser/Shield.d.ts +35 -0
- package/dist/browser/Shield.d.ts.map +1 -0
- package/dist/browser/Shield.js +177 -0
- package/dist/browser/Shield.js.map +1 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +11 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +269 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config.d.ts +65 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +21 -0
- package/dist/core/config.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/server/BotAnalyzer.d.ts +24 -0
- package/dist/server/BotAnalyzer.d.ts.map +1 -0
- package/dist/server/BotAnalyzer.js +124 -0
- package/dist/server/BotAnalyzer.js.map +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +10 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware.d.ts +28 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +63 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/utils/obfuscate.d.ts +21 -0
- package/dist/utils/obfuscate.d.ts.map +1 -0
- package/dist/utils/obfuscate.js +59 -0
- package/dist/utils/obfuscate.js.map +1 -0
- package/dist/utils/signatures.d.ts +13 -0
- package/dist/utils/signatures.d.ts.map +1 -0
- package/dist/utils/signatures.js +87 -0
- package/dist/utils/signatures.js.map +1 -0
- package/package.json +73 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const program = new commander_1.Command();
|
|
41
|
+
program
|
|
42
|
+
.name('ai-appshield')
|
|
43
|
+
.description('CLI to wrap and protect your application from bots and AI scrapers')
|
|
44
|
+
.version('1.0.0');
|
|
45
|
+
program
|
|
46
|
+
.command('init')
|
|
47
|
+
.description('Initialize ai-appshield in your project')
|
|
48
|
+
.option('-f, --framework <type>', 'Target framework: vanilla, react, express, next', 'vanilla')
|
|
49
|
+
.option('-o, --output <dir>', 'Output directory', '.')
|
|
50
|
+
.action((opts) => {
|
|
51
|
+
const outDir = path.resolve(opts.output);
|
|
52
|
+
console.log(`\n🛡️ Initializing ai-appshield (${opts.framework}) in ${outDir}\n`);
|
|
53
|
+
switch (opts.framework) {
|
|
54
|
+
case 'react':
|
|
55
|
+
writeReactSetup(outDir);
|
|
56
|
+
break;
|
|
57
|
+
case 'express':
|
|
58
|
+
writeExpressSetup(outDir);
|
|
59
|
+
break;
|
|
60
|
+
case 'next':
|
|
61
|
+
writeNextSetup(outDir);
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
writeVanillaSetup(outDir);
|
|
65
|
+
}
|
|
66
|
+
writeConfig(outDir);
|
|
67
|
+
console.log('\n✅ ai-appshield initialized! See ai-appshield.config.js for options.\n');
|
|
68
|
+
});
|
|
69
|
+
program
|
|
70
|
+
.command('wrap')
|
|
71
|
+
.description('Generate a protection snippet for your HTML entry point')
|
|
72
|
+
.option('-e, --entry <file>', 'HTML entry file', 'index.html')
|
|
73
|
+
.option('-o, --output <file>', 'Output file')
|
|
74
|
+
.action((opts) => {
|
|
75
|
+
const entryPath = path.resolve(opts.entry);
|
|
76
|
+
if (!fs.existsSync(entryPath)) {
|
|
77
|
+
console.error(`Entry file not found: ${entryPath}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
let html = fs.readFileSync(entryPath, 'utf-8');
|
|
81
|
+
const snippet = getInjectionSnippet();
|
|
82
|
+
if (html.includes('ai-appshield')) {
|
|
83
|
+
console.log('ai-appshield already injected in entry file.');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (html.includes('</body>')) {
|
|
87
|
+
html = html.replace('</body>', `${snippet}\n</body>`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
html += `\n${snippet}\n`;
|
|
91
|
+
}
|
|
92
|
+
const outputPath = opts.output ? path.resolve(opts.output) : entryPath;
|
|
93
|
+
fs.writeFileSync(outputPath, html);
|
|
94
|
+
console.log(`✅ Protection injected into ${outputPath}`);
|
|
95
|
+
});
|
|
96
|
+
program
|
|
97
|
+
.command('encode')
|
|
98
|
+
.description('Encode sensitive text for data-shield obfuscation')
|
|
99
|
+
.argument('<text>', 'Text to encode')
|
|
100
|
+
.action((text) => {
|
|
101
|
+
const encoded = encodeForCli(text);
|
|
102
|
+
console.log(`\nEncoded: ${encoded}`);
|
|
103
|
+
console.log(`\nHTML usage:`);
|
|
104
|
+
console.log(` <span data-shield="${encoded}"></span>\n`);
|
|
105
|
+
});
|
|
106
|
+
program
|
|
107
|
+
.command('check')
|
|
108
|
+
.description('Analyze a user-agent string for bot indicators')
|
|
109
|
+
.argument('<userAgent>', 'User-agent string to check')
|
|
110
|
+
.action((userAgent) => {
|
|
111
|
+
const { analyzeRequest } = require('./server/BotAnalyzer');
|
|
112
|
+
const result = analyzeRequest({
|
|
113
|
+
headers: { 'user-agent': userAgent },
|
|
114
|
+
path: '/',
|
|
115
|
+
method: 'GET',
|
|
116
|
+
});
|
|
117
|
+
console.log('\n🔍 User-Agent Analysis\n');
|
|
118
|
+
console.log(` Score: ${result.score}/100`);
|
|
119
|
+
console.log(` Blocked: ${result.blocked ? 'YES ⛔' : 'NO ✅'}`);
|
|
120
|
+
if (result.signals.length > 0) {
|
|
121
|
+
console.log(` Signals:`);
|
|
122
|
+
result.signals.forEach((s) => console.log(` - ${s}`));
|
|
123
|
+
}
|
|
124
|
+
console.log();
|
|
125
|
+
});
|
|
126
|
+
program.parse();
|
|
127
|
+
function writeVanillaSetup(outDir) {
|
|
128
|
+
const snippet = `// ai-appshield setup — add to your main JS file
|
|
129
|
+
import { protect } from 'ai-appshield/browser';
|
|
130
|
+
|
|
131
|
+
const shield = protect({
|
|
132
|
+
botDetection: true,
|
|
133
|
+
devToolsGuard: true,
|
|
134
|
+
contentProtection: true,
|
|
135
|
+
honeypot: true,
|
|
136
|
+
fingerprint: true,
|
|
137
|
+
threatAction: 'warn',
|
|
138
|
+
onThreatDetected: (threat) => {
|
|
139
|
+
console.warn('[Shield]', threat.type, threat.message);
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
`;
|
|
143
|
+
fs.writeFileSync(path.join(outDir, 'ai-appshield.setup.js'), snippet);
|
|
144
|
+
console.log(' Created: ai-appshield.setup.js');
|
|
145
|
+
}
|
|
146
|
+
function writeReactSetup(outDir) {
|
|
147
|
+
const snippet = `// ai-appshield React hook — src/hooks/useAppShield.ts
|
|
148
|
+
import { useEffect } from 'react';
|
|
149
|
+
import { Shield } from 'ai-appshield/browser';
|
|
150
|
+
|
|
151
|
+
export function useAppShield() {
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
const shield = new Shield({
|
|
154
|
+
botDetection: true,
|
|
155
|
+
devToolsGuard: true,
|
|
156
|
+
contentProtection: true,
|
|
157
|
+
honeypot: true,
|
|
158
|
+
fingerprint: true,
|
|
159
|
+
threatAction: 'warn',
|
|
160
|
+
});
|
|
161
|
+
shield.activate();
|
|
162
|
+
return () => shield.deactivate();
|
|
163
|
+
}, []);
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
const dir = path.join(outDir, 'src', 'hooks');
|
|
167
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
168
|
+
fs.writeFileSync(path.join(dir, 'useAppShield.ts'), snippet);
|
|
169
|
+
console.log(' Created: src/hooks/useAppShield.ts');
|
|
170
|
+
}
|
|
171
|
+
function writeExpressSetup(outDir) {
|
|
172
|
+
const snippet = `// ai-appshield Express middleware
|
|
173
|
+
const { createShieldMiddleware } = require('ai-appshield/server');
|
|
174
|
+
|
|
175
|
+
const shieldMiddleware = createShieldMiddleware({
|
|
176
|
+
botAnalysis: true,
|
|
177
|
+
blockBots: true,
|
|
178
|
+
rateLimit: { maxRequests: 100, windowMs: 60000 },
|
|
179
|
+
blockStatusCode: 403,
|
|
180
|
+
onBlocked: (info) => {
|
|
181
|
+
console.warn('[Shield] Blocked:', info.ip, info.reason);
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Add BEFORE your routes:
|
|
186
|
+
// app.use(shieldMiddleware);
|
|
187
|
+
`;
|
|
188
|
+
fs.writeFileSync(path.join(outDir, 'ai-appshield.middleware.js'), snippet);
|
|
189
|
+
console.log(' Created: ai-appshield.middleware.js');
|
|
190
|
+
}
|
|
191
|
+
function writeNextSetup(outDir) {
|
|
192
|
+
const snippet = `// ai-appshield Next.js middleware — middleware.ts
|
|
193
|
+
import { NextResponse } from 'next/server';
|
|
194
|
+
import type { NextRequest } from 'next/server';
|
|
195
|
+
|
|
196
|
+
const BOT_SIGNATURES = ['bot', 'crawl', 'spider', 'scrape', 'gptbot', 'claudebot', 'bytespider'];
|
|
197
|
+
|
|
198
|
+
export function middleware(request: NextRequest) {
|
|
199
|
+
const ua = request.headers.get('user-agent')?.toLowerCase() ?? '';
|
|
200
|
+
const isBot = BOT_SIGNATURES.some((sig) => ua.includes(sig));
|
|
201
|
+
|
|
202
|
+
if (isBot) {
|
|
203
|
+
return new NextResponse('Access Denied', { status: 403 });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return NextResponse.next();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export const config = {
|
|
210
|
+
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
211
|
+
};
|
|
212
|
+
`;
|
|
213
|
+
fs.writeFileSync(path.join(outDir, 'middleware.ts'), snippet);
|
|
214
|
+
console.log(' Created: middleware.ts');
|
|
215
|
+
}
|
|
216
|
+
function writeConfig(outDir) {
|
|
217
|
+
const config = `/** @type {import('ai-appshield').ShieldConfig} */
|
|
218
|
+
module.exports = {
|
|
219
|
+
// Client-side protection
|
|
220
|
+
client: {
|
|
221
|
+
botDetection: true,
|
|
222
|
+
devToolsGuard: true,
|
|
223
|
+
contentProtection: true,
|
|
224
|
+
honeypot: true,
|
|
225
|
+
fingerprint: true,
|
|
226
|
+
obfuscateContent: false,
|
|
227
|
+
threatAction: 'warn', // 'block' | 'warn' | 'redirect'
|
|
228
|
+
// redirectUrl: '/blocked',
|
|
229
|
+
// reportEndpoint: '/api/shield-report',
|
|
230
|
+
debug: false,
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
// Server-side protection
|
|
234
|
+
server: {
|
|
235
|
+
botAnalysis: true,
|
|
236
|
+
blockBots: true,
|
|
237
|
+
requireFingerprint: false,
|
|
238
|
+
rateLimit: { maxRequests: 100, windowMs: 60000 },
|
|
239
|
+
blockStatusCode: 403,
|
|
240
|
+
excludePaths: ['/health', '/api/public'],
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
`;
|
|
244
|
+
fs.writeFileSync(path.join(outDir, 'ai-appshield.config.js'), config);
|
|
245
|
+
console.log(' Created: ai-appshield.config.js');
|
|
246
|
+
}
|
|
247
|
+
function getInjectionSnippet() {
|
|
248
|
+
return ` <!-- ai-appshield protection -->
|
|
249
|
+
<script src="https://unpkg.com/ai-appshield/browser/shield.min.js"></script>
|
|
250
|
+
<script>
|
|
251
|
+
AppShield.protect({
|
|
252
|
+
botDetection: true,
|
|
253
|
+
devToolsGuard: true,
|
|
254
|
+
contentProtection: true,
|
|
255
|
+
honeypot: true,
|
|
256
|
+
fingerprint: true,
|
|
257
|
+
threatAction: 'warn'
|
|
258
|
+
});
|
|
259
|
+
</script>`;
|
|
260
|
+
}
|
|
261
|
+
function encodeForCli(text) {
|
|
262
|
+
const key = 'ai-appshield';
|
|
263
|
+
const encoded = [];
|
|
264
|
+
for (let i = 0; i < text.length; i++) {
|
|
265
|
+
encoded.push(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
|
|
266
|
+
}
|
|
267
|
+
return Buffer.from(String.fromCharCode(...encoded)).toString('base64');
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface ShieldConfig {
|
|
2
|
+
/** Enable bot/automation detection (Puppeteer, Selenium, Playwright, etc.) */
|
|
3
|
+
botDetection?: boolean;
|
|
4
|
+
/** Block or warn when browser DevTools are open */
|
|
5
|
+
devToolsGuard?: boolean;
|
|
6
|
+
/** Prevent text selection, copy, right-click, and drag */
|
|
7
|
+
contentProtection?: boolean;
|
|
8
|
+
/** Inject hidden honeypot traps for scrapers */
|
|
9
|
+
honeypot?: boolean;
|
|
10
|
+
/** Collect browser fingerprint for server-side validation */
|
|
11
|
+
fingerprint?: boolean;
|
|
12
|
+
/** Obfuscate sensitive DOM text content */
|
|
13
|
+
obfuscateContent?: boolean;
|
|
14
|
+
/** CSS selector for elements to protect (default: body) */
|
|
15
|
+
protectSelector?: string;
|
|
16
|
+
/** Callback when a threat is detected */
|
|
17
|
+
onThreatDetected?: (threat: ThreatEvent) => void;
|
|
18
|
+
/** Action to take on threat: 'block' | 'warn' | 'redirect' */
|
|
19
|
+
threatAction?: 'block' | 'warn' | 'redirect';
|
|
20
|
+
/** URL to redirect to when threatAction is 'redirect' */
|
|
21
|
+
redirectUrl?: string;
|
|
22
|
+
/** Server endpoint to report threats (optional) */
|
|
23
|
+
reportEndpoint?: string;
|
|
24
|
+
/** Enable debug logging */
|
|
25
|
+
debug?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ThreatEvent {
|
|
28
|
+
type: ThreatType;
|
|
29
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
30
|
+
message: string;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
export type ThreatType = 'bot_detected' | 'devtools_open' | 'automation_tool' | 'headless_browser' | 'honeypot_triggered' | 'suspicious_fingerprint' | 'rate_limit_exceeded' | 'content_scrape_attempt';
|
|
35
|
+
export interface ServerShieldConfig {
|
|
36
|
+
/** Enable request-level bot analysis */
|
|
37
|
+
botAnalysis?: boolean;
|
|
38
|
+
/** Rate limit: max requests per window */
|
|
39
|
+
rateLimit?: {
|
|
40
|
+
maxRequests: number;
|
|
41
|
+
windowMs: number;
|
|
42
|
+
};
|
|
43
|
+
/** Block known bot user agents */
|
|
44
|
+
blockBots?: boolean;
|
|
45
|
+
/** Require valid fingerprint header from client */
|
|
46
|
+
requireFingerprint?: boolean;
|
|
47
|
+
/** Secret key for signing/validating requests */
|
|
48
|
+
secretKey?: string;
|
|
49
|
+
/** Custom block response status code */
|
|
50
|
+
blockStatusCode?: number;
|
|
51
|
+
/** Paths to exclude from protection */
|
|
52
|
+
excludePaths?: string[];
|
|
53
|
+
/** Callback on blocked request */
|
|
54
|
+
onBlocked?: (info: BlockedRequestInfo) => void;
|
|
55
|
+
}
|
|
56
|
+
export interface BlockedRequestInfo {
|
|
57
|
+
ip: string;
|
|
58
|
+
userAgent: string;
|
|
59
|
+
path: string;
|
|
60
|
+
reason: string;
|
|
61
|
+
timestamp: number;
|
|
62
|
+
}
|
|
63
|
+
export declare const DEFAULT_SHIELD_CONFIG: Required<Pick<ShieldConfig, 'botDetection' | 'devToolsGuard' | 'contentProtection' | 'honeypot' | 'fingerprint' | 'obfuscateContent' | 'protectSelector' | 'threatAction' | 'debug'>>;
|
|
64
|
+
export declare const DEFAULT_SERVER_CONFIG: Required<Pick<ServerShieldConfig, 'botAnalysis' | 'blockBots' | 'requireFingerprint' | 'blockStatusCode'>>;
|
|
65
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;IAC7C,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,MAAM,UAAU,GAClB,cAAc,GACd,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,oBAAoB,GACpB,wBAAwB,GACxB,qBAAqB,GACrB,wBAAwB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kCAAkC;IAClC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAC1C,IAAI,CACF,YAAY,EACV,cAAc,GACd,eAAe,GACf,mBAAmB,GACnB,UAAU,GACV,aAAa,GACb,kBAAkB,GAClB,iBAAiB,GACjB,cAAc,GACd,OAAO,CACV,CAWF,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAC1C,IAAI,CACF,kBAAkB,EAClB,aAAa,GAAG,WAAW,GAAG,oBAAoB,GAAG,iBAAiB,CACvE,CAMF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_SERVER_CONFIG = exports.DEFAULT_SHIELD_CONFIG = void 0;
|
|
4
|
+
exports.DEFAULT_SHIELD_CONFIG = {
|
|
5
|
+
botDetection: true,
|
|
6
|
+
devToolsGuard: true,
|
|
7
|
+
contentProtection: true,
|
|
8
|
+
honeypot: true,
|
|
9
|
+
fingerprint: true,
|
|
10
|
+
obfuscateContent: false,
|
|
11
|
+
protectSelector: 'body',
|
|
12
|
+
threatAction: 'warn',
|
|
13
|
+
debug: false,
|
|
14
|
+
};
|
|
15
|
+
exports.DEFAULT_SERVER_CONFIG = {
|
|
16
|
+
botAnalysis: true,
|
|
17
|
+
blockBots: true,
|
|
18
|
+
requireFingerprint: false,
|
|
19
|
+
blockStatusCode: 403,
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":";;;AA2Ea,QAAA,qBAAqB,GAa9B;IACF,YAAY,EAAE,IAAI;IAClB,aAAa,EAAE,IAAI;IACnB,iBAAiB,EAAE,IAAI;IACvB,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,IAAI;IACjB,gBAAgB,EAAE,KAAK;IACvB,eAAe,EAAE,MAAM;IACvB,YAAY,EAAE,MAAM;IACpB,KAAK,EAAE,KAAK;CACb,CAAC;AAEW,QAAA,qBAAqB,GAK9B;IACF,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,IAAI;IACf,kBAAkB,EAAE,KAAK;IACzB,eAAe,EAAE,GAAG;CACrB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Shield, protect } from './browser/Shield';
|
|
2
|
+
export { createShieldMiddleware, validateRequest } from './server/middleware';
|
|
3
|
+
export { analyzeRequest, RateLimiter } from './server/BotAnalyzer';
|
|
4
|
+
export { encodeContent, decodeContent, obfuscateText } from './utils/obfuscate';
|
|
5
|
+
export type { ShieldConfig, ServerShieldConfig, ThreatEvent, ThreatType, BlockedRequestInfo, } from './core/config';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAChF,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.obfuscateText = exports.decodeContent = exports.encodeContent = exports.RateLimiter = exports.analyzeRequest = exports.validateRequest = exports.createShieldMiddleware = exports.protect = exports.Shield = void 0;
|
|
4
|
+
var Shield_1 = require("./browser/Shield");
|
|
5
|
+
Object.defineProperty(exports, "Shield", { enumerable: true, get: function () { return Shield_1.Shield; } });
|
|
6
|
+
Object.defineProperty(exports, "protect", { enumerable: true, get: function () { return Shield_1.protect; } });
|
|
7
|
+
var middleware_1 = require("./server/middleware");
|
|
8
|
+
Object.defineProperty(exports, "createShieldMiddleware", { enumerable: true, get: function () { return middleware_1.createShieldMiddleware; } });
|
|
9
|
+
Object.defineProperty(exports, "validateRequest", { enumerable: true, get: function () { return middleware_1.validateRequest; } });
|
|
10
|
+
var BotAnalyzer_1 = require("./server/BotAnalyzer");
|
|
11
|
+
Object.defineProperty(exports, "analyzeRequest", { enumerable: true, get: function () { return BotAnalyzer_1.analyzeRequest; } });
|
|
12
|
+
Object.defineProperty(exports, "RateLimiter", { enumerable: true, get: function () { return BotAnalyzer_1.RateLimiter; } });
|
|
13
|
+
var obfuscate_1 = require("./utils/obfuscate");
|
|
14
|
+
Object.defineProperty(exports, "encodeContent", { enumerable: true, get: function () { return obfuscate_1.encodeContent; } });
|
|
15
|
+
Object.defineProperty(exports, "decodeContent", { enumerable: true, get: function () { return obfuscate_1.decodeContent; } });
|
|
16
|
+
Object.defineProperty(exports, "obfuscateText", { enumerable: true, get: function () { return obfuscate_1.obfuscateText; } });
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAmD;AAA1C,gGAAA,MAAM,OAAA;AAAE,iGAAA,OAAO,OAAA;AACxB,kDAA8E;AAArE,oHAAA,sBAAsB,OAAA;AAAE,6GAAA,eAAe,OAAA;AAChD,oDAAmE;AAA1D,6GAAA,cAAc,OAAA;AAAE,0GAAA,WAAW,OAAA;AACpC,+CAAgF;AAAvE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServerShieldConfig } from '../core/config';
|
|
2
|
+
export interface RequestLike {
|
|
3
|
+
headers: Record<string, string | string[] | undefined>;
|
|
4
|
+
ip?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
method?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface AnalysisResult {
|
|
9
|
+
blocked: boolean;
|
|
10
|
+
reason?: string;
|
|
11
|
+
score: number;
|
|
12
|
+
signals: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function analyzeRequest(req: RequestLike, config?: ServerShieldConfig): AnalysisResult;
|
|
15
|
+
/** In-memory sliding-window rate limiter */
|
|
16
|
+
export declare class RateLimiter {
|
|
17
|
+
private requests;
|
|
18
|
+
private maxRequests;
|
|
19
|
+
private windowMs;
|
|
20
|
+
constructor(maxRequests?: number, windowMs?: number);
|
|
21
|
+
isRateLimited(key: string): boolean;
|
|
22
|
+
reset(key?: string): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=BotAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotAnalyzer.d.ts","sourceRoot":"","sources":["../../src/server/BotAnalyzer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAsB,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG7E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,MAAM,GAAE,kBAAuB,GAC9B,cAAc,CA+FhB;AAQD,4CAA4C;AAC5C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;gBAEb,WAAW,SAAM,EAAE,QAAQ,SAAS;IAKhD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAcnC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;CAO1B"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimiter = void 0;
|
|
4
|
+
exports.analyzeRequest = analyzeRequest;
|
|
5
|
+
const signatures_1 = require("../utils/signatures");
|
|
6
|
+
const config_1 = require("../core/config");
|
|
7
|
+
function analyzeRequest(req, config = {}) {
|
|
8
|
+
const cfg = { ...config_1.DEFAULT_SERVER_CONFIG, ...config };
|
|
9
|
+
const signals = [];
|
|
10
|
+
let score = 0;
|
|
11
|
+
const userAgent = getHeader(req, 'user-agent').toLowerCase();
|
|
12
|
+
const ip = req.ip ?? getHeader(req, 'x-forwarded-for') ?? 'unknown';
|
|
13
|
+
const path = req.path ?? '/';
|
|
14
|
+
// Skip excluded paths
|
|
15
|
+
if (config.excludePaths?.some((p) => path.startsWith(p))) {
|
|
16
|
+
return { blocked: false, score: 0, signals: [] };
|
|
17
|
+
}
|
|
18
|
+
// Bot user-agent check
|
|
19
|
+
if (cfg.blockBots && userAgent) {
|
|
20
|
+
for (const botSig of signatures_1.BOT_USER_AGENTS) {
|
|
21
|
+
if (userAgent.includes(botSig)) {
|
|
22
|
+
signals.push(`Bot user-agent: ${botSig}`);
|
|
23
|
+
score += 50;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Missing or suspicious user-agent
|
|
29
|
+
if (!userAgent || userAgent.length < 10) {
|
|
30
|
+
signals.push('Missing or abnormally short user-agent');
|
|
31
|
+
score += 20;
|
|
32
|
+
}
|
|
33
|
+
// Headless indicators in user-agent
|
|
34
|
+
if (userAgent.includes('headless')) {
|
|
35
|
+
signals.push('Headless browser user-agent');
|
|
36
|
+
score += 40;
|
|
37
|
+
}
|
|
38
|
+
// Check for automation headers
|
|
39
|
+
const automationHeaders = [
|
|
40
|
+
'x-automated-tool',
|
|
41
|
+
'x-puppeteer',
|
|
42
|
+
'x-playwright',
|
|
43
|
+
'x-selenium',
|
|
44
|
+
];
|
|
45
|
+
for (const header of automationHeaders) {
|
|
46
|
+
if (getHeader(req, header)) {
|
|
47
|
+
signals.push(`Automation header: ${header}`);
|
|
48
|
+
score += 45;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Fingerprint validation
|
|
52
|
+
if (cfg.requireFingerprint) {
|
|
53
|
+
const fp = getHeader(req, 'x-ai-appshield-fingerprint');
|
|
54
|
+
if (!fp) {
|
|
55
|
+
signals.push('Missing fingerprint header');
|
|
56
|
+
score += 30;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Suspicious request patterns
|
|
60
|
+
if (cfg.botAnalysis) {
|
|
61
|
+
const accept = getHeader(req, 'accept');
|
|
62
|
+
if (!accept) {
|
|
63
|
+
signals.push('No Accept header');
|
|
64
|
+
score += 10;
|
|
65
|
+
}
|
|
66
|
+
const acceptLang = getHeader(req, 'accept-language');
|
|
67
|
+
if (!acceptLang) {
|
|
68
|
+
signals.push('No Accept-Language header');
|
|
69
|
+
score += 10;
|
|
70
|
+
}
|
|
71
|
+
// Rapid sequential path scanning pattern
|
|
72
|
+
const referer = getHeader(req, 'referer');
|
|
73
|
+
if (!referer && req.method === 'GET' && !path.match(/\.(js|css|png|jpg|svg|ico|woff)/)) {
|
|
74
|
+
signals.push('Direct navigation without referer');
|
|
75
|
+
score += 5;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const blocked = score >= 40;
|
|
79
|
+
if (blocked && config.onBlocked) {
|
|
80
|
+
config.onBlocked({
|
|
81
|
+
ip: String(ip),
|
|
82
|
+
userAgent,
|
|
83
|
+
path,
|
|
84
|
+
reason: signals.join('; '),
|
|
85
|
+
timestamp: Date.now(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return { blocked, reason: signals.join('; '), score, signals };
|
|
89
|
+
}
|
|
90
|
+
function getHeader(req, name) {
|
|
91
|
+
const value = req.headers[name];
|
|
92
|
+
if (Array.isArray(value))
|
|
93
|
+
return value[0] ?? '';
|
|
94
|
+
return value ?? '';
|
|
95
|
+
}
|
|
96
|
+
/** In-memory sliding-window rate limiter */
|
|
97
|
+
class RateLimiter {
|
|
98
|
+
constructor(maxRequests = 100, windowMs = 60000) {
|
|
99
|
+
this.requests = new Map();
|
|
100
|
+
this.maxRequests = maxRequests;
|
|
101
|
+
this.windowMs = windowMs;
|
|
102
|
+
}
|
|
103
|
+
isRateLimited(key) {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const timestamps = this.requests.get(key) ?? [];
|
|
106
|
+
const recent = timestamps.filter((t) => now - t < this.windowMs);
|
|
107
|
+
if (recent.length >= this.maxRequests) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
recent.push(now);
|
|
111
|
+
this.requests.set(key, recent);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
reset(key) {
|
|
115
|
+
if (key) {
|
|
116
|
+
this.requests.delete(key);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
this.requests.clear();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.RateLimiter = RateLimiter;
|
|
124
|
+
//# sourceMappingURL=BotAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotAnalyzer.js","sourceRoot":"","sources":["../../src/server/BotAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimiter = exports.analyzeRequest = exports.validateRequest = exports.createShieldMiddleware = void 0;
|
|
4
|
+
var middleware_1 = require("./middleware");
|
|
5
|
+
Object.defineProperty(exports, "createShieldMiddleware", { enumerable: true, get: function () { return middleware_1.createShieldMiddleware; } });
|
|
6
|
+
Object.defineProperty(exports, "validateRequest", { enumerable: true, get: function () { return middleware_1.validateRequest; } });
|
|
7
|
+
var BotAnalyzer_1 = require("./BotAnalyzer");
|
|
8
|
+
Object.defineProperty(exports, "analyzeRequest", { enumerable: true, get: function () { return BotAnalyzer_1.analyzeRequest; } });
|
|
9
|
+
Object.defineProperty(exports, "RateLimiter", { enumerable: true, get: function () { return BotAnalyzer_1.RateLimiter; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;AAAA,2CAAuE;AAA9D,oHAAA,sBAAsB,OAAA;AAAE,6GAAA,eAAe,OAAA;AAChD,6CAA4D;AAAnD,6GAAA,cAAc,OAAA;AAAE,0GAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ServerShieldConfig } from '../core/config';
|
|
2
|
+
export interface MiddlewareRequest {
|
|
3
|
+
headers: Record<string, string | string[] | undefined>;
|
|
4
|
+
ip?: string;
|
|
5
|
+
path: string;
|
|
6
|
+
method: string;
|
|
7
|
+
}
|
|
8
|
+
export interface MiddlewareResponse {
|
|
9
|
+
status(code: number): MiddlewareResponse;
|
|
10
|
+
json(body: unknown): void;
|
|
11
|
+
end(): void;
|
|
12
|
+
}
|
|
13
|
+
export type NextFunction = () => void;
|
|
14
|
+
/**
|
|
15
|
+
* Express-compatible middleware factory.
|
|
16
|
+
* Also works with any framework that uses (req, res, next) pattern.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createShieldMiddleware(config?: ServerShieldConfig): (req: MiddlewareRequest, res: MiddlewareResponse, next: NextFunction) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Standalone request validator (for non-Express frameworks).
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateRequest(req: MiddlewareRequest, config?: ServerShieldConfig): {
|
|
23
|
+
allowed: boolean;
|
|
24
|
+
statusCode: number;
|
|
25
|
+
reason?: string;
|
|
26
|
+
};
|
|
27
|
+
export { analyzeRequest, RateLimiter } from './BotAnalyzer';
|
|
28
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACzC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,GAAG,IAAI,IAAI,CAAC;CACb;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,kBAAuB,IAOlE,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,MAAM,YAAY,KACjB,IAAI,CA+BR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,iBAAiB,EACtB,MAAM,CAAC,EAAE,kBAAkB,GAC1B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAa3D;AAED,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|