mastercontroller 1.3.14 → 1.3.16

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/MasterControl.js CHANGED
@@ -1,16 +1,28 @@
1
1
  // MasterControl - by Alexander rich
2
2
  // version 1.0.252
3
3
 
4
- var url = require('url');
5
- var fileserver = require('fs');
6
- var http = require('http');
7
- var https = require('https');
8
- var tls = require('tls');
9
- var fs = require('fs');
10
- var url = require('url');
11
- var path = require('path');
12
- var globSearch = require("glob");
13
- var crypto = require('crypto'); // CRITICAL FIX: For ETag generation
4
+ const url = require('url');
5
+ const fileserver = require('fs');
6
+ const http = require('http');
7
+ const https = require('https');
8
+ const tls = require('tls');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const globSearch = require("glob");
12
+ const crypto = require('crypto'); // CRITICAL FIX: For ETag generation
13
+
14
+ // HTTP Status Code Constants
15
+ const HTTP_STATUS = {
16
+ OK: 200,
17
+ MOVED_PERMANENTLY: 301,
18
+ FOUND: 302,
19
+ NOT_MODIFIED: 304,
20
+ BAD_REQUEST: 400,
21
+ FORBIDDEN: 403,
22
+ NOT_FOUND: 404,
23
+ PAYLOAD_TOO_LARGE: 413,
24
+ INTERNAL_ERROR: 500
25
+ };
14
26
 
15
27
  // Enhanced error handling - setup global handlers
16
28
  const { setupGlobalErrorHandlers } = require('./error/MasterErrorMiddleware');
@@ -176,7 +188,10 @@ class MasterControl {
176
188
  return false;
177
189
  };
178
190
 
179
- console.log('[MasterControl] Prototype pollution protection initialized');
191
+ logger.info({
192
+ code: 'MC_INFO_PROTOTYPE_PROTECTION',
193
+ message: 'Prototype pollution protection initialized'
194
+ });
180
195
  }
181
196
 
182
197
  // extends class methods to be used inside of the view class using the THIS keyword
