Skip to content

Commit af085f0

Browse files
committed
f
1 parent 4d495f5 commit af085f0

6 files changed

Lines changed: 31 additions & 34 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
"egg-path-matching": "^2.1.0",
4343
"escape-html": "^1.0.3",
4444
"extend": "^3.0.1",
45-
"extend2": "^4.0.0",
4645
"koa-compose": "^4.1.0",
4746
"matcher": "^4.0.0",
4847
"nanoid": "^3.3.8",
@@ -55,6 +54,7 @@
5554
"@eggjs/mock": "^6.0.5",
5655
"@eggjs/tsconfig": "1",
5756
"@types/escape-html": "^1.0.4",
57+
"@types/extend": "^3.0.4",
5858
"@types/koa-compose": "^3.2.8",
5959
"@types/mocha": "10",
6060
"@types/node": "22",

src/lib/middlewares/csp.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { extend } from 'extend2';
1+
import extend from 'extend';
22
import type { Context, Next } from '@eggjs/core';
3-
import * as utils from '../utils.js';
3+
import { checkIfIgnore } from '../utils.js';
44
import type { SecurityConfig } from '../../types.js';
55

66
const HEADER = [
@@ -23,10 +23,9 @@ export default (options: SecurityConfig['csp']) => {
2323
...options,
2424
...ctx.securityOptions.csp,
2525
};
26-
if (utils.checkIfIgnore(opts, ctx)) return;
26+
if (checkIfIgnore(opts, ctx)) return;
2727

2828
let finalHeader;
29-
let value;
3029
const matchedOption = extend(true, {}, opts.policy);
3130
const bufArray = [];
3231

@@ -38,30 +37,30 @@ export default (options: SecurityConfig['csp']) => {
3837
}
3938

4039
for (const key in matchedOption) {
41-
value = matchedOption[key];
42-
value = Array.isArray(value) ? value : [ value ];
43-
40+
const value = matchedOption[key];
4441
// Other arrays are splitted into strings EXCEPT `sandbox`
45-
if (key === 'sandbox' && value[0] === true) {
42+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
43+
if (key === 'sandbox' && value === true) {
4644
bufArray.push(key);
4745
} else {
46+
let values = (Array.isArray(value) ? value : [ value ]) as string[];
4847
if (key === 'script-src') {
49-
const hasNonce = value.some(function(val) {
48+
const hasNonce = values.some(function(val) {
5049
return val.indexOf('nonce-') !== -1;
5150
});
5251

5352
if (!hasNonce) {
54-
value.push('\'nonce-' + ctx.nonce + '\'');
53+
values.push('\'nonce-' + ctx.nonce + '\'');
5554
}
5655
}
5756

58-
value = value.map(function(d) {
57+
values = values.map(function(d) {
5958
if (d.startsWith('.')) {
6059
d = '*' + d;
6160
}
6261
return d;
6362
});
64-
bufArray.push(key + ' ' + value.join(' '));
63+
bufArray.push(key + ' ' + values.join(' '));
6564
}
6665
}
6766
const headerString = bufArray.join(';');

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export interface SecurityConfig {
221221
*/
222222
enable: boolean;
223223
// https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#csp_overview
224-
policy: Record<string, string | string[]>;
224+
policy: Record<string, string | string[] | boolean>;
225225
/**
226226
* whether enable report only mode
227227
* Default to `undefined`

test/csp.test.js renamed to test/csp.test.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
1-
const { strict: assert } = require('node:assert');
2-
const mm = require('egg-mock');
1+
import { strict as assert } from 'node:assert';
2+
import { mm, MockApplication } from '@eggjs/mock';
33

4-
describe('test/csp.test.js', () => {
5-
let app;
6-
let app2;
7-
let app3;
8-
let app4;
4+
describe('test/csp.test.ts', () => {
5+
let app: MockApplication;
6+
let app2: MockApplication;
7+
let app3: MockApplication;
8+
let app4: MockApplication;
99
before(async () => {
1010
app = mm.app({
1111
baseDir: 'apps/csp',
12-
plugin: 'security',
1312
});
1413
await app.ready();
1514
app2 = mm.app({
1615
baseDir: 'apps/csp-ignore',
17-
plugin: 'security',
1816
});
1917
await app2.ready();
2018
app3 = mm.app({
2119
baseDir: 'apps/csp-reportonly',
22-
plugin: 'security',
2320
});
2421
await app3.ready();
2522
app4 = mm.app({
2623
baseDir: 'apps/csp-supportie',
27-
plugin: 'security',
2824
});
2925
await app4.ready();
3026
});
3127

28+
after(async () => {
29+
await app.close();
30+
await app2.close();
31+
await app3.close();
32+
await app4.close();
33+
});
34+
3235
afterEach(mm.restore);
3336

3437
describe('directives', () => {
@@ -84,9 +87,8 @@ describe('test/csp.test.js', () => {
8487
const nonce = res.text;
8588
const header = res.headers['content-security-policy'];
8689
const re_nonce = /nonce-([^']+)/;
87-
header.match(re_nonce, function(_, match) {
88-
assert.equal(nonce, match);
89-
});
90+
const m = re_nonce.exec(header);
91+
assert.equal(nonce, m![1], header);
9092
});
9193

9294
it('should have X-CSP-Nonce header', async () => {
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
'use strict';
2-
31
module.exports = function(app) {
4-
app.get('/testcsp', function *(){
2+
app.get('/testcsp', function(){
53
this.body = this.nonce;
64
});
7-
app.get('/testcsp2', function *(){
5+
app.get('/testcsp2', function(){
86
this.body = this.nonce;
97
});
108
};

test/fixtures/apps/csp-supportie/config/config.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use strict';
2-
31
exports.keys = 'test key';
42

53
exports.security = {

0 commit comments

Comments
 (0)