@zerooneit/expressive-tea 1.3.0-beta.3 → 1.3.0-beta.5
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/classes/Boot.d.ts +2 -3
- package/classes/Boot.js +31 -26
- package/classes/Engine.d.ts +14 -0
- package/classes/Engine.js +29 -0
- package/engines/constants/constants.d.ts +2 -0
- package/engines/constants/constants.js +5 -0
- package/engines/http/index.d.ts +2 -6
- package/engines/http/index.js +14 -20
- package/engines/socketio/index.d.ts +6 -0
- package/engines/socketio/index.js +20 -0
- package/engines/teacup/index.d.ts +2 -7
- package/engines/teacup/index.js +29 -50
- package/engines/teapot/index.d.ts +4 -8
- package/engines/teapot/index.js +44 -81
- package/engines/websocket/index.d.ts +2 -5
- package/engines/websocket/index.js +7 -13
- package/helpers/promise-helper.d.ts +1 -0
- package/helpers/promise-helper.js +7 -0
- package/helpers/server.d.ts +2 -2
- package/helpers/server.js +6 -6
- package/helpers/teapot-helper.d.ts +4 -0
- package/helpers/teapot-helper.js +16 -3
- package/interfaces/index.d.ts +4 -0
- package/interfaces/index.js +2 -0
- package/package.json +26 -27
- package/.circleci/config.yml +0 -58
package/classes/Boot.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import '../inversify.config';
|
|
3
2
|
import { Express } from 'express';
|
|
4
|
-
import Settings from '../classes/Settings';
|
|
5
3
|
import { ExpressiveTeaApplication } from '@expressive-tea/commons/interfaces';
|
|
4
|
+
import Settings from '../classes/Settings';
|
|
6
5
|
/**
|
|
7
6
|
* Expressive Tea Application interface is the response from an started application, contains the express application
|
|
8
7
|
* and a node http server instance.
|
|
9
8
|
* @typedef {Object} ExpressiveTeaApplication
|
|
10
9
|
* @property {Express} application - Express Application Instance
|
|
11
|
-
* @property {HTTPServer} server - HTTP Server Object
|
|
10
|
+
* @property { HTTPServer } server - HTTP Server Object
|
|
12
11
|
* @summary Application Interface
|
|
13
12
|
*/
|
|
14
13
|
/**
|
package/classes/Boot.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
require("reflect-metadata");
|
|
4
|
-
require("../inversify.config");
|
|
5
|
-
const $P = require("bluebird");
|
|
4
|
+
const inversify_config_1 = require("../inversify.config");
|
|
6
5
|
// tslint:disable-next-line:no-duplicate-imports
|
|
7
6
|
const express = require("express");
|
|
7
|
+
const constants_1 = require("@expressive-tea/commons/constants");
|
|
8
|
+
const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
9
|
+
const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
|
|
10
|
+
const http_1 = require("../engines/http");
|
|
11
|
+
const websocket_1 = require("../engines/websocket");
|
|
12
|
+
const index_1 = require("../engines/teapot/index");
|
|
13
|
+
const teacup_1 = require("../engines/teacup");
|
|
14
|
+
const Engine_1 = require("../classes/Engine");
|
|
15
|
+
const Settings_1 = require("../classes/Settings");
|
|
16
|
+
const index_2 = require("../engines/socketio/index");
|
|
8
17
|
const fs = require("fs");
|
|
9
18
|
const http = require("http");
|
|
10
19
|
const https = require("https");
|
|
11
|
-
const Settings_1 = require("../classes/Settings");
|
|
12
|
-
const constants_1 = require("@expressive-tea/commons/constants");
|
|
13
|
-
const index_1 = require("../engines/http/index");
|
|
14
|
-
const index_2 = require("../engines/websocket/index");
|
|
15
|
-
const index_3 = require("../engines/teapot/index");
|
|
16
|
-
const teacup_1 = require("../engines/teacup");
|
|
17
|
-
// tslint:disable-next-line:no-duplicate-imports
|
|
18
|
-
const inversify_config_1 = require("../inversify.config");
|
|
19
20
|
/**
|
|
20
21
|
* Expressive Tea Application interface is the response from an started application, contains the express application
|
|
21
22
|
* and a node http server instance.
|
|
22
23
|
* @typedef {Object} ExpressiveTeaApplication
|
|
23
24
|
* @property {Express} application - Express Application Instance
|
|
24
|
-
* @property {HTTPServer} server - HTTP Server Object
|
|
25
|
+
* @property { HTTPServer } server - HTTP Server Object
|
|
25
26
|
* @summary Application Interface
|
|
26
27
|
*/
|
|
27
28
|
/**
|
|
@@ -59,7 +60,7 @@ class Boot {
|
|
|
59
60
|
* @returns {Promise<ExpressiveTeaApplication>}
|
|
60
61
|
*/
|
|
61
62
|
async start() {
|
|
62
|
-
return new
|
|
63
|
+
return new Promise(async (resolver, reject) => {
|
|
63
64
|
try {
|
|
64
65
|
const localContainer = inversify_config_1.default.createChild();
|
|
65
66
|
const privateKey = this.settings.get('privateKey');
|
|
@@ -68,29 +69,33 @@ class Boot {
|
|
|
68
69
|
const secureServer = privateKey && certificate && https.createServer({
|
|
69
70
|
cert: fs.readFileSync(certificate).toString('utf-8'),
|
|
70
71
|
key: fs.readFileSync(privateKey).toString('utf-8')
|
|
71
|
-
}
|
|
72
|
+
});
|
|
72
73
|
// Injectables
|
|
73
74
|
localContainer.bind('server').toConstantValue(server);
|
|
74
75
|
localContainer.bind('secureServer').toConstantValue(secureServer || undefined);
|
|
75
76
|
localContainer.bind('context').toConstantValue(this);
|
|
76
77
|
localContainer.bind('settings').toConstantValue(this.settings);
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
78
|
+
// Activation
|
|
79
|
+
const isActiveTeapot = Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, (0, object_helper_1.getClass)(this), 'isTeapotActive');
|
|
80
|
+
const isActiveTeacup = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this), 'isTeacupActive');
|
|
81
|
+
const isActiveWebsockets = this.settings.get('startWebsocket');
|
|
82
|
+
// Resolve Engines
|
|
83
|
+
const httpEngine = localContainer.resolve(http_1.default);
|
|
84
|
+
const availableEngines = [
|
|
85
|
+
localContainer.resolve(index_2.default),
|
|
86
|
+
...isActiveWebsockets ? [localContainer.resolve(websocket_1.default)] : [],
|
|
87
|
+
...isActiveTeapot ? [localContainer.resolve(index_1.default)] : [],
|
|
88
|
+
...isActiveTeacup ? [localContainer.resolve(teacup_1.default)] : [],
|
|
89
|
+
];
|
|
90
|
+
// Initialize Engines
|
|
91
|
+
await Engine_1.default.exec(availableEngines, 'init');
|
|
82
92
|
await httpEngine.init();
|
|
83
|
-
await httpEngine.
|
|
84
|
-
await
|
|
85
|
-
await httpEngine.resolveStages([constants_1.BOOT_STAGES.AFTER_APPLICATION_MIDDLEWARES, constants_1.BOOT_STAGES.ON_HTTP_CREATION], server, secureServer);
|
|
86
|
-
const listenerServers = await httpEngine.start();
|
|
87
|
-
await httpEngine.resolveStages([constants_1.BOOT_STAGES.START], ...listenerServers);
|
|
88
|
-
await teapotEngine.start();
|
|
89
|
-
await teacupEngine.start();
|
|
93
|
+
await httpEngine.start();
|
|
94
|
+
await Engine_1.default.exec(availableEngines, 'start');
|
|
90
95
|
resolver({ application: this.server, server, secureServer });
|
|
91
96
|
}
|
|
92
97
|
catch (e) {
|
|
93
|
-
return
|
|
98
|
+
return reject(e);
|
|
94
99
|
}
|
|
95
100
|
});
|
|
96
101
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import Settings from './Settings';
|
|
4
|
+
import Boot from './Boot';
|
|
5
|
+
import http from 'http';
|
|
6
|
+
import https from 'https';
|
|
7
|
+
export default class ExpressiveTeaEngine {
|
|
8
|
+
protected readonly settings: Settings;
|
|
9
|
+
protected readonly context: Boot;
|
|
10
|
+
protected readonly server: http.Server;
|
|
11
|
+
protected readonly serverSecure?: https.Server;
|
|
12
|
+
constructor(ctx: any, server: any, serverSecure: any, settings: any);
|
|
13
|
+
static exec(availableEngines: ExpressiveTeaEngine[], method: string): any;
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const inversify_1 = require("inversify");
|
|
5
|
+
let ExpressiveTeaEngine = class ExpressiveTeaEngine {
|
|
6
|
+
constructor(ctx, server, serverSecure, settings) {
|
|
7
|
+
this.settings = settings;
|
|
8
|
+
this.context = ctx;
|
|
9
|
+
this.server = server;
|
|
10
|
+
this.serverSecure = serverSecure;
|
|
11
|
+
}
|
|
12
|
+
static exec(availableEngines, method) {
|
|
13
|
+
return Promise.all(availableEngines
|
|
14
|
+
// tslint:disable-next-line:no-string-literal
|
|
15
|
+
.filter(engine => typeof engine[method] === 'function')
|
|
16
|
+
// tslint:disable-next-line:no-string-literal
|
|
17
|
+
.map(engine => engine[method]()));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
ExpressiveTeaEngine = tslib_1.__decorate([
|
|
21
|
+
(0, inversify_1.injectable)(),
|
|
22
|
+
tslib_1.__param(0, (0, inversify_1.inject)('context')),
|
|
23
|
+
tslib_1.__param(1, (0, inversify_1.inject)('server')),
|
|
24
|
+
tslib_1.__param(2, (0, inversify_1.inject)('secureServer')),
|
|
25
|
+
tslib_1.__param(2, (0, inversify_1.optional)()),
|
|
26
|
+
tslib_1.__param(3, (0, inversify_1.inject)('settings')),
|
|
27
|
+
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object])
|
|
28
|
+
], ExpressiveTeaEngine);
|
|
29
|
+
exports.default = ExpressiveTeaEngine;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SOCKET_IO_SECURE_INSTANCE_KEY = exports.SOCKET_IO_INSTANCE_KEY = void 0;
|
|
4
|
+
exports.SOCKET_IO_INSTANCE_KEY = 'SOCKETIO:INSTANCE';
|
|
5
|
+
exports.SOCKET_IO_SECURE_INSTANCE_KEY = 'SOCKETIO:INSTANCE:SECURE';
|
package/engines/http/index.d.ts
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
import * as http from 'http';
|
|
4
4
|
import * as https from 'https';
|
|
5
5
|
import { BOOT_STAGES } from '@expressive-tea/commons/constants';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
private readonly context;
|
|
9
|
-
private readonly server;
|
|
10
|
-
private readonly serverSecure?;
|
|
11
|
-
constructor(ctx: any, server: any, serverSecure: any, settings: any);
|
|
6
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
7
|
+
export default class HTTPEngine extends ExpressiveTeaEngine {
|
|
12
8
|
private listen;
|
|
13
9
|
start(): Promise<(http.Server | https.Server)[]>;
|
|
14
10
|
init(): Promise<void>;
|
package/engines/http/index.js
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
const $P = require("bluebird");
|
|
5
4
|
const inversify_1 = require("inversify");
|
|
6
5
|
const boot_helper_1 = require("../../helpers/boot-helper");
|
|
7
6
|
const constants_1 = require("@expressive-tea/commons/constants");
|
|
8
7
|
const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
|
|
9
8
|
const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.context = ctx;
|
|
13
|
-
this.server = server;
|
|
14
|
-
this.serverSecure = serverSecure;
|
|
15
|
-
this.settings = settings;
|
|
16
|
-
}
|
|
9
|
+
const Engine_1 = require("../../classes/Engine");
|
|
10
|
+
let HTTPEngine = class HTTPEngine extends Engine_1.default {
|
|
17
11
|
listen(server, port) {
|
|
18
|
-
return new
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
console.log('Listening on port', port, server.listen);
|
|
19
14
|
server.listen(port);
|
|
20
15
|
server.on('error', error => {
|
|
21
16
|
reject(error);
|
|
@@ -27,19 +22,24 @@ let HTTPEngine = class HTTPEngine {
|
|
|
27
22
|
});
|
|
28
23
|
}
|
|
29
24
|
async start() {
|
|
30
|
-
|
|
25
|
+
console.log(`Starting Server Test`);
|
|
26
|
+
const listenerServers = [
|
|
31
27
|
await this.listen(this.server, this.settings.get('port')),
|
|
32
28
|
(this.serverSecure) ? await this.listen(this.serverSecure, this.settings.get('securePort')) : null
|
|
33
29
|
];
|
|
30
|
+
await this.resolveStages([constants_1.BOOT_STAGES.START], ...listenerServers);
|
|
31
|
+
return listenerServers;
|
|
34
32
|
}
|
|
35
33
|
async init() {
|
|
36
34
|
await (0, boot_helper_1.resolveDirectives)(this.context, this.context.getApplication());
|
|
37
35
|
await (0, boot_helper_1.resolveStatic)(this.context, this.context.getApplication());
|
|
36
|
+
// HTTP Engine Resolve Stages
|
|
37
|
+
await this.resolveProxyContainers();
|
|
38
|
+
await this.resolveStages(constants_1.BOOT_ORDER);
|
|
39
|
+
await this.resolveStages([constants_1.BOOT_STAGES.AFTER_APPLICATION_MIDDLEWARES, constants_1.BOOT_STAGES.ON_HTTP_CREATION], this.server, this.serverSecure);
|
|
38
40
|
}
|
|
39
41
|
async resolveStages(stages, ...extraArgs) {
|
|
40
|
-
return
|
|
41
|
-
return (0, boot_helper_1.resolveStage)(s, this.context, this.context.getApplication(), ...extraArgs);
|
|
42
|
-
});
|
|
42
|
+
return Promise.all(stages.map(s => (0, boot_helper_1.resolveStage)(s, this.context, this.context.getApplication(), ...extraArgs)));
|
|
43
43
|
}
|
|
44
44
|
async resolveProxyContainers() {
|
|
45
45
|
const ProxyContainers = Metadata_1.default.get(constants_1.ROUTER_PROXIES_KEY, (0, object_helper_1.getClass)(this.context)) || [];
|
|
@@ -49,12 +49,6 @@ let HTTPEngine = class HTTPEngine {
|
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
HTTPEngine = tslib_1.__decorate([
|
|
52
|
-
(0, inversify_1.injectable)()
|
|
53
|
-
tslib_1.__param(0, (0, inversify_1.inject)('context')),
|
|
54
|
-
tslib_1.__param(1, (0, inversify_1.inject)('server')),
|
|
55
|
-
tslib_1.__param(2, (0, inversify_1.inject)('secureServer')),
|
|
56
|
-
tslib_1.__param(2, (0, inversify_1.optional)()),
|
|
57
|
-
tslib_1.__param(3, (0, inversify_1.inject)('settings')),
|
|
58
|
-
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object])
|
|
52
|
+
(0, inversify_1.injectable)()
|
|
59
53
|
], HTTPEngine);
|
|
60
54
|
exports.default = HTTPEngine;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const socket_io_1 = require("socket.io");
|
|
4
|
+
const Engine_1 = require("../../classes/Engine");
|
|
5
|
+
const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
6
|
+
const constants_1 = require("../constants/constants");
|
|
7
|
+
class SocketIOEngine extends Engine_1.default {
|
|
8
|
+
async init() {
|
|
9
|
+
const commonConfig = {
|
|
10
|
+
path: '/exp-tea/',
|
|
11
|
+
transports: ['websocket', 'polling']
|
|
12
|
+
};
|
|
13
|
+
this.io = this.server && new socket_io_1.Server(this.server, Object.assign({}, commonConfig));
|
|
14
|
+
this.ioSecure = this.serverSecure && new socket_io_1.Server(this.serverSecure, Object.assign({}, commonConfig));
|
|
15
|
+
Metadata_1.default.set(constants_1.SOCKET_IO_INSTANCE_KEY, this.io, this.context);
|
|
16
|
+
Metadata_1.default.set(constants_1.SOCKET_IO_SECURE_INSTANCE_KEY, this.ioSecure, this.context);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.default = SocketIOEngine;
|
|
20
|
+
;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
private readonly context;
|
|
4
|
-
private readonly server;
|
|
5
|
-
private readonly serverSecure?;
|
|
1
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
2
|
+
export default class TeacupEngine extends ExpressiveTeaEngine {
|
|
6
3
|
private teacupSettings;
|
|
7
|
-
private isActive;
|
|
8
4
|
private publicKey;
|
|
9
5
|
private privateKey;
|
|
10
6
|
private publicServerKey;
|
|
@@ -12,7 +8,6 @@ export default class TeacupEngine {
|
|
|
12
8
|
private clientSignature;
|
|
13
9
|
private client;
|
|
14
10
|
private header;
|
|
15
|
-
constructor(ctx: any, settings: any, server: any, serverSecure: any);
|
|
16
11
|
private handshaked;
|
|
17
12
|
private accepted;
|
|
18
13
|
start(): Promise<void>;
|
package/engines/teacup/index.js
CHANGED
|
@@ -10,7 +10,8 @@ const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
|
10
10
|
const constants_1 = require("@expressive-tea/commons/constants");
|
|
11
11
|
const teapot_helper_1 = require("../../helpers/teapot-helper");
|
|
12
12
|
const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
|
|
13
|
-
|
|
13
|
+
const Engine_1 = require("../../classes/Engine");
|
|
14
|
+
let TeacupEngine = class TeacupEngine extends Engine_1.default {
|
|
14
15
|
header() {
|
|
15
16
|
console.log(chalk.white.bold('Teacup Engine is initializing...'));
|
|
16
17
|
console.log(chalk `
|
|
@@ -25,69 +26,53 @@ let TeacupEngine = class TeacupEngine {
|
|
|
25
26
|
All Communication are encrypted to ensure intruder can not connected, however, please does not share any sensitive data like keys or passwords to avoid security issues.
|
|
26
27
|
`);
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
this.server = server;
|
|
30
|
-
this.serverSecure = serverSecure;
|
|
31
|
-
this.settings = settings;
|
|
32
|
-
this.context = ctx;
|
|
33
|
-
this.teacupSettings = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this.context));
|
|
34
|
-
this.isActive = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this.context), 'isTeacupActive');
|
|
35
|
-
if (!this.isActive) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const scheme = url.parse(this.teacupSettings.serverUrl);
|
|
39
|
-
const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teacupSettings.clientKey);
|
|
40
|
-
this.publicKey = publicKey;
|
|
41
|
-
this.privateKey = privateKey;
|
|
42
|
-
this.clientSignature = teapot_helper_1.default.sign(this.teacupSettings.clientKey, this.privateKey, this.teacupSettings.clientKey);
|
|
43
|
-
this.client = (0, socket_io_client_1.io)(`http://${scheme.host}`, {
|
|
44
|
-
path: '/teapot',
|
|
45
|
-
reconnection: true,
|
|
46
|
-
autoConnect: false
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
handshaked(data) {
|
|
29
|
+
handshaked(key, signature, isSecure, cb) {
|
|
50
30
|
try {
|
|
51
|
-
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {yellow.bold
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (teapot_helper_1.default.verify(this.teacupSettings.clientKey, serverPublicKey, serverSignature)) {
|
|
55
|
-
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Verified}`);
|
|
56
|
-
this.publicServerKey = serverPublicKey;
|
|
57
|
-
this.serverSignature = serverSignature;
|
|
58
|
-
this.client.emit('handshake', {
|
|
59
|
-
key: Buffer.from(this.publicKey).toString('base64'),
|
|
60
|
-
signature: this.clientSignature.toString('base64')
|
|
61
|
-
});
|
|
62
|
-
return;
|
|
31
|
+
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {yellow.bold Server Verification Started}`);
|
|
32
|
+
if (!teapot_helper_1.default.verify(this.teacupSettings.clientKey, key.toString('ascii'), signature)) {
|
|
33
|
+
throw new Error('Fail to Verify Client on Teapod.');
|
|
63
34
|
}
|
|
64
|
-
|
|
35
|
+
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Server Has Been Verified}`);
|
|
36
|
+
this.publicServerKey = key;
|
|
37
|
+
this.serverSignature = signature;
|
|
38
|
+
cb(Buffer.from(this.publicKey), this.clientSignature);
|
|
65
39
|
}
|
|
66
40
|
catch (e) {
|
|
67
41
|
console.error(chalk `{cyan.bold [TEACUP]} - {red.bold TEAPOD} {magenta.bold ${this.client.id}}: Failed with next message: ${e.message}`);
|
|
68
42
|
this.client.disconnect();
|
|
69
43
|
}
|
|
70
44
|
}
|
|
71
|
-
accepted() {
|
|
45
|
+
accepted(cb) {
|
|
72
46
|
var _a;
|
|
73
47
|
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Registered} - {blue.bold <${this.teacupSettings.serverUrl}>} <-> {white.bold ${this.teacupSettings.mountTo}}`);
|
|
74
|
-
|
|
48
|
+
const encryptedMessage = teapot_helper_1.default.encrypt({
|
|
75
49
|
mountTo: this.teacupSettings.mountTo,
|
|
76
50
|
address: this.teacupSettings.address
|
|
77
|
-
}, this.serverSignature.slice(0, 32))
|
|
51
|
+
}, this.serverSignature.slice(0, 32));
|
|
52
|
+
cb(encryptedMessage);
|
|
78
53
|
const onClose = () => {
|
|
79
54
|
try {
|
|
80
55
|
this.client.close();
|
|
81
56
|
}
|
|
82
|
-
catch (_) {
|
|
57
|
+
catch (_) {
|
|
58
|
+
}
|
|
83
59
|
};
|
|
84
60
|
this.server.on('close', onClose);
|
|
85
61
|
(_a = this.serverSecure) === null || _a === void 0 ? void 0 : _a.on('close', onClose);
|
|
86
62
|
}
|
|
87
63
|
async start() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
64
|
+
this.teacupSettings = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this.context));
|
|
65
|
+
const scheme = url.parse(this.teacupSettings.serverUrl);
|
|
66
|
+
const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teacupSettings.clientKey);
|
|
67
|
+
const protocol = teapot_helper_1.default.httpSchema(scheme.protocol);
|
|
68
|
+
this.publicKey = publicKey;
|
|
69
|
+
this.privateKey = privateKey;
|
|
70
|
+
this.clientSignature = teapot_helper_1.default.sign(this.teacupSettings.clientKey, this.privateKey, this.teacupSettings.clientKey);
|
|
71
|
+
this.client = (0, socket_io_client_1.io)(`${protocol}//${scheme.host}/teapot`, {
|
|
72
|
+
path: '/exp-tea/',
|
|
73
|
+
reconnection: true,
|
|
74
|
+
autoConnect: false
|
|
75
|
+
});
|
|
91
76
|
this.header();
|
|
92
77
|
this.client.on('handshake', this.handshaked.bind(this));
|
|
93
78
|
this.client.on('accepted', this.accepted.bind(this));
|
|
@@ -96,12 +81,6 @@ All Communication are encrypted to ensure intruder can not connected, however, p
|
|
|
96
81
|
}
|
|
97
82
|
};
|
|
98
83
|
TeacupEngine = tslib_1.__decorate([
|
|
99
|
-
(0, inversify_1.injectable)()
|
|
100
|
-
tslib_1.__param(0, (0, inversify_1.inject)('context')),
|
|
101
|
-
tslib_1.__param(1, (0, inversify_1.inject)('settings')),
|
|
102
|
-
tslib_1.__param(2, (0, inversify_1.inject)('server')),
|
|
103
|
-
tslib_1.__param(3, (0, inversify_1.inject)('secureServer')),
|
|
104
|
-
tslib_1.__param(3, (0, inversify_1.optional)()),
|
|
105
|
-
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object])
|
|
84
|
+
(0, inversify_1.injectable)()
|
|
106
85
|
], TeacupEngine);
|
|
107
86
|
exports.default = TeacupEngine;
|
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
private readonly context;
|
|
4
|
-
private readonly server;
|
|
5
|
-
private readonly serverSecure?;
|
|
1
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
2
|
+
export default class TeapotEngine extends ExpressiveTeaEngine {
|
|
6
3
|
private clients;
|
|
7
4
|
private registeredRoute;
|
|
8
5
|
private teapotSettings;
|
|
9
6
|
private publicKey;
|
|
10
7
|
private privateKey;
|
|
11
|
-
private isActive;
|
|
12
8
|
private serverSignature;
|
|
13
9
|
private socketServer;
|
|
14
10
|
private static header;
|
|
15
11
|
private registerTeacup;
|
|
16
|
-
private
|
|
12
|
+
private clientVerification;
|
|
17
13
|
private registered;
|
|
18
14
|
private removeFromRoutes;
|
|
19
15
|
private findClientInRoutes;
|
|
20
16
|
private disconnected;
|
|
21
|
-
|
|
17
|
+
init(): Promise<void>;
|
|
22
18
|
start(): Promise<void>;
|
|
23
19
|
}
|
package/engines/teapot/index.js
CHANGED
|
@@ -4,11 +4,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const inversify_1 = require("inversify");
|
|
7
|
-
const ProxyRoute_1 = require("../../classes/ProxyRoute");
|
|
8
7
|
const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
9
8
|
const constants_1 = require("@expressive-tea/commons/constants");
|
|
9
|
+
const ProxyRoute_1 = require("../../classes/ProxyRoute");
|
|
10
|
+
const Engine_1 = require("../../classes/Engine");
|
|
10
11
|
const teapot_helper_1 = require("../../helpers/teapot-helper");
|
|
11
|
-
|
|
12
|
+
const constants_2 = require("../constants/constants");
|
|
13
|
+
let TeapotEngine = TeapotEngine_1 = class TeapotEngine extends Engine_1.default {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.clients = new Map();
|
|
17
|
+
this.registeredRoute = new Map();
|
|
18
|
+
}
|
|
12
19
|
static header(teapotSettings) {
|
|
13
20
|
console.log(chalk.white.bold('Teapot Engine is initializing...'));
|
|
14
21
|
console.log(chalk `
|
|
@@ -28,64 +35,44 @@ All Communication are encrypted to ensure intruder can not connected, however, p
|
|
|
28
35
|
}
|
|
29
36
|
registerTeacup(teacup) {
|
|
30
37
|
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {grey.bold Connected}`);
|
|
31
|
-
teacup.emit('handshake',
|
|
32
|
-
|
|
33
|
-
signature: this.serverSignature.toString('base64')
|
|
34
|
-
});
|
|
35
|
-
teacup.on('handshake', this.acceptedHandshake.bind(teacup, this));
|
|
36
|
-
teacup.on('register', this.registered.bind(teacup, this));
|
|
37
|
-
teacup.on('disconnect', this.disconnected.bind(teacup, this));
|
|
38
|
+
teacup.emit('handshake', Buffer.from(this.publicKey), this.serverSignature, Boolean(this.serverSecure), this.clientVerification.bind(this, teacup));
|
|
39
|
+
teacup.on('disconnect', this.disconnected.bind(this, teacup));
|
|
38
40
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
clientVerification(teacup, userPublicKey, userSignature) {
|
|
42
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {yellow.bold Client Verification Started}`);
|
|
43
|
+
console.log('userKey', userPublicKey.toString('base64'));
|
|
44
|
+
console.log('userSignature', userSignature.toString('base64'));
|
|
41
45
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (teapot_helper_1.default.verify(ctx.teapotSettings.clientKey, clientPublicKey, clientSignature)) {
|
|
46
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${self.id}}]: {green.bold Verified correctly}`);
|
|
47
|
-
ctx.clients.set(self.id, {
|
|
48
|
-
publicKey: clientPublicKey,
|
|
49
|
-
signature: clientSignature
|
|
50
|
-
});
|
|
51
|
-
self.emit('accepted', teapot_helper_1.default.encrypt({
|
|
52
|
-
signature: ctx.serverSignature.toString('base64')
|
|
53
|
-
}, clientSignature.slice(0, 32)));
|
|
54
|
-
return;
|
|
46
|
+
if (!teapot_helper_1.default.verify(this.teapotSettings.clientKey, userPublicKey.toString('ascii'), userSignature)) {
|
|
47
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed to verify and will be disconnected...`);
|
|
48
|
+
return teacup.disconnect();
|
|
55
49
|
}
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
this.clients.set(teacup.id, {
|
|
51
|
+
publicKey: userPublicKey,
|
|
52
|
+
signature: userSignature
|
|
53
|
+
});
|
|
54
|
+
teacup.emit('accepted', this.registered.bind(this, teacup));
|
|
55
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {green.bold Client Verified}`);
|
|
58
56
|
}
|
|
59
57
|
catch (e) {
|
|
60
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${
|
|
61
|
-
|
|
58
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed wiht next message: ${e.message}`);
|
|
59
|
+
teacup.disconnect();
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
|
-
registered(
|
|
65
|
-
const self = this;
|
|
62
|
+
registered(teacup, encryptedMessage) {
|
|
66
63
|
try {
|
|
67
|
-
const message = teapot_helper_1.default.decrypt(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
const message = teapot_helper_1.default.decrypt(encryptedMessage, this.serverSignature.slice(0, 32));
|
|
65
|
+
const isRegistered = this.registeredRoute.has(message.mountTo);
|
|
66
|
+
const proxyRoute = isRegistered ? this.registeredRoute.get(message.mountTo) : new ProxyRoute_1.default(message.mountTo);
|
|
67
|
+
proxyRoute.registerServer(message.address, teacup.id);
|
|
68
|
+
if (!isRegistered) {
|
|
69
|
+
this.registeredRoute.set(message.mountTo, proxyRoute);
|
|
70
|
+
this.context.getApplication().use(message.mountTo, teapot_helper_1.default.proxyResponse.bind(this, proxyRoute));
|
|
72
71
|
}
|
|
73
|
-
|
|
74
|
-
proxyRoute = new ProxyRoute_1.default(message.mountTo);
|
|
75
|
-
proxyRoute.registerServer(message.address, self.id);
|
|
76
|
-
ctx.registeredRoute.set(message.mountTo, proxyRoute);
|
|
77
|
-
ctx.context.getApplication().use(message.mountTo, (req, res, next) => {
|
|
78
|
-
const router = proxyRoute.registerRoute();
|
|
79
|
-
if (!proxyRoute.hasClients()) {
|
|
80
|
-
return next();
|
|
81
|
-
}
|
|
82
|
-
return router(req, res, next);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${self.id}}] {blue.bold <${message.address}>} <--> {white.bold ${message.mountTo}}`);
|
|
72
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}] {blue.bold <${message.address}>} <--> {white.bold ${message.mountTo}}`);
|
|
86
73
|
}
|
|
87
74
|
catch (e) {
|
|
88
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${
|
|
75
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
|
|
89
76
|
}
|
|
90
77
|
}
|
|
91
78
|
removeFromRoutes(routes = [], id) {
|
|
@@ -103,54 +90,30 @@ All Communication are encrypted to ensure intruder can not connected, however, p
|
|
|
103
90
|
});
|
|
104
91
|
return routes;
|
|
105
92
|
}
|
|
106
|
-
disconnected(
|
|
107
|
-
const self = this;
|
|
93
|
+
disconnected(teacup, reason) {
|
|
108
94
|
try {
|
|
109
|
-
const routes =
|
|
110
|
-
|
|
111
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${
|
|
95
|
+
const routes = this.findClientInRoutes(teacup.id);
|
|
96
|
+
this.removeFromRoutes(routes, teacup.id);
|
|
97
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: Got disconnected by ${reason}`);
|
|
112
98
|
}
|
|
113
99
|
catch (e) {
|
|
114
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${
|
|
100
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
|
|
115
101
|
}
|
|
116
102
|
}
|
|
117
|
-
|
|
118
|
-
this.clients = new Map();
|
|
119
|
-
this.registeredRoute = new Map();
|
|
120
|
-
this.settings = settings;
|
|
121
|
-
this.context = ctx;
|
|
122
|
-
this.server = server;
|
|
123
|
-
this.serverSecure = serverSecure;
|
|
124
|
-
this.isActive = Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, this.context, 'isTeapotActive');
|
|
103
|
+
async init() {
|
|
125
104
|
this.teapotSettings = Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, this.context);
|
|
126
|
-
if (!this.isActive) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
105
|
const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teapotSettings.serverKey);
|
|
130
106
|
this.publicKey = publicKey;
|
|
131
107
|
this.privateKey = privateKey;
|
|
132
108
|
this.serverSignature = teapot_helper_1.default.sign(this.teapotSettings.clientKey, privateKey, this.teapotSettings.serverKey);
|
|
133
|
-
this.socketServer = require('socket.io')({
|
|
134
|
-
path: '/teapot',
|
|
135
|
-
cookie: false
|
|
136
|
-
});
|
|
137
109
|
}
|
|
138
110
|
async start() {
|
|
139
|
-
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
111
|
+
this.socketServer = Metadata_1.default.get(constants_2.SOCKET_IO_INSTANCE_KEY, this.context).of('/teapot');
|
|
142
112
|
TeapotEngine_1.header(this.teapotSettings);
|
|
143
113
|
this.socketServer.on('connection', this.registerTeacup.bind(this));
|
|
144
|
-
this.socketServer.listen(this.server);
|
|
145
114
|
}
|
|
146
115
|
};
|
|
147
116
|
TeapotEngine = TeapotEngine_1 = tslib_1.__decorate([
|
|
148
|
-
(0, inversify_1.injectable)()
|
|
149
|
-
tslib_1.__param(0, (0, inversify_1.inject)('context')),
|
|
150
|
-
tslib_1.__param(1, (0, inversify_1.inject)('server')),
|
|
151
|
-
tslib_1.__param(2, (0, inversify_1.inject)('secureServer')),
|
|
152
|
-
tslib_1.__param(2, (0, inversify_1.optional)()),
|
|
153
|
-
tslib_1.__param(3, (0, inversify_1.inject)('settings')),
|
|
154
|
-
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object])
|
|
117
|
+
(0, inversify_1.injectable)()
|
|
155
118
|
], TeapotEngine);
|
|
156
119
|
exports.default = TeapotEngine;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
private readonly server;
|
|
4
|
-
private readonly serverSecure?;
|
|
1
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
2
|
+
export default class WebsocketEngine extends ExpressiveTeaEngine {
|
|
5
3
|
canStart: boolean;
|
|
6
4
|
isDetached: boolean;
|
|
7
|
-
constructor(server: any, serverSecure: any, settings: any);
|
|
8
5
|
init(): Promise<void>;
|
|
9
6
|
}
|
|
@@ -4,17 +4,16 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const WebsocketService_1 = require("../../services/WebsocketService");
|
|
5
5
|
const WebSocket = require("ws");
|
|
6
6
|
const inversify_1 = require("inversify");
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const Engine_1 = require("../../classes/Engine");
|
|
8
|
+
let WebsocketEngine = class WebsocketEngine extends Engine_1.default {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
9
11
|
this.canStart = false;
|
|
10
12
|
this.isDetached = false;
|
|
11
|
-
this.settings = settings;
|
|
12
|
-
this.server = server;
|
|
13
|
-
this.serverSecure = serverSecure;
|
|
14
|
-
this.canStart = this.settings.get('startWebsocket');
|
|
15
|
-
this.isDetached = this.settings.get('detachWebsocket');
|
|
16
13
|
}
|
|
17
14
|
async init() {
|
|
15
|
+
this.canStart = this.settings.get('startWebsocket');
|
|
16
|
+
this.isDetached = this.settings.get('detachWebsocket');
|
|
18
17
|
if (this.canStart) {
|
|
19
18
|
WebsocketService_1.default.init();
|
|
20
19
|
WebsocketService_1.default.getInstance().setWebSocket(new WebSocket.Server(this.isDetached ? { noServer: true } : { server: this.server }));
|
|
@@ -27,11 +26,6 @@ let WebsocketEngine = class WebsocketEngine {
|
|
|
27
26
|
}
|
|
28
27
|
};
|
|
29
28
|
WebsocketEngine = tslib_1.__decorate([
|
|
30
|
-
(0, inversify_1.injectable)()
|
|
31
|
-
tslib_1.__param(0, (0, inversify_1.inject)('server')),
|
|
32
|
-
tslib_1.__param(1, (0, inversify_1.inject)('secureServer')),
|
|
33
|
-
tslib_1.__param(1, (0, inversify_1.optional)()),
|
|
34
|
-
tslib_1.__param(2, (0, inversify_1.inject)('settings')),
|
|
35
|
-
tslib_1.__metadata("design:paramtypes", [Object, Object, Object])
|
|
29
|
+
(0, inversify_1.injectable)()
|
|
36
30
|
], WebsocketEngine);
|
|
37
31
|
exports.default = WebsocketEngine;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function delay(ms: number): Promise<unknown>;
|
package/helpers/server.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { NextFunction, Request, Response } from 'express';
|
|
|
2
2
|
import { ExpressiveTeaAnnotations, ExpressiveTeaArgumentOptions } from '@expressive-tea/commons/interfaces';
|
|
3
3
|
export declare function autoResponse(request: Request, response: Response, annotations: ExpressiveTeaAnnotations[], responseResult?: any): void;
|
|
4
4
|
export declare function executeRequest(request: Request, response: Response, next: NextFunction): Promise<void>;
|
|
5
|
-
export declare function mapArguments(decoratedArguments: ExpressiveTeaArgumentOptions[], request: Request, response: Response, next: NextFunction, introspectedArgs?: string[]):
|
|
6
|
-
export declare function extractParameters(target: unknown, args?: string | string[], propertyName?: string
|
|
5
|
+
export declare function mapArguments(decoratedArguments: ExpressiveTeaArgumentOptions[], request: Request, response: Response, next: NextFunction, introspectedArgs?: string[]): any[];
|
|
6
|
+
export declare function extractParameters(target: unknown, args?: string | string[], propertyName?: string): any;
|
|
7
7
|
export declare function generateRoute(route: string, verb: string, ...settings: any): (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
8
8
|
export declare function router(verb: string, route: string, target: any, handler: (...args: any[]) => void | any | Promise<any>, propertyKey: string | symbol, settings?: any): void;
|
|
9
9
|
export declare function fileSettings(): any;
|
package/helpers/server.js
CHANGED
|
@@ -22,7 +22,7 @@ async function executeRequest(request, response, next) {
|
|
|
22
22
|
next(error);
|
|
23
23
|
isNextUsed = true;
|
|
24
24
|
};
|
|
25
|
-
const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper(),
|
|
25
|
+
const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper(), this.options.introspectedArgs));
|
|
26
26
|
if (!response.headersSent && !isNextUsed) {
|
|
27
27
|
autoResponse(request, response, this.annotations, result);
|
|
28
28
|
}
|
|
@@ -39,7 +39,6 @@ function mapArguments(decoratedArguments, request, response, next, introspectedA
|
|
|
39
39
|
return (0, lodash_1.chain)(decoratedArguments)
|
|
40
40
|
.sortBy('index')
|
|
41
41
|
.map((argument) => {
|
|
42
|
-
const argumentKey = (0, lodash_1.get)(introspectedArgs, argument.index);
|
|
43
42
|
switch (argument.type) {
|
|
44
43
|
case constants_1.ARGUMENT_TYPES.REQUEST:
|
|
45
44
|
return request;
|
|
@@ -48,11 +47,11 @@ function mapArguments(decoratedArguments, request, response, next, introspectedA
|
|
|
48
47
|
case constants_1.ARGUMENT_TYPES.NEXT:
|
|
49
48
|
return next;
|
|
50
49
|
case constants_1.ARGUMENT_TYPES.QUERY:
|
|
51
|
-
return extractParameters(request.query, argument.arguments,
|
|
50
|
+
return extractParameters(request.query, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
52
51
|
case constants_1.ARGUMENT_TYPES.BODY:
|
|
53
|
-
return extractParameters(request.body, argument.arguments,
|
|
52
|
+
return extractParameters(request.body, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
54
53
|
case constants_1.ARGUMENT_TYPES.GET_PARAM:
|
|
55
|
-
return extractParameters(request.params, argument.arguments,
|
|
54
|
+
return extractParameters(request.params, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
56
55
|
default:
|
|
57
56
|
return;
|
|
58
57
|
}
|
|
@@ -82,8 +81,9 @@ function generateRoute(route, verb, ...settings) {
|
|
|
82
81
|
}
|
|
83
82
|
exports.generateRoute = generateRoute;
|
|
84
83
|
function router(verb, route, target, handler, propertyKey, settings) {
|
|
84
|
+
const introspectedArgs = (0, object_helper_1.getOwnArgumentNames)(handler);
|
|
85
85
|
const existedRoutesHandlers = Metadata_1.default.get(constants_1.ROUTER_HANDLERS_KEY, target) || [];
|
|
86
|
-
existedRoutesHandlers.unshift({ verb, route, handler, target, propertyKey, settings });
|
|
86
|
+
existedRoutesHandlers.unshift({ verb, route, handler, target, propertyKey, settings, introspectedArgs });
|
|
87
87
|
Metadata_1.default.set(constants_1.ROUTER_HANDLERS_KEY, existedRoutesHandlers, target);
|
|
88
88
|
}
|
|
89
89
|
exports.router = router;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { KeyPairSyncResult } from 'crypto';
|
|
4
|
+
import { NextFunction, Request, Response } from 'express';
|
|
5
|
+
import ProxyRoute from '../classes/ProxyRoute';
|
|
4
6
|
export interface EncryptedMessage {
|
|
5
7
|
iv: string;
|
|
6
8
|
message: string;
|
|
@@ -14,4 +16,6 @@ export default class TeaGatewayHelper {
|
|
|
14
16
|
static sign(data: string, privateKey: string, passphrase: string): Buffer;
|
|
15
17
|
static verify(data: string, publicKey: string, signature: Buffer): boolean;
|
|
16
18
|
static generateKeys(passphrase: string): KeyPairSyncResult<any, any>;
|
|
19
|
+
static proxyResponse(proxyRoute: ProxyRoute, req: Request, res: Response, next: NextFunction): void;
|
|
20
|
+
static httpSchema(schema: string): "http:" | "https:";
|
|
17
21
|
}
|
package/helpers/teapot-helper.js
CHANGED
|
@@ -17,19 +17,19 @@ class TeaGatewayHelper {
|
|
|
17
17
|
return JSON.parse(decrypted.toString());
|
|
18
18
|
}
|
|
19
19
|
static sign(data, privateKey, passphrase) {
|
|
20
|
-
return crypto.sign(
|
|
20
|
+
return crypto.sign(null, Buffer.from(data), {
|
|
21
21
|
key: privateKey,
|
|
22
22
|
passphrase
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
static verify(data, publicKey, signature) {
|
|
26
|
-
return crypto.verify(
|
|
26
|
+
return crypto.verify(null, Buffer.from(data), {
|
|
27
27
|
key: publicKey
|
|
28
28
|
}, signature);
|
|
29
29
|
}
|
|
30
30
|
static generateKeys(passphrase) {
|
|
31
31
|
const { generateKeyPairSync } = require('crypto');
|
|
32
|
-
return generateKeyPairSync('
|
|
32
|
+
return generateKeyPairSync('ed25519', {
|
|
33
33
|
modulusLength: 2048,
|
|
34
34
|
publicKeyEncoding: {
|
|
35
35
|
type: 'spki',
|
|
@@ -43,5 +43,18 @@ class TeaGatewayHelper {
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
+
static proxyResponse(proxyRoute, req, res, next) {
|
|
47
|
+
const router = proxyRoute.registerRoute();
|
|
48
|
+
if (!proxyRoute.hasClients())
|
|
49
|
+
return next();
|
|
50
|
+
return router(req, res, next);
|
|
51
|
+
}
|
|
52
|
+
static httpSchema(schema) {
|
|
53
|
+
if (schema.includes('teapot'))
|
|
54
|
+
return 'http:';
|
|
55
|
+
if (schema.includes('teapots'))
|
|
56
|
+
return 'https:';
|
|
57
|
+
throw new Error(`Invalid Schema: ${schema}`);
|
|
58
|
+
}
|
|
46
59
|
}
|
|
47
60
|
exports.default = TeaGatewayHelper;
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerooneit/expressive-tea",
|
|
3
|
-
"version": "1.3.0-beta.
|
|
3
|
+
"version": "1.3.0-beta.5",
|
|
4
4
|
"description": "A REST API over Express and Typescript",
|
|
5
5
|
"main": "classes/Boot.js",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=16.0.0"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "
|
|
11
|
-
"test:dev": "
|
|
10
|
+
"test": "yarn run linter && jest --clearCache && jest --coverage --ci --detectOpenHandles --forceExit --silent",
|
|
11
|
+
"test:dev": "yarn run linter && jest --clearCache && jest --detectOpenHandles --forceExit",
|
|
12
12
|
"linter": "tslint -c tslint.json -p tsconfig.json",
|
|
13
13
|
"build:dev": "tsc --project tsconfig.json --watch",
|
|
14
14
|
"build": "tsc --project tsconfig.json",
|
|
15
15
|
"clean:build": "trash '**/*.js' '**/*.d.ts' '**/*.js.map' '**/*.d.ts.map' '!node_modules/**/*' '!docs/**/*' '!coverage/**/*' '!gulpfile.js' '!tasks/*.js' '!jest.config.js' '!tools/**/*'",
|
|
16
|
-
"publish:prepare": "
|
|
17
|
-
"postpublish": "
|
|
18
|
-
"prepublishOnly": "
|
|
16
|
+
"publish:prepare": "yarn run clean:build && yarn run build",
|
|
17
|
+
"postpublish": "yarn run clean:build",
|
|
18
|
+
"prepublishOnly": "yarn test && yarn run publish:prepare"
|
|
19
19
|
},
|
|
20
20
|
"publishConfig": {
|
|
21
21
|
"access": "public"
|
|
@@ -25,45 +25,42 @@
|
|
|
25
25
|
],
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@expressive-tea/commons": "1.0.
|
|
29
|
-
"@expressive-tea/plugin": "1.0.
|
|
30
|
-
"@types/
|
|
31
|
-
"@types/express": "4.17.15",
|
|
28
|
+
"@expressive-tea/commons": "^1.0.1",
|
|
29
|
+
"@expressive-tea/plugin": "1.0.3",
|
|
30
|
+
"@types/express": "4.17.17",
|
|
32
31
|
"@types/express-http-proxy": "1.6.3",
|
|
33
|
-
"@types/express-serve-static-core": "4.17.
|
|
34
|
-
"@types/jest": "29.
|
|
35
|
-
"@types/lodash": "4.14.
|
|
36
|
-
"@types/node": "
|
|
32
|
+
"@types/express-serve-static-core": "4.17.34",
|
|
33
|
+
"@types/jest": "29.5.1",
|
|
34
|
+
"@types/lodash": "4.14.194",
|
|
35
|
+
"@types/node": "20.1.0",
|
|
37
36
|
"@types/reflect-metadata": "0.1.0",
|
|
38
37
|
"@types/socket.io": "3.0.2",
|
|
39
38
|
"@types/socket.io-client": "3.0.0",
|
|
40
39
|
"@types/ws": "8.5.4",
|
|
41
40
|
"http-terminator": "3.2.0",
|
|
42
|
-
"jest": "29.
|
|
41
|
+
"jest": "29.5.0",
|
|
43
42
|
"jest-express": "1.12.0",
|
|
44
|
-
"jest-junit": "
|
|
43
|
+
"jest-junit": "16.0.0",
|
|
45
44
|
"reflect-metadata": "0.1.13",
|
|
46
|
-
"rimraf": "
|
|
45
|
+
"rimraf": "5.0.0",
|
|
47
46
|
"supertest": "6.3.3",
|
|
48
47
|
"toast-jsdoc": "1.0.2",
|
|
49
48
|
"trash-cli": "5.0.0",
|
|
50
|
-
"ts-jest": "29.0
|
|
49
|
+
"ts-jest": "29.1.0",
|
|
51
50
|
"ts-node": "10.9.1",
|
|
52
51
|
"tslint": "6.1.3",
|
|
53
|
-
"typescript": "
|
|
52
|
+
"typescript": "5.0.4"
|
|
54
53
|
},
|
|
55
54
|
"dependencies": {
|
|
56
|
-
"bluebird": "3.7.2",
|
|
57
|
-
"eiows": "^4.1.2",
|
|
58
55
|
"express": "4.18.2",
|
|
59
56
|
"express-http-proxy": "1.6.3",
|
|
60
57
|
"inversify": "6.0.1",
|
|
61
58
|
"inversify-inject-decorators": "3.1.0",
|
|
62
59
|
"lodash": "4.17.21",
|
|
63
|
-
"socket.io": "4.
|
|
64
|
-
"socket.io-client": "4.
|
|
60
|
+
"socket.io": "4.6.1",
|
|
61
|
+
"socket.io-client": "4.6.1",
|
|
65
62
|
"url-scheme": "1.0.5",
|
|
66
|
-
"ws": "8.
|
|
63
|
+
"ws": "8.13.0"
|
|
67
64
|
},
|
|
68
65
|
"repository": {
|
|
69
66
|
"type": "git",
|
|
@@ -111,6 +108,8 @@
|
|
|
111
108
|
},
|
|
112
109
|
"resolutions": {
|
|
113
110
|
"set-value": "4.1.0",
|
|
114
|
-
"glob-parent": "6.0.2"
|
|
115
|
-
|
|
111
|
+
"glob-parent": "6.0.2",
|
|
112
|
+
"engine.io": "6.4.2"
|
|
113
|
+
},
|
|
114
|
+
"packageManager": "yarn@3.5.1"
|
|
116
115
|
}
|
package/.circleci/config.yml
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# Use the latest 2.1 version of CircleCI pipeline process engine.
|
|
2
|
-
# See: https://circleci.com/docs/2.0/configuration-reference
|
|
3
|
-
version: 2.1
|
|
4
|
-
|
|
5
|
-
orbs:
|
|
6
|
-
# The Node.js orb contains a set of prepackaged CircleCI configuration you can utilize
|
|
7
|
-
# Orbs reduce the amount of configuration required for common tasks.
|
|
8
|
-
# See the orb documentation here: https://circleci.com/developer/orbs/orb/circleci/node
|
|
9
|
-
node: circleci/node@4.7
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
# Below is the definition of your job to build and test your app, you can rename and customize it as you want.
|
|
13
|
-
build-and-test:
|
|
14
|
-
# These next lines define a Docker executor: https://circleci.com/docs/2.0/executor-types/
|
|
15
|
-
# You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
|
|
16
|
-
# A list of available CircleCI Docker Convenience Images are available here: https://circleci.com/developer/images/image/cimg/node
|
|
17
|
-
docker:
|
|
18
|
-
- image: cimg/node:16.10
|
|
19
|
-
# Then run your tests!
|
|
20
|
-
# CircleCI will report the results back to your VCS provider.
|
|
21
|
-
steps:
|
|
22
|
-
# Checkout the code as the first step.
|
|
23
|
-
- checkout
|
|
24
|
-
# Next, the node orb's install-packages step will install the dependencies from a package.json.
|
|
25
|
-
# The orb install-packages step will also automatically cache them for faster future runs.
|
|
26
|
-
- restore_cache:
|
|
27
|
-
keys:
|
|
28
|
-
- expressive-tea-{{ checksum "package.json" }}
|
|
29
|
-
- expressive-tea-
|
|
30
|
-
|
|
31
|
-
- node/install-packages:
|
|
32
|
-
# If you are using yarn, change the line below from "npm" to "yarn"
|
|
33
|
-
pkg-manager: yarn
|
|
34
|
-
- save_cache:
|
|
35
|
-
paths:
|
|
36
|
-
- node_modules
|
|
37
|
-
key: expressive-tea-{{ checksum "package.json" }}
|
|
38
|
-
- run:
|
|
39
|
-
name: Expressive Tea Tests
|
|
40
|
-
command: npm test
|
|
41
|
-
environment:
|
|
42
|
-
JEST_JUNIT_OUTPUT_DIR: "./coverage"
|
|
43
|
-
JUNIT_REPORT_NAME: "junit.xml"
|
|
44
|
-
- store_test_results:
|
|
45
|
-
path: ./coverage
|
|
46
|
-
- store_artifacts:
|
|
47
|
-
path: ./coverage
|
|
48
|
-
|
|
49
|
-
workflows:
|
|
50
|
-
# Below is the definition of your workflow.
|
|
51
|
-
# Inside the workflow, you provide the jobs you want to run, e.g this workflow runs the build-and-test job above.
|
|
52
|
-
# CircleCI will run this workflow on every commit.
|
|
53
|
-
# For more details on extending your workflow, see the configuration docs: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
|
54
|
-
Testing:
|
|
55
|
-
jobs:
|
|
56
|
-
- build-and-test
|
|
57
|
-
# For running simple node tests, you could optionally use the node/test job from the orb to replicate and replace the job above in fewer lines.
|
|
58
|
-
# - node/test
|