1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | var getFragment = require('./getFragment');
|
32 | var resilientMode = require('./resilientMode');
|
33 | var handleJWT = require('./jwtHandler');
|
34 | var dumpDocuments = require('./dumpDocuments');
|
35 | var saveDocuments = require('./saveDocuments');
|
36 |
|
37 | function loadModule(application, finished) {
|
38 | try {
|
39 | var moduleName = application;
|
40 | if (this.userDefined.config.moduleMap && this.userDefined.config.moduleMap[application]) {
|
41 | moduleName = this.userDefined.config.moduleMap[application];
|
42 | }
|
43 | var appModule = require(moduleName);
|
44 | if (!appModule.handlers) appModule.handlers = {};
|
45 | if (appModule.handlers) this.handlers[application] = appModule.handlers;
|
46 | if (appModule.beforeHandler) {
|
47 | this.beforeHandlers[application] = appModule.beforeHandler;
|
48 | }
|
49 | if (appModule.beforeMicroServiceHandler) {
|
50 | this.beforeHandlers[application] = function(messageObj, session, send, finished) {
|
51 | return appModule.beforeMicroServiceHandler.call(this, messageObj, finished);
|
52 | };
|
53 | }
|
54 | if (appModule.afterHandler) {
|
55 | this.afterHandlers[application] = appModule.afterHandler;
|
56 | }
|
57 | if (appModule.servicesAllowed) {
|
58 | this.servicesAllowed[application] = appModule.servicesAllowed;
|
59 | }
|
60 |
|
61 | if (appModule.init && typeof appModule.init === 'function') {
|
62 | appModule.init.call(this, application);
|
63 | }
|
64 | console.log('loadModule: handler module loaded for application ' + application + '; module: ' + moduleName);
|
65 | return true;
|
66 | }
|
67 | catch(err) {
|
68 | var error = 'Unable to load handler module for: ' + application;
|
69 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].moduleLoadError) error = this.errorMessages[application].moduleLoadError;
|
70 | console.log(error + ': ' + err);
|
71 | error = {
|
72 | error: error,
|
73 | reason: err
|
74 | };
|
75 | if (finished) {
|
76 | finished(error);
|
77 | return false;
|
78 | }
|
79 | return error;
|
80 | }
|
81 | }
|
82 |
|
83 | function customError(errorObj) {
|
84 | var error;
|
85 | if (typeof errorObj === 'string') {
|
86 | error = {error: errorObj};
|
87 | }
|
88 | else {
|
89 | error = {
|
90 | error: errorObj.text,
|
91 | status: {
|
92 | code: errorObj.statusCode
|
93 | }
|
94 | };
|
95 | }
|
96 | return error;
|
97 | }
|
98 |
|
99 | module.exports = function() {
|
100 |
|
101 | this.on('message', function(messageObj, sendFn, finishedFn) {
|
102 |
|
103 |
|
104 |
|
105 | var finished = finishedFn;
|
106 | var q = this;
|
107 |
|
108 | if (this.userDefined.config.resilientMode && messageObj.dbIndex) {
|
109 |
|
110 | finished = function(responseObj) {
|
111 | if (responseObj.error) {
|
112 | resilientMode.storeWorkerStatusUpdate.call(q, messageObj, 'error');
|
113 | }
|
114 | else {
|
115 | resilientMode.storeWorkerStatusUpdate.call(q, messageObj, 'finished');
|
116 | }
|
117 | finishedFn(responseObj);
|
118 | };
|
119 | resilientMode.storeWorkerStatusUpdate.call(q, messageObj, 'started');
|
120 | }
|
121 |
|
122 | var error;
|
123 | var errorObj;
|
124 | if (!this.documentStore) {
|
125 | error = {error: 'No Document Store has been created - you must use ewd-document-store!'};
|
126 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].noDocumentStore)
|
127 | errorObj = customError(this.errorMessages[application].noDocumentStore);
|
128 | if (errorObj) error = errorObj;
|
129 | finished(error);
|
130 | return;
|
131 | }
|
132 |
|
133 | var session;
|
134 | var application;
|
135 | var status;
|
136 | var ok;
|
137 | var fin;
|
138 | var type = messageObj.type;
|
139 | var send = sendFn;
|
140 |
|
141 | if (type === 'ewd-dump-documents') {
|
142 |
|
143 | if (messageObj.params && messageObj.params.password && messageObj.params.password === this.userDefined.config.managementPassword) {
|
144 | dumpDocuments.call(this, messageObj);
|
145 | return finished({ok: true});
|
146 | }
|
147 | else {
|
148 | return finished({error: 'Unauthorised attempt to use ' + type + ' message'});
|
149 | }
|
150 | }
|
151 |
|
152 | if (type === 'ewd-save-documents') {
|
153 |
|
154 | if (messageObj.params && messageObj.params.documents && messageObj.params.password && messageObj.params.password === this.userDefined.config.managementPassword) {
|
155 | saveDocuments.call(this, messageObj.params.documents);
|
156 | return finished({ok: true});
|
157 | }
|
158 | else {
|
159 | return finished({error: 'Unauthorised attempt to use ' + type + ' message'});
|
160 | }
|
161 | }
|
162 |
|
163 | if (type === 'ewd-jwt-decode') {
|
164 |
|
165 | var payload = handleJWT.decodeJWT.call(this, messageObj.params.jwt);
|
166 | return finished(payload);
|
167 | }
|
168 |
|
169 | if (type === 'ewd-jwt-encode') {
|
170 |
|
171 | var jwt = handleJWT.encodeJWT.call(this, messageObj.params.payload);
|
172 | return finished({jwt: jwt});
|
173 | }
|
174 |
|
175 | if (type === 'ewd-jwt-updateExpiry') {
|
176 |
|
177 |
|
178 | var token = handleJWT.updateJWTExpiry.call(this, messageObj.params.jwt, messageObj.params.application);
|
179 | return finished({jwt: token});
|
180 | }
|
181 |
|
182 | if (type === 'ewd-jwt-isValid') {
|
183 |
|
184 |
|
185 | status = handleJWT.isJWTValid.call(this, messageObj.params.jwt);
|
186 | return finished(status);
|
187 | }
|
188 |
|
189 | if (type === 'ewd-qoper8-express') {
|
190 |
|
191 | if (messageObj.headers && messageObj.headers.qewd && messageObj.headers.qewd === 'ajax') {
|
192 |
|
193 | var ip = messageObj.ip;
|
194 | var ips = messageObj.ips;
|
195 | messageObj = messageObj.body;
|
196 | type = messageObj.type;
|
197 | if (type === 'ewd-register') {
|
198 | messageObj.ipAddress = ip;
|
199 | }
|
200 | messageObj.ip = ip;
|
201 | messageObj.ips = ips;
|
202 |
|
203 | send = function(msg) {
|
204 | console.log('** Unable to use send() function over Ajax for intermediate message ' + JSON.stringify(msg));
|
205 | };
|
206 | }
|
207 | else if (messageObj.expressType) {
|
208 | type = messageObj.expressType;
|
209 | }
|
210 | if (messageObj.application) {
|
211 | application = messageObj.application;
|
212 | if (!this.restModule) this.restModule = {};
|
213 | if (!this.handlers[application]) {
|
214 | try {
|
215 | var moduleName = application;
|
216 | if (this.userDefined.config.moduleMap && this.userDefined.config.moduleMap[application]) {
|
217 | moduleName = this.userDefined.config.moduleMap[application];
|
218 | }
|
219 | var appModule = require(moduleName);
|
220 | if (!appModule.handlers) appModule.handlers = {};
|
221 | if (appModule.handlers) this.handlers[application] = appModule.handlers;
|
222 |
|
223 | if (appModule.beforeHandler) {
|
224 | this.beforeHandlers[application] = appModule.beforeHandler;
|
225 | }
|
226 | if (appModule.afterHandler) {
|
227 | this.afterHandlers[application] = appModule.afterHandler;
|
228 | }
|
229 | if (appModule.servicesAllowed) this.servicesAllowed[application] = appModule.servicesAllowed;
|
230 | if (appModule.restModule === true) this.restModule[application] = true;
|
231 | if (appModule.init && typeof appModule.init === 'function') appModule.init.call(this, application);
|
232 | console.log('handler module loaded for ' + application);
|
233 | }
|
234 | catch(err) {
|
235 | error = 'Unable to load handler module for: ' + application;
|
236 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].moduleLoadError) error = this.errorMessages[application].moduleLoadError;
|
237 | console.log(error + ': ' + err);
|
238 | finished({
|
239 | error: error,
|
240 | reason: err
|
241 | });
|
242 | return;
|
243 | }
|
244 | }
|
245 |
|
246 | if (this.restModule[application]) {
|
247 | if (this.handlers[application][type]) {
|
248 |
|
249 | fin = function(results) {
|
250 | results.restMessage = true;
|
251 |
|
252 | results.ewd_application = application;
|
253 | finished(results);
|
254 | };
|
255 |
|
256 | if (this.jwt && typeof this.jwt.handlers !== 'function') {
|
257 | this.jwt.handlers = handleJWT;
|
258 | }
|
259 |
|
260 | if (this.beforeHandlers[application]) {
|
261 | status = this.beforeHandlers[application].call(this, messageObj, fin);
|
262 | if (status === false) return;
|
263 | }
|
264 | this.handlers[application][type].call(this, messageObj, fin);
|
265 | if (this.afterHandlers[application]) {
|
266 | this.afterHandlers[application].call(this, messageObj, fin);
|
267 | }
|
268 | }
|
269 | else {
|
270 | error = {error: 'No handler defined for ' + application + ' messages of type ' + type};
|
271 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].noTypeHandler) {
|
272 | errorObj = customError(this.errorMessages[application].noTypeHandler);
|
273 | if (errorObj) error = errorObj;
|
274 | }
|
275 | finished(error);
|
276 | }
|
277 | return;
|
278 | }
|
279 | }
|
280 | console.log('ewd-qoper8-express message remapped to: type ' + type + ': ' + JSON.stringify(messageObj));
|
281 | }
|
282 |
|
283 | if (type === 'ewd-register') {
|
284 |
|
285 | if (messageObj.jwt) {
|
286 | return finished(handleJWT.register.call(this, messageObj));
|
287 | }
|
288 |
|
289 | var params = {
|
290 | application: messageObj.application,
|
291 | timeout: this.userDefined.config.initialSessionTimeout
|
292 | };
|
293 | session = this.sessions.create(params);
|
294 | if (messageObj.socketId) session.socketId = messageObj.socketId;
|
295 | if (messageObj.ipAddress) session.ipAddress = messageObj.ipAddress;
|
296 | finished({token: session.token});
|
297 | return;
|
298 | }
|
299 |
|
300 | var result;
|
301 | if (messageObj.jwt) {
|
302 | if (messageObj.path && messageObj.path.startsWith('/qewd/importRoutes/')) {
|
303 |
|
304 | result = handleJWT.validate.call(this, messageObj, true);
|
305 | }
|
306 | else {
|
307 | result = handleJWT.validate.call(this, messageObj);
|
308 | }
|
309 | }
|
310 | else {
|
311 | result = this.sessions.authenticate(messageObj.token, 'noCheck');
|
312 | }
|
313 | if (result.error) {
|
314 | error = result.error;
|
315 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].sessionNotAuthenticated) error = this.errorMessages[application].sessionNotAuthenticated;
|
316 | var errorResponse = {
|
317 | error: error,
|
318 | disconnect: true
|
319 | };
|
320 | if (messageObj.ms_requestId) {
|
321 | errorResponse.ms_requestId = messageObj.ms_requestId;
|
322 | delete errorResponse.disconnect;
|
323 | }
|
324 | finished(errorResponse);
|
325 | return;
|
326 | }
|
327 | session = result.session;
|
328 | if (messageObj.jwt && !session) {
|
329 | session = {};
|
330 | }
|
331 |
|
332 | if (type === 'ewd-reregister') {
|
333 |
|
334 | console.log('re-register token ' + messageObj.token);
|
335 | if (messageObj.jwt) {
|
336 | result = handleJWT.reregister.call(this, session, messageObj);
|
337 | }
|
338 | else {
|
339 | session.socketId = messageObj.socketId;
|
340 | result = {ok: true};
|
341 | }
|
342 | finished(result);
|
343 | return;
|
344 | }
|
345 |
|
346 | if (!messageObj.jwt) session.updateExpiry();
|
347 |
|
348 |
|
349 |
|
350 | application = session.application;
|
351 |
|
352 | if (messageObj.qewd_destination && messageObj.qewd_application) {
|
353 |
|
354 | if (process.env.mode === 'microservice') {
|
355 | application = messageObj.qewd_application;
|
356 | }
|
357 | }
|
358 |
|
359 | if (type === 'ewd-fragment') {
|
360 | if (messageObj.service && !this.servicesAllowed[application]) {
|
361 | ok = loadModule.call(this, application, finished);
|
362 | if (!ok) return;
|
363 | }
|
364 |
|
365 | getFragment.call(this, messageObj, application, finished);
|
366 | return;
|
367 | }
|
368 |
|
369 |
|
370 |
|
371 |
|
372 | if (!this.handlers[application]) {
|
373 | ok = loadModule.call(this, application);
|
374 | if (ok.error) {
|
375 | if (messageObj.ms_requestId) ok.ms_requestId = messageObj.ms_requestId;
|
376 | finished(ok);
|
377 | return;
|
378 | }
|
379 | if (!ok) return;
|
380 | }
|
381 |
|
382 |
|
383 | if (this.userDefined.config.lockSession) {
|
384 | var timeout = this.userDefined.config.lockSession.timeout || 30;
|
385 | this.sessionLocked = {
|
386 | global: this.userDefined.config.sessionDocumentName,
|
387 | subscripts: ["session", session.id]
|
388 | };
|
389 | console.log('*** session locked: ' + JSON.stringify(this.sessionLocked));
|
390 | ok = this.db.lock(this.sessionLocked, timeout);
|
391 | if (ok.result.toString() === '0') {
|
392 | finished({error: 'Timed out waiting for EWD session to be released'});
|
393 | return;
|
394 | }
|
395 | }
|
396 |
|
397 |
|
398 |
|
399 |
|
400 | var servicesAllowed = this.servicesAllowed[application];
|
401 | var service = messageObj.service;
|
402 |
|
403 | if (service) {
|
404 |
|
405 |
|
406 |
|
407 |
|
408 | var allowService = false;
|
409 | var sessionAllowService;
|
410 | if (servicesAllowed && servicesAllowed[service]) allowService = true;
|
411 |
|
412 | if (session && session.allowedServices && typeof session.allowedServices[service] !== 'undefined') {
|
413 | allowService = session.allowedServices[service];
|
414 | sessionAllowService = allowService;
|
415 | }
|
416 |
|
417 | if (allowService) {
|
418 | if (!this.handlers[service]) {
|
419 | try {
|
420 |
|
421 | ok = loadModule.call(this, service, finished);
|
422 | if (!ok) return;
|
423 |
|
424 | }
|
425 | catch(err) {
|
426 | error = 'Unable to load handler module: ' + service;
|
427 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].serviceModuleLoad) error = this.errorMessages[application].serviceModuleLoad;
|
428 | console.log(error + ': ' + err);
|
429 | finished({
|
430 | error: error,
|
431 | reason: err,
|
432 | service: service
|
433 | });
|
434 | return;
|
435 | }
|
436 | }
|
437 | if (this.handlers[service][type]) {
|
438 |
|
439 | if (this.beforeHandlers[service]) {
|
440 | status = this.beforeHandlers[service].call(this, messageObj, session, send, finished);
|
441 | if (status === false) return;
|
442 | }
|
443 | fin = function(responseObj) {
|
444 | responseObj.ewd_application = service;
|
445 | finished(responseObj);
|
446 | };
|
447 | this.handlers[service][type].call(this, messageObj, session, send, fin);
|
448 | if (this.afterHandlers[service]) {
|
449 | this.afterHandlers[service].call(this, messageObj, session, send, finished);
|
450 | }
|
451 | return;
|
452 | }
|
453 | else {
|
454 | error = 'No handler defined for ' + service + ' service messages of type ' + type;
|
455 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].noServiceModuleType) error = this.errorMessages[application].noServiceModuleType;
|
456 | finished({
|
457 | error: error,
|
458 | service: service
|
459 | });
|
460 | return;
|
461 | }
|
462 | }
|
463 | else {
|
464 | error = service + ' service is not permitted for the ' + application + ' application';
|
465 | if (sessionAllowService === false) error = 'You are not allowed access to the ' + service + ' service';
|
466 | if (this.errorMessages && this.errorMessages[application]) {
|
467 | if (this.errorMessages[application].serviceNotAllowed) error = this.errorMessages[application].serviceNotAllowed;
|
468 | if (sessionAllowService === false && this.errorMessages[application].serviceNotAllowedForUser) error = this.errorMessages[application].serviceNotAllowedForUser;
|
469 | }
|
470 | finished({
|
471 | error: error,
|
472 | service: service
|
473 | });
|
474 | return;
|
475 | }
|
476 | }
|
477 |
|
478 |
|
479 |
|
480 |
|
481 | if (this.jwt && typeof this.jwt.handlers !== 'function') {
|
482 | this.jwt.handlers = handleJWT;
|
483 | }
|
484 |
|
485 |
|
486 |
|
487 |
|
488 | fin = function(results) {
|
489 |
|
490 |
|
491 | results = results || {};
|
492 |
|
493 | if (messageObj.ms_requestId && Array.isArray(results)) results = {results: results};
|
494 | results.ewd_application = application;
|
495 | if (messageObj.jwt && !results.error) {
|
496 |
|
497 | results.token = handleJWT.updateJWT.call(q, session);
|
498 | }
|
499 |
|
500 | if (messageObj.ms_requestId) results.ms_requestId = messageObj.ms_requestId;
|
501 | finished(results);
|
502 | };
|
503 | if (this.beforeHandlers[application]) {
|
504 | status = this.beforeHandlers[application].call(this, messageObj, session, send, fin);
|
505 | if (status === false) return;
|
506 | }
|
507 |
|
508 | if (this.handlers[application][type]) {
|
509 | this.handlers[application][type].call(this, messageObj, session, send, fin);
|
510 | if (this.afterHandlers[application]) {
|
511 | this.afterHandlers[application].call(this, messageObj, session, send, fin);
|
512 | }
|
513 | }
|
514 | else {
|
515 | error = {error: 'Handler not defined for ' + application + ' messages of type ' + type};
|
516 | if (this.errorMessages && this.errorMessages[application] && this.errorMessages[application].noTypeHandler) {
|
517 | errorObj = customError(this.errorMessages[application].noTypeHandler);
|
518 | if (errorObj) error = errorObj;
|
519 | }
|
520 | finished(error);
|
521 | }
|
522 |
|
523 | });
|
524 |
|
525 | };
|