Skip to content

Commit 1388e8b

Browse files
fix: replace serve-static with express.static in CSP demo server to resolve CodeQL alert (#32925)
1 parent 2d047d5 commit 1388e8b

2 files changed

Lines changed: 54 additions & 64 deletions

File tree

apps/demos/utils/server/csp-check.js

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const DEMO_ROOT = join(__dirname, '..', '..');
99
const REPORT_DIR = join(DEMO_ROOT, 'csp-reports');
1010
const SERVER_URL = process.env.CSP_SERVER_URL || 'http://localhost:8080';
1111
const FRAMEWORK = (process.env.CSP_FRAMEWORKS || 'jQuery').trim();
12-
const CONCURRENCY = parseInt(process.env.CSP_CONCURRENCY, 10) || 8;
12+
const CONCURRENCY = parseInt(process.env.CSP_CONCURRENCY, 10) || 10;
1313

1414
function findChrome() {
1515
const candidates = [
@@ -84,10 +84,16 @@ function visitPage(url) {
8484
'--disable-software-rasterizer',
8585
'--disable-dev-shm-usage',
8686
'--dump-dom',
87-
'--virtual-time-budget=5000',
87+
'--virtual-time-budget=2000',
8888
'--window-size=100,100',
8989
url,
90-
], { timeout: 30000 }, () => resolve());
90+
], { timeout: 50000, killSignal: 'SIGKILL' }, (error) => {
91+
if (error && error.killed) {
92+
reject(new Error(`Chrome timed out for ${url}`));
93+
} else {
94+
resolve();
95+
}
96+
});
9197
child.on('error', (err) => {
9298
reject(new Error(`Failed to launch Chrome at "${CHROME_PATH}": ${err.message}`));
9399
});
@@ -112,6 +118,22 @@ function httpRequest(url, method) {
112118
});
113119
}
114120