@@ -291,7 +306,7 @@ class MasterControl {
291
306
 
292
307
  // Enhanced: Support both relative (to master.root) and absolute paths
293
308
  // If folderLocation is absolute, use it directly; otherwise join with master.root
294
- var rootFolderLocation;
309
+ let rootFolderLocation;
295
310
  if (path.isAbsolute(folderLocation)) {
296
311
  // Absolute path provided - use it directly
297
312
  rootFolderLocation = path.join(folderLocation, innerFolder);
@@ -301,16 +316,20 @@ class MasterControl {
301
316
  }
302
317
 
303
318
  // Structure is always: {rootFolderLocation}/config/initializers/config.js
304
- var configPath = path.join(rootFolderLocation, 'config', 'initializers', 'config.js');
319
+ const configPath =path.join(rootFolderLocation, 'config', 'initializers', 'config.js');
305
320
  if(fs.existsSync(configPath)){
306
321
  require(configPath);
307
322
  }else{
308
- this.error.log(`Cannot find config file at ${configPath}`, "error");
323
+ logger.error({
324
+ code: 'MC_ERR_CONFIG_NOT_FOUND',
325
+ message: 'Cannot find config file',
326
+ path: configPath
327
+ });
309
328
  }
310
329
 
311
330
  // Structure is always: {rootFolderLocation}/config/routes.js
312
- var routePath = path.join(rootFolderLocation, 'config', 'routes.js');
313
- var routeObject = {
331
+ const routePath =path.join(rootFolderLocation, 'config', 'routes.js');
332
+ const routeObject ={
314
333
  isComponent : true,
315
334
  root : rootFolderLocation
316
335
  }
@@ -318,7 +337,11 @@ class MasterControl {
318
337
  if(fs.existsSync(routePath)){
319
338
  require(routePath);
320
339
  }else{
321
- this.error.log(`Cannot find routes file at ${routePath}`, "error");
340
+ logger.error({
341
+ code: 'MC_ERR_ROUTES_NOT_FOUND',
342
+ message: 'Cannot find routes file',
343
+ path: routePath
344
+ });
322
345
  }
323
346
  }
324
347
 
@@ -335,7 +358,7 @@ class MasterControl {
335
358
 
336
359
  if(settings.httpPort || settings.requestTimeout){
337
360
  this.server.timeout = settings.requestTimeout;
338
- var host = settings.hostname || settings.host || settings.http;
361
+ const host =settings.hostname || settings.host || settings.http;
339
362
  if(host){
340
363
  this.server.listen(settings.httpPort, host);
341
364
  }else{
@@ -391,7 +414,7 @@ class MasterControl {
391
414
  // sets up https or http server protocals
392
415
  setupServer(type, credentials ){
393
416
  try {
394
- var $that = this;
417
+ const $that = this;
395
418
 
396
419
  // SECURITY: Initialize prototype pollution protection
397
420
  this._initPrototypePollutionProtection();
@@ -547,7 +570,7 @@ class MasterControl {
547
570
  * @security CRITICAL: Always provide allowedHosts in production to prevent open redirect attacks
548
571
  */
549
572
  startHttpToHttpsRedirect(redirectPort, bindHost, allowedHosts = []){
550
- var $that = this;
573
+ const $that = this;
551
574
 
552
575
  // Security warning if no hosts specified
553
576
  if (allowedHosts.length === 0) {
@@ -558,8 +581,8 @@ class MasterControl {
558
581
 
559
582
  return http.createServer(function (req, res) {
560
583
  try{
561
- var host = req.headers['host'] || '';
562
- var hostname = host.split(':')[0]; // Remove port number
584
+ const host = req.headers['host'] || '';
585
+ const hostname = host.split(':')[0]; // Remove port number
563
586
 
564
587
  // CRITICAL SECURITY: Validate host header to prevent open redirect attacks
565
588
  if (allowedHosts.length > 0) {
@@ -707,7 +730,7 @@ class MasterControl {
707
730
  * This includes: static files, body parsing, scoped services, routing, error handling
708
731
  */
709
732
  _registerCoreMiddleware(){
710
- var $that = this;
733
+ const $that = this;
711
734
 
712
735
  // 1. Static File Serving (with path traversal protection)
713
736
  $that.pipeline.use(async (ctx, next) => {
@@ -750,17 +773,17 @@ class MasterControl {
750
773
  return;
751
774
  }
752
775
 
753
- // Check if file exists
754
- fs.exists(resolvedPath, function (exist) {
755
- if (!exist) {
756
- ctx.response.statusCode = 404;
757
- ctx.response.setHeader('Content-Type', 'text/plain');
758
- ctx.response.end('Not Found');
759
- return;
760
- }
776
+ // Check if file exists (use synchronous check for better performance in middleware)
777
+ if (!fs.existsSync(resolvedPath)) {
778
+ ctx.response.statusCode = 404;
779
+ ctx.response.setHeader('Content-Type', 'text/plain');
780
+ ctx.response.end('Not Found');
781
+ return;
782
+ }
761
783
 
762
- // Get file stats
763
- let finalPath = resolvedPath;
784
+ // Get file stats
785
+ let finalPath = resolvedPath;
786
+ try {
764
787
  const stats = fs.statSync(resolvedPath);
765
788
 
766
789
  // If directory, try to serve index.html
@@ -877,7 +900,19 @@ class MasterControl {
877
900
  }
878
901
  });
879
902
  }
880
- });
903
+ } catch (error) {
904
+ // Handle file stat errors
905
+ logger.error({
906
+ code: 'MC_ERR_FILE_STAT',
907
+ message: 'Error accessing static file',
908
+ path: resolvedPath,
909
+ error: error.message
910
+ });
911
+ ctx.response.statusCode = 500;
912
+ ctx.response.setHeader('Content-Type', 'text/plain');
913
+ ctx.response.end('Internal Server Error');
914
+ return;
915
+ }
881
916
 
882
917
  return; // Terminal - don't call next()
883
918
  }
@@ -968,7 +1003,7 @@ class MasterControl {
968
1003
  }
969
1004
 
970
1005
  async serverRun(req, res){
971
- var $that = this;
1006
+ const $that = this;
972
1007
  console.log("path", `${req.method} ${req.url}`);
973
1008
 
974
1009
  // Create request context for middleware pipeline
@@ -1016,7 +1051,7 @@ class MasterControl {
1016
1051
  var rootFolderLocation = path.join(this.root, foldername);
1017
1052
 
1018
1053
  // Structure is always: {rootFolderLocation}/routes.js
1019
- var routePath = path.join(rootFolderLocation, 'routes.js');
1054
+ const routePath =path.join(rootFolderLocation, 'routes.js');
1020
1055
  var route = {
1021
1056
  isComponent : false,
1022
1057
  root : `${this.root}`
@@ -1025,14 +1060,18 @@ class MasterControl {
1025
1060
  if(fs.existsSync(routePath)){
1026
1061
  require(routePath);
1027
1062
  }else{
1028
- this.error.log(`Cannot find routes file at ${routePath}`, "error");
1063
+ logger.error({
1064
+ code: 'MC_ERR_ROUTES_NOT_FOUND',
1065
+ message: 'Cannot find routes file',
1066
+ path: routePath
1067
+ });
1029
1068
  }
1030
1069
  }
1031
1070
 
1032
1071
 
1033
1072
  // builds and calls all the required tools to have master running completely
1034
1073
  addInternalTools(requiredList){
1035
- if(requiredList.constructor === Array){
1074
+ if(Array.isArray(requiredList)){
1036
1075
  // Map module names to their new organized paths
1037
1076
  const modulePathMap = {
1038
1077
  'MasterPipeline': './MasterPipeline',
package/MasterCors.js CHANGED
@@ -1,6 +1,27 @@
1
1
  // version 0.0.3 - robust origin handling (all envs), creds-safe reflection, function origins, extended Vary
2
2
 
3
- // todo - res.setHeader('Access-Control-Request-Method', '*');
3
+ const { logger } = require('./error/MasterErrorLogger');
4
+
5
+ // HTTP Status Code Constants
6
+ const HTTP_STATUS = {
7
+ NO_CONTENT: 204,
8
+ BAD_REQUEST: 400
9
+ };
10
+
11
+ // CORS Header Name Constants
12
+ const CORS_HEADERS = {
13
+ ALLOW_ORIGIN: 'Access-Control-Allow-Origin',
14
+ ALLOW_METHODS: 'Access-Control-Allow-Methods',
15
+ ALLOW_HEADERS: 'Access-Control-Allow-Headers',
16
+ ALLOW_CREDENTIALS: 'Access-Control-Allow-Credentials',
17
+ MAX_AGE: 'Access-Control-Max-Age',
18
+ EXPOSE_HEADERS: 'Access-Control-Expose-Headers',
19
+ REQUEST_HEADERS: 'Access-Control-Request-Headers',
20
+ REQUEST_METHOD: 'Access-Control-Request-Method',
21
+ VARY: 'Vary'
22
+ };
23
+
24
+ // todo - res.setHeader('Access-Control-Request-Method', '*');
4
25
  class MasterCors{
5
26
 
6
27
  // Lazy-load master to avoid circular dependency (Google-style lazy initialization)
@@ -16,7 +37,10 @@ class MasterCors{
16
37
  this.options = options;
17
38
  }
18
39
  else{
19
- this._master.error.log("cors options missing", "warn");
40
+ logger.warn({
41
+ code: 'MC_CORS_OPTIONS_MISSING',
42
+ message: 'CORS options missing'
43
+ });
20
44
  }
21
45
 
22
46
  // Auto-register with pipeline if available
@@ -32,7 +56,15 @@ class MasterCors{
32
56
  this.response = params.response;
33
57
  this.request = params.request;
34
58
  // Always signal that response may vary by Origin and requested headers/method
35
- try { this.response.setHeader('Vary', 'Origin, Access-Control-Request-Headers, Access-Control-Request-Method'); } catch(_) {}
59
+ try {
60
+ this.response.setHeader('Vary', 'Origin, Access-Control-Request-Headers, Access-Control-Request-Method');
61
+ } catch(error) {
62
+ logger.warn({
63
+ code: 'MC_CORS_VARY_HEADER_FAILED',
64
+ message: 'Failed to set Vary header',
65
+ error: error.message
66
+ });
67
+ }
36
68
  this.configureOrigin();
37
69
  this.configureMethods()
38
70
  this.configureAllowedHeaders();
@@ -41,7 +73,10 @@ class MasterCors{
41
73
  this.configureMaxAge();
42
74
  }
43
75
  else{
44
- this._master.error.log("cors response and requests missing", "warn");
76
+ logger.warn({
77
+ code: 'MC_CORS_PARAMS_MISSING',
78
+ message: 'CORS response and request params missing'
79
+ });
45
80
  }
46
81
  }
47
82
 
@@ -63,7 +98,7 @@ class MasterCors{
63
98
 
64
99
  if(this.options.origin === true){
65
100
  // If credentials are enabled, reflect request origin per spec
66
- var requestOrigin = this.request.headers.origin;
101
+ const requestOrigin =this.request.headers.origin;
67
102
  if (this.options.credentials === true && requestOrigin) {
68
103
  this.setHeader('access-control-allow-origin', requestOrigin);
69
104
  } else {
@@ -76,9 +111,9 @@ class MasterCors{
76
111
  this.removeHeader('access-control-allow-origin');
77
112
  }
78
113
 
79
- if(this.options.origin.constructor === Array){
114
+ if(Array.isArray(this.options.origin)){
80
115
  // Get the origin from the incoming request
81
- var requestOrigin = this.request.headers.origin;
116
+ const requestOrigin =this.request.headers.origin;
82
117
 
83
118
  // Check if the request origin is in our allowed list
84
119
  if(requestOrigin && this.options.origin.includes(requestOrigin)){
@@ -90,15 +125,22 @@ class MasterCors{
90
125
  // Function predicate support: (origin, req) => boolean|string
91
126
  if (typeof this.options.origin === 'function'){
92
127
  try {
93
- var requestOrigin = this.request.headers.origin;
94
- var res = this.options.origin(requestOrigin, this.request);
128
+ const requestOrigin = this.request.headers.origin;
129
+ const res = this.options.origin(requestOrigin, this.request);
95
130
  if (res === true && requestOrigin){
96
131
  this.setHeader('access-control-allow-origin', requestOrigin);
97
132
  }
98
133
  else if (typeof res === 'string' && res){
99
134
  this.setHeader('access-control-allow-origin', res);
100
135
  }
101
- } catch(_) {}
136
+ } catch(error) {
137
+ logger.error({
138
+ code: 'MC_CORS_ORIGIN_FUNCTION_ERROR',
139
+ message: 'Error in origin function predicate',
140
+ error: error.message,
141
+ stack: error.stack
142
+ });
143
+ }
102
144
  }
103
145
 
104
146
  }
@@ -106,16 +148,16 @@ class MasterCors{
106
148
 
107
149
  configureMethods(){
108
150
  if(this.options.methods){
109
- if(this.options.methods.constructor === Array){
110
- var elements = this.options.methods.join(", ");
151
+ if(Array.isArray(this.options.methods)){
152
+ const elements =this.options.methods.join(", ");
111
153
  this.setHeader('access-control-allow-methods', elements);
112
154
  }
113
155
  }
114
156
  }
115
157
 
116
158
  configureAllowedHeaders(){
117
- var requestheader = this.request.headers["access-control-request-headers"];
118
- var $that = this;
159
+ const requestheader =this.request.headers["access-control-request-headers"];
160
+ const $that =this;
119
161
  if(this.options.allowedHeaders){
120
162
 
121
163
  if($that.options.allowedHeaders === true){
@@ -135,8 +177,8 @@ class MasterCors{
135
177
  this.setHeader("access-control-allow-headers", $that.options.allowedHeaders);
136
178
  }
137
179
 
138
- if($that.options.allowedHeaders.constructor === Array){
139
- var elements = $that.options.allowedHeaders.join(", ");
180
+ if(Array.isArray($that.options.allowedHeaders)){
181
+ const elements =$that.options.allowedHeaders.join(", ");
140
182
  $that.request.headers['access-control-allow-headers'] = elements;
141
183
  this.setHeader("access-control-allow-headers", elements);
142
184
  }
@@ -158,8 +200,8 @@ class MasterCors{
158
200
  this.setHeader('access-control-expose-headers', this.options.exposeHeaders);
159
201
  }
160
202
 
161
- if(this.options.exposeHeaders.constructor === Array){
162
- var elements = this.options.exposeHeaders.join(", ");
203
+ if(Array.isArray(this.options.exposeHeaders)){
204
+ const elements =this.options.exposeHeaders.join(", ");
163
205
  this.setHeader('access-control-expose-headers', elements);
164
206
  }
165
207
 
@@ -187,7 +229,7 @@ class MasterCors{
187
229
  * Handles both preflight OPTIONS requests and regular requests
188
230
  */
189
231
  middleware() {
190
- var $that = this;
232
+ const $that =this;
191
233
 
192
234
  return async (ctx, next) => {
193
235
  // Handle preflight OPTIONS request
package/MasterPipeline.js CHANGED
@@ -3,6 +3,11 @@
3
3
 
4
4
  const { logger } = require('./error/MasterErrorLogger');
5
5
 
6
+ // HTTP Status Code Constants
7
+ const HTTP_STATUS = {
8
+ INTERNAL_ERROR: 500
9
+ };
10
+
6
11
  class MasterPipeline {
7
12
  constructor() {
8
13
  this.middleware = [];
@@ -214,7 +219,7 @@ class MasterPipeline {
214
219
  });
215
220
 
216
221
  if (!context.response.headersSent) {
217
- context.response.statusCode = 500;
222
+ context.response.statusCode = HTTP_STATUS.INTERNAL_ERROR;
218
223
  context.response.end('Internal Server Error');
219
224
  }
220
225
  return;
@@ -285,7 +290,11 @@ class MasterPipeline {
285
290
  folders.forEach(folder => {
286
291
  const dir = path.join(this._master.root, folder);
287
292
  if (!fs.existsSync(dir)) {
288
- console.warn(`[Middleware] Folder not found: ${folder}`);
293
+ logger.warn({
294
+ code: 'MC_MIDDLEWARE_FOLDER_NOT_FOUND',
295
+ message: 'Middleware folder not found',
296
+ folder: folder
297
+ });
289
298
  return;
290
299
  }
291
300
 
@@ -305,16 +314,30 @@ class MasterPipeline {
305
314
  }
306
315
  // Pattern 2: module.exports = { register: (master) => {} }
307
316
  else if (middleware.register && typeof middleware.register === 'function') {
308
- middleware.register(master);
317
+ middleware.register(this._master);
309
318
  }
310
319
  else {
311
- console.warn(`[Middleware] Invalid export in ${folder}/${file}`);
320
+ logger.warn({
321
+ code: 'MC_MIDDLEWARE_INVALID_EXPORT',
322
+ message: 'Invalid middleware export',
323
+ file: `${folder}/${file}`
324
+ });
312
325
  return;
313
326
  }
314
327
 
315
- console.log(`[Middleware] Loaded: ${folder}/${file}`);
328
+ logger.info({
329
+ code: 'MC_MIDDLEWARE_LOADED',
330
+ message: 'Middleware loaded',
331
+ file: `${folder}/${file}`
332
+ });
316
333
  } catch (err) {
317
- console.error(`[Middleware] Failed to load ${folder}/${file}:`, err.message);
334
+ logger.error({
335
+ code: 'MC_MIDDLEWARE_LOAD_FAILED',
336
+ message: 'Failed to load middleware',
337
+ file: `${folder}/${file}`,
338
+ error: err.message,
339
+ stack: err.stack
340
+ });
318
341
  }
319
342
  });
320
343
  });