Spaces:
Paused
Paused
File size: 5,600 Bytes
529090e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | import { Router } from 'express';
import { z } from 'zod';
import {
getFeedOverview,
executeSecuritySearch,
securityTemplates,
securityHistory,
securityActivity,
} from './securityService.js';
import { registerActivityStream } from './activityStream.js';
import { setActivityAcknowledged } from './securityRepository.js';
import {
getWidgetPermissions,
checkWidgetAccess,
setWidgetPermission,
setPlatformDefault
} from './securityRepository.js';
export const securityRouter = Router();
securityRouter.get('/feeds', async (_req, res) => {
const overview = await getFeedOverview();
res.json(overview);
});
securityRouter.get('/search/templates', (_req, res) => {
securityTemplates.list().then(templates => res.json({ templates })).catch(() => res.status(500).json({ error: 'Could not fetch templates' }));
});
securityRouter.get('/search/history', (req, res) => {
const limit = Number(req.query.limit ?? 6);
securityHistory.list(limit).then(history => res.json({ history })).catch(() => res.status(500).json({ error: 'Could not fetch history' }));
});
const searchSchema = z.object({
query: z.string().default(''),
severity: z.string().default('all'),
timeframe: z.string().default('24h'),
sources: z.array(z.string()).default([]),
});
securityRouter.post('/search/query', async (req, res) => {
const parsed = searchSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid payload', details: parsed.error.flatten() });
}
const payload = await executeSecuritySearch(parsed.data as any);
res.json(payload);
});
securityRouter.get('/activity', (req, res) => {
const severity = typeof req.query.severity === 'string' ? req.query.severity : undefined;
const category = typeof req.query.category === 'string' ? req.query.category : undefined;
const limit = req.query.limit ? Number(req.query.limit) : undefined;
securityActivity.list(severity, category, limit)
.then(events => res.json({ events }))
.catch(() => res.status(500).json({ error: 'Could not fetch activity' }));
});
securityRouter.post('/activity/:id/ack', (req, res) => {
const acknowledged = typeof req.body?.acknowledged === 'boolean' ? req.body.acknowledged : true;
setActivityAcknowledged(req.params.id, acknowledged).then(updated => {
if (!updated) {
return res.status(404).json({ error: 'Event not found' });
}
res.json(updated);
}).catch(() => res.status(500).json({ error: 'Could not update event' }));
});
securityRouter.get('/activity/stream', (req, res) => {
registerActivityStream(res, {
severity: typeof req.query.severity === 'string' ? req.query.severity : undefined,
category: typeof req.query.category === 'string' ? req.query.category : undefined,
});
});
const registryEventSchema = z.object({
id: z.string().optional(),
title: z.string(),
description: z.string(),
category: z.union([z.literal('ingestion'), z.literal('alert'), z.literal('automation'), z.literal('audit')]),
severity: z.union([z.literal('low'), z.literal('medium'), z.literal('high'), z.literal('critical')]),
source: z.string(),
rule: z.string().optional(),
channel: z.union([z.literal('SSE'), z.literal('Webhook'), z.literal('Job')]).optional(),
payload: z.record(z.any()).optional(),
createdAt: z.string().optional(),
acknowledged: z.boolean().optional(),
});
securityRouter.post('/activity/registry', (req, res) => {
const parsed = registryEventSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid registry event', details: parsed.error.flatten() });
}
const event = securityActivity.publish({
id: parsed.data.id ?? `evt-${Date.now()}`,
title: parsed.data.title,
description: parsed.data.description,
category: parsed.data.category,
severity: parsed.data.severity,
source: parsed.data.source,
rule: parsed.data.rule,
channel: parsed.data.channel ?? 'SSE',
payload: parsed.data.payload,
createdAt: parsed.data.createdAt ?? new Date().toISOString(),
acknowledged: parsed.data.acknowledged ?? false,
});
res.status(201).json(event);
});
// Get permissions for a widget
securityRouter.get('/permissions/:widgetId', async (req, res) => {
try {
const { widgetId } = req.params;
const permissions = await getWidgetPermissions(widgetId);
res.json(permissions);
} catch (_error) {
res.status(500).json({ error: 'Could not fetch permissions' });
}
});
// Set widget permission (override)
securityRouter.put('/permissions/:widgetId', async (req, res) => {
try {
const { widgetId } = req.params;
const { resourceType, accessLevel, override = true } = req.body;
await setWidgetPermission(widgetId, resourceType, accessLevel, override);
res.json({ success: true });
} catch (_error) {
res.status(500).json({ error: 'Could not set permission' });
}
});
// Check access
securityRouter.post('/check-access', async (req, res) => {
try {
const { widgetId, resourceType, requiredLevel } = req.body;
const hasAccess = await checkWidgetAccess(widgetId, resourceType, requiredLevel);
res.json({ hasAccess });
} catch (_error) {
res.status(500).json({ error: 'Could not check access' });
}
});
// Set platform default
securityRouter.post('/platform-defaults', async (req, res) => {
try {
const { resourceType, accessLevel } = req.body;
await setPlatformDefault(resourceType, accessLevel);
res.json({ success: true });
} catch (_error) {
res.status(500).json({ error: 'Could not set platform default' });
}
});
|