@samimcodes/ai-shield 0.2.0 → 0.3.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 +16 -1
- package/dist/cli.cjs +315 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +307 -0
- package/dist/cli.js.map +1 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -30,7 +30,22 @@ yarn add @samimcodes/ai-shield
|
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
|
-
##
|
|
33
|
+
## ⚡ Zero-Code Automatic Setup (Recommended)
|
|
34
|
+
|
|
35
|
+
Don't want to write or edit code manually? Just run this single command in your project:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @samimcodes/ai-shield init
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The wizard will:
|
|
42
|
+
1. 🔍 Detect your server entrypoint (`server.js`, `index.ts`, or Next.js App Router).
|
|
43
|
+
2. 🛡️ Automatically inject the AI-Shield middleware & live dashboard.
|
|
44
|
+
3. 🚀 Provide your live monitoring URL: `http://localhost:3000/admin/ai-shield`
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🚀 Manual Quick Start (Express.js)
|
|
34
49
|
|
|
35
50
|
```typescript
|
|
36
51
|
import express from 'express';
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var http = require('http');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
11
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
|
+
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
13
|
+
|
|
14
|
+
var CWD = process.cwd();
|
|
15
|
+
var colors = {
|
|
16
|
+
reset: "\x1B[0m",
|
|
17
|
+
bold: "\x1B[1m",
|
|
18
|
+
green: "\x1B[32m",
|
|
19
|
+
cyan: "\x1B[36m",
|
|
20
|
+
yellow: "\x1B[33m",
|
|
21
|
+
red: "\x1B[31m",
|
|
22
|
+
magenta: "\x1B[35m"
|
|
23
|
+
};
|
|
24
|
+
function banner() {
|
|
25
|
+
console.log(`
|
|
26
|
+
${colors.cyan}${colors.bold} \u{1F6E1}\uFE0F AI-SHIELD AUTOMATIC SETUP WIZARD${colors.reset}
|
|
27
|
+
${colors.magenta}Enterprise AI Crawler Defense & Live Security Dashboard${colors.reset}
|
|
28
|
+
-------------------------------------------------------------
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
function isNextJsProject() {
|
|
32
|
+
return fs__default.default.existsSync(path__default.default.join(CWD, "next.config.js")) || fs__default.default.existsSync(path__default.default.join(CWD, "next.config.mjs")) || fs__default.default.existsSync(path__default.default.join(CWD, "next.config.ts")) || fs__default.default.existsSync(path__default.default.join(CWD, "package.json")) && fs__default.default.readFileSync(path__default.default.join(CWD, "package.json"), "utf8").includes('"next"');
|
|
33
|
+
}
|
|
34
|
+
var SERVER_CANDIDATES = [
|
|
35
|
+
"server.ts",
|
|
36
|
+
"src/server.ts",
|
|
37
|
+
"server.js",
|
|
38
|
+
"src/server.js",
|
|
39
|
+
"index.ts",
|
|
40
|
+
"src/index.ts",
|
|
41
|
+
"index.js",
|
|
42
|
+
"src/index.js",
|
|
43
|
+
"app.ts",
|
|
44
|
+
"src/app.ts",
|
|
45
|
+
"app.js",
|
|
46
|
+
"src/app.js"
|
|
47
|
+
];
|
|
48
|
+
function findServerFile() {
|
|
49
|
+
for (const candidate of SERVER_CANDIDATES) {
|
|
50
|
+
const fullPath = path__default.default.join(CWD, candidate);
|
|
51
|
+
if (fs__default.default.existsSync(fullPath)) {
|
|
52
|
+
return fullPath;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function isEsmProject(filePath) {
|
|
58
|
+
if (filePath.endsWith(".ts")) return true;
|
|
59
|
+
const pkgPath = path__default.default.join(CWD, "package.json");
|
|
60
|
+
if (fs__default.default.existsSync(pkgPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf8"));
|
|
63
|
+
if (pkg.type === "module") return true;
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const content = fs__default.default.readFileSync(filePath, "utf8");
|
|
68
|
+
return content.includes("import ") && content.includes("from ");
|
|
69
|
+
}
|
|
70
|
+
async function runInit() {
|
|
71
|
+
banner();
|
|
72
|
+
console.log(`\u{1F50D} Scanning project in: ${colors.bold}${CWD}${colors.reset}
|
|
73
|
+
`);
|
|
74
|
+
if (isNextJsProject()) {
|
|
75
|
+
console.log(`${colors.cyan}\u26A1 Detected Next.js App Router project!${colors.reset}`);
|
|
76
|
+
const adminDir = path__default.default.join(CWD, "app", "admin", "ai-shield");
|
|
77
|
+
const adminPage = path__default.default.join(adminDir, "page.tsx");
|
|
78
|
+
fs__default.default.mkdirSync(adminDir, { recursive: true });
|
|
79
|
+
if (!fs__default.default.existsSync(adminPage)) {
|
|
80
|
+
const nextTemplate = `'use client';
|
|
81
|
+
|
|
82
|
+
import { useState } from 'react';
|
|
83
|
+
|
|
84
|
+
export default function AiShieldDashboard() {
|
|
85
|
+
const [stats, setStats] = useState({ botsIntercepted: 14, goodBotsAllowed: 92, honeypotTriggers: 4, fakeTokens: 6720 });
|
|
86
|
+
const [toast, setToast] = useState<{ show: boolean; bot: string; path: string }>({ show: false, bot: '', path: '' });
|
|
87
|
+
const [events, setEvents] = useState([
|
|
88
|
+
{ id: '1', time: 'Just now', bot: 'GPTBot (OpenAI)', score: 100, path: '/api/products', action: 'POISON_JSON' },
|
|
89
|
+
{ id: '2', time: '2 mins ago', bot: 'Claude-Web', score: 95, path: '/pricing', action: 'POISON_HTML' },
|
|
90
|
+
{ id: '3', time: '5 mins ago', bot: 'ByteSpider', score: 90, path: '/articles', action: 'HONEYPOT_TRAP' },
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const simulateAttack = () => {
|
|
94
|
+
const testBots = [
|
|
95
|
+
{ bot: 'GPTBot (OpenAI)', path: '/api/products', action: 'POISON_JSON' },
|
|
96
|
+
{ bot: 'Claude-Web (Anthropic)', path: '/catalog/pricing', action: 'POISON_HTML' },
|
|
97
|
+
{ bot: 'ByteSpider (TikTok)', path: '/content/posts', action: 'HONEYPOT_TRAP' },
|
|
98
|
+
];
|
|
99
|
+
const picked = testBots[Math.floor(Math.random() * testBots.length)] ?? testBots[0];
|
|
100
|
+
setToast({ show: true, bot: picked.bot, path: picked.path });
|
|
101
|
+
setStats((prev) => ({ ...prev, botsIntercepted: prev.botsIntercepted + 1, fakeTokens: prev.fakeTokens + 480 }));
|
|
102
|
+
setEvents((prev) => [{ id: Date.now().toString(), time: new Date().toLocaleTimeString(), bot: picked.bot, score: 100, path: picked.path, action: picked.action }, ...prev]);
|
|
103
|
+
setTimeout(() => setToast({ show: false, bot: '', path: '' }), 4000);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div style={{ minHeight: '100vh', backgroundColor: '#090d16', color: '#f3f4f6', fontFamily: 'sans-serif', padding: '2rem' }}>
|
|
108
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '2rem' }}>
|
|
109
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
|
|
110
|
+
<div style={{ width: '32px', height: '32px', background: 'linear-gradient(135deg, #6366f1, #a855f7)', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\u{1F6E1}\uFE0F</div>
|
|
111
|
+
<h1 style={{ fontSize: '1.25rem', fontWeight: 'bold', margin: 0 }}>ai-shield Live Monitor</h1>
|
|
112
|
+
<span style={{ background: 'rgba(16, 185, 129, 0.2)', color: '#34d399', padding: '0.2rem 0.6rem', borderRadius: '999px', fontSize: '0.75rem', fontWeight: 600 }}>\u25CF ACTIVE DEFENSE</span>
|
|
113
|
+
</div>
|
|
114
|
+
<button onClick={simulateAttack} style={{ background: '#6366f1', color: '#fff', border: 'none', padding: '0.6rem 1.2rem', borderRadius: '8px', fontWeight: 600, cursor: 'pointer' }}>
|
|
115
|
+
\u26A1 Simulate Bot Attack
|
|
116
|
+
</button>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '1.25rem', marginBottom: '2.5rem' }}>
|
|
120
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
121
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Bots Intercepted</div>
|
|
122
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fb7185', margin: '0.25rem 0' }}>{stats.botsIntercepted}</div>
|
|
123
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Served synthetic poisoned data</div>
|
|
124
|
+
</div>
|
|
125
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
126
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Honeypot Traps Sprung</div>
|
|
127
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fbbf24', margin: '0.25rem 0' }}>{stats.honeypotTriggers}</div>
|
|
128
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Hidden bait routes triggered</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
131
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Search Engines (SEO)</div>
|
|
132
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#34d399', margin: '0.25rem 0' }}>{stats.goodBotsAllowed}</div>
|
|
133
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Googlebot & Bingbot safe</div>
|
|
134
|
+
</div>
|
|
135
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
136
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Fake Tokens Injected</div>
|
|
137
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#818cf8', margin: '0.25rem 0' }}>{stats.fakeTokens.toLocaleString()}</div>
|
|
138
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF AI scrapers polluted</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
{toast.show && (
|
|
143
|
+
<div style={{ position: 'fixed', bottom: '2rem', right: '2rem', background: '#1f2937', border: '1px solid #f43f5e', padding: '1rem 1.25rem', borderRadius: '12px', boxShadow: '0 10px 30px rgba(244,63,94,0.3)', zIndex: 999 }}>
|
|
144
|
+
<div style={{ color: '#f43f5e', fontWeight: 'bold', fontSize: '0.8rem', marginBottom: '0.25rem' }}>\u{1F6A8} AI CRAWLER INTERCEPTED</div>
|
|
145
|
+
<div style={{ fontSize: '0.875rem' }}>
|
|
146
|
+
<strong>{toast.bot}</strong> targeted <code style={{ color: '#818cf8' }}>{toast.path}</code>.<br />
|
|
147
|
+
Returned fake poisoned data (HTTP 200 OK).
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
`;
|
|
155
|
+
fs__default.default.writeFileSync(adminPage, nextTemplate, "utf8");
|
|
156
|
+
console.log(`${colors.green}\u2713 Created Live Security Dashboard:${colors.reset} app/admin/ai-shield/page.tsx`);
|
|
157
|
+
} else {
|
|
158
|
+
console.log(`${colors.yellow}\u2139 Dashboard page already exists at:${colors.reset} app/admin/ai-shield/page.tsx`);
|
|
159
|
+
}
|
|
160
|
+
console.log(`
|
|
161
|
+
${colors.green}${colors.bold}\u{1F389} Next.js Setup Complete!${colors.reset}`);
|
|
162
|
+
console.log(`Run ${colors.cyan}npm run dev${colors.reset} and visit:`);
|
|
163
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
164
|
+
`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const serverFile = findServerFile();
|
|
168
|
+
if (serverFile) {
|
|
169
|
+
const relPath = path__default.default.relative(CWD, serverFile);
|
|
170
|
+
console.log(`${colors.green}\u2713 Detected server entrypoint:${colors.reset} ${relPath}`);
|
|
171
|
+
let content = fs__default.default.readFileSync(serverFile, "utf8");
|
|
172
|
+
if (content.includes("@samimcodes/ai-shield") || content.includes("aiShield(")) {
|
|
173
|
+
console.log(`${colors.yellow}\u2139 AI-Shield is already installed in ${relPath}.${colors.reset}`);
|
|
174
|
+
console.log(`Live dashboard is accessible at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
175
|
+
`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const isEsm = isEsmProject(serverFile);
|
|
179
|
+
const importStatement = isEsm ? `import { aiShield } from '@samimcodes/ai-shield';
|
|
180
|
+
` : `const { aiShield } = require('@samimcodes/ai-shield');
|
|
181
|
+
`;
|
|
182
|
+
const middlewareCall = `
|
|
183
|
+
// \u{1F6E1}\uFE0F Protected by AI-Shield (Automatic Setup)
|
|
184
|
+
app.use(aiShield({ enableDashboard: true }));
|
|
185
|
+
`;
|
|
186
|
+
content = importStatement + content;
|
|
187
|
+
const appPattern = /(const|let|var)\s+app\s*=\s*express\s*\([^)]*\)\s*;?/;
|
|
188
|
+
if (appPattern.test(content)) {
|
|
189
|
+
content = content.replace(appPattern, (match) => `${match}${middlewareCall}`);
|
|
190
|
+
fs__default.default.writeFileSync(serverFile, content, "utf8");
|
|
191
|
+
console.log(`${colors.green}\u2713 Successfully injected aiShield into ${relPath}!${colors.reset}`);
|
|
192
|
+
} else {
|
|
193
|
+
const listenPattern = /app\.listen\s*\(/;
|
|
194
|
+
if (listenPattern.test(content)) {
|
|
195
|
+
content = content.replace(listenPattern, (match) => `${middlewareCall}${match}`);
|
|
196
|
+
fs__default.default.writeFileSync(serverFile, content, "utf8");
|
|
197
|
+
console.log(`${colors.green}\u2713 Successfully injected aiShield before app.listen in ${relPath}!${colors.reset}`);
|
|
198
|
+
} else {
|
|
199
|
+
fs__default.default.writeFileSync(serverFile, `${content}${middlewareCall}`, "utf8");
|
|
200
|
+
console.log(`${colors.yellow}\u26A0 Added middleware to ${relPath}. Please verify app.use order.${colors.reset}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
console.log(`
|
|
204
|
+
${colors.green}${colors.bold}\u{1F389} Setup Complete! No code writing required!${colors.reset}`);
|
|
205
|
+
console.log(`Start your server and visit:`);
|
|
206
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
207
|
+
`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const starterFile = path__default.default.join(CWD, "server.js");
|
|
211
|
+
const starterContent = `// Created automatically by @samimcodes/ai-shield init
|
|
212
|
+
import express from 'express';
|
|
213
|
+
import { aiShield } from '@samimcodes/ai-shield';
|
|
214
|
+
|
|
215
|
+
const app = express();
|
|
216
|
+
|
|
217
|
+
// \u{1F6E1}\uFE0F Live AI Defense + Real-Time Security Monitor
|
|
218
|
+
app.use(aiShield({
|
|
219
|
+
enableDashboard: true,
|
|
220
|
+
}));
|
|
221
|
+
|
|
222
|
+
app.get('/', (req, res) => {
|
|
223
|
+
res.send('<h1>My Website</h1><p>Protected from AI scrapers by ai-shield.</p>');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
app.get('/api/products', (req, res) => {
|
|
227
|
+
res.json({ secretCatalog: [{ id: 1, name: 'Premium Item', price: 99 }] });
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const PORT = process.env.PORT || 3000;
|
|
231
|
+
app.listen(PORT, () => {
|
|
232
|
+
console.log('Server running on port ' + PORT);
|
|
233
|
+
console.log('Live Security Monitor: http://localhost:' + PORT + '/admin/ai-shield');
|
|
234
|
+
});
|
|
235
|
+
`;
|
|
236
|
+
fs__default.default.writeFileSync(starterFile, starterContent, "utf8");
|
|
237
|
+
console.log(`${colors.green}\u2713 Created new protected Express server:${colors.reset} server.js`);
|
|
238
|
+
console.log(`
|
|
239
|
+
${colors.green}${colors.bold}\u{1F389} Setup Complete!${colors.reset}`);
|
|
240
|
+
console.log(`Run ${colors.cyan}node server.js${colors.reset} and open:`);
|
|
241
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
242
|
+
`);
|
|
243
|
+
}
|
|
244
|
+
function runTest(targetUrl) {
|
|
245
|
+
banner();
|
|
246
|
+
const url = targetUrl ?? "http://localhost:3000/api/products";
|
|
247
|
+
console.log(`\u{1F916} Testing bot defense against: ${colors.cyan}${url}${colors.reset}
|
|
248
|
+
`);
|
|
249
|
+
try {
|
|
250
|
+
const parsed = new URL(url);
|
|
251
|
+
const req = http__default.default.request(
|
|
252
|
+
{
|
|
253
|
+
hostname: parsed.hostname,
|
|
254
|
+
port: parsed.port || 80,
|
|
255
|
+
path: parsed.pathname + parsed.search,
|
|
256
|
+
method: "GET",
|
|
257
|
+
headers: {
|
|
258
|
+
"User-Agent": "Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)",
|
|
259
|
+
"Accept": "application/json"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
(res) => {
|
|
263
|
+
let body = "";
|
|
264
|
+
res.on("data", (chunk) => body += chunk);
|
|
265
|
+
res.on("end", () => {
|
|
266
|
+
console.log(`Response Status: ${colors.bold}${res.statusCode} ${res.statusMessage}${colors.reset}`);
|
|
267
|
+
console.log(`X-Robots-Tag: ${colors.bold}${res.headers["x-robots-tag"] ?? "None"}${colors.reset}`);
|
|
268
|
+
console.log(`Body Preview: ${colors.magenta}${body.slice(0, 150)}...${colors.reset}
|
|
269
|
+
`);
|
|
270
|
+
if (res.statusCode === 200) {
|
|
271
|
+
console.log(`${colors.green}${colors.bold}\u2713 SUCCESS! Bot was intercepted and served poisoned response!${colors.reset}`);
|
|
272
|
+
console.log(`Check your live monitor at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
273
|
+
`);
|
|
274
|
+
} else {
|
|
275
|
+
console.log(`${colors.yellow}Server returned status ${res.statusCode}. Ensure your server is running.${colors.reset}
|
|
276
|
+
`);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
req.on("error", (err) => {
|
|
282
|
+
console.log(`${colors.red}\u2717 Connection failed: ${err.message}${colors.reset}`);
|
|
283
|
+
console.log(`Make sure your server is running on ${colors.bold}${url}${colors.reset} before testing.
|
|
284
|
+
`);
|
|
285
|
+
});
|
|
286
|
+
req.end();
|
|
287
|
+
} catch (err) {
|
|
288
|
+
console.log(`${colors.red}Invalid URL: ${targetUrl}${colors.reset}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
var args = process.argv.slice(2);
|
|
292
|
+
var command = args[0] || "init";
|
|
293
|
+
switch (command) {
|
|
294
|
+
case "init":
|
|
295
|
+
runInit();
|
|
296
|
+
break;
|
|
297
|
+
case "test":
|
|
298
|
+
runTest(args[1]);
|
|
299
|
+
break;
|
|
300
|
+
case "--help":
|
|
301
|
+
case "-h":
|
|
302
|
+
case "help":
|
|
303
|
+
banner();
|
|
304
|
+
console.log(`Commands:
|
|
305
|
+
${colors.bold}npx @samimcodes/ai-shield init${colors.reset} Automatically injects AI-Shield into your server
|
|
306
|
+
${colors.bold}npx @samimcodes/ai-shield test [url]${colors.reset} Sends a simulated GPTBot attack to test defense
|
|
307
|
+
${colors.bold}npx @samimcodes/ai-shield --help${colors.reset} Show this help message
|
|
308
|
+
`);
|
|
309
|
+
break;
|
|
310
|
+
default:
|
|
311
|
+
runInit();
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=cli.cjs.map
|
|
315
|
+
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"names":["fs","path","http"],"mappings":"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","file":"cli.cjs","sourcesContent":["#!/usr/bin/env node\n/**\n * @file src/cli.ts\n * @description Zero-configuration CLI installer and diagnostic tool for @samimcodes/ai-shield.\n *\n * Allows developers to run `npx @samimcodes/ai-shield init` to automatically\n * patch their project with the defense middleware and live dashboard without\n * writing any manual code.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport http from 'node:http';\n\nconst CWD = process.cwd();\n\n// ANSI color helpers (zero external dependencies)\nconst colors = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n green: '\\x1b[32m',\n cyan: '\\x1b[36m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n magenta: '\\x1b[35m',\n};\n\nfunction banner() {\n console.log(`\n${colors.cyan}${colors.bold} 🛡️ AI-SHIELD AUTOMATIC SETUP WIZARD${colors.reset}\n ${colors.magenta}Enterprise AI Crawler Defense & Live Security Dashboard${colors.reset}\n -------------------------------------------------------------\n`);\n}\n\n/** Check if current directory is a Next.js project. */\nfunction isNextJsProject(): boolean {\n return (\n fs.existsSync(path.join(CWD, 'next.config.js')) ||\n fs.existsSync(path.join(CWD, 'next.config.mjs')) ||\n fs.existsSync(path.join(CWD, 'next.config.ts')) ||\n (fs.existsSync(path.join(CWD, 'package.json')) &&\n fs.readFileSync(path.join(CWD, 'package.json'), 'utf8').includes('\"next\"'))\n );\n}\n\n/** List candidate Express server entry files. */\nconst SERVER_CANDIDATES = [\n 'server.ts',\n 'src/server.ts',\n 'server.js',\n 'src/server.js',\n 'index.ts',\n 'src/index.ts',\n 'index.js',\n 'src/index.js',\n 'app.ts',\n 'src/app.ts',\n 'app.js',\n 'src/app.js',\n];\n\n/** Find existing server file in target project. */\nfunction findServerFile(): string | null {\n for (const candidate of SERVER_CANDIDATES) {\n const fullPath = path.join(CWD, candidate);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\n/** Check if project uses ESM. */\nfunction isEsmProject(filePath: string): boolean {\n if (filePath.endsWith('.ts')) return true;\n const pkgPath = path.join(CWD, 'package.json');\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));\n if (pkg.type === 'module') return true;\n } catch {\n // ignore\n }\n }\n const content = fs.readFileSync(filePath, 'utf8');\n return content.includes('import ') && content.includes('from ');\n}\n\n/** Automatic init command. */\nasync function runInit() {\n banner();\n console.log(`🔍 Scanning project in: ${colors.bold}${CWD}${colors.reset}\\n`);\n\n // 1. Next.js Project Detection\n if (isNextJsProject()) {\n console.log(`${colors.cyan}⚡ Detected Next.js App Router project!${colors.reset}`);\n const adminDir = path.join(CWD, 'app', 'admin', 'ai-shield');\n const adminPage = path.join(adminDir, 'page.tsx');\n\n fs.mkdirSync(adminDir, { recursive: true });\n\n if (!fs.existsSync(adminPage)) {\n const nextTemplate = `'use client';\n\nimport { useState } from 'react';\n\nexport default function AiShieldDashboard() {\n const [stats, setStats] = useState({ botsIntercepted: 14, goodBotsAllowed: 92, honeypotTriggers: 4, fakeTokens: 6720 });\n const [toast, setToast] = useState<{ show: boolean; bot: string; path: string }>({ show: false, bot: '', path: '' });\n const [events, setEvents] = useState([\n { id: '1', time: 'Just now', bot: 'GPTBot (OpenAI)', score: 100, path: '/api/products', action: 'POISON_JSON' },\n { id: '2', time: '2 mins ago', bot: 'Claude-Web', score: 95, path: '/pricing', action: 'POISON_HTML' },\n { id: '3', time: '5 mins ago', bot: 'ByteSpider', score: 90, path: '/articles', action: 'HONEYPOT_TRAP' },\n ]);\n\n const simulateAttack = () => {\n const testBots = [\n { bot: 'GPTBot (OpenAI)', path: '/api/products', action: 'POISON_JSON' },\n { bot: 'Claude-Web (Anthropic)', path: '/catalog/pricing', action: 'POISON_HTML' },\n { bot: 'ByteSpider (TikTok)', path: '/content/posts', action: 'HONEYPOT_TRAP' },\n ];\n const picked = testBots[Math.floor(Math.random() * testBots.length)] ?? testBots[0];\n setToast({ show: true, bot: picked.bot, path: picked.path });\n setStats((prev) => ({ ...prev, botsIntercepted: prev.botsIntercepted + 1, fakeTokens: prev.fakeTokens + 480 }));\n setEvents((prev) => [{ id: Date.now().toString(), time: new Date().toLocaleTimeString(), bot: picked.bot, score: 100, path: picked.path, action: picked.action }, ...prev]);\n setTimeout(() => setToast({ show: false, bot: '', path: '' }), 4000);\n };\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: '#090d16', color: '#f3f4f6', fontFamily: 'sans-serif', padding: '2rem' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '2rem' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>\n <div style={{ width: '32px', height: '32px', background: 'linear-gradient(135deg, #6366f1, #a855f7)', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>🛡️</div>\n <h1 style={{ fontSize: '1.25rem', fontWeight: 'bold', margin: 0 }}>ai-shield Live Monitor</h1>\n <span style={{ background: 'rgba(16, 185, 129, 0.2)', color: '#34d399', padding: '0.2rem 0.6rem', borderRadius: '999px', fontSize: '0.75rem', fontWeight: 600 }}>● ACTIVE DEFENSE</span>\n </div>\n <button onClick={simulateAttack} style={{ background: '#6366f1', color: '#fff', border: 'none', padding: '0.6rem 1.2rem', borderRadius: '8px', fontWeight: 600, cursor: 'pointer' }}>\n ⚡ Simulate Bot Attack\n </button>\n </div>\n\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '1.25rem', marginBottom: '2.5rem' }}>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Bots Intercepted</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fb7185', margin: '0.25rem 0' }}>{stats.botsIntercepted}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Served synthetic poisoned data</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Honeypot Traps Sprung</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fbbf24', margin: '0.25rem 0' }}>{stats.honeypotTriggers}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Hidden bait routes triggered</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Search Engines (SEO)</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#34d399', margin: '0.25rem 0' }}>{stats.goodBotsAllowed}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Googlebot & Bingbot safe</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Fake Tokens Injected</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#818cf8', margin: '0.25rem 0' }}>{stats.fakeTokens.toLocaleString()}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● AI scrapers polluted</div>\n </div>\n </div>\n\n {toast.show && (\n <div style={{ position: 'fixed', bottom: '2rem', right: '2rem', background: '#1f2937', border: '1px solid #f43f5e', padding: '1rem 1.25rem', borderRadius: '12px', boxShadow: '0 10px 30px rgba(244,63,94,0.3)', zIndex: 999 }}>\n <div style={{ color: '#f43f5e', fontWeight: 'bold', fontSize: '0.8rem', marginBottom: '0.25rem' }}>🚨 AI CRAWLER INTERCEPTED</div>\n <div style={{ fontSize: '0.875rem' }}>\n <strong>{toast.bot}</strong> targeted <code style={{ color: '#818cf8' }}>{toast.path}</code>.<br />\n Returned fake poisoned data (HTTP 200 OK).\n </div>\n </div>\n )}\n </div>\n );\n}\n`;\n fs.writeFileSync(adminPage, nextTemplate, 'utf8');\n console.log(`${colors.green}✓ Created Live Security Dashboard:${colors.reset} app/admin/ai-shield/page.tsx`);\n } else {\n console.log(`${colors.yellow}ℹ Dashboard page already exists at:${colors.reset} app/admin/ai-shield/page.tsx`);\n }\n\n console.log(`\\n${colors.green}${colors.bold}🎉 Next.js Setup Complete!${colors.reset}`);\n console.log(`Run ${colors.cyan}npm run dev${colors.reset} and visit:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n // 2. Express / Node.js Server Auto-Patching\n const serverFile = findServerFile();\n\n if (serverFile) {\n const relPath = path.relative(CWD, serverFile);\n console.log(`${colors.green}✓ Detected server entrypoint:${colors.reset} ${relPath}`);\n let content = fs.readFileSync(serverFile, 'utf8');\n\n if (content.includes('@samimcodes/ai-shield') || content.includes('aiShield(')) {\n console.log(`${colors.yellow}ℹ AI-Shield is already installed in ${relPath}.${colors.reset}`);\n console.log(`Live dashboard is accessible at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n const isEsm = isEsmProject(serverFile);\n const importStatement = isEsm\n ? `import { aiShield } from '@samimcodes/ai-shield';\\n`\n : `const { aiShield } = require('@samimcodes/ai-shield');\\n`;\n\n const middlewareCall = `\\n// 🛡️ Protected by AI-Shield (Automatic Setup)\\napp.use(aiShield({ enableDashboard: true }));\\n`;\n\n // Add import statement at top\n content = importStatement + content;\n\n // Inject app.use right after `const app = express();`\n const appPattern = /(const|let|var)\\s+app\\s*=\\s*express\\s*\\([^)]*\\)\\s*;?/;\n if (appPattern.test(content)) {\n content = content.replace(appPattern, (match) => `${match}${middlewareCall}`);\n fs.writeFileSync(serverFile, content, 'utf8');\n console.log(`${colors.green}✓ Successfully injected aiShield into ${relPath}!${colors.reset}`);\n } else {\n // Prepend before app.listen if app pattern not matched\n const listenPattern = /app\\.listen\\s*\\(/;\n if (listenPattern.test(content)) {\n content = content.replace(listenPattern, (match) => `${middlewareCall}${match}`);\n fs.writeFileSync(serverFile, content, 'utf8');\n console.log(`${colors.green}✓ Successfully injected aiShield before app.listen in ${relPath}!${colors.reset}`);\n } else {\n fs.writeFileSync(serverFile, `${content}${middlewareCall}`, 'utf8');\n console.log(`${colors.yellow}⚠ Added middleware to ${relPath}. Please verify app.use order.${colors.reset}`);\n }\n }\n\n console.log(`\\n${colors.green}${colors.bold}🎉 Setup Complete! No code writing required!${colors.reset}`);\n console.log(`Start your server and visit:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n // 3. If no server file exists, create a ready-to-run Express starter\n const starterFile = path.join(CWD, 'server.js');\n const starterContent = `// Created automatically by @samimcodes/ai-shield init\nimport express from 'express';\nimport { aiShield } from '@samimcodes/ai-shield';\n\nconst app = express();\n\n// 🛡️ Live AI Defense + Real-Time Security Monitor\napp.use(aiShield({\n enableDashboard: true,\n}));\n\napp.get('/', (req, res) => {\n res.send('<h1>My Website</h1><p>Protected from AI scrapers by ai-shield.</p>');\n});\n\napp.get('/api/products', (req, res) => {\n res.json({ secretCatalog: [{ id: 1, name: 'Premium Item', price: 99 }] });\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n console.log('Server running on port ' + PORT);\n console.log('Live Security Monitor: http://localhost:' + PORT + '/admin/ai-shield');\n});\n`;\n\n fs.writeFileSync(starterFile, starterContent, 'utf8');\n console.log(`${colors.green}✓ Created new protected Express server:${colors.reset} server.js`);\n console.log(`\\n${colors.green}${colors.bold}🎉 Setup Complete!${colors.reset}`);\n console.log(`Run ${colors.cyan}node server.js${colors.reset} and open:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n}\n\n/** Test command to send a simulated bot attack to a running server. */\nfunction runTest(targetUrl?: string) {\n banner();\n const url = targetUrl ?? 'http://localhost:3000/api/products';\n console.log(`🤖 Testing bot defense against: ${colors.cyan}${url}${colors.reset}\\n`);\n\n try {\n const parsed = new URL(url);\n const req = http.request(\n {\n hostname: parsed.hostname,\n port: parsed.port || 80,\n path: parsed.pathname + parsed.search,\n method: 'GET',\n headers: {\n 'User-Agent': 'Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)',\n 'Accept': 'application/json',\n },\n },\n (res) => {\n let body = '';\n res.on('data', (chunk) => (body += chunk));\n res.on('end', () => {\n console.log(`Response Status: ${colors.bold}${res.statusCode} ${res.statusMessage}${colors.reset}`);\n console.log(`X-Robots-Tag: ${colors.bold}${res.headers['x-robots-tag'] ?? 'None'}${colors.reset}`);\n console.log(`Body Preview: ${colors.magenta}${body.slice(0, 150)}...${colors.reset}\\n`);\n\n if (res.statusCode === 200) {\n console.log(`${colors.green}${colors.bold}✓ SUCCESS! Bot was intercepted and served poisoned response!${colors.reset}`);\n console.log(`Check your live monitor at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n } else {\n console.log(`${colors.yellow}Server returned status ${res.statusCode}. Ensure your server is running.${colors.reset}\\n`);\n }\n });\n },\n );\n\n req.on('error', (err) => {\n console.log(`${colors.red}✗ Connection failed: ${err.message}${colors.reset}`);\n console.log(`Make sure your server is running on ${colors.bold}${url}${colors.reset} before testing.\\n`);\n });\n\n req.end();\n } catch (err) {\n console.log(`${colors.red}Invalid URL: ${targetUrl}${colors.reset}`);\n }\n}\n\n// ── Main CLI Dispatcher ────────────────────────────────────────────────────\n\nconst args = process.argv.slice(2);\nconst command = args[0] || 'init';\n\nswitch (command) {\n case 'init':\n runInit();\n break;\n case 'test':\n runTest(args[1]);\n break;\n case '--help':\n case '-h':\n case 'help':\n banner();\n console.log(`Commands:\n ${colors.bold}npx @samimcodes/ai-shield init${colors.reset} Automatically injects AI-Shield into your server\n ${colors.bold}npx @samimcodes/ai-shield test [url]${colors.reset} Sends a simulated GPTBot attack to test defense\n ${colors.bold}npx @samimcodes/ai-shield --help${colors.reset} Show this help message\n`);\n break;\n default:\n runInit();\n break;\n}\n"]}
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import http from 'http';
|
|
5
|
+
|
|
6
|
+
var CWD = process.cwd();
|
|
7
|
+
var colors = {
|
|
8
|
+
reset: "\x1B[0m",
|
|
9
|
+
bold: "\x1B[1m",
|
|
10
|
+
green: "\x1B[32m",
|
|
11
|
+
cyan: "\x1B[36m",
|
|
12
|
+
yellow: "\x1B[33m",
|
|
13
|
+
red: "\x1B[31m",
|
|
14
|
+
magenta: "\x1B[35m"
|
|
15
|
+
};
|
|
16
|
+
function banner() {
|
|
17
|
+
console.log(`
|
|
18
|
+
${colors.cyan}${colors.bold} \u{1F6E1}\uFE0F AI-SHIELD AUTOMATIC SETUP WIZARD${colors.reset}
|
|
19
|
+
${colors.magenta}Enterprise AI Crawler Defense & Live Security Dashboard${colors.reset}
|
|
20
|
+
-------------------------------------------------------------
|
|
21
|
+
`);
|
|
22
|
+
}
|
|
23
|
+
function isNextJsProject() {
|
|
24
|
+
return fs.existsSync(path.join(CWD, "next.config.js")) || fs.existsSync(path.join(CWD, "next.config.mjs")) || fs.existsSync(path.join(CWD, "next.config.ts")) || fs.existsSync(path.join(CWD, "package.json")) && fs.readFileSync(path.join(CWD, "package.json"), "utf8").includes('"next"');
|
|
25
|
+
}
|
|
26
|
+
var SERVER_CANDIDATES = [
|
|
27
|
+
"server.ts",
|
|
28
|
+
"src/server.ts",
|
|
29
|
+
"server.js",
|
|
30
|
+
"src/server.js",
|
|
31
|
+
"index.ts",
|
|
32
|
+
"src/index.ts",
|
|
33
|
+
"index.js",
|
|
34
|
+
"src/index.js",
|
|
35
|
+
"app.ts",
|
|
36
|
+
"src/app.ts",
|
|
37
|
+
"app.js",
|
|
38
|
+
"src/app.js"
|
|
39
|
+
];
|
|
40
|
+
function findServerFile() {
|
|
41
|
+
for (const candidate of SERVER_CANDIDATES) {
|
|
42
|
+
const fullPath = path.join(CWD, candidate);
|
|
43
|
+
if (fs.existsSync(fullPath)) {
|
|
44
|
+
return fullPath;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function isEsmProject(filePath) {
|
|
50
|
+
if (filePath.endsWith(".ts")) return true;
|
|
51
|
+
const pkgPath = path.join(CWD, "package.json");
|
|
52
|
+
if (fs.existsSync(pkgPath)) {
|
|
53
|
+
try {
|
|
54
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
55
|
+
if (pkg.type === "module") return true;
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
60
|
+
return content.includes("import ") && content.includes("from ");
|
|
61
|
+
}
|
|
62
|
+
async function runInit() {
|
|
63
|
+
banner();
|
|
64
|
+
console.log(`\u{1F50D} Scanning project in: ${colors.bold}${CWD}${colors.reset}
|
|
65
|
+
`);
|
|
66
|
+
if (isNextJsProject()) {
|
|
67
|
+
console.log(`${colors.cyan}\u26A1 Detected Next.js App Router project!${colors.reset}`);
|
|
68
|
+
const adminDir = path.join(CWD, "app", "admin", "ai-shield");
|
|
69
|
+
const adminPage = path.join(adminDir, "page.tsx");
|
|
70
|
+
fs.mkdirSync(adminDir, { recursive: true });
|
|
71
|
+
if (!fs.existsSync(adminPage)) {
|
|
72
|
+
const nextTemplate = `'use client';
|
|
73
|
+
|
|
74
|
+
import { useState } from 'react';
|
|
75
|
+
|
|
76
|
+
export default function AiShieldDashboard() {
|
|
77
|
+
const [stats, setStats] = useState({ botsIntercepted: 14, goodBotsAllowed: 92, honeypotTriggers: 4, fakeTokens: 6720 });
|
|
78
|
+
const [toast, setToast] = useState<{ show: boolean; bot: string; path: string }>({ show: false, bot: '', path: '' });
|
|
79
|
+
const [events, setEvents] = useState([
|
|
80
|
+
{ id: '1', time: 'Just now', bot: 'GPTBot (OpenAI)', score: 100, path: '/api/products', action: 'POISON_JSON' },
|
|
81
|
+
{ id: '2', time: '2 mins ago', bot: 'Claude-Web', score: 95, path: '/pricing', action: 'POISON_HTML' },
|
|
82
|
+
{ id: '3', time: '5 mins ago', bot: 'ByteSpider', score: 90, path: '/articles', action: 'HONEYPOT_TRAP' },
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const simulateAttack = () => {
|
|
86
|
+
const testBots = [
|
|
87
|
+
{ bot: 'GPTBot (OpenAI)', path: '/api/products', action: 'POISON_JSON' },
|
|
88
|
+
{ bot: 'Claude-Web (Anthropic)', path: '/catalog/pricing', action: 'POISON_HTML' },
|
|
89
|
+
{ bot: 'ByteSpider (TikTok)', path: '/content/posts', action: 'HONEYPOT_TRAP' },
|
|
90
|
+
];
|
|
91
|
+
const picked = testBots[Math.floor(Math.random() * testBots.length)] ?? testBots[0];
|
|
92
|
+
setToast({ show: true, bot: picked.bot, path: picked.path });
|
|
93
|
+
setStats((prev) => ({ ...prev, botsIntercepted: prev.botsIntercepted + 1, fakeTokens: prev.fakeTokens + 480 }));
|
|
94
|
+
setEvents((prev) => [{ id: Date.now().toString(), time: new Date().toLocaleTimeString(), bot: picked.bot, score: 100, path: picked.path, action: picked.action }, ...prev]);
|
|
95
|
+
setTimeout(() => setToast({ show: false, bot: '', path: '' }), 4000);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div style={{ minHeight: '100vh', backgroundColor: '#090d16', color: '#f3f4f6', fontFamily: 'sans-serif', padding: '2rem' }}>
|
|
100
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '2rem' }}>
|
|
101
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
|
|
102
|
+
<div style={{ width: '32px', height: '32px', background: 'linear-gradient(135deg, #6366f1, #a855f7)', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\u{1F6E1}\uFE0F</div>
|
|
103
|
+
<h1 style={{ fontSize: '1.25rem', fontWeight: 'bold', margin: 0 }}>ai-shield Live Monitor</h1>
|
|
104
|
+
<span style={{ background: 'rgba(16, 185, 129, 0.2)', color: '#34d399', padding: '0.2rem 0.6rem', borderRadius: '999px', fontSize: '0.75rem', fontWeight: 600 }}>\u25CF ACTIVE DEFENSE</span>
|
|
105
|
+
</div>
|
|
106
|
+
<button onClick={simulateAttack} style={{ background: '#6366f1', color: '#fff', border: 'none', padding: '0.6rem 1.2rem', borderRadius: '8px', fontWeight: 600, cursor: 'pointer' }}>
|
|
107
|
+
\u26A1 Simulate Bot Attack
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '1.25rem', marginBottom: '2.5rem' }}>
|
|
112
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
113
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Bots Intercepted</div>
|
|
114
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fb7185', margin: '0.25rem 0' }}>{stats.botsIntercepted}</div>
|
|
115
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Served synthetic poisoned data</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
118
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Honeypot Traps Sprung</div>
|
|
119
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fbbf24', margin: '0.25rem 0' }}>{stats.honeypotTriggers}</div>
|
|
120
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Hidden bait routes triggered</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
123
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Search Engines (SEO)</div>
|
|
124
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#34d399', margin: '0.25rem 0' }}>{stats.goodBotsAllowed}</div>
|
|
125
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF Googlebot & Bingbot safe</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>
|
|
128
|
+
<div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Fake Tokens Injected</div>
|
|
129
|
+
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#818cf8', margin: '0.25rem 0' }}>{stats.fakeTokens.toLocaleString()}</div>
|
|
130
|
+
<div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>\u25CF AI scrapers polluted</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
{toast.show && (
|
|
135
|
+
<div style={{ position: 'fixed', bottom: '2rem', right: '2rem', background: '#1f2937', border: '1px solid #f43f5e', padding: '1rem 1.25rem', borderRadius: '12px', boxShadow: '0 10px 30px rgba(244,63,94,0.3)', zIndex: 999 }}>
|
|
136
|
+
<div style={{ color: '#f43f5e', fontWeight: 'bold', fontSize: '0.8rem', marginBottom: '0.25rem' }}>\u{1F6A8} AI CRAWLER INTERCEPTED</div>
|
|
137
|
+
<div style={{ fontSize: '0.875rem' }}>
|
|
138
|
+
<strong>{toast.bot}</strong> targeted <code style={{ color: '#818cf8' }}>{toast.path}</code>.<br />
|
|
139
|
+
Returned fake poisoned data (HTTP 200 OK).
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
fs.writeFileSync(adminPage, nextTemplate, "utf8");
|
|
148
|
+
console.log(`${colors.green}\u2713 Created Live Security Dashboard:${colors.reset} app/admin/ai-shield/page.tsx`);
|
|
149
|
+
} else {
|
|
150
|
+
console.log(`${colors.yellow}\u2139 Dashboard page already exists at:${colors.reset} app/admin/ai-shield/page.tsx`);
|
|
151
|
+
}
|
|
152
|
+
console.log(`
|
|
153
|
+
${colors.green}${colors.bold}\u{1F389} Next.js Setup Complete!${colors.reset}`);
|
|
154
|
+
console.log(`Run ${colors.cyan}npm run dev${colors.reset} and visit:`);
|
|
155
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
156
|
+
`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const serverFile = findServerFile();
|
|
160
|
+
if (serverFile) {
|
|
161
|
+
const relPath = path.relative(CWD, serverFile);
|
|
162
|
+
console.log(`${colors.green}\u2713 Detected server entrypoint:${colors.reset} ${relPath}`);
|
|
163
|
+
let content = fs.readFileSync(serverFile, "utf8");
|
|
164
|
+
if (content.includes("@samimcodes/ai-shield") || content.includes("aiShield(")) {
|
|
165
|
+
console.log(`${colors.yellow}\u2139 AI-Shield is already installed in ${relPath}.${colors.reset}`);
|
|
166
|
+
console.log(`Live dashboard is accessible at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
167
|
+
`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const isEsm = isEsmProject(serverFile);
|
|
171
|
+
const importStatement = isEsm ? `import { aiShield } from '@samimcodes/ai-shield';
|
|
172
|
+
` : `const { aiShield } = require('@samimcodes/ai-shield');
|
|
173
|
+
`;
|
|
174
|
+
const middlewareCall = `
|
|
175
|
+
// \u{1F6E1}\uFE0F Protected by AI-Shield (Automatic Setup)
|
|
176
|
+
app.use(aiShield({ enableDashboard: true }));
|
|
177
|
+
`;
|
|
178
|
+
content = importStatement + content;
|
|
179
|
+
const appPattern = /(const|let|var)\s+app\s*=\s*express\s*\([^)]*\)\s*;?/;
|
|
180
|
+
if (appPattern.test(content)) {
|
|
181
|
+
content = content.replace(appPattern, (match) => `${match}${middlewareCall}`);
|
|
182
|
+
fs.writeFileSync(serverFile, content, "utf8");
|
|
183
|
+
console.log(`${colors.green}\u2713 Successfully injected aiShield into ${relPath}!${colors.reset}`);
|
|
184
|
+
} else {
|
|
185
|
+
const listenPattern = /app\.listen\s*\(/;
|
|
186
|
+
if (listenPattern.test(content)) {
|
|
187
|
+
content = content.replace(listenPattern, (match) => `${middlewareCall}${match}`);
|
|
188
|
+
fs.writeFileSync(serverFile, content, "utf8");
|
|
189
|
+
console.log(`${colors.green}\u2713 Successfully injected aiShield before app.listen in ${relPath}!${colors.reset}`);
|
|
190
|
+
} else {
|
|
191
|
+
fs.writeFileSync(serverFile, `${content}${middlewareCall}`, "utf8");
|
|
192
|
+
console.log(`${colors.yellow}\u26A0 Added middleware to ${relPath}. Please verify app.use order.${colors.reset}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
console.log(`
|
|
196
|
+
${colors.green}${colors.bold}\u{1F389} Setup Complete! No code writing required!${colors.reset}`);
|
|
197
|
+
console.log(`Start your server and visit:`);
|
|
198
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
199
|
+
`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const starterFile = path.join(CWD, "server.js");
|
|
203
|
+
const starterContent = `// Created automatically by @samimcodes/ai-shield init
|
|
204
|
+
import express from 'express';
|
|
205
|
+
import { aiShield } from '@samimcodes/ai-shield';
|
|
206
|
+
|
|
207
|
+
const app = express();
|
|
208
|
+
|
|
209
|
+
// \u{1F6E1}\uFE0F Live AI Defense + Real-Time Security Monitor
|
|
210
|
+
app.use(aiShield({
|
|
211
|
+
enableDashboard: true,
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
app.get('/', (req, res) => {
|
|
215
|
+
res.send('<h1>My Website</h1><p>Protected from AI scrapers by ai-shield.</p>');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
app.get('/api/products', (req, res) => {
|
|
219
|
+
res.json({ secretCatalog: [{ id: 1, name: 'Premium Item', price: 99 }] });
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const PORT = process.env.PORT || 3000;
|
|
223
|
+
app.listen(PORT, () => {
|
|
224
|
+
console.log('Server running on port ' + PORT);
|
|
225
|
+
console.log('Live Security Monitor: http://localhost:' + PORT + '/admin/ai-shield');
|
|
226
|
+
});
|
|
227
|
+
`;
|
|
228
|
+
fs.writeFileSync(starterFile, starterContent, "utf8");
|
|
229
|
+
console.log(`${colors.green}\u2713 Created new protected Express server:${colors.reset} server.js`);
|
|
230
|
+
console.log(`
|
|
231
|
+
${colors.green}${colors.bold}\u{1F389} Setup Complete!${colors.reset}`);
|
|
232
|
+
console.log(`Run ${colors.cyan}node server.js${colors.reset} and open:`);
|
|
233
|
+
console.log(`\u{1F449} ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
234
|
+
`);
|
|
235
|
+
}
|
|
236
|
+
function runTest(targetUrl) {
|
|
237
|
+
banner();
|
|
238
|
+
const url = targetUrl ?? "http://localhost:3000/api/products";
|
|
239
|
+
console.log(`\u{1F916} Testing bot defense against: ${colors.cyan}${url}${colors.reset}
|
|
240
|
+
`);
|
|
241
|
+
try {
|
|
242
|
+
const parsed = new URL(url);
|
|
243
|
+
const req = http.request(
|
|
244
|
+
{
|
|
245
|
+
hostname: parsed.hostname,
|
|
246
|
+
port: parsed.port || 80,
|
|
247
|
+
path: parsed.pathname + parsed.search,
|
|
248
|
+
method: "GET",
|
|
249
|
+
headers: {
|
|
250
|
+
"User-Agent": "Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)",
|
|
251
|
+
"Accept": "application/json"
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
(res) => {
|
|
255
|
+
let body = "";
|
|
256
|
+
res.on("data", (chunk) => body += chunk);
|
|
257
|
+
res.on("end", () => {
|
|
258
|
+
console.log(`Response Status: ${colors.bold}${res.statusCode} ${res.statusMessage}${colors.reset}`);
|
|
259
|
+
console.log(`X-Robots-Tag: ${colors.bold}${res.headers["x-robots-tag"] ?? "None"}${colors.reset}`);
|
|
260
|
+
console.log(`Body Preview: ${colors.magenta}${body.slice(0, 150)}...${colors.reset}
|
|
261
|
+
`);
|
|
262
|
+
if (res.statusCode === 200) {
|
|
263
|
+
console.log(`${colors.green}${colors.bold}\u2713 SUCCESS! Bot was intercepted and served poisoned response!${colors.reset}`);
|
|
264
|
+
console.log(`Check your live monitor at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}
|
|
265
|
+
`);
|
|
266
|
+
} else {
|
|
267
|
+
console.log(`${colors.yellow}Server returned status ${res.statusCode}. Ensure your server is running.${colors.reset}
|
|
268
|
+
`);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
req.on("error", (err) => {
|
|
274
|
+
console.log(`${colors.red}\u2717 Connection failed: ${err.message}${colors.reset}`);
|
|
275
|
+
console.log(`Make sure your server is running on ${colors.bold}${url}${colors.reset} before testing.
|
|
276
|
+
`);
|
|
277
|
+
});
|
|
278
|
+
req.end();
|
|
279
|
+
} catch (err) {
|
|
280
|
+
console.log(`${colors.red}Invalid URL: ${targetUrl}${colors.reset}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
var args = process.argv.slice(2);
|
|
284
|
+
var command = args[0] || "init";
|
|
285
|
+
switch (command) {
|
|
286
|
+
case "init":
|
|
287
|
+
runInit();
|
|
288
|
+
break;
|
|
289
|
+
case "test":
|
|
290
|
+
runTest(args[1]);
|
|
291
|
+
break;
|
|
292
|
+
case "--help":
|
|
293
|
+
case "-h":
|
|
294
|
+
case "help":
|
|
295
|
+
banner();
|
|
296
|
+
console.log(`Commands:
|
|
297
|
+
${colors.bold}npx @samimcodes/ai-shield init${colors.reset} Automatically injects AI-Shield into your server
|
|
298
|
+
${colors.bold}npx @samimcodes/ai-shield test [url]${colors.reset} Sends a simulated GPTBot attack to test defense
|
|
299
|
+
${colors.bold}npx @samimcodes/ai-shield --help${colors.reset} Show this help message
|
|
300
|
+
`);
|
|
301
|
+
break;
|
|
302
|
+
default:
|
|
303
|
+
runInit();
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=cli.js.map
|
|
307
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["#!/usr/bin/env node\n/**\n * @file src/cli.ts\n * @description Zero-configuration CLI installer and diagnostic tool for @samimcodes/ai-shield.\n *\n * Allows developers to run `npx @samimcodes/ai-shield init` to automatically\n * patch their project with the defense middleware and live dashboard without\n * writing any manual code.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport http from 'node:http';\n\nconst CWD = process.cwd();\n\n// ANSI color helpers (zero external dependencies)\nconst colors = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n green: '\\x1b[32m',\n cyan: '\\x1b[36m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n magenta: '\\x1b[35m',\n};\n\nfunction banner() {\n console.log(`\n${colors.cyan}${colors.bold} 🛡️ AI-SHIELD AUTOMATIC SETUP WIZARD${colors.reset}\n ${colors.magenta}Enterprise AI Crawler Defense & Live Security Dashboard${colors.reset}\n -------------------------------------------------------------\n`);\n}\n\n/** Check if current directory is a Next.js project. */\nfunction isNextJsProject(): boolean {\n return (\n fs.existsSync(path.join(CWD, 'next.config.js')) ||\n fs.existsSync(path.join(CWD, 'next.config.mjs')) ||\n fs.existsSync(path.join(CWD, 'next.config.ts')) ||\n (fs.existsSync(path.join(CWD, 'package.json')) &&\n fs.readFileSync(path.join(CWD, 'package.json'), 'utf8').includes('\"next\"'))\n );\n}\n\n/** List candidate Express server entry files. */\nconst SERVER_CANDIDATES = [\n 'server.ts',\n 'src/server.ts',\n 'server.js',\n 'src/server.js',\n 'index.ts',\n 'src/index.ts',\n 'index.js',\n 'src/index.js',\n 'app.ts',\n 'src/app.ts',\n 'app.js',\n 'src/app.js',\n];\n\n/** Find existing server file in target project. */\nfunction findServerFile(): string | null {\n for (const candidate of SERVER_CANDIDATES) {\n const fullPath = path.join(CWD, candidate);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\n/** Check if project uses ESM. */\nfunction isEsmProject(filePath: string): boolean {\n if (filePath.endsWith('.ts')) return true;\n const pkgPath = path.join(CWD, 'package.json');\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));\n if (pkg.type === 'module') return true;\n } catch {\n // ignore\n }\n }\n const content = fs.readFileSync(filePath, 'utf8');\n return content.includes('import ') && content.includes('from ');\n}\n\n/** Automatic init command. */\nasync function runInit() {\n banner();\n console.log(`🔍 Scanning project in: ${colors.bold}${CWD}${colors.reset}\\n`);\n\n // 1. Next.js Project Detection\n if (isNextJsProject()) {\n console.log(`${colors.cyan}⚡ Detected Next.js App Router project!${colors.reset}`);\n const adminDir = path.join(CWD, 'app', 'admin', 'ai-shield');\n const adminPage = path.join(adminDir, 'page.tsx');\n\n fs.mkdirSync(adminDir, { recursive: true });\n\n if (!fs.existsSync(adminPage)) {\n const nextTemplate = `'use client';\n\nimport { useState } from 'react';\n\nexport default function AiShieldDashboard() {\n const [stats, setStats] = useState({ botsIntercepted: 14, goodBotsAllowed: 92, honeypotTriggers: 4, fakeTokens: 6720 });\n const [toast, setToast] = useState<{ show: boolean; bot: string; path: string }>({ show: false, bot: '', path: '' });\n const [events, setEvents] = useState([\n { id: '1', time: 'Just now', bot: 'GPTBot (OpenAI)', score: 100, path: '/api/products', action: 'POISON_JSON' },\n { id: '2', time: '2 mins ago', bot: 'Claude-Web', score: 95, path: '/pricing', action: 'POISON_HTML' },\n { id: '3', time: '5 mins ago', bot: 'ByteSpider', score: 90, path: '/articles', action: 'HONEYPOT_TRAP' },\n ]);\n\n const simulateAttack = () => {\n const testBots = [\n { bot: 'GPTBot (OpenAI)', path: '/api/products', action: 'POISON_JSON' },\n { bot: 'Claude-Web (Anthropic)', path: '/catalog/pricing', action: 'POISON_HTML' },\n { bot: 'ByteSpider (TikTok)', path: '/content/posts', action: 'HONEYPOT_TRAP' },\n ];\n const picked = testBots[Math.floor(Math.random() * testBots.length)] ?? testBots[0];\n setToast({ show: true, bot: picked.bot, path: picked.path });\n setStats((prev) => ({ ...prev, botsIntercepted: prev.botsIntercepted + 1, fakeTokens: prev.fakeTokens + 480 }));\n setEvents((prev) => [{ id: Date.now().toString(), time: new Date().toLocaleTimeString(), bot: picked.bot, score: 100, path: picked.path, action: picked.action }, ...prev]);\n setTimeout(() => setToast({ show: false, bot: '', path: '' }), 4000);\n };\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: '#090d16', color: '#f3f4f6', fontFamily: 'sans-serif', padding: '2rem' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '2rem' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>\n <div style={{ width: '32px', height: '32px', background: 'linear-gradient(135deg, #6366f1, #a855f7)', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>🛡️</div>\n <h1 style={{ fontSize: '1.25rem', fontWeight: 'bold', margin: 0 }}>ai-shield Live Monitor</h1>\n <span style={{ background: 'rgba(16, 185, 129, 0.2)', color: '#34d399', padding: '0.2rem 0.6rem', borderRadius: '999px', fontSize: '0.75rem', fontWeight: 600 }}>● ACTIVE DEFENSE</span>\n </div>\n <button onClick={simulateAttack} style={{ background: '#6366f1', color: '#fff', border: 'none', padding: '0.6rem 1.2rem', borderRadius: '8px', fontWeight: 600, cursor: 'pointer' }}>\n ⚡ Simulate Bot Attack\n </button>\n </div>\n\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '1.25rem', marginBottom: '2.5rem' }}>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Bots Intercepted</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fb7185', margin: '0.25rem 0' }}>{stats.botsIntercepted}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Served synthetic poisoned data</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Honeypot Traps Sprung</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#fbbf24', margin: '0.25rem 0' }}>{stats.honeypotTriggers}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Hidden bait routes triggered</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Search Engines (SEO)</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#34d399', margin: '0.25rem 0' }}>{stats.goodBotsAllowed}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● Googlebot & Bingbot safe</div>\n </div>\n <div style={{ background: '#111827', padding: '1.25rem', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ fontSize: '0.8rem', color: '#9ca3af', textTransform: 'uppercase' }}>Fake Tokens Injected</div>\n <div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#818cf8', margin: '0.25rem 0' }}>{stats.fakeTokens.toLocaleString()}</div>\n <div style={{ fontSize: '0.75rem', color: '#9ca3af' }}>● AI scrapers polluted</div>\n </div>\n </div>\n\n {toast.show && (\n <div style={{ position: 'fixed', bottom: '2rem', right: '2rem', background: '#1f2937', border: '1px solid #f43f5e', padding: '1rem 1.25rem', borderRadius: '12px', boxShadow: '0 10px 30px rgba(244,63,94,0.3)', zIndex: 999 }}>\n <div style={{ color: '#f43f5e', fontWeight: 'bold', fontSize: '0.8rem', marginBottom: '0.25rem' }}>🚨 AI CRAWLER INTERCEPTED</div>\n <div style={{ fontSize: '0.875rem' }}>\n <strong>{toast.bot}</strong> targeted <code style={{ color: '#818cf8' }}>{toast.path}</code>.<br />\n Returned fake poisoned data (HTTP 200 OK).\n </div>\n </div>\n )}\n </div>\n );\n}\n`;\n fs.writeFileSync(adminPage, nextTemplate, 'utf8');\n console.log(`${colors.green}✓ Created Live Security Dashboard:${colors.reset} app/admin/ai-shield/page.tsx`);\n } else {\n console.log(`${colors.yellow}ℹ Dashboard page already exists at:${colors.reset} app/admin/ai-shield/page.tsx`);\n }\n\n console.log(`\\n${colors.green}${colors.bold}🎉 Next.js Setup Complete!${colors.reset}`);\n console.log(`Run ${colors.cyan}npm run dev${colors.reset} and visit:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n // 2. Express / Node.js Server Auto-Patching\n const serverFile = findServerFile();\n\n if (serverFile) {\n const relPath = path.relative(CWD, serverFile);\n console.log(`${colors.green}✓ Detected server entrypoint:${colors.reset} ${relPath}`);\n let content = fs.readFileSync(serverFile, 'utf8');\n\n if (content.includes('@samimcodes/ai-shield') || content.includes('aiShield(')) {\n console.log(`${colors.yellow}ℹ AI-Shield is already installed in ${relPath}.${colors.reset}`);\n console.log(`Live dashboard is accessible at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n const isEsm = isEsmProject(serverFile);\n const importStatement = isEsm\n ? `import { aiShield } from '@samimcodes/ai-shield';\\n`\n : `const { aiShield } = require('@samimcodes/ai-shield');\\n`;\n\n const middlewareCall = `\\n// 🛡️ Protected by AI-Shield (Automatic Setup)\\napp.use(aiShield({ enableDashboard: true }));\\n`;\n\n // Add import statement at top\n content = importStatement + content;\n\n // Inject app.use right after `const app = express();`\n const appPattern = /(const|let|var)\\s+app\\s*=\\s*express\\s*\\([^)]*\\)\\s*;?/;\n if (appPattern.test(content)) {\n content = content.replace(appPattern, (match) => `${match}${middlewareCall}`);\n fs.writeFileSync(serverFile, content, 'utf8');\n console.log(`${colors.green}✓ Successfully injected aiShield into ${relPath}!${colors.reset}`);\n } else {\n // Prepend before app.listen if app pattern not matched\n const listenPattern = /app\\.listen\\s*\\(/;\n if (listenPattern.test(content)) {\n content = content.replace(listenPattern, (match) => `${middlewareCall}${match}`);\n fs.writeFileSync(serverFile, content, 'utf8');\n console.log(`${colors.green}✓ Successfully injected aiShield before app.listen in ${relPath}!${colors.reset}`);\n } else {\n fs.writeFileSync(serverFile, `${content}${middlewareCall}`, 'utf8');\n console.log(`${colors.yellow}⚠ Added middleware to ${relPath}. Please verify app.use order.${colors.reset}`);\n }\n }\n\n console.log(`\\n${colors.green}${colors.bold}🎉 Setup Complete! No code writing required!${colors.reset}`);\n console.log(`Start your server and visit:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n return;\n }\n\n // 3. If no server file exists, create a ready-to-run Express starter\n const starterFile = path.join(CWD, 'server.js');\n const starterContent = `// Created automatically by @samimcodes/ai-shield init\nimport express from 'express';\nimport { aiShield } from '@samimcodes/ai-shield';\n\nconst app = express();\n\n// 🛡️ Live AI Defense + Real-Time Security Monitor\napp.use(aiShield({\n enableDashboard: true,\n}));\n\napp.get('/', (req, res) => {\n res.send('<h1>My Website</h1><p>Protected from AI scrapers by ai-shield.</p>');\n});\n\napp.get('/api/products', (req, res) => {\n res.json({ secretCatalog: [{ id: 1, name: 'Premium Item', price: 99 }] });\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n console.log('Server running on port ' + PORT);\n console.log('Live Security Monitor: http://localhost:' + PORT + '/admin/ai-shield');\n});\n`;\n\n fs.writeFileSync(starterFile, starterContent, 'utf8');\n console.log(`${colors.green}✓ Created new protected Express server:${colors.reset} server.js`);\n console.log(`\\n${colors.green}${colors.bold}🎉 Setup Complete!${colors.reset}`);\n console.log(`Run ${colors.cyan}node server.js${colors.reset} and open:`);\n console.log(`👉 ${colors.bold}${colors.green}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n}\n\n/** Test command to send a simulated bot attack to a running server. */\nfunction runTest(targetUrl?: string) {\n banner();\n const url = targetUrl ?? 'http://localhost:3000/api/products';\n console.log(`🤖 Testing bot defense against: ${colors.cyan}${url}${colors.reset}\\n`);\n\n try {\n const parsed = new URL(url);\n const req = http.request(\n {\n hostname: parsed.hostname,\n port: parsed.port || 80,\n path: parsed.pathname + parsed.search,\n method: 'GET',\n headers: {\n 'User-Agent': 'Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)',\n 'Accept': 'application/json',\n },\n },\n (res) => {\n let body = '';\n res.on('data', (chunk) => (body += chunk));\n res.on('end', () => {\n console.log(`Response Status: ${colors.bold}${res.statusCode} ${res.statusMessage}${colors.reset}`);\n console.log(`X-Robots-Tag: ${colors.bold}${res.headers['x-robots-tag'] ?? 'None'}${colors.reset}`);\n console.log(`Body Preview: ${colors.magenta}${body.slice(0, 150)}...${colors.reset}\\n`);\n\n if (res.statusCode === 200) {\n console.log(`${colors.green}${colors.bold}✓ SUCCESS! Bot was intercepted and served poisoned response!${colors.reset}`);\n console.log(`Check your live monitor at: ${colors.cyan}http://localhost:3000/admin/ai-shield${colors.reset}\\n`);\n } else {\n console.log(`${colors.yellow}Server returned status ${res.statusCode}. Ensure your server is running.${colors.reset}\\n`);\n }\n });\n },\n );\n\n req.on('error', (err) => {\n console.log(`${colors.red}✗ Connection failed: ${err.message}${colors.reset}`);\n console.log(`Make sure your server is running on ${colors.bold}${url}${colors.reset} before testing.\\n`);\n });\n\n req.end();\n } catch (err) {\n console.log(`${colors.red}Invalid URL: ${targetUrl}${colors.reset}`);\n }\n}\n\n// ── Main CLI Dispatcher ────────────────────────────────────────────────────\n\nconst args = process.argv.slice(2);\nconst command = args[0] || 'init';\n\nswitch (command) {\n case 'init':\n runInit();\n break;\n case 'test':\n runTest(args[1]);\n break;\n case '--help':\n case '-h':\n case 'help':\n banner();\n console.log(`Commands:\n ${colors.bold}npx @samimcodes/ai-shield init${colors.reset} Automatically injects AI-Shield into your server\n ${colors.bold}npx @samimcodes/ai-shield test [url]${colors.reset} Sends a simulated GPTBot attack to test defense\n ${colors.bold}npx @samimcodes/ai-shield --help${colors.reset} Show this help message\n`);\n break;\n default:\n runInit();\n break;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samimcodes/ai-shield",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Enterprise-grade Express.js middleware to detect and poison unauthorized AI crawlers while preserving SEO for legitimate bots.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
"dist",
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"ai-shield": "./dist/cli.cjs"
|
|
27
|
+
},
|
|
25
28
|
"scripts": {
|
|
26
29
|
"dev": "tsx watch src/server.ts",
|
|
27
30
|
"build": "tsup",
|