@panguard-ai/panguard 1.4.15 → 1.4.17
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/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +5 -6
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +11 -11
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/commands/config.d.ts +4 -4
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +32 -21
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/demo.js +5 -5
- package/dist/cli/commands/demo.js.map +1 -1
- package/dist/cli/commands/deploy.js +10 -10
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +30 -65
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +42 -45
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/hacktivity.d.ts +2 -2
- package/dist/cli/commands/hacktivity.d.ts.map +1 -1
- package/dist/cli/commands/hacktivity.js +10 -10
- package/dist/cli/commands/hacktivity.js.map +1 -1
- package/dist/cli/commands/hardening.js +6 -6
- package/dist/cli/commands/hardening.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +2 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/login.js +1 -1
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/logout.js +1 -1
- package/dist/cli/commands/logout.js.map +1 -1
- package/dist/cli/commands/report.js +6 -6
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/scan.d.ts.map +1 -1
- package/dist/cli/commands/scan.js +146 -10
- package/dist/cli/commands/scan.js.map +1 -1
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +16 -15
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/skills.d.ts.map +1 -1
- package/dist/cli/commands/skills.js +4 -4
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +4 -4
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/threat.d.ts.map +1 -1
- package/dist/cli/commands/threat.js +15 -15
- package/dist/cli/commands/threat.js.map +1 -1
- package/dist/cli/commands/trap.js +7 -7
- package/dist/cli/commands/trap.js.map +1 -1
- package/dist/cli/commands/up.d.ts.map +1 -1
- package/dist/cli/commands/up.js +249 -40
- package/dist/cli/commands/up.js.map +1 -1
- package/dist/cli/commands/upgrade.js +1 -1
- package/dist/cli/commands/upgrade.js.map +1 -1
- package/dist/cli/commands/whoami.js +1 -1
- package/dist/cli/commands/whoami.js.map +1 -1
- package/dist/cli/consent.js +1 -1
- package/dist/cli/consent.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive/actions/audit.js +2 -2
- package/dist/cli/interactive/actions/audit.js.map +1 -1
- package/dist/cli/interactive/actions/scan.js +2 -2
- package/dist/cli/interactive/actions/scan.js.map +1 -1
- package/dist/cli/interactive.js +2 -2
- package/dist/cli/interactive.js.map +1 -1
- package/dist/init/config-writer.d.ts.map +1 -1
- package/dist/init/config-writer.js +2 -1
- package/dist/init/config-writer.js.map +1 -1
- package/dist/init/steps.js +2 -2
- package/dist/init/steps.js.map +1 -1
- package/dist/init/wizard-runner.js +18 -18
- package/dist/init/wizard-runner.js.map +1 -1
- package/package.json +12 -12
- package/dist/cli/commands/admin.d.ts +0 -9
- package/dist/cli/commands/admin.d.ts.map +0 -1
- package/dist/cli/commands/admin.js +0 -130
- package/dist/cli/commands/admin.js.map +0 -1
- package/dist/cli/commands/manager.d.ts +0 -7
- package/dist/cli/commands/manager.d.ts.map +0 -1
- package/dist/cli/commands/manager.js +0 -113
- package/dist/cli/commands/manager.js.map +0 -1
- package/dist/cli/commands/serve-admin.d.ts +0 -11
- package/dist/cli/commands/serve-admin.d.ts.map +0 -1
- package/dist/cli/commands/serve-admin.js +0 -302
- package/dist/cli/commands/serve-admin.js.map +0 -1
- package/dist/cli/commands/serve-auth.d.ts +0 -11
- package/dist/cli/commands/serve-auth.d.ts.map +0 -1
- package/dist/cli/commands/serve-auth.js +0 -119
- package/dist/cli/commands/serve-auth.js.map +0 -1
- package/dist/cli/commands/serve-core.d.ts +0 -25
- package/dist/cli/commands/serve-core.d.ts.map +0 -1
- package/dist/cli/commands/serve-core.js +0 -215
- package/dist/cli/commands/serve-core.js.map +0 -1
- package/dist/cli/commands/serve-tc.d.ts +0 -12
- package/dist/cli/commands/serve-tc.d.ts.map +0 -1
- package/dist/cli/commands/serve-tc.js +0 -287
- package/dist/cli/commands/serve-tc.js.map +0 -1
- package/dist/cli/commands/serve-types.d.ts +0 -38
- package/dist/cli/commands/serve-types.d.ts.map +0 -1
- package/dist/cli/commands/serve-types.js +0 -108
- package/dist/cli/commands/serve-types.js.map +0 -1
- package/dist/cli/commands/serve.d.ts +0 -14
- package/dist/cli/commands/serve.d.ts.map +0 -1
- package/dist/cli/commands/serve.js +0 -383
- package/dist/cli/commands/serve.js.map +0 -1
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Threat Cloud route handlers for panguard serve.
|
|
3
|
-
* Uses centralized Zod schemas from @panguard-ai/core for input validation.
|
|
4
|
-
*/
|
|
5
|
-
import { sendJson, readRequestBody, requireTCWriteAuth, requireTCAdminAuth, requireJsonContentType, checkTCRateLimit, } from './serve-types.js';
|
|
6
|
-
import { tryValidateInput, ClientIdSchema, ISODateSchema, PaginationLimitSchema, ReputationSchema, ThreatDataSchema, RulePublishSchema, ATRProposalSchema, ATRFeedbackSchema, SkillThreatSchema, SkillWhitelistItemSchema, } from '@panguard-ai/core';
|
|
7
|
-
/** Threat Cloud rate-limited endpoint paths */
|
|
8
|
-
const TC_RATE_LIMITED_PATHS = new Set([
|
|
9
|
-
'/api/threats',
|
|
10
|
-
'/api/rules',
|
|
11
|
-
'/api/stats',
|
|
12
|
-
'/api/atr-proposals',
|
|
13
|
-
'/api/atr-feedback',
|
|
14
|
-
'/api/skill-threats',
|
|
15
|
-
'/api/atr-rules',
|
|
16
|
-
'/api/feeds/ip-blocklist',
|
|
17
|
-
'/api/feeds/domain-blocklist',
|
|
18
|
-
]);
|
|
19
|
-
/**
|
|
20
|
-
* Parse JSON body and validate against a Zod schema.
|
|
21
|
-
* Sends 400 response on failure and returns null.
|
|
22
|
-
*/
|
|
23
|
-
async function parseAndValidate(req, res, schema) {
|
|
24
|
-
const body = await readRequestBody(req);
|
|
25
|
-
let raw;
|
|
26
|
-
try {
|
|
27
|
-
raw = JSON.parse(body);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
sendJson(res, 400, { ok: false, error: 'Invalid JSON body' });
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
const result = tryValidateInput(schema, raw);
|
|
34
|
-
if (!result.ok) {
|
|
35
|
-
sendJson(res, 400, { ok: false, error: result.error });
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
return result.data;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Extract and validate the x-panguard-client-id header.
|
|
42
|
-
* Returns the client ID string or null if invalid/missing.
|
|
43
|
-
*/
|
|
44
|
-
function extractClientId(req) {
|
|
45
|
-
const raw = req.headers['x-panguard-client-id'];
|
|
46
|
-
if (typeof raw !== 'string')
|
|
47
|
-
return null;
|
|
48
|
-
const result = ClientIdSchema.safeParse(raw);
|
|
49
|
-
return result.success ? result.data : null;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Parse URL search params with standard helpers.
|
|
53
|
-
*/
|
|
54
|
-
function parseUrl(url, host) {
|
|
55
|
-
return new URL(url, `http://${host ?? 'localhost'}`);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Handle Threat Cloud API routes (/api/threats, /api/rules, /api/stats, etc.).
|
|
59
|
-
* Returns true if the route was handled, false otherwise.
|
|
60
|
-
*/
|
|
61
|
-
export async function handleTCRoutes(req, res, url, pathname, ctx) {
|
|
62
|
-
const { threatDb, llmReviewer, db } = ctx;
|
|
63
|
-
// Only handle TC paths when threatDb is available and path is a TC endpoint
|
|
64
|
-
if (!threatDb || !pathname.startsWith('/api/'))
|
|
65
|
-
return false;
|
|
66
|
-
// Rate limiting for known TC endpoints
|
|
67
|
-
if (TC_RATE_LIMITED_PATHS.has(pathname)) {
|
|
68
|
-
const clientIP = req.socket.remoteAddress ?? 'unknown';
|
|
69
|
-
if (!checkTCRateLimit(clientIP)) {
|
|
70
|
-
sendJson(res, 429, { ok: false, error: 'Rate limit exceeded. Try again later.' });
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// POST /api/threats - Upload anonymized threat data
|
|
75
|
-
if (pathname === '/api/threats' && req.method === 'POST') {
|
|
76
|
-
if (!requireTCWriteAuth(req, res))
|
|
77
|
-
return true;
|
|
78
|
-
if (!requireJsonContentType(req, res))
|
|
79
|
-
return true;
|
|
80
|
-
const data = await parseAndValidate(req, res, ThreatDataSchema);
|
|
81
|
-
if (!data)
|
|
82
|
-
return true;
|
|
83
|
-
// Anonymize IP (zero last octet)
|
|
84
|
-
const mutableData = { ...data };
|
|
85
|
-
const ip = data.attackSourceIP;
|
|
86
|
-
if (ip.includes('.')) {
|
|
87
|
-
const parts = ip.split('.');
|
|
88
|
-
if (parts.length === 4) {
|
|
89
|
-
parts[3] = '0';
|
|
90
|
-
mutableData['attackSourceIP'] = parts.join('.');
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
threatDb.insertThreat(mutableData);
|
|
94
|
-
sendJson(res, 201, { ok: true, data: { message: 'Threat data received' } });
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
// GET /api/rules - Fetch rules (optional ?since= filter, paginated)
|
|
98
|
-
if (pathname === '/api/rules' && req.method === 'GET') {
|
|
99
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
100
|
-
const rawSince = urlObj.searchParams.get('since');
|
|
101
|
-
if (rawSince) {
|
|
102
|
-
const sinceResult = ISODateSchema.safeParse(rawSince);
|
|
103
|
-
if (!sinceResult.success) {
|
|
104
|
-
sendJson(res, 400, { ok: false, error: 'Invalid since parameter: must be ISO 8601' });
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const limit = PaginationLimitSchema.parse(urlObj.searchParams.get('limit') ?? '1000');
|
|
109
|
-
const rules = rawSince ? threatDb.getRulesSince(rawSince) : threatDb.getAllRules(limit);
|
|
110
|
-
sendJson(res, 200, { ok: true, data: rules });
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
// POST /api/rules - Publish a new community rule
|
|
114
|
-
if (pathname === '/api/rules' && req.method === 'POST') {
|
|
115
|
-
if (!requireTCWriteAuth(req, res))
|
|
116
|
-
return true;
|
|
117
|
-
if (!requireJsonContentType(req, res))
|
|
118
|
-
return true;
|
|
119
|
-
const rule = await parseAndValidate(req, res, RulePublishSchema);
|
|
120
|
-
if (!rule)
|
|
121
|
-
return true;
|
|
122
|
-
const ruleData = {
|
|
123
|
-
...rule,
|
|
124
|
-
publishedAt: rule.publishedAt || new Date().toISOString(),
|
|
125
|
-
};
|
|
126
|
-
threatDb.upsertRule(ruleData);
|
|
127
|
-
sendJson(res, 201, { ok: true, data: { message: 'Rule published', ruleId: rule.ruleId } });
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
// GET /api/stats - Threat statistics
|
|
131
|
-
if (pathname === '/api/stats' && req.method === 'GET') {
|
|
132
|
-
const stats = threatDb.getStats();
|
|
133
|
-
sendJson(res, 200, { ok: true, data: stats });
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
// POST /api/atr-proposals - Submit ATR rule proposal
|
|
137
|
-
if (pathname === '/api/atr-proposals' && req.method === 'POST') {
|
|
138
|
-
if (!requireTCWriteAuth(req, res))
|
|
139
|
-
return true;
|
|
140
|
-
if (!requireJsonContentType(req, res))
|
|
141
|
-
return true;
|
|
142
|
-
const proposal = await parseAndValidate(req, res, ATRProposalSchema);
|
|
143
|
-
if (!proposal)
|
|
144
|
-
return true;
|
|
145
|
-
const clientId = extractClientId(req);
|
|
146
|
-
const proposalData = { ...proposal, clientId };
|
|
147
|
-
const pHash = proposal.patternHash;
|
|
148
|
-
// Check if this pattern already has a proposal - if so, increment confirmation
|
|
149
|
-
const existing = threatDb
|
|
150
|
-
.getATRProposals()
|
|
151
|
-
.find((p) => p['pattern_hash'] === pHash);
|
|
152
|
-
if (existing) {
|
|
153
|
-
threatDb.confirmATRProposal(pHash);
|
|
154
|
-
sendJson(res, 200, {
|
|
155
|
-
ok: true,
|
|
156
|
-
data: { message: 'Confirmation recorded', patternHash: pHash },
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
threatDb.insertATRProposal(proposalData);
|
|
161
|
-
// Fire-and-forget LLM review on first submission
|
|
162
|
-
if (llmReviewer?.isAvailable()) {
|
|
163
|
-
void llmReviewer.reviewProposal(pHash, proposal.ruleContent).catch((err) => {
|
|
164
|
-
console.error(`LLM review error for ${pHash}:`, err);
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
sendJson(res, 201, {
|
|
168
|
-
ok: true,
|
|
169
|
-
data: { message: 'Proposal submitted', patternHash: pHash },
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
// GET /api/atr-proposals - List proposals (admin-only)
|
|
175
|
-
if (pathname === '/api/atr-proposals' && req.method === 'GET') {
|
|
176
|
-
if (!requireTCAdminAuth(req, res, db))
|
|
177
|
-
return true;
|
|
178
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
179
|
-
const status = urlObj.searchParams.get('status') ?? undefined;
|
|
180
|
-
const proposals = threatDb.getATRProposals(status);
|
|
181
|
-
sendJson(res, 200, { ok: true, data: proposals });
|
|
182
|
-
return true;
|
|
183
|
-
}
|
|
184
|
-
// POST /api/atr-feedback - Report ATR rule match feedback
|
|
185
|
-
if (pathname === '/api/atr-feedback' && req.method === 'POST') {
|
|
186
|
-
if (!requireTCWriteAuth(req, res))
|
|
187
|
-
return true;
|
|
188
|
-
if (!requireJsonContentType(req, res))
|
|
189
|
-
return true;
|
|
190
|
-
const feedback = await parseAndValidate(req, res, ATRFeedbackSchema);
|
|
191
|
-
if (!feedback)
|
|
192
|
-
return true;
|
|
193
|
-
const cid = extractClientId(req);
|
|
194
|
-
threatDb.insertATRFeedback(feedback.ruleId, feedback.isTruePositive, cid);
|
|
195
|
-
sendJson(res, 201, { ok: true, data: { message: 'Feedback recorded' } });
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
// POST /api/skill-threats - Submit skill audit result
|
|
199
|
-
if (pathname === '/api/skill-threats' && req.method === 'POST') {
|
|
200
|
-
if (!requireTCWriteAuth(req, res))
|
|
201
|
-
return true;
|
|
202
|
-
if (!requireJsonContentType(req, res))
|
|
203
|
-
return true;
|
|
204
|
-
const submission = await parseAndValidate(req, res, SkillThreatSchema);
|
|
205
|
-
if (!submission)
|
|
206
|
-
return true;
|
|
207
|
-
const cid = extractClientId(req);
|
|
208
|
-
const submissionData = { ...submission, clientId: cid };
|
|
209
|
-
threatDb.insertSkillThreat(submissionData);
|
|
210
|
-
sendJson(res, 201, { ok: true, data: { message: 'Skill threat recorded' } });
|
|
211
|
-
return true;
|
|
212
|
-
}
|
|
213
|
-
// GET /api/skill-threats - List skill threats (admin-only)
|
|
214
|
-
if (pathname === '/api/skill-threats' && req.method === 'GET') {
|
|
215
|
-
if (!requireTCAdminAuth(req, res, db))
|
|
216
|
-
return true;
|
|
217
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
218
|
-
const limit = PaginationLimitSchema.parse(urlObj.searchParams.get('limit') ?? '50');
|
|
219
|
-
const threats = threatDb.getSkillThreats(Math.min(limit, 500));
|
|
220
|
-
sendJson(res, 200, { ok: true, data: threats });
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
// GET /api/atr-rules - Fetch confirmed ATR rules (for Guard sync)
|
|
224
|
-
if (pathname === '/api/atr-rules' && req.method === 'GET') {
|
|
225
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
226
|
-
const since = urlObj.searchParams.get('since') ?? undefined;
|
|
227
|
-
const rules = threatDb.getConfirmedATRRules(since);
|
|
228
|
-
sendJson(res, 200, { ok: true, data: rules });
|
|
229
|
-
return true;
|
|
230
|
-
}
|
|
231
|
-
// GET /api/feeds/ip-blocklist - IP blocklist feed (plain text)
|
|
232
|
-
if (pathname === '/api/feeds/ip-blocklist' && req.method === 'GET') {
|
|
233
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
234
|
-
const minReputation = ReputationSchema.parse(urlObj.searchParams.get('minReputation') ?? '70');
|
|
235
|
-
const ips = threatDb.getIPBlocklist(minReputation);
|
|
236
|
-
res.setHeader('Content-Type', 'text/plain');
|
|
237
|
-
res.writeHead(200);
|
|
238
|
-
res.end(ips.join('\n'));
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
// GET /api/feeds/domain-blocklist - Domain blocklist feed (plain text)
|
|
242
|
-
if (pathname === '/api/feeds/domain-blocklist' && req.method === 'GET') {
|
|
243
|
-
const urlObj = parseUrl(url, req.headers.host);
|
|
244
|
-
const minReputation = ReputationSchema.parse(urlObj.searchParams.get('minReputation') ?? '70');
|
|
245
|
-
const domains = threatDb.getDomainBlocklist(minReputation);
|
|
246
|
-
res.setHeader('Content-Type', 'text/plain');
|
|
247
|
-
res.writeHead(200);
|
|
248
|
-
res.end(domains.join('\n'));
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
// POST /api/skill-whitelist - Report safe skill (audit passed)
|
|
252
|
-
if (pathname === '/api/skill-whitelist' && req.method === 'POST') {
|
|
253
|
-
if (!requireTCWriteAuth(req, res))
|
|
254
|
-
return true;
|
|
255
|
-
if (!requireJsonContentType(req, res))
|
|
256
|
-
return true;
|
|
257
|
-
const body = await readRequestBody(req);
|
|
258
|
-
let raw;
|
|
259
|
-
try {
|
|
260
|
-
raw = JSON.parse(body);
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
sendJson(res, 400, { ok: false, error: 'Invalid JSON body' });
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
const data = raw;
|
|
267
|
-
const skills = 'skills' in data && Array.isArray(data['skills']) ? data['skills'] : [data];
|
|
268
|
-
let count = 0;
|
|
269
|
-
for (const skill of skills) {
|
|
270
|
-
const result = SkillWhitelistItemSchema.safeParse(skill);
|
|
271
|
-
if (!result.success)
|
|
272
|
-
continue;
|
|
273
|
-
threatDb.reportSafeSkill(result.data.skillName, result.data.fingerprintHash);
|
|
274
|
-
count++;
|
|
275
|
-
}
|
|
276
|
-
sendJson(res, 201, { ok: true, data: { message: `${count} skill(s) reported`, count } });
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
279
|
-
// GET /api/skill-whitelist - Fetch community whitelist
|
|
280
|
-
if (pathname === '/api/skill-whitelist' && req.method === 'GET') {
|
|
281
|
-
const whitelist = threatDb.getSkillWhitelist();
|
|
282
|
-
sendJson(res, 200, { ok: true, data: whitelist });
|
|
283
|
-
return true;
|
|
284
|
-
}
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
//# sourceMappingURL=serve-tc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve-tc.js","sourceRoot":"","sources":["../../../src/cli/commands/serve-tc.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared types, helpers and middleware for serve sub-modules.
|
|
3
|
-
*/
|
|
4
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
-
import type { AuthDB } from '@panguard-ai/panguard-auth';
|
|
6
|
-
import type { ManagerProxy } from '@panguard-ai/panguard-auth';
|
|
7
|
-
import type { createAuthHandlers } from '@panguard-ai/panguard-auth';
|
|
8
|
-
export type ThreatCloudDBInstance = any;
|
|
9
|
-
export type LLMReviewerInstance = any;
|
|
10
|
-
/** Context passed to every route handler module */
|
|
11
|
-
export interface RouteContext {
|
|
12
|
-
readonly handlers: ReturnType<typeof createAuthHandlers>;
|
|
13
|
-
readonly db: AuthDB;
|
|
14
|
-
readonly adminDir: string | undefined;
|
|
15
|
-
readonly managerProxy: ManagerProxy;
|
|
16
|
-
readonly threatDb: ThreatCloudDBInstance;
|
|
17
|
-
readonly llmReviewer: LLMReviewerInstance;
|
|
18
|
-
}
|
|
19
|
-
export declare function sendJson(res: ServerResponse, status: number, data: unknown): void;
|
|
20
|
-
/** Read request body with 1MB size limit */
|
|
21
|
-
export declare function readRequestBody(req: IncomingMessage): Promise<string>;
|
|
22
|
-
/** Timing-safe string comparison to prevent side-channel attacks */
|
|
23
|
-
export declare function timingSafeCompare(a: string, b: string): boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Require TC_API_KEY auth for write endpoints.
|
|
26
|
-
* In production: BLOCK if TC_API_KEY not set (refuse unauthenticated writes).
|
|
27
|
-
* In dev: allow passthrough with warning.
|
|
28
|
-
*/
|
|
29
|
-
export declare function requireTCWriteAuth(req: IncomingMessage, res: ServerResponse): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Require admin session auth for admin-only GET endpoints.
|
|
32
|
-
* Verifies the Bearer token is a valid session with admin role.
|
|
33
|
-
*/
|
|
34
|
-
export declare function requireTCAdminAuth(req: IncomingMessage, res: ServerResponse, db: AuthDB): boolean;
|
|
35
|
-
/** Validate Content-Type is application/json for POST requests */
|
|
36
|
-
export declare function requireJsonContentType(req: IncomingMessage, res: ServerResponse): boolean;
|
|
37
|
-
export declare function checkTCRateLimit(ip: string): boolean;
|
|
38
|
-
//# sourceMappingURL=serve-types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve-types.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/serve-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,MAAM,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAExC,MAAM,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEtC,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACzD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;CAC3C;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjF;AAID,4CAA4C;AAC5C,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBrE;AAID,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAW/D;AAID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAmBrF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAWjG;AAED,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAOzF;AAOD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CASpD"}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared types, helpers and middleware for serve sub-modules.
|
|
3
|
-
*/
|
|
4
|
-
import { authenticateRequest, requireAdmin } from '@panguard-ai/panguard-auth';
|
|
5
|
-
// ── JSON Response ──────────────────────────────────────────────
|
|
6
|
-
export function sendJson(res, status, data) {
|
|
7
|
-
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
8
|
-
res.end(JSON.stringify(data));
|
|
9
|
-
}
|
|
10
|
-
// ── Request Body Reader ────────────────────────────────────────
|
|
11
|
-
/** Read request body with 1MB size limit */
|
|
12
|
-
export function readRequestBody(req) {
|
|
13
|
-
return new Promise((resolve, reject) => {
|
|
14
|
-
const chunks = [];
|
|
15
|
-
let size = 0;
|
|
16
|
-
const MAX_BODY = 1_048_576; // 1MB
|
|
17
|
-
req.on('data', (chunk) => {
|
|
18
|
-
size += chunk.length;
|
|
19
|
-
if (size > MAX_BODY) {
|
|
20
|
-
req.destroy();
|
|
21
|
-
reject(new Error('Request body too large'));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
chunks.push(chunk);
|
|
25
|
-
});
|
|
26
|
-
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
27
|
-
req.on('error', reject);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
// ── Timing-safe Comparison ─────────────────────────────────────
|
|
31
|
-
/** Timing-safe string comparison to prevent side-channel attacks */
|
|
32
|
-
export function timingSafeCompare(a, b) {
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
34
|
-
const { timingSafeEqual } = require('node:crypto');
|
|
35
|
-
const ab = Buffer.from(a);
|
|
36
|
-
const bb = Buffer.from(b);
|
|
37
|
-
if (ab.length !== bb.length) {
|
|
38
|
-
// Compare against self to maintain constant time
|
|
39
|
-
timingSafeEqual(ab, ab);
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
return timingSafeEqual(ab, bb);
|
|
43
|
-
}
|
|
44
|
-
// ── Threat Cloud Auth Helpers ──────────────────────────────────
|
|
45
|
-
/**
|
|
46
|
-
* Require TC_API_KEY auth for write endpoints.
|
|
47
|
-
* In production: BLOCK if TC_API_KEY not set (refuse unauthenticated writes).
|
|
48
|
-
* In dev: allow passthrough with warning.
|
|
49
|
-
*/
|
|
50
|
-
export function requireTCWriteAuth(req, res) {
|
|
51
|
-
const tcApiKey = process.env['TC_API_KEY'];
|
|
52
|
-
if (!tcApiKey) {
|
|
53
|
-
if (process.env['NODE_ENV'] === 'production') {
|
|
54
|
-
sendJson(res, 503, {
|
|
55
|
-
ok: false,
|
|
56
|
-
error: 'Threat Cloud write API not configured (TC_API_KEY missing)',
|
|
57
|
-
});
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
return true; // dev passthrough
|
|
61
|
-
}
|
|
62
|
-
const authHeader = req.headers.authorization ?? '';
|
|
63
|
-
const token = authHeader.replace('Bearer ', '');
|
|
64
|
-
if (!timingSafeCompare(token, tcApiKey)) {
|
|
65
|
-
sendJson(res, 401, { ok: false, error: 'Invalid API key' });
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Require admin session auth for admin-only GET endpoints.
|
|
72
|
-
* Verifies the Bearer token is a valid session with admin role.
|
|
73
|
-
*/
|
|
74
|
-
export function requireTCAdminAuth(req, res, db) {
|
|
75
|
-
const user = authenticateRequest(req, db);
|
|
76
|
-
if (!user) {
|
|
77
|
-
sendJson(res, 401, { ok: false, error: 'Authentication required' });
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
if (!requireAdmin(user)) {
|
|
81
|
-
sendJson(res, 403, { ok: false, error: 'Admin access required' });
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
/** Validate Content-Type is application/json for POST requests */
|
|
87
|
-
export function requireJsonContentType(req, res) {
|
|
88
|
-
const ct = req.headers['content-type'] ?? '';
|
|
89
|
-
if (!ct.includes('application/json')) {
|
|
90
|
-
sendJson(res, 400, { ok: false, error: 'Content-Type must be application/json' });
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
// ── Rate Limiter ───────────────────────────────────────────────
|
|
96
|
-
/** Per-IP rate limiter for Threat Cloud endpoints (120 req/min) */
|
|
97
|
-
const tcRateLimits = new Map();
|
|
98
|
-
export function checkTCRateLimit(ip) {
|
|
99
|
-
const now = Date.now();
|
|
100
|
-
const entry = tcRateLimits.get(ip);
|
|
101
|
-
if (!entry || now > entry.resetAt) {
|
|
102
|
-
tcRateLimits.set(ip, { count: 1, resetAt: now + 60_000 });
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
entry.count++;
|
|
106
|
-
return entry.count <= 120;
|
|
107
|
-
}
|
|
108
|
-
//# sourceMappingURL=serve-types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve-types.js","sourceRoot":"","sources":["../../../src/cli/commands/serve-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* panguard serve - Unified HTTP server gateway
|
|
3
|
-
*
|
|
4
|
-
* Serves auth API, admin API, admin dashboard UI, and health check.
|
|
5
|
-
* Route handling is delegated to focused sub-modules:
|
|
6
|
-
* serve-core.ts -- middleware, health, static files, rule seeding
|
|
7
|
-
* serve-auth.ts -- auth, waitlist, usage routes
|
|
8
|
-
* serve-admin.ts -- admin dashboard + manager proxy routes
|
|
9
|
-
* serve-tc.ts -- Threat Cloud API routes
|
|
10
|
-
* serve-types.ts -- shared types and utilities
|
|
11
|
-
*/
|
|
12
|
-
import { Command } from 'commander';
|
|
13
|
-
export declare function serveCommand(): Command;
|
|
14
|
-
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CpC,wBAAgB,YAAY,IAAI,OAAO,CA+XtC"}
|