121+
async function runPool(items, concurrency, fn) {
122+
let nextIndex = 0;
123+
async function worker() {
124+
while (nextIndex < items.length) {
125+
const i = nextIndex;
126+
nextIndex += 1;
127+
await fn(items[i], i);
128+
}
129+
}
130+
const workers = [];
131+
for (let w = 0; w < Math.min(concurrency, items.length); w += 1) {
132+
workers.push(worker());
133+
}
134+
await Promise.all(workers);
135+
}
136+
115137
async function main() {
116138
console.log(`Chrome: ${CHROME_PATH}`);
117139
console.log(`Server: ${SERVER_URL}`);
@@ -130,48 +152,40 @@ async function main() {
130152
let demosWithViolations = 0;
131153
const allViolations = [];
132154

133-
for (let batchStart = 0; batchStart < demos.length; batchStart += CONCURRENCY) {
134-
const batch = demos.slice(batchStart, batchStart + CONCURRENCY);
155+
await httpRequest(`${SERVER_URL}/csp-violations`, 'DELETE');
135156

136-
await httpRequest(`${SERVER_URL}/csp-violations`, 'DELETE');
157+
await runPool(demos, CONCURRENCY, async (demo, i) => {
158+
const idx = i + 1;
159+
const snapshot = await httpRequest(`${SERVER_URL}/csp-violations`);
160+
const since = snapshot.lastId || 0;
137161

138-
await Promise.all(batch.map((demo) => visitPage(demo.url)));
139-
140-
await new Promise((resolve) => { setTimeout(resolve, 500); });
141-
142-
const result = await httpRequest(`${SERVER_URL}/csp-violations`);
143-
const violations = result.violations || [];
144-
145-
const violationsByUrl = {};
146-
for (const v of violations) {
147-
const uri = v.documentUri || '';
148-
if (!violationsByUrl[uri]) violationsByUrl[uri] = [];
149-
violationsByUrl[uri].push(v);
162+
try {
163+
await visitPage(demo.url);
164+
} catch (err) {
165+
console.log(` ⚠️ [${idx}/${demos.length}] ${demo.widget}/${demo.demo}/${demo.framework}${err.message}`);
166+
return;
150167
}
151168

152-
for (let j = 0; j < batch.length; j += 1) {
153-
const demo = batch[j];
154-
const idx = batchStart + j + 1;
155-
const demoViolations = violationsByUrl[demo.url]
156-
|| violationsByUrl[`${demo.url}index.html`]
157-
|| [];
158-
159-
if (demoViolations.length > 0) {
160-
demosWithViolations += 1;
161-
totalViolations += demoViolations.length;
162-
163-
console.log(` ❌ [${idx}/${demos.length}] ${demo.widget}/${demo.demo}/${demo.framework}${demoViolations.length} violation(s)`);
164-
for (const v of demoViolations) {
165-
const blocked = v.blockedUri || 'N/A';
166-
const directive = v.effectiveDirective || v.violatedDirective || '?';
167-
console.log(` ${directive}: ${blocked}`);
168-
allViolations.push({ ...v, framework: FRAMEWORK });
169-
}
170-
} else {
171-
console.log(` ✅ [${idx}/${demos.length}] ${demo.widget}/${demo.demo}/${demo.framework}`);
169+
const result = await httpRequest(`${SERVER_URL}/csp-violations?since=${since}`);
170+
const violations = (result.violations || []).filter(
171+
(v) => v.documentUri === demo.url || v.documentUri === `${demo.url}index.html`,
172+
);
173+
174+
if (violations.length > 0) {
175+
demosWithViolations += 1;
176+
totalViolations += violations.length;
177+
178+
console.log(` ❌ [${idx}/${demos.length}] ${demo.widget}/${demo.demo}/${demo.framework}${violations.length} violation(s)`);
179+
for (const v of violations) {
180+
const blocked = v.blockedUri || 'N/A';
181+
const directive = v.effectiveDirective || v.violatedDirective || '?';
182+
console.log(` ${directive}: ${blocked}`);
183+
allViolations.push({ ...v, framework: FRAMEWORK });
172184
}
185+
} else {
186+
console.log(` ✅ [${idx}/${demos.length}] ${demo.widget}/${demo.demo}/${demo.framework}`);
173187
}
174-
}
188+
});
175189

176190
const reportFile = join(REPORT_DIR, `csp-violations-${FRAMEWORK.toLowerCase()}.jsonl`);
177191

apps/demos/utils/server/csp-server.js

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const crypto = require('crypto');
44
const express = require('express');
5-
const serveStatic = require('serve-static');
65
const cookieParser = require('cookie-parser');
76
const { join, resolve } = require('path');
87
const { readFileSync, readdirSync } = require('fs');
@@ -376,30 +375,9 @@ const demoIndexHandler = (request, response) => {
376375
response.send(fileContent);
377376
};
378377

379-
const createRateLimiter = (windowMs = 60000, maxRequests = 200) => {
380-
const hits = new Map();
381-
382-
setInterval(() => hits.clear(), windowMs);
383-
384-
return (req, res, next) => {
385-
const key = req.ip;
386-
const count = (hits.get(key) || 0) + 1;
387-
hits.set(key, count);
388-
389-
if (count > maxRequests) {
390-
res.status(429).send('Too Many Requests');
391-
return;
392-
}
393-
next();
394-
};
395-
};
396-
397-
const rateLimiter = createRateLimiter();
398-
399378
const app = express();
400379
app.use(cookieParser());
401380
app.use(cspMiddleware);
402-
app.use(rateLimiter);
403381

404382
app.post('/csp-report', cspReportHandler);
405383
app.get('/csp-violations', cspViolationsHandler);
@@ -408,9 +386,7 @@ app.delete('/csp-violations', cspViolationsClearHandler);
408386
app.get('/apps/demos/Demos/:widget/:name/:approach', demoIndexHandler);
409387
app.get(`/apps/demos/Demos/:widget/:name/:approach/${indexFileName}`, demoIndexHandler);
410388

411-
app.use(
412-
serveStatic(root, { index: [indexFileName] }),
413-
);
389+
app.use(express.static(root, { index: [indexFileName] }));
414390

415391
const server = app.listen(port, host, () => {
416392
console.log(`CSP Demo server listening on http://${host}:${port}`);

0 commit comments

Comments
 (0)