@zerooneit/expressive-tea 1.3.0-beta.4 → 1.3.0-beta.6
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/.eslintrc.js +44 -0
- package/.gitattributes +4 -0
- package/classes/Boot.d.ts +7 -4
- package/classes/Boot.js +53 -46
- package/classes/Engine.d.ts +15 -0
- package/classes/Engine.js +30 -0
- package/classes/LoadBalancer.js +1 -1
- package/classes/ProxyRoute.d.ts +3 -3
- package/decorators/annotations.d.ts +1 -1
- package/decorators/module.d.ts +4 -3
- package/decorators/module.js +2 -1
- package/decorators/proxy.d.ts +2 -2
- package/decorators/proxy.js +5 -1
- package/decorators/router.d.ts +4 -4
- package/decorators/router.js +6 -4
- package/decorators/server.d.ts +4 -4
- package/engines/constants/constants.d.ts +2 -0
- package/engines/constants/constants.js +5 -0
- package/engines/http/index.d.ts +5 -6
- package/engines/http/index.js +20 -22
- package/engines/socketio/index.d.ts +9 -0
- package/engines/socketio/index.js +23 -0
- package/engines/teacup/index.d.ts +5 -7
- package/engines/teacup/index.js +35 -52
- package/engines/teapot/index.d.ts +9 -10
- package/engines/teapot/index.js +51 -81
- package/engines/websocket/index.d.ts +5 -5
- package/engines/websocket/index.js +10 -13
- package/exceptions/RequestExceptions.d.ts +1 -1
- package/helpers/boot-helper.d.ts +2 -2
- package/helpers/boot-helper.js +3 -2
- package/helpers/promise-helper.d.ts +1 -0
- package/helpers/promise-helper.js +7 -0
- package/helpers/server.d.ts +5 -5
- package/helpers/server.js +12 -10
- package/helpers/teapot-helper.d.ts +6 -4
- package/helpers/teapot-helper.js +19 -4
- package/helpers/websocket-helper.d.ts +2 -2
- package/interfaces/index.d.ts +4 -0
- package/interfaces/index.js +2 -0
- package/inversify.config.d.ts +4 -4
- package/package.json +42 -33
- package/services/DependencyInjection.d.ts +4 -2
- package/services/DependencyInjection.js +2 -2
- package/services/WebsocketService.d.ts +2 -2
- package/tsconfig.linter.json +24 -0
- package/tslint-to-eslint-config.log +12 -0
- package/.circleci/config.yml +0 -58
package/engines/teacup/index.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const chalk = require("chalk");
|
|
5
|
-
const
|
|
6
|
-
// tslint:disable-next-line:no-duplicate-imports
|
|
5
|
+
const url_1 = require("url");
|
|
7
6
|
const socket_io_client_1 = require("socket.io-client");
|
|
8
7
|
const inversify_1 = require("inversify");
|
|
9
8
|
const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
|
|
10
9
|
const constants_1 = require("@expressive-tea/commons/constants");
|
|
11
10
|
const teapot_helper_1 = require("../../helpers/teapot-helper");
|
|
12
11
|
const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
|
|
13
|
-
|
|
12
|
+
const Engine_1 = require("../../classes/Engine");
|
|
13
|
+
let TeacupEngine = class TeacupEngine extends Engine_1.default {
|
|
14
14
|
header() {
|
|
15
15
|
console.log(chalk.white.bold('Teacup Engine is initializing...'));
|
|
16
16
|
console.log(chalk `
|
|
@@ -25,83 +25,66 @@ let TeacupEngine = class TeacupEngine {
|
|
|
25
25
|
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
26
|
`);
|
|
27
27
|
}
|
|
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) {
|
|
28
|
+
handshaked(key, signature, isSecure, cb) {
|
|
50
29
|
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;
|
|
30
|
+
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {yellow.bold Server Verification Started}`);
|
|
31
|
+
if (!teapot_helper_1.default.verify(this.teacupSettings.clientKey, key.toString('ascii'), signature)) {
|
|
32
|
+
throw new Error('Fail to Verify Client on Teapod.');
|
|
63
33
|
}
|
|
64
|
-
|
|
34
|
+
console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Server Has Been Verified}`);
|
|
35
|
+
this.publicServerKey = key;
|
|
36
|
+
this.serverSignature = signature;
|
|
37
|
+
cb(Buffer.from(this.publicKey), this.clientSignature);
|
|
65
38
|
}
|
|
66
39
|
catch (e) {
|
|
67
40
|
console.error(chalk `{cyan.bold [TEACUP]} - {red.bold TEAPOD} {magenta.bold ${this.client.id}}: Failed with next message: ${e.message}`);
|
|
68
41
|
this.client.disconnect();
|
|
69
42
|
}
|
|
70
43
|
}
|
|
71
|
-
accepted() {
|
|
44
|
+
accepted(cb) {
|
|
72
45
|
var _a;
|
|
73
46
|
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
|
-
|
|
47
|
+
const encryptedMessage = teapot_helper_1.default.encrypt({
|
|
75
48
|
mountTo: this.teacupSettings.mountTo,
|
|
76
49
|
address: this.teacupSettings.address
|
|
77
|
-
}, this.serverSignature.slice(0, 32))
|
|
50
|
+
}, this.serverSignature.slice(0, 32));
|
|
51
|
+
cb(encryptedMessage);
|
|
78
52
|
const onClose = () => {
|
|
79
53
|
try {
|
|
80
54
|
this.client.close();
|
|
81
55
|
}
|
|
82
|
-
catch (_) {
|
|
56
|
+
catch (_) {
|
|
57
|
+
}
|
|
83
58
|
};
|
|
84
59
|
this.server.on('close', onClose);
|
|
85
60
|
(_a = this.serverSecure) === null || _a === void 0 ? void 0 : _a.on('close', onClose);
|
|
86
61
|
}
|
|
87
62
|
async start() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
63
|
+
this.teacupSettings = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this.context));
|
|
64
|
+
const scheme = new url_1.URL(this.teacupSettings.serverUrl);
|
|
65
|
+
const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teacupSettings.clientKey);
|
|
66
|
+
const protocol = teapot_helper_1.default.httpSchema(scheme.protocol);
|
|
67
|
+
this.publicKey = publicKey;
|
|
68
|
+
this.privateKey = privateKey;
|
|
69
|
+
this.clientSignature = teapot_helper_1.default.sign(this.teacupSettings.clientKey, this.privateKey, this.teacupSettings.clientKey);
|
|
70
|
+
this.client = (0, socket_io_client_1.io)(`${protocol}//${scheme.host}/teapot`, {
|
|
71
|
+
path: '/exp-tea/',
|
|
72
|
+
reconnection: true,
|
|
73
|
+
autoConnect: false
|
|
74
|
+
});
|
|
91
75
|
this.header();
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
92
77
|
this.client.on('handshake', this.handshaked.bind(this));
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
93
79
|
this.client.on('accepted', this.accepted.bind(this));
|
|
94
80
|
this.client.on('error', console.log);
|
|
95
81
|
this.client.connect();
|
|
96
82
|
}
|
|
83
|
+
static canRegister(ctx, settings) {
|
|
84
|
+
return Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(ctx), 'isTeacupActive');
|
|
85
|
+
}
|
|
97
86
|
};
|
|
98
87
|
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])
|
|
88
|
+
(0, inversify_1.injectable)()
|
|
106
89
|
], TeacupEngine);
|
|
107
90
|
exports.default = TeacupEngine;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
private readonly
|
|
6
|
-
private
|
|
7
|
-
private registeredRoute;
|
|
1
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
2
|
+
import Boot from '../../classes/Boot';
|
|
3
|
+
import Settings from '../../classes/Settings';
|
|
4
|
+
export default class TeapotEngine extends ExpressiveTeaEngine {
|
|
5
|
+
private readonly clients;
|
|
6
|
+
private readonly registeredRoute;
|
|
8
7
|
private teapotSettings;
|
|
9
8
|
private publicKey;
|
|
10
9
|
private privateKey;
|
|
11
|
-
private isActive;
|
|
12
10
|
private serverSignature;
|
|
13
11
|
private socketServer;
|
|
14
12
|
private static header;
|
|
15
13
|
private registerTeacup;
|
|
16
|
-
private
|
|
14
|
+
private clientVerification;
|
|
17
15
|
private registered;
|
|
18
16
|
private removeFromRoutes;
|
|
19
17
|
private findClientInRoutes;
|
|
20
18
|
private disconnected;
|
|
21
|
-
|
|
19
|
+
init(): Promise<void>;
|
|
22
20
|
start(): Promise<void>;
|
|
21
|
+
static canRegister(ctx?: Boot, settings?: Settings): boolean;
|
|
23
22
|
}
|
package/engines/teapot/index.js
CHANGED
|
@@ -4,11 +4,19 @@ 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
|
+
const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
|
|
14
|
+
let TeapotEngine = TeapotEngine_1 = class TeapotEngine extends Engine_1.default {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.clients = new Map();
|
|
18
|
+
this.registeredRoute = new Map();
|
|
19
|
+
}
|
|
12
20
|
static header(teapotSettings) {
|
|
13
21
|
console.log(chalk.white.bold('Teapot Engine is initializing...'));
|
|
14
22
|
console.log(chalk `
|
|
@@ -28,64 +36,46 @@ All Communication are encrypted to ensure intruder can not connected, however, p
|
|
|
28
36
|
}
|
|
29
37
|
registerTeacup(teacup) {
|
|
30
38
|
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {grey.bold Connected}`);
|
|
31
|
-
teacup.emit('handshake',
|
|
32
|
-
|
|
33
|
-
|
|
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));
|
|
39
|
+
teacup.emit('handshake', Buffer.from(this.publicKey), this.serverSignature, Boolean(this.serverSecure), this.clientVerification.bind(this, teacup));
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
41
|
+
teacup.on('disconnect', this.disconnected.bind(this, teacup));
|
|
38
42
|
}
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
clientVerification(teacup, userPublicKey, userSignature) {
|
|
44
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {yellow.bold Client Verification Started}`);
|
|
45
|
+
console.log('userKey', userPublicKey.toString('base64'));
|
|
46
|
+
console.log('userSignature', userSignature.toString('base64'));
|
|
41
47
|
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;
|
|
48
|
+
if (!teapot_helper_1.default.verify(this.teapotSettings.clientKey, userPublicKey.toString('ascii'), userSignature)) {
|
|
49
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed to verify and will be disconnected...`);
|
|
50
|
+
return teacup.disconnect();
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
this.clients.set(teacup.id, {
|
|
53
|
+
publicKey: userPublicKey,
|
|
54
|
+
signature: userSignature
|
|
55
|
+
});
|
|
56
|
+
teacup.emit('accepted', this.registered.bind(this, teacup));
|
|
57
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {green.bold Client Verified}`);
|
|
58
58
|
}
|
|
59
59
|
catch (e) {
|
|
60
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${
|
|
61
|
-
|
|
60
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed wiht next message: ${e.message}`);
|
|
61
|
+
teacup.disconnect();
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
registered(
|
|
65
|
-
const self = this;
|
|
64
|
+
registered(teacup, encryptedMessage) {
|
|
66
65
|
try {
|
|
67
|
-
const message = teapot_helper_1.default.decrypt(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
});
|
|
66
|
+
const message = teapot_helper_1.default.decrypt(encryptedMessage, this.serverSignature.slice(0, 32));
|
|
67
|
+
const isRegistered = this.registeredRoute.has(message.mountTo);
|
|
68
|
+
const proxyRoute = isRegistered ? this.registeredRoute.get(message.mountTo) : new ProxyRoute_1.default(message.mountTo);
|
|
69
|
+
proxyRoute.registerServer(message.address, teacup.id);
|
|
70
|
+
if (!isRegistered) {
|
|
71
|
+
this.registeredRoute.set(message.mountTo, proxyRoute);
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
73
|
+
this.context.getApplication().use(message.mountTo, teapot_helper_1.default.proxyResponse.bind(this, proxyRoute));
|
|
84
74
|
}
|
|
85
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${
|
|
75
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}] {blue.bold <${message.address}>} <--> {white.bold ${message.mountTo}}`);
|
|
86
76
|
}
|
|
87
77
|
catch (e) {
|
|
88
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${
|
|
78
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
|
|
89
79
|
}
|
|
90
80
|
}
|
|
91
81
|
removeFromRoutes(routes = [], id) {
|
|
@@ -103,54 +93,34 @@ All Communication are encrypted to ensure intruder can not connected, however, p
|
|
|
103
93
|
});
|
|
104
94
|
return routes;
|
|
105
95
|
}
|
|
106
|
-
disconnected(
|
|
107
|
-
const self = this;
|
|
96
|
+
disconnected(teacup, reason) {
|
|
108
97
|
try {
|
|
109
|
-
const routes =
|
|
110
|
-
|
|
111
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${
|
|
98
|
+
const routes = this.findClientInRoutes(teacup.id);
|
|
99
|
+
this.removeFromRoutes(routes, teacup.id);
|
|
100
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: Got disconnected by ${reason}`);
|
|
112
101
|
}
|
|
113
102
|
catch (e) {
|
|
114
|
-
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${
|
|
103
|
+
console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
|
|
115
104
|
}
|
|
116
105
|
}
|
|
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');
|
|
106
|
+
async init() {
|
|
125
107
|
this.teapotSettings = Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, this.context);
|
|
126
|
-
if (!this.isActive) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
108
|
const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teapotSettings.serverKey);
|
|
130
109
|
this.publicKey = publicKey;
|
|
131
110
|
this.privateKey = privateKey;
|
|
132
111
|
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
112
|
}
|
|
138
113
|
async start() {
|
|
139
|
-
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
114
|
+
this.socketServer = Metadata_1.default.get(constants_2.SOCKET_IO_INSTANCE_KEY, this.context).of('/teapot');
|
|
142
115
|
TeapotEngine_1.header(this.teapotSettings);
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
143
117
|
this.socketServer.on('connection', this.registerTeacup.bind(this));
|
|
144
|
-
|
|
118
|
+
}
|
|
119
|
+
static canRegister(ctx, settings) {
|
|
120
|
+
return Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, (0, object_helper_1.getClass)(ctx), 'isTeapotActive');
|
|
145
121
|
}
|
|
146
122
|
};
|
|
147
123
|
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])
|
|
124
|
+
(0, inversify_1.injectable)()
|
|
155
125
|
], TeapotEngine);
|
|
156
126
|
exports.default = TeapotEngine;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import ExpressiveTeaEngine from '../../classes/Engine';
|
|
2
|
+
import Boot from '../../classes/Boot';
|
|
3
|
+
import Settings from '../../classes/Settings';
|
|
4
|
+
export default class WebsocketEngine extends ExpressiveTeaEngine {
|
|
5
5
|
canStart: boolean;
|
|
6
6
|
isDetached: boolean;
|
|
7
|
-
constructor(server: any, serverSecure: any, settings: any);
|
|
8
7
|
init(): Promise<void>;
|
|
8
|
+
static canRegister(ctx?: Boot, settings?: Settings): boolean;
|
|
9
9
|
}
|
|
@@ -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 }));
|
|
@@ -25,13 +24,11 @@ let WebsocketEngine = class WebsocketEngine {
|
|
|
25
24
|
WebsocketService_1.default.getInstance().setHttpServer(this.serverSecure);
|
|
26
25
|
}
|
|
27
26
|
}
|
|
27
|
+
static canRegister(ctx, settings) {
|
|
28
|
+
return settings.get('startWebsocket');
|
|
29
|
+
}
|
|
28
30
|
};
|
|
29
31
|
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])
|
|
32
|
+
(0, inversify_1.injectable)()
|
|
36
33
|
], WebsocketEngine);
|
|
37
34
|
exports.default = WebsocketEngine;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
export declare class GenericRequestException extends Error {
|
|
26
26
|
statusCode: number;
|
|
27
27
|
message: string;
|
|
28
|
-
constructor(message:
|
|
28
|
+
constructor(message: string | never, statusCode?: number);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Shortcut Exception for 400 HTTP Errors (Bad Request).
|
package/helpers/boot-helper.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BOOT_STAGES } from '@expressive-tea/commons/constants';
|
|
2
|
-
import { Express } from 'express';
|
|
3
|
-
import Boot from '../classes/Boot';
|
|
2
|
+
import { type Express } from 'express';
|
|
3
|
+
import type Boot from '../classes/Boot';
|
|
4
4
|
export declare function resolveStage(stage: BOOT_STAGES, ctx: Boot, server: Express, ...extraArgs: unknown[]): Promise<void>;
|
|
5
5
|
export declare function resolveDirectives(instance: typeof Boot | Boot, server: Express): Promise<void>;
|
|
6
6
|
export declare function resolveStatic(instance: typeof Boot | Boot, server: Express): Promise<void>;
|
package/helpers/boot-helper.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// tslint:disable:no-duplicate-imports
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.resolveProxy = exports.resolveStatic = exports.resolveDirectives = exports.resolveStage = void 0;
|
|
5
4
|
const constants_1 = require("@expressive-tea/commons/constants");
|
|
@@ -24,7 +23,9 @@ exports.resolveStage = resolveStage;
|
|
|
24
23
|
async function resolveDirectives(instance, server) {
|
|
25
24
|
const registeredDirectives = Metadata_1.default.get(constants_1.REGISTERED_DIRECTIVES_KEY, (0, object_helper_1.getClass)(instance)) || [];
|
|
26
25
|
registeredDirectives.forEach((options) => {
|
|
27
|
-
|
|
26
|
+
// @ts-expect-error Settings can be any parameter
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
28
|
+
server.set(options.name, ...options.settings);
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
exports.resolveDirectives = resolveDirectives;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function delay(ms: number): Promise<unknown>;
|
package/helpers/server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { NextFunction, Request, Response } from 'express';
|
|
2
|
-
import { ExpressiveTeaAnnotations, ExpressiveTeaArgumentOptions } from '@expressive-tea/commons/interfaces';
|
|
1
|
+
import { type NextFunction, type Request, type Response } from 'express';
|
|
2
|
+
import { type ExpressiveTeaAnnotations, type 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
|
-
export declare function router(verb: string, route: string, target: any, handler: (...args: any[]) =>
|
|
8
|
+
export declare function router(verb: string, route: string, target: any, handler: (...args: any[]) => never | any | Promise<any>, propertyKey: string | symbol, settings?: any): void;
|
|
9
9
|
export declare function fileSettings(): any;
|
package/helpers/server.js
CHANGED
|
@@ -10,7 +10,8 @@ const fs = require("fs");
|
|
|
10
10
|
function autoResponse(request, response, annotations, responseResult) {
|
|
11
11
|
const view = (0, lodash_1.find)(annotations, { type: 'view' });
|
|
12
12
|
if (view) {
|
|
13
|
-
|
|
13
|
+
response.render(view.arguments[0], responseResult);
|
|
14
|
+
return;
|
|
14
15
|
}
|
|
15
16
|
response.send((0, lodash_1.isNumber)(responseResult) ? responseResult.toString() : responseResult);
|
|
16
17
|
}
|
|
@@ -22,14 +23,15 @@ async function executeRequest(request, response, next) {
|
|
|
22
23
|
next(error);
|
|
23
24
|
isNextUsed = true;
|
|
24
25
|
};
|
|
25
|
-
const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper(),
|
|
26
|
+
const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper(), this.options.introspectedArgs));
|
|
26
27
|
if (!response.headersSent && !isNextUsed) {
|
|
27
28
|
autoResponse(request, response, this.annotations, result);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
catch (e) {
|
|
31
32
|
if (e instanceof RequestExceptions_1.GenericRequestException) {
|
|
32
|
-
|
|
33
|
+
next(e);
|
|
34
|
+
return;
|
|
33
35
|
}
|
|
34
36
|
next(new RequestExceptions_1.GenericRequestException(e.message || 'System Error'));
|
|
35
37
|
}
|
|
@@ -39,7 +41,6 @@ function mapArguments(decoratedArguments, request, response, next, introspectedA
|
|
|
39
41
|
return (0, lodash_1.chain)(decoratedArguments)
|
|
40
42
|
.sortBy('index')
|
|
41
43
|
.map((argument) => {
|
|
42
|
-
const argumentKey = (0, lodash_1.get)(introspectedArgs, argument.index);
|
|
43
44
|
switch (argument.type) {
|
|
44
45
|
case constants_1.ARGUMENT_TYPES.REQUEST:
|
|
45
46
|
return request;
|
|
@@ -48,13 +49,13 @@ function mapArguments(decoratedArguments, request, response, next, introspectedA
|
|
|
48
49
|
case constants_1.ARGUMENT_TYPES.NEXT:
|
|
49
50
|
return next;
|
|
50
51
|
case constants_1.ARGUMENT_TYPES.QUERY:
|
|
51
|
-
return extractParameters(request.query, argument.arguments,
|
|
52
|
+
return extractParameters(request.query, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
52
53
|
case constants_1.ARGUMENT_TYPES.BODY:
|
|
53
|
-
return extractParameters(request.body, argument.arguments,
|
|
54
|
+
return extractParameters(request.body, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
54
55
|
case constants_1.ARGUMENT_TYPES.GET_PARAM:
|
|
55
|
-
return extractParameters(request.params, argument.arguments,
|
|
56
|
+
return extractParameters(request.params, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
|
|
56
57
|
default:
|
|
57
|
-
return;
|
|
58
|
+
return undefined;
|
|
58
59
|
}
|
|
59
60
|
})
|
|
60
61
|
.thru((args) => (0, lodash_1.size)(args) ? args : [request, response, next])
|
|
@@ -78,12 +79,13 @@ function extractParameters(target, args, propertyName) {
|
|
|
78
79
|
}
|
|
79
80
|
exports.extractParameters = extractParameters;
|
|
80
81
|
function generateRoute(route, verb, ...settings) {
|
|
81
|
-
return (target, propertyKey, descriptor) => router(verb, route, target, descriptor.value, propertyKey, settings);
|
|
82
|
+
return (target, propertyKey, descriptor) => { router(verb, route, target, descriptor.value, propertyKey, settings); };
|
|
82
83
|
}
|
|
83
84
|
exports.generateRoute = generateRoute;
|
|
84
85
|
function router(verb, route, target, handler, propertyKey, settings) {
|
|
86
|
+
const introspectedArgs = (0, object_helper_1.getOwnArgumentNames)(handler);
|
|
85
87
|
const existedRoutesHandlers = Metadata_1.default.get(constants_1.ROUTER_HANDLERS_KEY, target) || [];
|
|
86
|
-
existedRoutesHandlers.unshift({ verb, route, handler, target, propertyKey, settings });
|
|
88
|
+
existedRoutesHandlers.unshift({ verb, route, handler, target, propertyKey, settings, introspectedArgs });
|
|
87
89
|
Metadata_1.default.set(constants_1.ROUTER_HANDLERS_KEY, existedRoutesHandlers, target);
|
|
88
90
|
}
|
|
89
91
|
exports.router = router;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import { KeyPairSyncResult } from 'crypto';
|
|
3
|
+
import { type KeyPairSyncResult } from 'crypto';
|
|
4
|
+
import { type NextFunction, type Request, type Response } from 'express';
|
|
5
|
+
import type ProxyRoute from '../classes/ProxyRoute';
|
|
4
6
|
export interface EncryptedMessage {
|
|
5
7
|
iv: string;
|
|
6
8
|
message: string;
|
|
7
9
|
}
|
|
8
|
-
export
|
|
9
|
-
[property: string]: any;
|
|
10
|
-
}
|
|
10
|
+
export type TeaGatewayMessage = Record<string, any>;
|
|
11
11
|
export default class TeaGatewayHelper {
|
|
12
12
|
static encrypt(data: TeaGatewayMessage, signature: Buffer): EncryptedMessage;
|
|
13
13
|
static decrypt(data: EncryptedMessage, signature: Buffer): TeaGatewayMessage;
|
|
14
14
|
static sign(data: string, privateKey: string, passphrase: string): Buffer;
|
|
15
15
|
static verify(data: string, publicKey: string, signature: Buffer): boolean;
|
|
16
16
|
static generateKeys(passphrase: string): KeyPairSyncResult<any, any>;
|
|
17
|
+
static proxyResponse(proxyRoute: ProxyRoute, req: Request, res: Response, next: NextFunction): void;
|
|
18
|
+
static httpSchema(schema: string): "http:" | "https:";
|
|
17
19
|
}
|
package/helpers/teapot-helper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const crypto = require("crypto");
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
4
5
|
class TeaGatewayHelper {
|
|
5
6
|
static encrypt(data, signature) {
|
|
6
7
|
const iv = crypto.randomBytes(16);
|
|
@@ -17,19 +18,18 @@ class TeaGatewayHelper {
|
|
|
17
18
|
return JSON.parse(decrypted.toString());
|
|
18
19
|
}
|
|
19
20
|
static sign(data, privateKey, passphrase) {
|
|
20
|
-
return crypto.sign(
|
|
21
|
+
return crypto.sign(null, Buffer.from(data), {
|
|
21
22
|
key: privateKey,
|
|
22
23
|
passphrase
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
static verify(data, publicKey, signature) {
|
|
26
|
-
return crypto.verify(
|
|
27
|
+
return crypto.verify(null, Buffer.from(data), {
|
|
27
28
|
key: publicKey
|
|
28
29
|
}, signature);
|
|
29
30
|
}
|
|
30
31
|
static generateKeys(passphrase) {
|
|
31
|
-
|
|
32
|
-
return generateKeyPairSync('rsa', {
|
|
32
|
+
return (0, crypto_1.generateKeyPairSync)('ed25519', {
|
|
33
33
|
modulusLength: 2048,
|
|
34
34
|
publicKeyEncoding: {
|
|
35
35
|
type: 'spki',
|
|
@@ -43,5 +43,20 @@ 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
|
+
next();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
router(req, res, next);
|
|
53
|
+
}
|
|
54
|
+
static httpSchema(schema) {
|
|
55
|
+
if (schema.includes('teapot'))
|
|
56
|
+
return 'http:';
|
|
57
|
+
if (schema.includes('teapots'))
|
|
58
|
+
return 'https:';
|
|
59
|
+
throw new Error(`Invalid Schema: ${schema}`);
|
|
60
|
+
}
|
|
46
61
|
}
|
|
47
62
|
exports.default = TeaGatewayHelper;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import * as http from 'http';
|
|
4
|
-
import * as https from 'https';
|
|
3
|
+
import type * as http from 'http';
|
|
4
|
+
import type * as https from 'https';
|
|
5
5
|
export declare function initWebsocket(server: http.Server, secureServer: https.Server): Promise<void>;
|