badmfck-api-server 4.0.73 → 4.0.75
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.
|
@@ -13,6 +13,7 @@ exports.REQ_MICROSERVICE_CALL = new badmfck_signal_1.Req(undefined, "REQ_MICROSE
|
|
|
13
13
|
class MicroserviceClient extends BaseService_1.BaseService {
|
|
14
14
|
static #clients = new Map();
|
|
15
15
|
static #listener = false;
|
|
16
|
+
static #nextID = 1;
|
|
16
17
|
options;
|
|
17
18
|
constructor(opt) {
|
|
18
19
|
super("MicroserviceClient");
|
|
@@ -34,31 +35,32 @@ class MicroserviceClient extends BaseService_1.BaseService {
|
|
|
34
35
|
}
|
|
35
36
|
async requestMicroserviceCall(req) {
|
|
36
37
|
const url = this.options.host + "/__ms_host_control/receiver";
|
|
37
|
-
const ts =
|
|
38
|
-
const nonce = crypto_1.default.randomBytes(
|
|
38
|
+
const ts = Date.now().toString();
|
|
39
|
+
const nonce = crypto_1.default.randomBytes(12).toString("hex");
|
|
39
40
|
const headers = {
|
|
40
41
|
"Content-Type": "application/json",
|
|
41
42
|
"x-microservice-id": this.options.id,
|
|
42
43
|
"x-microservice-ts": ts,
|
|
43
44
|
"x-microservice-nonce": nonce
|
|
44
45
|
};
|
|
45
|
-
const data = Buffer.from(JSON.stringify(req), "utf8");
|
|
46
46
|
const secret = Buffer.from(this.options.securityKey, "base64");
|
|
47
|
-
const
|
|
48
|
-
const key =
|
|
49
|
-
const iv =
|
|
50
|
-
const aad = Buffer.from(ts
|
|
47
|
+
const hash = crypto_1.default.createHash("sha256").update(nonce + ts + this.options.securityKey).digest();
|
|
48
|
+
const key = secret;
|
|
49
|
+
const iv = hash.subarray(0, 12);
|
|
50
|
+
const aad = Buffer.from(`${ts}.${nonce}.${this.options.id}`, "utf8");
|
|
51
|
+
const data = Buffer.from(JSON.stringify(req), "utf8");
|
|
51
52
|
const cipher = crypto_1.default.createCipheriv("aes-256-gcm", key, iv);
|
|
52
53
|
cipher.setAAD(aad);
|
|
53
54
|
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
54
55
|
const tag = cipher.getAuthTag();
|
|
55
|
-
const resp = await Http_1.Http.post(url, {
|
|
56
|
+
const resp = await Http_1.Http.post(url, {
|
|
57
|
+
tag: tag.toString("base64"),
|
|
58
|
+
enc: encrypted.toString("base64")
|
|
59
|
+
}, { headers });
|
|
56
60
|
if (!resp.ok)
|
|
57
|
-
return { ...DefaultErrors_1.default.BAD_REQUEST, details: resp.details
|
|
61
|
+
return { ...DefaultErrors_1.default.BAD_REQUEST, details: resp.details };
|
|
58
62
|
const body = resp.data;
|
|
59
|
-
|
|
60
|
-
return body.error;
|
|
61
|
-
return body.data ?? null;
|
|
63
|
+
return (body && typeof body === "object" && "error" in body) ? body.error : (body.data ?? null);
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
exports.MicroserviceClient = MicroserviceClient;
|
|
@@ -1,34 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
6
|
exports.MicroserviceHost = void 0;
|
|
30
7
|
const BaseService_1 = require("../BaseService");
|
|
31
|
-
const DefaultErrors_1 =
|
|
8
|
+
const DefaultErrors_1 = __importDefault(require("../structures/DefaultErrors"));
|
|
32
9
|
const crypto_1 = __importDefault(require("crypto"));
|
|
33
10
|
class MicroserviceHost extends BaseService_1.BaseService {
|
|
34
11
|
static #calls = new Set();
|
|
@@ -46,62 +23,49 @@ class MicroserviceHost extends BaseService_1.BaseService {
|
|
|
46
23
|
return MicroserviceHost.#instances.get(id) || null;
|
|
47
24
|
}
|
|
48
25
|
async handleIncomingRequest(req) {
|
|
49
|
-
console.log("Handling incoming request for MicroserviceHost:", this.getName());
|
|
50
26
|
const nonce = req.headers["x-microservice-nonce"];
|
|
51
27
|
const ts = req.headers["x-microservice-ts"];
|
|
52
28
|
if (!nonce || !ts)
|
|
53
29
|
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "missing headers" };
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "timestamp
|
|
58
|
-
const checkCall = MicroserviceHost.#calls.has(nonce + "|" + ts);
|
|
59
|
-
if (checkCall)
|
|
60
|
-
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "replay attack detected" };
|
|
61
|
-
MicroserviceHost.#calls.add(nonce + "|" + ts);
|
|
62
|
-
if (MicroserviceHost.#calls.size > 1000) {
|
|
63
|
-
const first = MicroserviceHost.#calls.values().next().value;
|
|
64
|
-
if (first)
|
|
65
|
-
MicroserviceHost.#calls.delete(first);
|
|
66
|
-
}
|
|
67
|
-
const secret = Buffer.from(this.options.securityKey, "base64");
|
|
68
|
-
const salt = crypto_1.default.createHash("sha256").update(nonce + ts).digest();
|
|
69
|
-
const key = crypto_1.default.pbkdf2Sync(secret, salt, 100, 32, "sha256");
|
|
70
|
-
const iv = crypto_1.default.pbkdf2Sync(secret, salt, 100, 16, "sha256");
|
|
71
|
-
const aad = Buffer.from(ts + "." + nonce + "." + this.options.id + "." + this.options.password, "utf8");
|
|
72
|
-
const tag = Buffer.from(req.data.tag, "base64");
|
|
73
|
-
const enc = Buffer.from(req.data.enc, "base64");
|
|
74
|
-
const decipher = crypto_1.default.createDecipheriv("aes-256-gcm", key, iv);
|
|
75
|
-
decipher.setAAD(aad);
|
|
76
|
-
decipher.setAuthTag(tag);
|
|
77
|
-
const decrypted = Buffer.concat([decipher.update(enc), decipher.final()]);
|
|
78
|
-
let request = null;
|
|
79
|
-
try {
|
|
80
|
-
request = JSON.parse(decrypted.toString("utf8"));
|
|
30
|
+
const requestTime = parseInt(ts);
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
if (isNaN(requestTime) || Math.abs(now - requestTime) > 1000 * 60 * 2) {
|
|
33
|
+
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "timestamp out of range" };
|
|
81
34
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (!request) {
|
|
86
|
-
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "no request found" };
|
|
87
|
-
}
|
|
88
|
-
if (typeof request !== "object" || !request.requestName) {
|
|
89
|
-
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "invalid request object" };
|
|
35
|
+
const callKey = `${nonce}|${ts}`;
|
|
36
|
+
if (MicroserviceHost.#calls.has(callKey)) {
|
|
37
|
+
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "replay attack detected" };
|
|
90
38
|
}
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
|
|
39
|
+
MicroserviceHost.#calls.add(callKey);
|
|
40
|
+
if (MicroserviceHost.#calls.size > 5000) {
|
|
41
|
+
const iterator = MicroserviceHost.#calls.values();
|
|
42
|
+
for (let i = 0; i < 100; i++) {
|
|
43
|
+
const val = iterator.next().value;
|
|
44
|
+
if (val)
|
|
45
|
+
MicroserviceHost.#calls.delete(val);
|
|
46
|
+
}
|
|
94
47
|
}
|
|
95
|
-
let response = null;
|
|
96
48
|
try {
|
|
97
|
-
|
|
49
|
+
const secret = Buffer.from(this.options.securityKey, "base64");
|
|
50
|
+
const hash = crypto_1.default.createHash("sha256").update(nonce + ts + this.options.securityKey).digest();
|
|
51
|
+
const key = secret;
|
|
52
|
+
const iv = hash.subarray(0, 12);
|
|
53
|
+
const aad = Buffer.from(`${ts}.${nonce}.${this.options.id}`, "utf8");
|
|
54
|
+
const tag = Buffer.from(req.data.tag, "base64");
|
|
55
|
+
const enc = Buffer.from(req.data.enc, "base64");
|
|
56
|
+
const decipher = crypto_1.default.createDecipheriv("aes-256-gcm", key, iv);
|
|
57
|
+
decipher.setAAD(aad);
|
|
58
|
+
decipher.setAuthTag(tag);
|
|
59
|
+
const decrypted = Buffer.concat([decipher.update(enc), decipher.final()]);
|
|
60
|
+
const request = JSON.parse(decrypted.toString("utf8"));
|
|
61
|
+
const reqCall = this.options.requests.find(r => r.name === request?.requestName);
|
|
62
|
+
if (!reqCall)
|
|
63
|
+
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "method not found" };
|
|
64
|
+
return await reqCall.request(request.requestData);
|
|
98
65
|
}
|
|
99
66
|
catch (e) {
|
|
100
|
-
|
|
101
|
-
return e;
|
|
102
|
-
return { ...DefaultErrors_1.default.INTERNAL_SERVER_ERROR, details: "request execution error: " + e?.message };
|
|
67
|
+
return { ...DefaultErrors_1.default.BAD_REQUEST, details: "decryption error" };
|
|
103
68
|
}
|
|
104
|
-
return response;
|
|
105
69
|
}
|
|
106
70
|
}
|
|
107
71
|
exports.MicroserviceHost = MicroserviceHost;
|