-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
128 lines (111 loc) · 3.63 KB
/
Copy pathserver.js
File metadata and controls
128 lines (111 loc) · 3.63 KB
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
require('dotenv').config();
const path = require('path');
const http = require('http');
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const { WebSocketServer } = require('ws');
const { initializeDatabase } = require('./config/database');
const createAuthRouter = require('./routes/auth');
const createDashboardRouter = require('./routes/dashboard');
const createScansRouter = require('./routes/scans');
const createTeamsRouter = require('./routes/teams');
const JobQueue = require('./lib/job-queue');
const logger = require('./lib/logger');
const { verifyToken } = require('./middleware/auth');
const app = express();
const server = http.createServer(app);
const db = initializeDatabase();
class Broadcaster {
constructor() {
this.clients = new Set();
}
add(client) {
this.clients.add(client);
}
remove(client) {
this.clients.delete(client);
}
broadcastCompany(companyId, payload) {
const message = JSON.stringify(payload);
for (const client of this.clients) {
if (client.companyId === companyId && client.ws.readyState === client.ws.OPEN) {
client.ws.send(message);
}
}
}
}
const broadcaster = new Broadcaster();
const queue = new JobQueue({ db, broadcaster });
app.disable('x-powered-by');
app.use(helmet({
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false
}));
app.use(cors({ origin: true, credentials: true }));
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: false }));
app.use(rateLimit({
windowMs: 15 * 60 * 1000,
limit: 400,
standardHeaders: true,
legacyHeaders: false
}));
app.use('/api/auth', createAuthRouter({ db }));
app.use('/api/scans', createScansRouter({ db, queue }));
app.use('/api/dashboard', createDashboardRouter({ db }));
app.use('/api/teams', createTeamsRouter({ db }));
app.get('/api/health', (_req, res) => {
res.json({ ok: true, name: 'AG GitHub Security Scanner', time: new Date().toISOString() });
});
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (_req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
const wss = new WebSocketServer({ server, path: '/ws' });
wss.on('connection', (ws, req) => {
try {
const url = new URL(req.url, `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (!token) {
ws.close(1008, 'Authentication token required');
return;
}
const payload = verifyToken(token);
const user = db.prepare('SELECT id, company_id, role FROM users WHERE id = ?').get(payload.sub);
if (!user) {
ws.close(1008, 'Invalid user');
return;
}
const client = { ws, userId: user.id, companyId: user.company_id };
broadcaster.add(client);
ws.send(JSON.stringify({ type: 'socket.ready', userId: user.id }));
ws.on('close', () => broadcaster.remove(client));
} catch (error) {
ws.close(1008, 'Invalid token');
}
});
app.use((err, req, res, _next) => {
logger.error('Request failed', {
path: req.path,
method: req.method,
error: err.stack || err.message
});
res.status(err.status || 400).json({ error: err.message || 'Request failed.' });
});
const port = Number(process.env.PORT || 3000);
server.listen(port, () => {
logger.info(`AG GitHub Security Scanner listening on http://localhost:${port}`);
});
function shutdown() {
logger.info('Shutting down AG GitHub Security Scanner');
wss.close();
server.close(() => {
db.close();
process.exit(0);
});
}
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
module.exports = { app, db, server };