Skip to content

Commit

Permalink
refactor: use zod to parse config
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Jan 16, 2025
1 parent 42299f4 commit 34b539f
Show file tree
Hide file tree
Showing 12 changed files with 564 additions and 392 deletions.
84 changes: 84 additions & 0 deletions __snapshots__/config.default.test.ts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
exports['test/config/config.default.test.ts should config default values keep stable 1'] = {
"security": {
"domainWhiteList": [],
"protocolWhiteList": [],
"defaultMiddleware": [
"csrf",
"hsts",
"methodnoallow",
"noopen",
"nosniff",
"csp",
"xssProtection",
"xframe",
"dta"
],
"csrf": {
"enable": true,
"type": "ctoken",
"ignoreJSON": false,
"cookieName": "csrfToken",
"sessionName": "csrfToken",
"headerName": "x-csrf-token",
"bodyName": "_csrf",
"queryName": "_csrf",
"rotateWhenInvalid": false,
"useSession": false,
"supportedRequests": [
{
"path": {},
"methods": [
"POST",
"PATCH",
"DELETE",
"PUT",
"CONNECT"
]
}
],
"refererWhiteList": [],
"cookieOptions": {
"signed": false,
"httpOnly": false,
"overwrite": true
}
},
"xframe": {
"enable": true,
"value": "SAMEORIGIN"
},
"hsts": {
"enable": false,
"maxAge": 31536000,
"includeSubdomains": false
},
"methodnoallow": {
"enable": true
},
"noopen": {
"enable": true
},
"nosniff": {
"enable": true
},
"xssProtection": {
"enable": true,
"value": "1; mode=block"
},
"csp": {
"enable": false,
"policy": {}
},
"referrerPolicy": {
"enable": false,
"value": "no-referrer-when-downgrade"
},
"dta": {
"enable": true
},
"ssrf": {}
},
"helper": {
"shtml": {}
}
}
90 changes: 90 additions & 0 deletions __snapshots__/csp.test.ts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
exports['test/csp.test.ts should ignore path 1'] = {
"domainWhiteList": [],
"protocolWhiteList": [],
"defaultMiddleware": "csp",
"csrf": {
"enable": true,
"type": "ctoken",
"ignoreJSON": false,
"cookieName": "csrfToken",
"sessionName": "csrfToken",
"headerName": "x-csrf-token",
"bodyName": "_csrf",
"queryName": "_csrf",
"rotateWhenInvalid": false,
"useSession": false,
"supportedRequests": [
{
"path": {},
"methods": [
"POST",
"PATCH",
"DELETE",
"PUT",
"CONNECT"
]
}
],
"refererWhiteList": [],
"cookieOptions": {
"signed": false,
"httpOnly": false,
"overwrite": true
}
},
"xframe": {
"enable": true,
"value": "SAMEORIGIN"
},
"hsts": {
"enable": false,
"maxAge": 31536000,
"includeSubdomains": false
},
"methodnoallow": {
"enable": true
},
"noopen": {
"enable": true
},
"nosniff": {
"enable": true
},
"xssProtection": {
"enable": true,
"value": "1; mode=block"
},
"csp": {
"ignore": "/api/",
"enable": true,
"policy": {
"script-src": [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
"www.google-analytics.com"
],
"style-src": [
"'unsafe-inline'",
"www.google-analytics.com"
],
"img-src": [
"'self'",
"data:",
"www.google-analytics.com"
],
"frame-ancestors": [
"'self'"
],
"report-uri": "http://pointman.domain.com/csp?app=csp"
}
},
"referrerPolicy": {
"enable": false,
"value": "no-referrer-when-downgrade"
},
"dta": {
"enable": true
},
"ssrf": {}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"matcher": "^4.0.0",
"nanoid": "^3.3.8",
"type-is": "^1.6.18",
"xss": "^1.0.3"
"xss": "^1.0.3",
"zod": "^3.24.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.1",
Expand All @@ -66,6 +67,7 @@
"eslint": "8",
"eslint-config-egg": "14",
"rimraf": "6",
"snap-shot-it": "^7.9.10",
"spy": "^1.0.0",
"supertest": "^6.3.3",
"tshy": "3",
Expand Down
3 changes: 3 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import assert from 'node:assert';
import type { ILifecycleBoot, EggCore } from '@eggjs/core';
import { preprocessConfig } from './lib/utils.js';
import { SecurityConfig } from './config/config.default.js';

export default class AgentBoot implements ILifecycleBoot {
private readonly app;
Expand All @@ -24,6 +25,8 @@ export default class AgentBoot implements ILifecycleBoot {
'[@eggjs/security/ap] `config.security.csrf.type` must be one of ' + legalTypes.join(', '));
}

// parse config and check if config is legal
app.config.security = SecurityConfig.parse(app.config.security);
preprocessConfig(app.config.security);
}
}
14 changes: 7 additions & 7 deletions src/app/middleware/securities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import compose from 'koa-compose';
import { pathMatching } from 'egg-path-matching';
import { EggCore, MiddlewareFunc } from '@eggjs/core';
import securityMiddlewares from '../../lib/middlewares/index.js';
import type { SecurityMiddlewareName } from '../../config/config.default.js';

export default (_: unknown, app: EggCore) => {
const options = app.config.security;
const middlewares: MiddlewareFunc[] = [];
const defaultMiddleware = options.defaultMiddleware.split(',').map(m => m.trim()).filter(m => !!m);
const defaultMiddlewares = typeof options.defaultMiddleware === 'string'
? options.defaultMiddleware.split(',').map(m => m.trim()).filter(m => !!m) as SecurityMiddlewareName[]
: options.defaultMiddleware;

if (options.match || options.ignore) {
app.coreLogger.warn('[@eggjs/security/middleware/securities] Please set `match` or `ignore` on sub config');
Expand All @@ -19,8 +22,8 @@ export default (_: unknown, app: EggCore) => {
options.csrf.cookieDomain = () => originalCookieDomain;
}

defaultMiddleware.forEach(middlewareName => {
const opt = Reflect.get(options, middlewareName);
defaultMiddlewares.forEach(middlewareName => {
const opt = Reflect.get(options, middlewareName) as any;
if (opt === false) {
app.coreLogger.warn('[egg-security] Please use `config.security.%s = { enable: false }` instead of `config.security.%s = false`', middlewareName, middlewareName);
}
Expand Down Expand Up @@ -49,10 +52,7 @@ export default (_: unknown, app: EggCore) => {
opt.matching = pathMatching(opt);

const createMiddleware = securityMiddlewares[middlewareName];
if (!createMiddleware) {
throw new TypeError(`[@eggjs/security/middleware/securities] Can't find middleware ${middlewareName}`);
}
const fn = createMiddleware(opt, app);
const fn = createMiddleware(opt);
middlewares.push(fn);
app.coreLogger.info('[@eggjs/security/middleware/securities] use %s middleware', middlewareName);
});
Expand Down
Loading

0 comments on commit 34b539f

Please sign in to comment.