mastercontroller 1.3.1 → 1.3.3

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/MasterHtml.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // version 0.0.25
2
2
 
3
- var master = require('./MasterControl');
4
3
  var fs = require('fs');
5
4
  var tempClass = require('./MasterTemplate');
6
5
  var toolClass = require('./MasterTools');
@@ -17,15 +16,41 @@ const { sanitizeTemplateHTML, sanitizeUserHTML, escapeHTML } = require('./securi
17
16
 
18
17
  class html {
19
18
 
19
+ // Lazy-load master to avoid circular dependency (Google-style lazy initialization)
20
+ get _master() {
21
+ if (!this.__masterCache) {
22
+ this.__masterCache = require('./MasterControl');
23
+ }
24
+ return this.__masterCache;
25
+ }
26
+
20
27
  javaScriptSerializer(name, obj){
28
+ // SECURITY: Escape closing script tags and dangerous characters
29
+ const jsonStr = JSON.stringify(obj)
30
+ .replace(/</g, '\\u003c')
31
+ .replace(/>/g, '\\u003e')
32
+ .replace(/&/g, '\\u0026')
33
+ .replace(/\u2028/g, '\\u2028')
34
+ .replace(/\u2029/g, '\\u2029');
35
+
21
36
  return `<script type="text/javascript">
22
- ${name} = ${JSON.stringify(obj)}
37
+ ${escapeHTML(name)} = ${jsonStr}
23
38
  </script>`;
24
39
  }
25
40
 
26
41
  // render partial views
27
42
  renderPartial(path, data){
28
43
  try {
44
+ // SECURITY: Validate path to prevent traversal attacks
45
+ if (!path || path.includes('..') || path.includes('~') || path.startsWith('/')) {
46
+ logger.warn({
47
+ code: 'MC_SECURITY_PATH_TRAVERSAL',
48
+ message: 'Path traversal attempt blocked in renderPartial',
49
+ path: path
50
+ });
51
+ return '<!-- Invalid path -->';
52
+ }
53
+
29
54
  var partialViewUrl = `/app/views/${path}`;
30
55
  var fullPath = master.router.currentRoute.root + partialViewUrl;
31
56
 
@@ -64,6 +89,16 @@ class html {
64
89
 
65
90
  // render all your link tags styles given the folder location
66
91
  renderStyles(folderName, typeArray){
92
+ // SECURITY: Validate folder name to prevent path traversal
93
+ if (folderName && (folderName.includes('..') || folderName.includes('~') || folderName.startsWith('/'))) {
94
+ logger.warn({
95
+ code: 'MC_SECURITY_PATH_TRAVERSAL',
96
+ message: 'Path traversal attempt blocked in renderStyles',
97
+ folderName: folderName
98
+ });
99
+ return '';
100
+ }
101
+
67
102
  var styles = [];
68
103
  var styleFolder = `/app/assets/stylesheets/`;
69
104
  var rootLocation = master.router.currentRoute.root;
@@ -108,6 +143,15 @@ class html {
108
143
 
109
144
  // renders all scripts in main folder or folder location inside of javascript also its type specific if you provide type
110
145
  renderScripts(folderName, typeArray){
146
+ // SECURITY: Validate folder name to prevent path traversal
147
+ if (folderName && (folderName.includes('..') || folderName.includes('~') || folderName.startsWith('/'))) {
148
+ logger.warn({
149
+ code: 'MC_SECURITY_PATH_TRAVERSAL',
150
+ message: 'Path traversal attempt blocked in renderScripts',
151
+ folderName: folderName
152
+ });
153
+ return '';
154
+ }
111
155
 
112
156
  var scripts = [];
113
157
  var jsFolder =`/app/assets/javascripts/`;
@@ -193,38 +237,46 @@ class html {
193
237
 
194
238
  // return link tag
195
239
  linkTo(name, location){
196
- return'<a href=' + location + '>' + name + '</a>';
240
+ const safeName = escapeHTML(String(name));
241
+ const safeLocation = escapeHTML(String(location));
242
+ return `<a href="${safeLocation}">${safeName}</a>`;
197
243
  }
198
244
 
199
245
  // return image tag
200
246
  imgTag(alt, location){
201
- return '<img src=' + location + ' alt='+ alt +'>';
247
+ const safeAlt = escapeHTML(String(alt));
248
+ const safeLocation = escapeHTML(String(location));
249
+ return `<img src="${safeLocation}" alt="${safeAlt}">`;
202
250
  }
203
251
 
204
252
  // return text are tag
205
253
  textAreaTag(name, message, obj){
206
-
207
- var textArea = "<textarea name='" + name + "'";
208
- for (var key in obj) {
209
- if (obj.hasOwnProperty(key)) {
210
- textArea = textArea + " " + key + "=" + "'" + obj[key] + "'";
211
- }
212
- };
254
+ const safeName = escapeHTML(String(name));
255
+ const safeMessage = escapeHTML(String(message));
256
+
257
+ let textArea = `<textarea name="${safeName}"`;
258
+
259
+ for (const [key, value] of Object.entries(obj || {})) {
260
+ const safeKey = escapeHTML(String(key));
261
+ const safeValue = escapeHTML(String(value));
262
+ textArea += ` ${safeKey}="${safeValue}"`;
263
+ }
213
264
 
214
- textArea = textArea + "/>" + message + "</textarea>";
265
+ textArea += `>${safeMessage}</textarea>`;
215
266
 
216
267
  return textArea;
217
268
  }
218
269
 
219
270
  // form element builder starter
220
271
  formTag(location, obj){
221
- var form = "<form action='" + location + "'" ;
272
+ const safeLocation = escapeHTML(String(location));
273
+ let form = `<form action="${safeLocation}"`;
222
274
 
223
- for (var key in obj) {
224
- if (obj.hasOwnProperty(key)) {
225
- form = form + " " + key + "=" + "'" + obj[key] + "'";
226
- }
227
- };
275
+ for (const [key, value] of Object.entries(obj || {})) {
276
+ const safeKey = escapeHTML(String(key));
277
+ const safeValue = escapeHTML(String(value));
278
+ form += ` ${safeKey}="${safeValue}"`;
279
+ }
228
280
 
229
281
  return form + ">";
230
282
  }
@@ -235,90 +287,102 @@ class html {
235
287
  }
236
288
  // return text tag
237
289
  passwordFieldTag(name, obj){
238
- var passwordField = "<input type='password' name='" + name + "'";
290
+ const safeName = escapeHTML(String(name));
291
+ let passwordField = `<input type="password" name="${safeName}"`;
239
292
 
240
- for (var key in obj) {
241
- if (obj.hasOwnProperty(key)) {
242
- passwordField = passwordField + " " + key + "=" + "'" + obj[key] + "'";
243
- }
244
- };
245
- passwordField = passwordField + '/>';
293
+ for (const [key, value] of Object.entries(obj || {})) {
294
+ const safeKey = escapeHTML(String(key));
295
+ const safeValue = escapeHTML(String(value));
296
+ passwordField += ` ${safeKey}="${safeValue}"`;
297
+ }
298
+
299
+ passwordField += '/>';
246
300
 
247
301
  return passwordField;
248
302
  }
249
-
303
+
250
304
  // return password field tag
251
305
  textFieldTag(name, obj){
252
- var textField = "<input type='text' name='" + name + "'";
306
+ const safeName = escapeHTML(String(name));
307
+ let textField = `<input type="text" name="${safeName}"`;
253
308
 
254
- for (var key in obj) {
255
- if (obj.hasOwnProperty(key)) {
256
- textField = textField + " " + key + "=" + "'" + obj[key] + "'";
257
- }
258
- };
259
- textField = textField + '/>';
309
+ for (const [key, value] of Object.entries(obj || {})) {
310
+ const safeKey = escapeHTML(String(key));
311
+ const safeValue = escapeHTML(String(value));
312
+ textField += ` ${safeKey}="${safeValue}"`;
313
+ }
314
+
315
+ textField += '/>';
260
316
  return textField;
261
317
  };
262
318
 
263
319
  // hidden field tag
264
320
  hiddenFieldTag(name, value, obj){
265
-
266
- var hiddenField = "<input type='hidden' name='" + name + "' value='" + value + "'";
321
+ const safeName = escapeHTML(String(name));
322
+ const safeValue = escapeHTML(String(value));
323
+
324
+ let hiddenField = `<input type="hidden" name="${safeName}" value="${safeValue}"`;
325
+
326
+ for (const [key, val] of Object.entries(obj || {})) {
327
+ const safeKey = escapeHTML(String(key));
328
+ const safeVal = escapeHTML(String(val));
329
+ hiddenField += ` ${safeKey}="${safeVal}"`;
330
+ }
331
+
332
+ hiddenField += '/>';
267
333
 
268
- for (var key in obj) {
269
- if (obj.hasOwnProperty(key)) {
270
- hiddenField = hiddenField + " " + key + "=" + "'" + obj[key] + "'";
271
- }
272
- };
273
- hiddenField = hiddenField + '/>';
274
-
275
334
  return hiddenField;
276
335
 
277
336
  }
278
337
 
279
338
  // subit tag
280
339
  submitButton(name, obj){
281
-
282
- var submitButton = "<button type='submit' name='" + name + "'";
340
+ const safeName = escapeHTML(String(name));
283
341
 
284
- for (var key in obj) {
285
- if (obj.hasOwnProperty(key)) {
286
- submitButton = submitButton + " " + key + "=" + "'" + obj[key] + "'";
287
- }
288
- };
342
+ let submitButton = `<button type="submit" name="${safeName}"`;
343
+
344
+ for (const [key, value] of Object.entries(obj || {})) {
345
+ const safeKey = escapeHTML(String(key));
346
+ const safeValue = escapeHTML(String(value));
347
+ submitButton += ` ${safeKey}="${safeValue}"`;
348
+ }
349
+
350
+ submitButton += `>${safeName}</button>`;
289
351
 
290
- submitButton = submitButton + ">" + name +'</button>';
291
-
292
352
  return submitButton;
293
353
 
294
354
  }
295
355
 
296
356
  // search tag
297
357
  searchField(name, obj){
298
-
299
- var searchField = "<input type='search' name='" + name + "'";
358
+ const safeName = escapeHTML(String(name));
359
+
360
+ let searchField = `<input type="search" name="${safeName}"`;
361
+
362
+ for (const [key, value] of Object.entries(obj || {})) {
363
+ const safeKey = escapeHTML(String(key));
364
+ const safeValue = escapeHTML(String(value));
365
+ searchField += ` ${safeKey}="${safeValue}"`;
366
+ }
367
+
368
+ searchField += '/>';
300
369
 
301
- for (var key in obj) {
302
- if (obj.hasOwnProperty(key)) {
303
- searchField = searchField + " " + key + "=" + "'" + obj[key] + "'";
304
- }
305
- };
306
- searchField = searchField + '/>';
307
-
308
370
  return searchField;
309
371
  }
310
372
 
311
373
  // telephone field tag
312
374
  telephoneField(name, obj){
375
+ const safeName = escapeHTML(String(name));
313
376
 
314
- var telephoneField = "<input type='tel' name='" + name + "'";
377
+ let telephoneField = `<input type="tel" name="${safeName}"`;
315
378
 
316
- for (var key in obj) {
317
- if (obj.hasOwnProperty(key)) {
318
- telephoneField = telephoneField + " " + key + "=" + "'" + obj[key] + "'";
319
- }
320
- };
321
- telephoneField = telephoneField + '/>';
379
+ for (const [key, value] of Object.entries(obj || {})) {
380
+ const safeKey = escapeHTML(String(key));
381
+ const safeValue = escapeHTML(String(value));
382
+ telephoneField += ` ${safeKey}="${safeValue}"`;
383
+ }
384
+
385
+ telephoneField += '/>';
322
386
 
323
387
  return telephoneField;
324
388
 
@@ -326,75 +390,85 @@ class html {
326
390
 
327
391
  // date field tag
328
392
  dateField(name, obj){
393
+ const safeName = escapeHTML(String(name));
329
394
 
330
- var dateField = "<input type='date' name='" + name + "'";
395
+ let dateField = `<input type="date" name="${safeName}"`;
331
396
 
332
- for (var key in obj) {
333
- if (obj.hasOwnProperty(key)) {
334
- dateField = dateField + " " + key + "=" + "'" + obj[key] + "'";
335
- }
336
- };
337
- dateField = dateField + '/>';
397
+ for (const [key, value] of Object.entries(obj || {})) {
398
+ const safeKey = escapeHTML(String(key));
399
+ const safeValue = escapeHTML(String(value));
400
+ dateField += ` ${safeKey}="${safeValue}"`;
401
+ }
402
+
403
+ dateField += '/>';
338
404
 
339
405
  return dateField;
340
406
  }
341
407
 
342
408
  // date time local field tag
343
409
  datetimeLocalField(name, obj){
410
+ const safeName = escapeHTML(String(name));
344
411
 
345
- var datetimeLocalField = "<input type='datetime-local' name='" + name + "' ";
412
+ let datetimeLocalField = `<input type="datetime-local" name="${safeName}"`;
346
413
 
347
- for (var key in obj) {
348
- if (obj.hasOwnProperty(key)) {
349
- datetimeLocalField = datetimeLocalField + " " + key + "=" + "'" + obj[key] + "'";
350
- }
351
- };
352
- datetimeLocalField = datetimeLocalField + '/>';
414
+ for (const [key, value] of Object.entries(obj || {})) {
415
+ const safeKey = escapeHTML(String(key));
416
+ const safeValue = escapeHTML(String(value));
417
+ datetimeLocalField += ` ${safeKey}="${safeValue}"`;
418
+ }
419
+
420
+ datetimeLocalField += '/>';
353
421
 
354
422
  return datetimeLocalField;
355
423
  }
356
424
 
357
425
  // date month field tag
358
426
  monthField(name, obj){
427
+ const safeName = escapeHTML(String(name));
359
428
 
360
- var monthField = "<input type='month' name='" + name + "' ";
429
+ let monthField = `<input type="month" name="${safeName}"`;
361
430
 
362
- for (var key in obj) {
363
- if (obj.hasOwnProperty(key)) {
364
- monthField = monthField + " " + key + "=" + "'" + obj[key] + "'";
365
- }
366
- };
367
- monthField = monthField + '/>';
431
+ for (const [key, value] of Object.entries(obj || {})) {
432
+ const safeKey = escapeHTML(String(key));
433
+ const safeValue = escapeHTML(String(value));
434
+ monthField += ` ${safeKey}="${safeValue}"`;
435
+ }
436
+
437
+ monthField += '/>';
368
438
 
369
439
  return monthField;
370
440
  }
371
441
 
372
442
  // date week field tag
373
443
  weekField(name, obj){
444
+ const safeName = escapeHTML(String(name));
374
445
 
375
- var weekField = "<input type='week' name='" + name + "' ";
446
+ let weekField = `<input type="week" name="${safeName}"`;
447
+
448
+ for (const [key, value] of Object.entries(obj || {})) {
449
+ const safeKey = escapeHTML(String(key));
450
+ const safeValue = escapeHTML(String(value));
451
+ weekField += ` ${safeKey}="${safeValue}"`;
452
+ }
453
+
454
+ weekField += '/>';
376
455
 
377
- for (var key in obj) {
378
- if (obj.hasOwnProperty(key)) {
379
- weekField = weekField + " " + key + "=" + "'" + obj[key] + "'";
380
- }
381
- };
382
- weekField = weekField + '/>';
383
-
384
456
  return weekField;
385
457
  }
386
458
 
387
459
  // date url field tag
388
460
  urlField(name, obj){
389
-
390
- var urlField = "<input type='url' name='" + name + "' ";
461
+ const safeName = escapeHTML(String(name));
391
462
 
392
- for (var key in obj) {
393
- if (obj.hasOwnProperty(key)) {
394
- urlField = urlField + " " + key + "=" + "'" + obj[key] + "'";
395
- }
396
- };
397
- urlField = urlField + '/>';
463
+ let urlField = `<input type="url" name="${safeName}"`;
464
+
465
+ for (const [key, value] of Object.entries(obj || {})) {
466
+ const safeKey = escapeHTML(String(key));
467
+ const safeValue = escapeHTML(String(value));
468
+ urlField += ` ${safeKey}="${safeValue}"`;
469
+ }
470
+
471
+ urlField += '/>';
398
472
 
399
473
  return urlField;
400
474
  }
@@ -402,76 +476,92 @@ class html {
402
476
 
403
477
  // date email field tag
404
478
  emailField(name, obj){
405
-
406
- var emailField = "<input type='email' name='" + name + "' ";
479
+ const safeName = escapeHTML(String(name));
407
480
 
408
- for (var key in obj) {
409
- if (obj.hasOwnProperty(key)) {
410
- emailField = emailField + " " + key + "=" + "'" + obj[key] + "'";
411
- }
412
- };
413
- emailField = emailField + '/>';
481
+ let emailField = `<input type="email" name="${safeName}"`;
482
+
483
+ for (const [key, value] of Object.entries(obj || {})) {
484
+ const safeKey = escapeHTML(String(key));
485
+ const safeValue = escapeHTML(String(value));
486
+ emailField += ` ${safeKey}="${safeValue}"`;
487
+ }
488
+
489
+ emailField += '/>';
414
490
 
415
491
  return emailField;
416
492
  }
417
493
 
418
494
  // date color field tag
419
495
  colorField(name, color, obj){
420
-
421
- var colorField = "<input type='color' name='" + name + "' value='" + color + "'";
496
+ const safeName = escapeHTML(String(name));
497
+ const safeColor = escapeHTML(String(color));
422
498
 
423
- for (var key in obj) {
424
- if (obj.hasOwnProperty(key)) {
425
- colorField = colorField + " " + key + "=" + "'" + obj[key] + "'";
426
- }
427
- };
428
- colorField = colorField + '/>';
499
+ let colorField = `<input type="color" name="${safeName}" value="${safeColor}"`;
500
+
501
+ for (const [key, value] of Object.entries(obj || {})) {
502
+ const safeKey = escapeHTML(String(key));
503
+ const safeValue = escapeHTML(String(value));
504
+ colorField += ` ${safeKey}="${safeValue}"`;
505
+ }
506
+
507
+ colorField += '/>';
429
508
 
430
509
  return colorField;
431
510
  }
432
511
 
433
512
  // date time field tag
434
513
  timeField(name, obj){
435
-
436
- var timeField = "<input type='time' name='" + name + "' ";
514
+ const safeName = escapeHTML(String(name));
437
515
 
438
- for (var key in obj) {
439
- if (obj.hasOwnProperty(key)) {
440
- timeField = timeField + " " + key + "=" + "'" + obj[key] + "'";
441
- }
442
- };
443
- timeField = timeField + '/>';
516
+ let timeField = `<input type="time" name="${safeName}"`;
517
+
518
+ for (const [key, value] of Object.entries(obj || {})) {
519
+ const safeKey = escapeHTML(String(key));
520
+ const safeValue = escapeHTML(String(value));
521
+ timeField += ` ${safeKey}="${safeValue}"`;
522
+ }
523
+
524
+ timeField += '/>';
444
525
 
445
526
  return timeField;
446
527
  }
447
528
 
448
529
  // date number field tag
449
530
  numberField(name, min, max, step, obj){
450
-
451
- var numberField = "<input type='number' name='" + name + "'" + " min='" + min + "'" + " max='" + max + "'" + " step='" + step + "'";
531
+ const safeName = escapeHTML(String(name));
532
+ const safeMin = escapeHTML(String(min));
533
+ const safeMax = escapeHTML(String(max));
534
+ const safeStep = escapeHTML(String(step));
452
535
 
453
- for (var key in obj) {
454
- if (obj.hasOwnProperty(key)) {
455
- numberField = numberField + " " + key + "=" + "'" + obj[key] + "'";
456
- }
457
- };
458
- numberField = numberField + '/>';
536
+ let numberField = `<input type="number" name="${safeName}" min="${safeMin}" max="${safeMax}" step="${safeStep}"`;
537
+
538
+ for (const [key, value] of Object.entries(obj || {})) {
539
+ const safeKey = escapeHTML(String(key));
540
+ const safeValue = escapeHTML(String(value));
541
+ numberField += ` ${safeKey}="${safeValue}"`;
542
+ }
543
+
544
+ numberField += '/>';
459
545
 
460
546
  return numberField;
461
547
  }
462
548
 
463
549
  // date range field tag
464
550
  rangeField(name, min, max, obj){
551
+ const safeName = escapeHTML(String(name));
552
+ const safeMin = escapeHTML(String(min));
553
+ const safeMax = escapeHTML(String(max));
465
554
 
466
- var rangeField = "<input type='range' name='" + name + "'" + " min='" + min + "'" + " max='" + max + "'";
555
+ let rangeField = `<input type="range" name="${safeName}" min="${safeMin}" max="${safeMax}"`;
556
+
557
+ for (const [key, value] of Object.entries(obj || {})) {
558
+ const safeKey = escapeHTML(String(key));
559
+ const safeValue = escapeHTML(String(value));
560
+ rangeField += ` ${safeKey}="${safeValue}"`;
561
+ }
562
+
563
+ rangeField += '/>';
467
564
 
468
- for (var key in obj) {
469
- if (obj.hasOwnProperty(key)) {
470
- rangeField = rangeField + " " + key + "=" + "'" + obj[key] + "'";
471
- }
472
- };
473
- rangeField = rangeField + '/>';
474
-
475
565
  return rangeField;
476
566
  }
477
567
 
@@ -547,5 +637,13 @@ class html {
547
637
 
548
638
  }
549
639
 
550
- master.extendView("html", html);
640
+ // Export and lazy register (prevents circular dependency - Spring/Angular pattern)
641
+ module.exports = html;
642
+
643
+ setImmediate(() => {
644
+ const master = require('./MasterControl');
645
+ if (master && master.extendView) {
646
+ master.extendView("html", html);
647
+ }
648
+ });
551
649
 
package/MasterPipeline.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // MasterPipeline - Middleware Pipeline System
2
2
  // version 1.0
3
3
 
4
- var master = require('./MasterControl');
5
4
  const { logger } = require('./error/MasterErrorLogger');
6
5
 
7
6
  class MasterPipeline {
@@ -340,5 +339,5 @@ class MasterPipeline {
340
339
  }
341
340
  }
342
341
 
343
- // Register with master
344
- master.extend("pipeline", MasterPipeline);
342
+ // Export for MasterControl to register (prevents circular dependency)
343
+ module.exports = { MasterPipeline };