mastercontroller 1.3.8 → 1.3.10
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/.claude/settings.local.json +4 -1
- package/FIXES_APPLIED.md +378 -0
- package/MasterAction.js +10 -263
- package/MasterControl.js +128 -27
- package/MasterRequest.js +6 -0
- package/MasterRouter.js +27 -32
- package/PERFORMANCE_SECURITY_AUDIT.md +677 -0
- package/README.md +117 -43
- package/monitoring/README.md +3112 -0
- package/package.json +1 -1
- package/security/README.md +1805 -0
- package/test-raw-body-preservation.js +128 -0
- package/MasterCors.js.tmp +0 -0
- package/MasterHtml.js +0 -649
- package/MasterPipeline.js.tmp +0 -0
- package/MasterRequest.js.tmp +0 -0
- package/MasterRouter.js.tmp +0 -0
- package/MasterSocket.js.tmp +0 -0
- package/MasterTemp.js.tmp +0 -0
- package/MasterTemplate.js +0 -230
- package/MasterTimeout.js.tmp +0 -0
- package/TemplateOverwrite.js +0 -41
- package/TemplateOverwrite.js.tmp +0 -0
- package/ssr/hydration-client.js +0 -93
- package/ssr/runtime-ssr.cjs +0 -553
- package/ssr/ssr-shims.js +0 -73
package/MasterTemplate.js
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
// version 0.0.5
|
|
2
|
-
// https://github.com/WebReflection/backtick-template
|
|
3
|
-
// https://stackoverflow.com/questions/29182244/convert-a-string-to-a-template-string
|
|
4
|
-
|
|
5
|
-
// Security - Template injection prevention
|
|
6
|
-
const { escapeHTML } = require('./security/MasterSanitizer');
|
|
7
|
-
const { logger } = require('./error/MasterErrorLogger');
|
|
8
|
-
|
|
9
|
-
var replace = ''.replace;
|
|
10
|
-
|
|
11
|
-
var ca = /[&<>'"]/g;
|
|
12
|
-
var es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
13
|
-
|
|
14
|
-
var esca = {
|
|
15
|
-
'&': '&',
|
|
16
|
-
'<': '<',
|
|
17
|
-
'>': '>',
|
|
18
|
-
"'": ''',
|
|
19
|
-
'"': '"'
|
|
20
|
-
};
|
|
21
|
-
var unes = {
|
|
22
|
-
'&': '&',
|
|
23
|
-
'&': '&',
|
|
24
|
-
'<': '<',
|
|
25
|
-
'<': '<',
|
|
26
|
-
'>': '>',
|
|
27
|
-
'>': '>',
|
|
28
|
-
''': "'",
|
|
29
|
-
''': "'",
|
|
30
|
-
'"': '"',
|
|
31
|
-
'"': '"'
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
class MasterTemplate{
|
|
35
|
-
|
|
36
|
-
_ = {};
|
|
37
|
-
$ = 0;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/*! (C) 2017-2018 Andrea Giammarchi - MIT Style License */
|
|
41
|
-
htmlBuilder( fn, $str, $object) {
|
|
42
|
-
'use strict';
|
|
43
|
-
|
|
44
|
-
try{
|
|
45
|
-
// reset cache every 32M
|
|
46
|
-
if (33554432 < this.$) {
|
|
47
|
-
this._ = {};
|
|
48
|
-
this.$ = 0;
|
|
49
|
-
}
|
|
50
|
-
var
|
|
51
|
-
hasTransformer = typeof fn === 'function',
|
|
52
|
-
str = hasTransformer ? $str : fn,
|
|
53
|
-
object = hasTransformer ? $object : $str,
|
|
54
|
-
_ = this._,
|
|
55
|
-
known = _.hasOwnProperty(str);
|
|
56
|
-
|
|
57
|
-
// Security: Validate template for dangerous patterns
|
|
58
|
-
if (!known) {
|
|
59
|
-
this.validateTemplate(str);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
var parsed = known ? _[str] : (_[str] = this.parse(str)),
|
|
63
|
-
chunks = parsed.chunks,
|
|
64
|
-
values = parsed.values,
|
|
65
|
-
strings
|
|
66
|
-
;
|
|
67
|
-
// add str length only if not known
|
|
68
|
-
if (!known)
|
|
69
|
-
this.$ += str.length;
|
|
70
|
-
if (hasTransformer) {
|
|
71
|
-
str = 'function' + (Math.random() * 1e5 | 0);
|
|
72
|
-
strings = [
|
|
73
|
-
str,
|
|
74
|
-
'with(this)return ' + str + '([' + chunks + ']' + (
|
|
75
|
-
values.length ? (',' + values.join(',')) : ''
|
|
76
|
-
) + ')'
|
|
77
|
-
];
|
|
78
|
-
} else {
|
|
79
|
-
strings = chunks.slice(0, 1);
|
|
80
|
-
for (var i = 1, length = chunks.length; i < length; i++)
|
|
81
|
-
strings.push(values[i - 1], chunks[i]);
|
|
82
|
-
strings = ['with(this)return ' + strings.join('+')];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return Function.apply(null, strings).apply(
|
|
86
|
-
object,
|
|
87
|
-
hasTransformer ? [fn] : []
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
catch(err){
|
|
91
|
-
console.log("error", err);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
parse(str) {
|
|
96
|
-
var
|
|
97
|
-
stringify = JSON.stringify,
|
|
98
|
-
open = 0, close = 0, counter = 0,
|
|
99
|
-
i = 0, length = str.length,
|
|
100
|
-
chunks = i < length ? [] : ['""'],
|
|
101
|
-
values = []
|
|
102
|
-
;
|
|
103
|
-
while (i < length) {
|
|
104
|
-
open = str.indexOf('${', i);
|
|
105
|
-
if (-1 < open) {
|
|
106
|
-
chunks.push(stringify(str.slice(i, open)));
|
|
107
|
-
open += 2;
|
|
108
|
-
close = open;
|
|
109
|
-
counter = 1;
|
|
110
|
-
while (close < length) {
|
|
111
|
-
switch (str.charAt(close++)) {
|
|
112
|
-
case '}': --counter; break;
|
|
113
|
-
case '{': ++counter; break;
|
|
114
|
-
}
|
|
115
|
-
if (counter < 1) {
|
|
116
|
-
values.push('(' + str.slice(open, close - 1) + ')');
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
i = close;
|
|
121
|
-
} else {
|
|
122
|
-
chunks.push(stringify(str.slice(i)));
|
|
123
|
-
i = length;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (chunks.length === values.length)
|
|
127
|
-
chunks.push('""');
|
|
128
|
-
return {chunks: chunks, values: values};
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
escape(es) {
|
|
132
|
-
return replace.call(es, ca, this.pe);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
unescape(un) {
|
|
136
|
-
return replace.call(un, es, this.cape);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
pe(m) {
|
|
140
|
-
return esca[m];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
cape(m) {
|
|
144
|
-
return unes[m];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ==================== Security Methods ====================
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Validate template for dangerous patterns
|
|
151
|
-
* Prevents template injection attacks
|
|
152
|
-
*/
|
|
153
|
-
validateTemplate(template) {
|
|
154
|
-
if (!template || typeof template !== 'string') {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.master === 'development';
|
|
159
|
-
|
|
160
|
-
// Dangerous patterns in templates
|
|
161
|
-
const dangerousPatterns = [
|
|
162
|
-
{ pattern: /\$\{.*__proto__/gi, name: 'Prototype pollution' },
|
|
163
|
-
{ pattern: /\$\{.*constructor.*\(/gi, name: 'Constructor access' },
|
|
164
|
-
{ pattern: /\$\{.*\beval\s*\(/gi, name: 'eval() usage' },
|
|
165
|
-
{ pattern: /\$\{.*Function\s*\(/gi, name: 'Function constructor' },
|
|
166
|
-
{ pattern: /\$\{.*require\s*\(/gi, name: 'require() usage' },
|
|
167
|
-
{ pattern: /\$\{.*import\s*\(/gi, name: 'import() usage' },
|
|
168
|
-
{ pattern: /\$\{.*process\./gi, name: 'Process access' },
|
|
169
|
-
{ pattern: /\$\{.*global\./gi, name: 'Global object access' },
|
|
170
|
-
{ pattern: /\$\{.*\bfs\./gi, name: 'File system access' },
|
|
171
|
-
{ pattern: /\$\{.*child_process/gi, name: 'Child process access' }
|
|
172
|
-
];
|
|
173
|
-
|
|
174
|
-
for (const { pattern, name } of dangerousPatterns) {
|
|
175
|
-
if (pattern.test(template)) {
|
|
176
|
-
logger.error({
|
|
177
|
-
code: 'MC_SECURITY_TEMPLATE_INJECTION',
|
|
178
|
-
message: `Dangerous template pattern detected: ${name}`,
|
|
179
|
-
pattern: pattern.toString(),
|
|
180
|
-
template: template.substring(0, 200) // Log first 200 chars only
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
if (isDevelopment) {
|
|
184
|
-
throw new Error(`[MasterController Security] Template injection attempt detected: ${name}\nPattern: ${pattern}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// In production, sanitize by removing the dangerous expression
|
|
188
|
-
template = template.replace(pattern, '${/* REMOVED: Security risk */}');
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return template;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Sanitize template variables before rendering
|
|
197
|
-
* Call this on user-provided data
|
|
198
|
-
*/
|
|
199
|
-
sanitizeVariable(value) {
|
|
200
|
-
if (value === null || value === undefined) {
|
|
201
|
-
return '';
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (typeof value === 'string') {
|
|
205
|
-
return escapeHTML(value);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (typeof value === 'object') {
|
|
209
|
-
// Prevent prototype pollution
|
|
210
|
-
if (value.__proto__ || value.constructor) {
|
|
211
|
-
logger.warn({
|
|
212
|
-
code: 'MC_SECURITY_OBJECT_POLLUTION',
|
|
213
|
-
message: 'Attempted to pass object with prototype/constructor to template'
|
|
214
|
-
});
|
|
215
|
-
return '[Object]';
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Safely stringify
|
|
219
|
-
try {
|
|
220
|
-
return JSON.stringify(value);
|
|
221
|
-
} catch (e) {
|
|
222
|
-
return '[Object]';
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return String(value);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
module.exports = MasterTemplate;
|
package/MasterTimeout.js.tmp
DELETED
|
File without changes
|
package/TemplateOverwrite.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// version 0.0.1
|
|
2
|
-
var master = require('mastercontroller');
|
|
3
|
-
|
|
4
|
-
class TemplateOverwrite{
|
|
5
|
-
|
|
6
|
-
#templateFunc;
|
|
7
|
-
#isTemplate = false;
|
|
8
|
-
|
|
9
|
-
// Lazy-load master to avoid circular dependency (Google-style lazy initialization)
|
|
10
|
-
get _master() {
|
|
11
|
-
if (!this.__masterCache) {
|
|
12
|
-
this.__masterCache = require('./MasterControl');
|
|
13
|
-
}
|
|
14
|
-
return this.__masterCache;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get isTemplate(){
|
|
18
|
-
return this.#isTemplate;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
template(func){
|
|
22
|
-
this.#isTemplate = true;
|
|
23
|
-
this.#templateFunc = func === undefined ? null : func;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
templateRender(data, type){
|
|
27
|
-
if(this.#templateFunc){
|
|
28
|
-
return this.#templateFunc(data, type);
|
|
29
|
-
}
|
|
30
|
-
else{
|
|
31
|
-
console.log("cannot call template render when no function has been declared. ")
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
close(response, code, content, end){
|
|
36
|
-
response.writeHead(code, content.type);
|
|
37
|
-
response.end(end);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = { TemplateOverwrite };
|
package/TemplateOverwrite.js.tmp
DELETED
|
File without changes
|
package/ssr/hydration-client.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MasterController Client-Side Hydration Runtime
|
|
3
|
-
* Handles error boundaries and hydration mismatch detection
|
|
4
|
-
* Version: 2.0.1
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Import error boundary
|
|
8
|
-
import { ErrorBoundary } from '../error/ErrorBoundary.js';
|
|
9
|
-
|
|
10
|
-
// Import hydration mismatch detection
|
|
11
|
-
const isDevelopment = window.location.hostname === 'localhost' ||
|
|
12
|
-
window.location.hostname === '127.0.0.1';
|
|
13
|
-
|
|
14
|
-
if (isDevelopment && typeof require !== 'undefined') {
|
|
15
|
-
try {
|
|
16
|
-
const { enableHydrationMismatchDetection } = require('../error/HydrationMismatch.js');
|
|
17
|
-
enableHydrationMismatchDetection({
|
|
18
|
-
verbose: localStorage.getItem('mc-hydration-debug') === 'true',
|
|
19
|
-
delay: 1000
|
|
20
|
-
});
|
|
21
|
-
} catch (e) {
|
|
22
|
-
console.warn('[MasterController] Could not load hydration mismatch detection:', e.message);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Auto-wrap app root with error boundary if not already wrapped
|
|
27
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
28
|
-
const appRoot = document.querySelector('root-layout') || document.body;
|
|
29
|
-
|
|
30
|
-
// Check if already wrapped
|
|
31
|
-
if (!appRoot.closest('error-boundary')) {
|
|
32
|
-
// Create error boundary wrapper
|
|
33
|
-
const boundary = document.createElement('error-boundary');
|
|
34
|
-
|
|
35
|
-
// Set development mode
|
|
36
|
-
if (isDevelopment) {
|
|
37
|
-
boundary.setAttribute('dev-mode', '');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Configure custom error handler
|
|
41
|
-
boundary.onError = (errorInfo) => {
|
|
42
|
-
console.error('[App Error]', errorInfo);
|
|
43
|
-
|
|
44
|
-
// Send to monitoring service if configured
|
|
45
|
-
if (window.masterControllerErrorReporter) {
|
|
46
|
-
window.masterControllerErrorReporter(errorInfo);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Wrap content
|
|
51
|
-
const parent = appRoot.parentNode;
|
|
52
|
-
parent.insertBefore(boundary, appRoot);
|
|
53
|
-
boundary.appendChild(appRoot);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Global error reporter hook
|
|
58
|
-
window.masterControllerErrorReporter = window.masterControllerErrorReporter || function(errorData) {
|
|
59
|
-
console.log('[MasterController] Error reported:', errorData);
|
|
60
|
-
|
|
61
|
-
// Example: Send to your monitoring service
|
|
62
|
-
// fetch('/api/errors', {
|
|
63
|
-
// method: 'POST',
|
|
64
|
-
// headers: { 'Content-Type': 'application/json' },
|
|
65
|
-
// body: JSON.stringify(errorData)
|
|
66
|
-
// });
|
|
67
|
-
|
|
68
|
-
// Example: Send to Sentry
|
|
69
|
-
// if (window.Sentry) {
|
|
70
|
-
// Sentry.captureException(new Error(errorData.message), {
|
|
71
|
-
// extra: errorData
|
|
72
|
-
// });
|
|
73
|
-
// }
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Log successful hydration
|
|
77
|
-
if (isDevelopment) {
|
|
78
|
-
window.addEventListener('load', () => {
|
|
79
|
-
const ssrElements = document.querySelectorAll('[data-ssr]');
|
|
80
|
-
if (ssrElements.length > 0) {
|
|
81
|
-
console.log(
|
|
82
|
-
`%c✓ MasterController Hydration Complete`,
|
|
83
|
-
'color: #10b981; font-weight: bold; font-size: 14px;'
|
|
84
|
-
);
|
|
85
|
-
console.log(` ${ssrElements.length} server-rendered components hydrated`);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Export for manual use
|
|
91
|
-
export {
|
|
92
|
-
ErrorBoundary
|
|
93
|
-
};
|