mastercontroller 1.2.11 → 1.2.13
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/CSPConfig.js +319 -0
- package/EventHandlerValidator.js +464 -0
- package/MasterAction.js +296 -72
- package/MasterBackendErrorHandler.js +769 -0
- package/MasterBenchmark.js +89 -0
- package/MasterBuildOptimizer.js +376 -0
- package/MasterBundleAnalyzer.js +108 -0
- package/MasterCache.js +400 -0
- package/MasterControl.js +77 -7
- package/MasterErrorHandler.js +487 -0
- package/MasterErrorLogger.js +360 -0
- package/MasterErrorMiddleware.js +407 -0
- package/MasterHtml.js +101 -14
- package/MasterMemoryMonitor.js +188 -0
- package/MasterProfiler.js +409 -0
- package/MasterRouter.js +273 -66
- package/MasterSanitizer.js +429 -0
- package/MasterTemplate.js +96 -3
- package/MasterValidator.js +546 -0
- package/README.md +0 -44
- package/SecurityMiddleware.js +486 -0
- package/SessionSecurity.js +416 -0
- package/package.json +2 -2
- package/ssr/ErrorBoundary.js +353 -0
- package/ssr/HTMLUtils.js +15 -0
- package/ssr/HydrationMismatch.js +265 -0
- package/ssr/PerformanceMonitor.js +233 -0
- package/ssr/SSRErrorHandler.js +273 -0
- package/ssr/hydration-client.js +93 -0
- package/ssr/runtime-ssr.cjs +553 -0
- package/ssr/ssr-shims.js +73 -0
- package/examples/FileServingExample.js +0 -88
package/CSPConfig.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// version 1.0.0
|
|
2
|
+
// MasterController Content Security Policy (CSP) Configuration
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Content Security Policy (CSP) configuration
|
|
6
|
+
* Helps prevent XSS, clickjacking, and other code injection attacks
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CSP Presets for different environments
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Development CSP - more relaxed for hot reload, dev tools
|
|
16
|
+
const DEVELOPMENT_CSP = {
|
|
17
|
+
'default-src': ["'self'"],
|
|
18
|
+
'script-src': ["'self'", "'unsafe-inline'", "'unsafe-eval'", "http://localhost:*", "ws://localhost:*"],
|
|
19
|
+
'style-src': ["'self'", "'unsafe-inline'"],
|
|
20
|
+
'img-src': ["'self'", 'data:', 'https:'],
|
|
21
|
+
'font-src': ["'self'", 'data:'],
|
|
22
|
+
'connect-src': ["'self'", 'http://localhost:*', 'ws://localhost:*'],
|
|
23
|
+
'media-src': ["'self'"],
|
|
24
|
+
'object-src': ["'none'"],
|
|
25
|
+
'frame-src': ["'self'"],
|
|
26
|
+
'base-uri': ["'self'"],
|
|
27
|
+
'form-action': ["'self'"],
|
|
28
|
+
'frame-ancestors': ["'self'"]
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Production CSP - strict security
|
|
32
|
+
const PRODUCTION_CSP = {
|
|
33
|
+
'default-src': ["'self'"],
|
|
34
|
+
'script-src': ["'self'"],
|
|
35
|
+
'style-src': ["'self'"],
|
|
36
|
+
'img-src': ["'self'", 'data:', 'https:'],
|
|
37
|
+
'font-src': ["'self'"],
|
|
38
|
+
'connect-src': ["'self'"],
|
|
39
|
+
'media-src': ["'self'"],
|
|
40
|
+
'object-src': ["'none'"],
|
|
41
|
+
'frame-src': ["'none'"],
|
|
42
|
+
'base-uri': ["'self'"],
|
|
43
|
+
'form-action': ["'self'"],
|
|
44
|
+
'frame-ancestors': ["'none'"],
|
|
45
|
+
'upgrade-insecure-requests': []
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Production with CDN support
|
|
49
|
+
const PRODUCTION_CDN_CSP = {
|
|
50
|
+
'default-src': ["'self'"],
|
|
51
|
+
'script-src': ["'self'", 'https://cdn.jsdelivr.net', 'https://unpkg.com'],
|
|
52
|
+
'style-src': ["'self'", 'https://cdn.jsdelivr.net', 'https://unpkg.com'],
|
|
53
|
+
'img-src': ["'self'", 'data:', 'https:'],
|
|
54
|
+
'font-src': ["'self'", 'https://cdn.jsdelivr.net', 'https://fonts.gstatic.com'],
|
|
55
|
+
'connect-src': ["'self'", 'https://*.sentry.io'],
|
|
56
|
+
'media-src': ["'self'"],
|
|
57
|
+
'object-src': ["'none'"],
|
|
58
|
+
'frame-src': ["'none'"],
|
|
59
|
+
'base-uri': ["'self'"],
|
|
60
|
+
'form-action': ["'self'"],
|
|
61
|
+
'frame-ancestors': ["'none'"],
|
|
62
|
+
'upgrade-insecure-requests': []
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
class CSPConfig {
|
|
66
|
+
constructor(options = {}) {
|
|
67
|
+
this.enabled = options.enabled !== false;
|
|
68
|
+
this.reportOnly = options.reportOnly || false;
|
|
69
|
+
this.reportUri = options.reportUri || null;
|
|
70
|
+
this.useNonce = options.useNonce || false;
|
|
71
|
+
this.useHash = options.useHash || false;
|
|
72
|
+
|
|
73
|
+
// Start with preset based on environment
|
|
74
|
+
const env = process.env.NODE_ENV || 'development';
|
|
75
|
+
let preset;
|
|
76
|
+
|
|
77
|
+
if (options.preset === 'production-cdn') {
|
|
78
|
+
preset = PRODUCTION_CDN_CSP;
|
|
79
|
+
} else if (env === 'production') {
|
|
80
|
+
preset = PRODUCTION_CSP;
|
|
81
|
+
} else {
|
|
82
|
+
preset = DEVELOPMENT_CSP;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Merge custom directives with preset
|
|
86
|
+
this.directives = { ...preset, ...options.directives };
|
|
87
|
+
|
|
88
|
+
// Nonce store (cleared per request)
|
|
89
|
+
this.currentNonce = null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate CSP header middleware
|
|
94
|
+
*/
|
|
95
|
+
middleware() {
|
|
96
|
+
return (req, res, next) => {
|
|
97
|
+
if (!this.enabled) {
|
|
98
|
+
return next();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Generate nonce for this request if needed
|
|
102
|
+
if (this.useNonce) {
|
|
103
|
+
this.currentNonce = this._generateNonce();
|
|
104
|
+
req.cspNonce = this.currentNonce;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Build CSP header
|
|
108
|
+
const headerValue = this.buildHeader(req);
|
|
109
|
+
|
|
110
|
+
// Set header
|
|
111
|
+
const headerName = this.reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy';
|
|
112
|
+
res.setHeader(headerName, headerValue);
|
|
113
|
+
|
|
114
|
+
next();
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Build CSP header value
|
|
120
|
+
*/
|
|
121
|
+
buildHeader(req = null) {
|
|
122
|
+
const directives = [];
|
|
123
|
+
|
|
124
|
+
for (const [directive, values] of Object.entries(this.directives)) {
|
|
125
|
+
if (!values || values.length === 0) {
|
|
126
|
+
// Directive with no value (e.g., upgrade-insecure-requests)
|
|
127
|
+
directives.push(directive);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let sources = [...values];
|
|
132
|
+
|
|
133
|
+
// Add nonce to script-src and style-src if enabled
|
|
134
|
+
if (this.useNonce && this.currentNonce && (directive === 'script-src' || directive === 'style-src')) {
|
|
135
|
+
sources.push(`'nonce-${this.currentNonce}'`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
directives.push(`${directive} ${sources.join(' ')}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Add report-uri if configured
|
|
142
|
+
if (this.reportUri) {
|
|
143
|
+
directives.push(`report-uri ${this.reportUri}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return directives.join('; ');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate nonce for inline scripts/styles
|
|
151
|
+
*/
|
|
152
|
+
_generateNonce() {
|
|
153
|
+
return crypto.randomBytes(16).toString('base64');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get current nonce (for use in templates)
|
|
158
|
+
*/
|
|
159
|
+
getNonce() {
|
|
160
|
+
return this.currentNonce;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Add source to directive
|
|
165
|
+
*/
|
|
166
|
+
addSource(directive, source) {
|
|
167
|
+
if (!this.directives[directive]) {
|
|
168
|
+
this.directives[directive] = [];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!this.directives[directive].includes(source)) {
|
|
172
|
+
this.directives[directive].push(source);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Remove source from directive
|
|
178
|
+
*/
|
|
179
|
+
removeSource(directive, source) {
|
|
180
|
+
if (!this.directives[directive]) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const index = this.directives[directive].indexOf(source);
|
|
185
|
+
if (index > -1) {
|
|
186
|
+
this.directives[directive].splice(index, 1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Set entire directive
|
|
192
|
+
*/
|
|
193
|
+
setDirective(directive, sources) {
|
|
194
|
+
this.directives[directive] = Array.isArray(sources) ? sources : [sources];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Remove directive
|
|
199
|
+
*/
|
|
200
|
+
removeDirective(directive) {
|
|
201
|
+
delete this.directives[directive];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generate hash for inline script/style
|
|
206
|
+
* Use this to allow specific inline scripts without 'unsafe-inline'
|
|
207
|
+
*/
|
|
208
|
+
generateHash(content, algorithm = 'sha256') {
|
|
209
|
+
const hash = crypto.createHash(algorithm).update(content).digest('base64');
|
|
210
|
+
return `'${algorithm}-${hash}'`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Helper to create nonce attribute for templates
|
|
215
|
+
*/
|
|
216
|
+
nonceAttr() {
|
|
217
|
+
return this.currentNonce ? ` nonce="${this.currentNonce}"` : '';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Enable/disable specific features
|
|
222
|
+
*/
|
|
223
|
+
allowInlineScripts() {
|
|
224
|
+
this.addSource('script-src', "'unsafe-inline'");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
allowInlineStyles() {
|
|
228
|
+
this.addSource('style-src', "'unsafe-inline'");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
allowEval() {
|
|
232
|
+
this.addSource('script-src', "'unsafe-eval'");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
allowFraming(sources = ["'self'"]) {
|
|
236
|
+
this.setDirective('frame-ancestors', sources);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
allowForms(sources = ["'self'"]) {
|
|
240
|
+
this.setDirective('form-action', sources);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Add monitoring/analytics services
|
|
245
|
+
*/
|
|
246
|
+
allowGoogleAnalytics() {
|
|
247
|
+
this.addSource('script-src', 'https://www.google-analytics.com');
|
|
248
|
+
this.addSource('connect-src', 'https://www.google-analytics.com');
|
|
249
|
+
this.addSource('img-src', 'https://www.google-analytics.com');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
allowSentry() {
|
|
253
|
+
this.addSource('script-src', 'https://browser.sentry-cdn.com');
|
|
254
|
+
this.addSource('connect-src', 'https://*.sentry.io');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
allowStripe() {
|
|
258
|
+
this.addSource('script-src', 'https://js.stripe.com');
|
|
259
|
+
this.addSource('frame-src', 'https://js.stripe.com');
|
|
260
|
+
this.addSource('connect-src', 'https://api.stripe.com');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get CSP configuration for debugging
|
|
265
|
+
*/
|
|
266
|
+
getConfig() {
|
|
267
|
+
return {
|
|
268
|
+
enabled: this.enabled,
|
|
269
|
+
reportOnly: this.reportOnly,
|
|
270
|
+
reportUri: this.reportUri,
|
|
271
|
+
useNonce: this.useNonce,
|
|
272
|
+
directives: this.directives
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Create CSP with common configurations
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
function createDevelopmentCSP() {
|
|
282
|
+
return new CSPConfig({
|
|
283
|
+
preset: 'development',
|
|
284
|
+
reportOnly: true
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function createProductionCSP(options = {}) {
|
|
289
|
+
return new CSPConfig({
|
|
290
|
+
preset: 'production',
|
|
291
|
+
reportOnly: false,
|
|
292
|
+
useNonce: true,
|
|
293
|
+
...options
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function createProductionCDNCSP(options = {}) {
|
|
298
|
+
return new CSPConfig({
|
|
299
|
+
preset: 'production-cdn',
|
|
300
|
+
reportOnly: false,
|
|
301
|
+
useNonce: true,
|
|
302
|
+
...options
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Create singleton instance based on environment
|
|
307
|
+
const env = process.env.NODE_ENV || 'development';
|
|
308
|
+
const csp = env === 'production' ? createProductionCSP() : createDevelopmentCSP();
|
|
309
|
+
|
|
310
|
+
module.exports = {
|
|
311
|
+
CSPConfig,
|
|
312
|
+
csp,
|
|
313
|
+
createDevelopmentCSP,
|
|
314
|
+
createProductionCSP,
|
|
315
|
+
createProductionCDNCSP,
|
|
316
|
+
DEVELOPMENT_CSP,
|
|
317
|
+
PRODUCTION_CSP,
|
|
318
|
+
PRODUCTION_CDN_CSP
|
|
319
|
+
};
|