@zero-server/sdk 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +460 -437
- package/index.js +414 -412
- package/lib/app.js +1172 -1172
- package/lib/auth/authorize.js +399 -399
- package/lib/auth/enrollment.js +367 -367
- package/lib/auth/index.js +57 -57
- package/lib/auth/jwt.js +731 -731
- package/lib/auth/oauth.js +362 -362
- package/lib/auth/session.js +588 -588
- package/lib/auth/trustedDevice.js +409 -409
- package/lib/auth/twoFactor.js +1150 -1150
- package/lib/auth/webauthn.js +946 -946
- package/lib/body/index.js +14 -14
- package/lib/body/json.js +109 -109
- package/lib/body/multipart.js +440 -440
- package/lib/body/raw.js +71 -71
- package/lib/body/rawBuffer.js +160 -160
- package/lib/body/sendError.js +25 -25
- package/lib/body/text.js +75 -75
- package/lib/body/typeMatch.js +41 -41
- package/lib/body/urlencoded.js +235 -235
- package/lib/cli.js +845 -845
- package/lib/cluster.js +666 -666
- package/lib/debug.js +372 -372
- package/lib/env/index.js +460 -460
- package/lib/errors.js +683 -683
- package/lib/fetch/index.js +256 -256
- package/lib/grpc/balancer.js +378 -378
- package/lib/grpc/call.js +708 -708
- package/lib/grpc/client.js +764 -764
- package/lib/grpc/codec.js +1221 -1221
- package/lib/grpc/credentials.js +398 -398
- package/lib/grpc/frame.js +262 -262
- package/lib/grpc/health.js +287 -287
- package/lib/grpc/index.js +121 -121
- package/lib/grpc/metadata.js +461 -461
- package/lib/grpc/proto.js +821 -821
- package/lib/grpc/reflection.js +590 -590
- package/lib/grpc/server.js +445 -445
- package/lib/grpc/status.js +118 -118
- package/lib/grpc/watch.js +173 -173
- package/lib/http/index.js +10 -10
- package/lib/http/request.js +727 -727
- package/lib/http/response.js +799 -799
- package/lib/lifecycle.js +557 -557
- package/lib/middleware/compress.js +230 -230
- package/lib/middleware/cookieParser.js +237 -237
- package/lib/middleware/cors.js +93 -93
- package/lib/middleware/csrf.js +136 -136
- package/lib/middleware/errorHandler.js +101 -101
- package/lib/middleware/helmet.js +175 -175
- package/lib/middleware/index.js +19 -17
- package/lib/middleware/logger.js +74 -74
- package/lib/middleware/rateLimit.js +88 -88
- package/lib/middleware/requestId.js +53 -53
- package/lib/middleware/static.js +326 -326
- package/lib/middleware/timeout.js +71 -71
- package/lib/middleware/validator.js +254 -254
- package/lib/observe/health.js +326 -326
- package/lib/observe/index.js +50 -50
- package/lib/observe/logger.js +359 -359
- package/lib/observe/metrics.js +805 -805
- package/lib/observe/tracing.js +592 -592
- package/lib/orm/adapters/json.js +290 -290
- package/lib/orm/adapters/memory.js +764 -764
- package/lib/orm/adapters/mongo.js +764 -764
- package/lib/orm/adapters/mysql.js +933 -933
- package/lib/orm/adapters/postgres.js +1144 -1144
- package/lib/orm/adapters/redis.js +1534 -1534
- package/lib/orm/adapters/sql-base.js +212 -212
- package/lib/orm/adapters/sqlite.js +858 -858
- package/lib/orm/audit.js +649 -649
- package/lib/orm/cache.js +394 -394
- package/lib/orm/geo.js +387 -387
- package/lib/orm/index.js +784 -784
- package/lib/orm/migrate.js +432 -432
- package/lib/orm/model.js +1706 -1706
- package/lib/orm/plugin.js +375 -375
- package/lib/orm/procedures.js +836 -836
- package/lib/orm/profiler.js +233 -233
- package/lib/orm/query.js +1772 -1772
- package/lib/orm/replicas.js +241 -241
- package/lib/orm/schema.js +307 -307
- package/lib/orm/search.js +380 -380
- package/lib/orm/seed/data/commerce.js +136 -136
- package/lib/orm/seed/data/internet.js +111 -111
- package/lib/orm/seed/data/locations.js +204 -204
- package/lib/orm/seed/data/names.js +338 -338
- package/lib/orm/seed/data/person.js +128 -128
- package/lib/orm/seed/data/phone.js +211 -211
- package/lib/orm/seed/data/words.js +134 -134
- package/lib/orm/seed/factory.js +178 -178
- package/lib/orm/seed/fake.js +1186 -1186
- package/lib/orm/seed/index.js +18 -18
- package/lib/orm/seed/rng.js +70 -70
- package/lib/orm/seed/seeder.js +124 -124
- package/lib/orm/seed/unique.js +68 -68
- package/lib/orm/snapshot.js +366 -366
- package/lib/orm/tenancy.js +605 -605
- package/lib/orm/views.js +350 -350
- package/lib/router/index.js +436 -436
- package/lib/sse/index.js +8 -8
- package/lib/sse/stream.js +349 -349
- package/lib/ws/connection.js +451 -451
- package/lib/ws/handshake.js +125 -125
- package/lib/ws/index.js +14 -14
- package/lib/ws/room.js +223 -223
- package/package.json +73 -73
- package/types/app.d.ts +223 -223
- package/types/auth.d.ts +520 -520
- package/types/cluster.d.ts +75 -75
- package/types/env.d.ts +80 -80
- package/types/errors.d.ts +316 -316
- package/types/fetch.d.ts +43 -43
- package/types/grpc.d.ts +432 -432
- package/types/index.d.ts +384 -384
- package/types/lifecycle.d.ts +60 -60
- package/types/middleware.d.ts +320 -320
- package/types/observe.d.ts +304 -304
- package/types/orm.d.ts +1887 -1887
- package/types/request.d.ts +109 -109
- package/types/response.d.ts +157 -157
- package/types/router.d.ts +78 -78
- package/types/sse.d.ts +78 -78
- package/types/websocket.d.ts +126 -126
package/lib/middleware/helmet.js
CHANGED
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module helmet
|
|
3
|
-
* @description Security headers middleware.
|
|
4
|
-
* Sets common security-related HTTP response headers to help
|
|
5
|
-
* protect against well-known web vulnerabilities (XSS, clickjacking,
|
|
6
|
-
* MIME sniffing, etc.).
|
|
7
|
-
*
|
|
8
|
-
* Inspired by the `helmet` npm package but zero-dependency.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Create a security headers middleware.
|
|
13
|
-
*
|
|
1
|
+
/**
|
|
2
|
+
* @module helmet
|
|
3
|
+
* @description Security headers middleware.
|
|
4
|
+
* Sets common security-related HTTP response headers to help
|
|
5
|
+
* protect against well-known web vulnerabilities (XSS, clickjacking,
|
|
6
|
+
* MIME sniffing, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Inspired by the `helmet` npm package but zero-dependency.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create a security headers middleware.
|
|
13
|
+
*
|
|
14
14
|
* @param {object} [opts] - Configuration options.
|
|
15
|
-
* @param {object|false} [opts.contentSecurityPolicy] - CSP directive object or `false` to disable.
|
|
16
|
-
* @param {boolean} [opts.crossOriginEmbedderPolicy=false] - Set COEP header.
|
|
17
|
-
* @param {string|false} [opts.crossOriginOpenerPolicy='same-origin'] - COOP value.
|
|
18
|
-
* @param {string|false} [opts.crossOriginResourcePolicy='same-origin'] - CORP value.
|
|
19
|
-
* @param {boolean} [opts.dnsPrefetchControl=true] - Set X-DNS-Prefetch-Control: off.
|
|
20
|
-
* @param {string|false} [opts.frameguard='deny'] - X-Frame-Options value ('deny' | 'sameorigin').
|
|
21
|
-
* @param {boolean} [opts.hidePoweredBy=true] - Remove X-Powered-By header.
|
|
22
|
-
* @param {boolean|number}[opts.hsts=true] - Set Strict-Transport-Security.
|
|
23
|
-
* @param {number} [opts.hstsMaxAge=15552000] - HSTS max-age in seconds (default ~180 days).
|
|
24
|
-
* @param {boolean} [opts.hstsIncludeSubDomains=true] - HSTS includeSubDomains directive.
|
|
25
|
-
* @param {boolean} [opts.hstsPreload=false] - HSTS preload directive.
|
|
26
|
-
* @param {boolean} [opts.ieNoOpen=true] - Set X-Download-Options: noopen.
|
|
27
|
-
* @param {boolean} [opts.noSniff=true] - Set X-Content-Type-Options: nosniff.
|
|
28
|
-
* @param {string|false} [opts.permittedCrossDomainPolicies='none'] - X-Permitted-Cross-Domain-Policies.
|
|
29
|
-
* @param {string|false} [opts.referrerPolicy='no-referrer'] - Referrer-Policy value.
|
|
30
|
-
* @param {boolean} [opts.xssFilter=false] - Set X-XSS-Protection (legacy, off by default).
|
|
31
|
-
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* app.use(helmet());
|
|
35
|
-
* app.use(helmet({ frameguard: 'sameorigin', hsts: false }));
|
|
36
|
-
* app.use(helmet({
|
|
37
|
-
* contentSecurityPolicy: {
|
|
38
|
-
* directives: {
|
|
39
|
-
* defaultSrc: ["'self'"],
|
|
40
|
-
* scriptSrc: ["'self'", "'unsafe-inline'"],
|
|
41
|
-
* styleSrc: ["'self'", "'unsafe-inline'"],
|
|
42
|
-
* imgSrc: ["'self'", "data:", "https:"],
|
|
43
|
-
* }
|
|
44
|
-
* }
|
|
45
|
-
* }));
|
|
46
|
-
*/
|
|
47
|
-
function helmet(opts = {})
|
|
48
|
-
{
|
|
49
|
-
return (req, res, next) =>
|
|
50
|
-
{
|
|
51
|
-
const raw = res.raw || res;
|
|
52
|
-
|
|
53
|
-
// -- Content-Security-Policy --------------------
|
|
54
|
-
if (opts.contentSecurityPolicy !== false)
|
|
55
|
-
{
|
|
56
|
-
const csp = opts.contentSecurityPolicy || {};
|
|
57
|
-
const directives = csp.directives || {
|
|
58
|
-
defaultSrc: ["'self'"],
|
|
59
|
-
baseUri: ["'self'"],
|
|
60
|
-
fontSrc: ["'self'", 'https:', 'data:'],
|
|
61
|
-
formAction: ["'self'"],
|
|
62
|
-
frameAncestors: ["'self'"],
|
|
63
|
-
imgSrc: ["'self'", 'data:'],
|
|
64
|
-
objectSrc: ["'none'"],
|
|
65
|
-
scriptSrc: ["'self'"],
|
|
66
|
-
scriptSrcAttr: ["'none'"],
|
|
67
|
-
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
68
|
-
upgradeInsecureRequests: [],
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const cspString = Object.entries(directives)
|
|
72
|
-
.map(([key, values]) =>
|
|
73
|
-
{
|
|
74
|
-
const directive = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
75
|
-
if (Array.isArray(values) && values.length === 0) return directive;
|
|
76
|
-
return `${directive} ${Array.isArray(values) ? values.join(' ') : values}`;
|
|
77
|
-
})
|
|
78
|
-
.join('; ');
|
|
79
|
-
|
|
80
|
-
if (cspString)
|
|
81
|
-
{
|
|
82
|
-
try { raw.setHeader('Content-Security-Policy', cspString); } catch (e) { }
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// -- Cross-Origin-Embedder-Policy ---------------
|
|
87
|
-
if (opts.crossOriginEmbedderPolicy)
|
|
88
|
-
{
|
|
89
|
-
try { raw.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); } catch (e) { }
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// -- Cross-Origin-Opener-Policy -----------------
|
|
93
|
-
if (opts.crossOriginOpenerPolicy !== false)
|
|
94
|
-
{
|
|
95
|
-
const coop = opts.crossOriginOpenerPolicy || 'same-origin';
|
|
96
|
-
try { raw.setHeader('Cross-Origin-Opener-Policy', coop); } catch (e) { }
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// -- Cross-Origin-Resource-Policy ---------------
|
|
100
|
-
if (opts.crossOriginResourcePolicy !== false)
|
|
101
|
-
{
|
|
102
|
-
const corp = opts.crossOriginResourcePolicy || 'same-origin';
|
|
103
|
-
try { raw.setHeader('Cross-Origin-Resource-Policy', corp); } catch (e) { }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// -- DNS Prefetch Control -----------------------
|
|
107
|
-
if (opts.dnsPrefetchControl !== false)
|
|
108
|
-
{
|
|
109
|
-
try { raw.setHeader('X-DNS-Prefetch-Control', 'off'); } catch (e) { }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// -- Frameguard (X-Frame-Options) ---------------
|
|
113
|
-
if (opts.frameguard !== false)
|
|
114
|
-
{
|
|
115
|
-
const frame = (opts.frameguard || 'deny').toUpperCase();
|
|
116
|
-
try { raw.setHeader('X-Frame-Options', frame); } catch (e) { }
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// -- Hide X-Powered-By -------------------------
|
|
120
|
-
if (opts.hidePoweredBy !== false)
|
|
121
|
-
{
|
|
122
|
-
try { raw.removeHeader('X-Powered-By'); } catch (e) { }
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// -- HSTS ---------------------------------------
|
|
126
|
-
if (opts.hsts !== false)
|
|
127
|
-
{
|
|
128
|
-
const maxAge = opts.hstsMaxAge || 15552000;
|
|
129
|
-
let hstsValue = `max-age=${maxAge}`;
|
|
130
|
-
if (opts.hstsIncludeSubDomains !== false) hstsValue += '; includeSubDomains';
|
|
131
|
-
if (opts.hstsPreload) hstsValue += '; preload';
|
|
132
|
-
try { raw.setHeader('Strict-Transport-Security', hstsValue); } catch (e) { }
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// -- IE No Open --------------------------------
|
|
136
|
-
if (opts.ieNoOpen !== false)
|
|
137
|
-
{
|
|
138
|
-
try { raw.setHeader('X-Download-Options', 'noopen'); } catch (e) { }
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// -- No Sniff -----------------------------------
|
|
142
|
-
if (opts.noSniff !== false)
|
|
143
|
-
{
|
|
144
|
-
try { raw.setHeader('X-Content-Type-Options', 'nosniff'); } catch (e) { }
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// -- Permitted Cross Domain Policies ------------
|
|
148
|
-
if (opts.permittedCrossDomainPolicies !== false)
|
|
149
|
-
{
|
|
150
|
-
const pcdp = opts.permittedCrossDomainPolicies || 'none';
|
|
151
|
-
try { raw.setHeader('X-Permitted-Cross-Domain-Policies', pcdp); } catch (e) { }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// -- Referrer Policy ----------------------------
|
|
155
|
-
if (opts.referrerPolicy !== false)
|
|
156
|
-
{
|
|
157
|
-
const rp = opts.referrerPolicy || 'no-referrer';
|
|
158
|
-
try { raw.setHeader('Referrer-Policy', rp); } catch (e) { }
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// -- XSS Filter (legacy) -----------------------
|
|
162
|
-
if (opts.xssFilter)
|
|
163
|
-
{
|
|
164
|
-
try { raw.setHeader('X-XSS-Protection', '1; mode=block'); } catch (e) { }
|
|
165
|
-
}
|
|
166
|
-
else
|
|
167
|
-
{
|
|
168
|
-
// Modern best practice: disable legacy XSS auditor
|
|
169
|
-
try { raw.setHeader('X-XSS-Protection', '0'); } catch (e) { }
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
next();
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
module.exports = helmet;
|
|
15
|
+
* @param {object|false} [opts.contentSecurityPolicy] - CSP directive object or `false` to disable.
|
|
16
|
+
* @param {boolean} [opts.crossOriginEmbedderPolicy=false] - Set COEP header.
|
|
17
|
+
* @param {string|false} [opts.crossOriginOpenerPolicy='same-origin'] - COOP value.
|
|
18
|
+
* @param {string|false} [opts.crossOriginResourcePolicy='same-origin'] - CORP value.
|
|
19
|
+
* @param {boolean} [opts.dnsPrefetchControl=true] - Set X-DNS-Prefetch-Control: off.
|
|
20
|
+
* @param {string|false} [opts.frameguard='deny'] - X-Frame-Options value ('deny' | 'sameorigin').
|
|
21
|
+
* @param {boolean} [opts.hidePoweredBy=true] - Remove X-Powered-By header.
|
|
22
|
+
* @param {boolean|number}[opts.hsts=true] - Set Strict-Transport-Security.
|
|
23
|
+
* @param {number} [opts.hstsMaxAge=15552000] - HSTS max-age in seconds (default ~180 days).
|
|
24
|
+
* @param {boolean} [opts.hstsIncludeSubDomains=true] - HSTS includeSubDomains directive.
|
|
25
|
+
* @param {boolean} [opts.hstsPreload=false] - HSTS preload directive.
|
|
26
|
+
* @param {boolean} [opts.ieNoOpen=true] - Set X-Download-Options: noopen.
|
|
27
|
+
* @param {boolean} [opts.noSniff=true] - Set X-Content-Type-Options: nosniff.
|
|
28
|
+
* @param {string|false} [opts.permittedCrossDomainPolicies='none'] - X-Permitted-Cross-Domain-Policies.
|
|
29
|
+
* @param {string|false} [opts.referrerPolicy='no-referrer'] - Referrer-Policy value.
|
|
30
|
+
* @param {boolean} [opts.xssFilter=false] - Set X-XSS-Protection (legacy, off by default).
|
|
31
|
+
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* app.use(helmet());
|
|
35
|
+
* app.use(helmet({ frameguard: 'sameorigin', hsts: false }));
|
|
36
|
+
* app.use(helmet({
|
|
37
|
+
* contentSecurityPolicy: {
|
|
38
|
+
* directives: {
|
|
39
|
+
* defaultSrc: ["'self'"],
|
|
40
|
+
* scriptSrc: ["'self'", "'unsafe-inline'"],
|
|
41
|
+
* styleSrc: ["'self'", "'unsafe-inline'"],
|
|
42
|
+
* imgSrc: ["'self'", "data:", "https:"],
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* }));
|
|
46
|
+
*/
|
|
47
|
+
function helmet(opts = {})
|
|
48
|
+
{
|
|
49
|
+
return (req, res, next) =>
|
|
50
|
+
{
|
|
51
|
+
const raw = res.raw || res;
|
|
52
|
+
|
|
53
|
+
// -- Content-Security-Policy --------------------
|
|
54
|
+
if (opts.contentSecurityPolicy !== false)
|
|
55
|
+
{
|
|
56
|
+
const csp = opts.contentSecurityPolicy || {};
|
|
57
|
+
const directives = csp.directives || {
|
|
58
|
+
defaultSrc: ["'self'"],
|
|
59
|
+
baseUri: ["'self'"],
|
|
60
|
+
fontSrc: ["'self'", 'https:', 'data:'],
|
|
61
|
+
formAction: ["'self'"],
|
|
62
|
+
frameAncestors: ["'self'"],
|
|
63
|
+
imgSrc: ["'self'", 'data:'],
|
|
64
|
+
objectSrc: ["'none'"],
|
|
65
|
+
scriptSrc: ["'self'"],
|
|
66
|
+
scriptSrcAttr: ["'none'"],
|
|
67
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
68
|
+
upgradeInsecureRequests: [],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const cspString = Object.entries(directives)
|
|
72
|
+
.map(([key, values]) =>
|
|
73
|
+
{
|
|
74
|
+
const directive = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
75
|
+
if (Array.isArray(values) && values.length === 0) return directive;
|
|
76
|
+
return `${directive} ${Array.isArray(values) ? values.join(' ') : values}`;
|
|
77
|
+
})
|
|
78
|
+
.join('; ');
|
|
79
|
+
|
|
80
|
+
if (cspString)
|
|
81
|
+
{
|
|
82
|
+
try { raw.setHeader('Content-Security-Policy', cspString); } catch (e) { }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// -- Cross-Origin-Embedder-Policy ---------------
|
|
87
|
+
if (opts.crossOriginEmbedderPolicy)
|
|
88
|
+
{
|
|
89
|
+
try { raw.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); } catch (e) { }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// -- Cross-Origin-Opener-Policy -----------------
|
|
93
|
+
if (opts.crossOriginOpenerPolicy !== false)
|
|
94
|
+
{
|
|
95
|
+
const coop = opts.crossOriginOpenerPolicy || 'same-origin';
|
|
96
|
+
try { raw.setHeader('Cross-Origin-Opener-Policy', coop); } catch (e) { }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// -- Cross-Origin-Resource-Policy ---------------
|
|
100
|
+
if (opts.crossOriginResourcePolicy !== false)
|
|
101
|
+
{
|
|
102
|
+
const corp = opts.crossOriginResourcePolicy || 'same-origin';
|
|
103
|
+
try { raw.setHeader('Cross-Origin-Resource-Policy', corp); } catch (e) { }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// -- DNS Prefetch Control -----------------------
|
|
107
|
+
if (opts.dnsPrefetchControl !== false)
|
|
108
|
+
{
|
|
109
|
+
try { raw.setHeader('X-DNS-Prefetch-Control', 'off'); } catch (e) { }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// -- Frameguard (X-Frame-Options) ---------------
|
|
113
|
+
if (opts.frameguard !== false)
|
|
114
|
+
{
|
|
115
|
+
const frame = (opts.frameguard || 'deny').toUpperCase();
|
|
116
|
+
try { raw.setHeader('X-Frame-Options', frame); } catch (e) { }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// -- Hide X-Powered-By -------------------------
|
|
120
|
+
if (opts.hidePoweredBy !== false)
|
|
121
|
+
{
|
|
122
|
+
try { raw.removeHeader('X-Powered-By'); } catch (e) { }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// -- HSTS ---------------------------------------
|
|
126
|
+
if (opts.hsts !== false)
|
|
127
|
+
{
|
|
128
|
+
const maxAge = opts.hstsMaxAge || 15552000;
|
|
129
|
+
let hstsValue = `max-age=${maxAge}`;
|
|
130
|
+
if (opts.hstsIncludeSubDomains !== false) hstsValue += '; includeSubDomains';
|
|
131
|
+
if (opts.hstsPreload) hstsValue += '; preload';
|
|
132
|
+
try { raw.setHeader('Strict-Transport-Security', hstsValue); } catch (e) { }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// -- IE No Open --------------------------------
|
|
136
|
+
if (opts.ieNoOpen !== false)
|
|
137
|
+
{
|
|
138
|
+
try { raw.setHeader('X-Download-Options', 'noopen'); } catch (e) { }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// -- No Sniff -----------------------------------
|
|
142
|
+
if (opts.noSniff !== false)
|
|
143
|
+
{
|
|
144
|
+
try { raw.setHeader('X-Content-Type-Options', 'nosniff'); } catch (e) { }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// -- Permitted Cross Domain Policies ------------
|
|
148
|
+
if (opts.permittedCrossDomainPolicies !== false)
|
|
149
|
+
{
|
|
150
|
+
const pcdp = opts.permittedCrossDomainPolicies || 'none';
|
|
151
|
+
try { raw.setHeader('X-Permitted-Cross-Domain-Policies', pcdp); } catch (e) { }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// -- Referrer Policy ----------------------------
|
|
155
|
+
if (opts.referrerPolicy !== false)
|
|
156
|
+
{
|
|
157
|
+
const rp = opts.referrerPolicy || 'no-referrer';
|
|
158
|
+
try { raw.setHeader('Referrer-Policy', rp); } catch (e) { }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// -- XSS Filter (legacy) -----------------------
|
|
162
|
+
if (opts.xssFilter)
|
|
163
|
+
{
|
|
164
|
+
try { raw.setHeader('X-XSS-Protection', '1; mode=block'); } catch (e) { }
|
|
165
|
+
}
|
|
166
|
+
else
|
|
167
|
+
{
|
|
168
|
+
// Modern best practice: disable legacy XSS auditor
|
|
169
|
+
try { raw.setHeader('X-XSS-Protection', '0'); } catch (e) { }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
next();
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = helmet;
|
package/lib/middleware/index.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module middleware
|
|
3
|
-
* @description Built-in middleware for zero-server.
|
|
4
|
-
* Re-exports all middleware.
|
|
5
|
-
*/
|
|
6
|
-
const cors = require('./cors');
|
|
7
|
-
const logger = require('./logger');
|
|
8
|
-
const rateLimit = require('./rateLimit');
|
|
9
|
-
const compress = require('./compress');
|
|
10
|
-
const serveStatic = require('./static');
|
|
11
|
-
const helmet = require('./helmet');
|
|
12
|
-
const timeout = require('./timeout');
|
|
13
|
-
const requestId = require('./requestId');
|
|
14
|
-
const cookieParser = require('./cookieParser');
|
|
15
|
-
const errorHandler = require('./errorHandler');
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module middleware
|
|
3
|
+
* @description Built-in middleware for zero-server.
|
|
4
|
+
* Re-exports all middleware.
|
|
5
|
+
*/
|
|
6
|
+
const cors = require('./cors');
|
|
7
|
+
const logger = require('./logger');
|
|
8
|
+
const rateLimit = require('./rateLimit');
|
|
9
|
+
const compress = require('./compress');
|
|
10
|
+
const serveStatic = require('./static');
|
|
11
|
+
const helmet = require('./helmet');
|
|
12
|
+
const timeout = require('./timeout');
|
|
13
|
+
const requestId = require('./requestId');
|
|
14
|
+
const cookieParser = require('./cookieParser');
|
|
15
|
+
const errorHandler = require('./errorHandler');
|
|
16
|
+
const csrf = require('./csrf');
|
|
17
|
+
const validate = require('./validator');
|
|
18
|
+
|
|
19
|
+
module.exports = { cors, logger, rateLimit, compress, static: serveStatic, helmet, timeout, requestId, cookieParser, errorHandler, csrf, validate };
|
package/lib/middleware/logger.js
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module middleware/logger
|
|
3
|
-
* @description Simple request-logging middleware.
|
|
4
|
-
* Logs method, url, status code, and response time.
|
|
5
|
-
*
|
|
6
|
-
* @param {object} [opts] - Configuration options.
|
|
7
|
-
* @param {function} [opts.logger] - Custom log function (default: console.log).
|
|
8
|
-
* @param {boolean} [opts.colors] - Colorize output (default: true when TTY).
|
|
9
|
-
* @param {string} [opts.format] - 'tiny' | 'short' | 'dev' (default: 'dev').
|
|
10
|
-
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* app.use(logger()); // default 'dev' format
|
|
14
|
-
* app.use(logger({ format: 'tiny' })); // minimal output
|
|
15
|
-
* app.use(logger({ colors: false, logger: msg => fs.appendFileSync('access.log', msg + '\n') }));
|
|
16
|
-
*/
|
|
17
|
-
function logger(opts = {})
|
|
18
|
-
{
|
|
19
|
-
const log = typeof opts.logger === 'function' ? opts.logger : console.log;
|
|
20
|
-
const useColors = opts.colors !== undefined ? opts.colors : (process.stdout.isTTY || false);
|
|
21
|
-
const format = opts.format || 'dev';
|
|
22
|
-
|
|
23
|
-
// ANSI color helpers
|
|
24
|
-
const c = {
|
|
25
|
-
reset: useColors ? '\x1b[0m' : '',
|
|
26
|
-
green: useColors ? '\x1b[32m' : '',
|
|
27
|
-
yellow: useColors ? '\x1b[33m' : '',
|
|
28
|
-
red: useColors ? '\x1b[31m' : '',
|
|
29
|
-
cyan: useColors ? '\x1b[36m' : '',
|
|
30
|
-
dim: useColors ? '\x1b[2m' : '',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
function statusColor(code)
|
|
34
|
-
{
|
|
35
|
-
if (code >= 500) return c.red;
|
|
36
|
-
if (code >= 400) return c.yellow;
|
|
37
|
-
if (code >= 300) return c.cyan;
|
|
38
|
-
return c.green;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return (req, res, next) =>
|
|
42
|
-
{
|
|
43
|
-
const start = Date.now();
|
|
44
|
-
|
|
45
|
-
// Hook into the raw response 'finish' event
|
|
46
|
-
const raw = res.raw;
|
|
47
|
-
const onFinish = () =>
|
|
48
|
-
{
|
|
49
|
-
raw.removeListener('finish', onFinish);
|
|
50
|
-
const ms = Date.now() - start;
|
|
51
|
-
const status = raw.statusCode || res._status;
|
|
52
|
-
const sc = statusColor(status);
|
|
53
|
-
|
|
54
|
-
if (format === 'tiny')
|
|
55
|
-
{
|
|
56
|
-
log(`${req.method} ${req.url} ${status} - ${ms}ms`);
|
|
57
|
-
}
|
|
58
|
-
else if (format === 'short')
|
|
59
|
-
{
|
|
60
|
-
log(`${req.ip || '-'} ${req.method} ${req.url} ${sc}${status}${c.reset} ${ms}ms`);
|
|
61
|
-
}
|
|
62
|
-
else
|
|
63
|
-
{
|
|
64
|
-
// dev format
|
|
65
|
-
log(` ${c.dim}${req.method}${c.reset} ${req.url} ${sc}${status}${c.reset} ${c.dim}${ms}ms${c.reset}`);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
raw.on('finish', onFinish);
|
|
69
|
-
|
|
70
|
-
next();
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
module.exports = logger;
|
|
1
|
+
/**
|
|
2
|
+
* @module middleware/logger
|
|
3
|
+
* @description Simple request-logging middleware.
|
|
4
|
+
* Logs method, url, status code, and response time.
|
|
5
|
+
*
|
|
6
|
+
* @param {object} [opts] - Configuration options.
|
|
7
|
+
* @param {function} [opts.logger] - Custom log function (default: console.log).
|
|
8
|
+
* @param {boolean} [opts.colors] - Colorize output (default: true when TTY).
|
|
9
|
+
* @param {string} [opts.format] - 'tiny' | 'short' | 'dev' (default: 'dev').
|
|
10
|
+
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* app.use(logger()); // default 'dev' format
|
|
14
|
+
* app.use(logger({ format: 'tiny' })); // minimal output
|
|
15
|
+
* app.use(logger({ colors: false, logger: msg => fs.appendFileSync('access.log', msg + '\n') }));
|
|
16
|
+
*/
|
|
17
|
+
function logger(opts = {})
|
|
18
|
+
{
|
|
19
|
+
const log = typeof opts.logger === 'function' ? opts.logger : console.log;
|
|
20
|
+
const useColors = opts.colors !== undefined ? opts.colors : (process.stdout.isTTY || false);
|
|
21
|
+
const format = opts.format || 'dev';
|
|
22
|
+
|
|
23
|
+
// ANSI color helpers
|
|
24
|
+
const c = {
|
|
25
|
+
reset: useColors ? '\x1b[0m' : '',
|
|
26
|
+
green: useColors ? '\x1b[32m' : '',
|
|
27
|
+
yellow: useColors ? '\x1b[33m' : '',
|
|
28
|
+
red: useColors ? '\x1b[31m' : '',
|
|
29
|
+
cyan: useColors ? '\x1b[36m' : '',
|
|
30
|
+
dim: useColors ? '\x1b[2m' : '',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function statusColor(code)
|
|
34
|
+
{
|
|
35
|
+
if (code >= 500) return c.red;
|
|
36
|
+
if (code >= 400) return c.yellow;
|
|
37
|
+
if (code >= 300) return c.cyan;
|
|
38
|
+
return c.green;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (req, res, next) =>
|
|
42
|
+
{
|
|
43
|
+
const start = Date.now();
|
|
44
|
+
|
|
45
|
+
// Hook into the raw response 'finish' event
|
|
46
|
+
const raw = res.raw;
|
|
47
|
+
const onFinish = () =>
|
|
48
|
+
{
|
|
49
|
+
raw.removeListener('finish', onFinish);
|
|
50
|
+
const ms = Date.now() - start;
|
|
51
|
+
const status = raw.statusCode || res._status;
|
|
52
|
+
const sc = statusColor(status);
|
|
53
|
+
|
|
54
|
+
if (format === 'tiny')
|
|
55
|
+
{
|
|
56
|
+
log(`${req.method} ${req.url} ${status} - ${ms}ms`);
|
|
57
|
+
}
|
|
58
|
+
else if (format === 'short')
|
|
59
|
+
{
|
|
60
|
+
log(`${req.ip || '-'} ${req.method} ${req.url} ${sc}${status}${c.reset} ${ms}ms`);
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
{
|
|
64
|
+
// dev format
|
|
65
|
+
log(` ${c.dim}${req.method}${c.reset} ${req.url} ${sc}${status}${c.reset} ${c.dim}${ms}ms${c.reset}`);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
raw.on('finish', onFinish);
|
|
69
|
+
|
|
70
|
+
next();
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = logger;
|