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