@meru2802/aux-server 1.0.0
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/README.md +168 -0
- package/dist/config/index.d.ts +37 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +76 -0
- package/dist/config/swagger.d.ts +2 -0
- package/dist/config/swagger.d.ts.map +1 -0
- package/dist/config/swagger.js +267 -0
- package/dist/controllers/BaseController.d.ts +16 -0
- package/dist/controllers/BaseController.d.ts.map +1 -0
- package/dist/controllers/BaseController.js +28 -0
- package/dist/controllers/apiController.d.ts +8 -0
- package/dist/controllers/apiController.d.ts.map +1 -0
- package/dist/controllers/apiController.js +60 -0
- package/dist/controllers/coreController.d.ts +11 -0
- package/dist/controllers/coreController.d.ts.map +1 -0
- package/dist/controllers/coreController.js +470 -0
- package/dist/controllers/healthController.d.ts +9 -0
- package/dist/controllers/healthController.d.ts.map +1 -0
- package/dist/controllers/healthController.js +35 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +97 -0
- package/dist/lib/utils/index.d.ts +10 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +78 -0
- package/dist/lib/utils/index.test.d.ts +3 -0
- package/dist/lib/utils/index.test.d.ts.map +1 -0
- package/dist/lib/utils/index.test.js +197 -0
- package/dist/middleware/BaseMiddleware.d.ts +13 -0
- package/dist/middleware/BaseMiddleware.d.ts.map +1 -0
- package/dist/middleware/BaseMiddleware.js +22 -0
- package/dist/middleware/authMiddleware.d.ts +9 -0
- package/dist/middleware/authMiddleware.d.ts.map +1 -0
- package/dist/middleware/authMiddleware.js +287 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +125 -0
- package/dist/routes/apiRoutes.d.ts +5 -0
- package/dist/routes/apiRoutes.d.ts.map +1 -0
- package/dist/routes/apiRoutes.js +46 -0
- package/dist/routes/coreRoutes.d.ts +5 -0
- package/dist/routes/coreRoutes.d.ts.map +1 -0
- package/dist/routes/coreRoutes.js +158 -0
- package/dist/routes/healthRoutes.d.ts +4 -0
- package/dist/routes/healthRoutes.d.ts.map +1 -0
- package/dist/routes/healthRoutes.js +63 -0
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +31 -0
- package/dist/routes/swaggerRoutes.d.ts +3 -0
- package/dist/routes/swaggerRoutes.d.ts.map +1 -0
- package/dist/routes/swaggerRoutes.js +35 -0
- package/dist/services/ApplicationService.d.ts +26 -0
- package/dist/services/ApplicationService.d.ts.map +1 -0
- package/dist/services/ApplicationService.js +46 -0
- package/dist/services/DatabaseService.d.ts +17 -0
- package/dist/services/DatabaseService.d.ts.map +1 -0
- package/dist/services/DatabaseService.js +38 -0
- package/dist/services/HttpServerService.d.ts +29 -0
- package/dist/services/HttpServerService.d.ts.map +1 -0
- package/dist/services/HttpServerService.js +101 -0
- package/dist/services/ServiceContainer.d.ts +26 -0
- package/dist/services/ServiceContainer.d.ts.map +1 -0
- package/dist/services/ServiceContainer.js +39 -0
- package/dist/services/WebSocketService.d.ts +27 -0
- package/dist/services/WebSocketService.d.ts.map +1 -0
- package/dist/services/WebSocketService.js +180 -0
- package/dist/types/index.d.ts +218 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/schemas/index.d.ts +31 -0
- package/dist/types/schemas/index.d.ts.map +1 -0
- package/dist/types/schemas/index.js +226 -0
- package/package.json +55 -0
|
@@ -0,0 +1,78 @@
|
|
|
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 () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CookieEncryptionError = void 0;
|
|
37
|
+
exports.encodeCookie = encodeCookie;
|
|
38
|
+
exports.getBinaryKey = getBinaryKey;
|
|
39
|
+
const crypto = __importStar(require("crypto"));
|
|
40
|
+
class CookieEncryptionError extends Error {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "CookieEncryptionError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.CookieEncryptionError = CookieEncryptionError;
|
|
47
|
+
function encodeCookie(o, key) {
|
|
48
|
+
try {
|
|
49
|
+
if (key == null) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (key.length < 32) {
|
|
53
|
+
throw new CookieEncryptionError("Key must be at least 32 bytes long");
|
|
54
|
+
}
|
|
55
|
+
const objectToEncode = { ...o };
|
|
56
|
+
objectToEncode.time = Math.floor(Date.now() / 1000);
|
|
57
|
+
const iv = crypto.randomBytes(12);
|
|
58
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key.subarray(0, 32), iv);
|
|
59
|
+
const crypted = Buffer.concat([
|
|
60
|
+
cipher.update(JSON.stringify(objectToEncode), "utf8"),
|
|
61
|
+
cipher.final(),
|
|
62
|
+
]);
|
|
63
|
+
const authTag = cipher.getAuthTag();
|
|
64
|
+
return Buffer.concat([iv, authTag, crypted])
|
|
65
|
+
.toString("base64")
|
|
66
|
+
.replace(/\+/g, "@")
|
|
67
|
+
.replace(/\//g, "$");
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e instanceof CookieEncryptionError) {
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getBinaryKey(key) {
|
|
77
|
+
return Buffer.from(key, "hex");
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/index.test.ts"],"names":[],"mappings":"AAWA,iBAAS,QAAQ,YAsLhB;AAGD,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,197 @@
|
|
|
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 () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runTests = runTests;
|
|
37
|
+
const crypto = __importStar(require("crypto"));
|
|
38
|
+
const index_1 = require("./index");
|
|
39
|
+
// Test suite for cookie utilities
|
|
40
|
+
function runTests() {
|
|
41
|
+
console.log("🧪 Running Cookie Utility Tests...\n");
|
|
42
|
+
let passed = 0;
|
|
43
|
+
let failed = 0;
|
|
44
|
+
function test(name, testFn) {
|
|
45
|
+
try {
|
|
46
|
+
testFn();
|
|
47
|
+
console.log(`✅ ${name}`);
|
|
48
|
+
passed++;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
52
|
+
console.log(`❌ ${name}: ${errorMessage}`);
|
|
53
|
+
failed++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function assert(condition, message) {
|
|
57
|
+
if (!condition) {
|
|
58
|
+
throw new Error(message);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function assertEquals(actual, expected, message) {
|
|
62
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
63
|
+
throw new Error(`${message}. Expected: ${JSON.stringify(expected)}, Got: ${JSON.stringify(actual)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Test 1: Generate cookie key
|
|
67
|
+
test("generateCookieKey() generates 32-byte key", () => {
|
|
68
|
+
const key = (0, index_1.generateCookieKey)();
|
|
69
|
+
assert(Buffer.isBuffer(key), "Should return a Buffer");
|
|
70
|
+
assert(key.length === 32, "Should be 32 bytes long");
|
|
71
|
+
});
|
|
72
|
+
// Test 2: Basic encode/decode functionality
|
|
73
|
+
test("encodeCookie() and decodeCookie() basic functionality", () => {
|
|
74
|
+
const key = (0, index_1.generateCookieKey)();
|
|
75
|
+
const testData = {
|
|
76
|
+
userId: "123",
|
|
77
|
+
role: "admin",
|
|
78
|
+
preferences: { theme: "dark" }
|
|
79
|
+
};
|
|
80
|
+
const encoded = (0, index_1.encodeCookie)(testData, key);
|
|
81
|
+
assert(encoded !== null, "Encoding should succeed");
|
|
82
|
+
assert(typeof encoded === "string", "Should return a string");
|
|
83
|
+
const decoded = (0, index_1.decodeCookie)(encoded, key);
|
|
84
|
+
assert(decoded !== null, "Decoding should succeed");
|
|
85
|
+
assert(decoded !== null && decoded.userId === testData.userId, "userId should match");
|
|
86
|
+
assert(decoded !== null && decoded.role === testData.role, "role should match");
|
|
87
|
+
assert(decoded !== null && typeof decoded.time === "number", "time should be added");
|
|
88
|
+
});
|
|
89
|
+
// Test 3: URL-safe base64 encoding
|
|
90
|
+
test("encoded string is URL-safe", () => {
|
|
91
|
+
const key = (0, index_1.generateCookieKey)();
|
|
92
|
+
const testData = { test: "data" };
|
|
93
|
+
const encoded = (0, index_1.encodeCookie)(testData, key);
|
|
94
|
+
assert(encoded !== null, "Encoding should succeed");
|
|
95
|
+
assert(!encoded.includes("+"), "Should not contain +");
|
|
96
|
+
assert(!encoded.includes("/"), "Should not contain /");
|
|
97
|
+
assert(encoded.includes("@") || encoded.includes("$") || true, "May contain URL-safe replacements");
|
|
98
|
+
});
|
|
99
|
+
// Test 4: Null key handling
|
|
100
|
+
test("handles null key gracefully", () => {
|
|
101
|
+
const testData = { test: "data" };
|
|
102
|
+
const encoded = (0, index_1.encodeCookie)(testData, null);
|
|
103
|
+
assert(encoded === null, "Should return null for null key");
|
|
104
|
+
const decoded = (0, index_1.decodeCookie)("somestring", null);
|
|
105
|
+
assert(decoded === null, "Should return null for null key");
|
|
106
|
+
});
|
|
107
|
+
// Test 5: Invalid key length
|
|
108
|
+
test("throws error for short key", () => {
|
|
109
|
+
const shortKey = Buffer.from("short");
|
|
110
|
+
const testData = { test: "data" };
|
|
111
|
+
try {
|
|
112
|
+
(0, index_1.encodeCookie)(testData, shortKey);
|
|
113
|
+
throw new Error("Should have thrown an error");
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
assert(error instanceof index_1.CookieEncryptionError, "Should throw CookieEncryptionError");
|
|
117
|
+
assert(error instanceof Error && error.message.includes("32 bytes"), "Error message should mention 32 bytes");
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Test 6: Invalid encoded string
|
|
121
|
+
test("handles invalid encoded string", () => {
|
|
122
|
+
const key = (0, index_1.generateCookieKey)();
|
|
123
|
+
const decoded1 = (0, index_1.decodeCookie)("invalid", key);
|
|
124
|
+
assert(decoded1 === null, "Should return null for invalid string");
|
|
125
|
+
const decoded2 = (0, index_1.decodeCookie)("", key);
|
|
126
|
+
assert(decoded2 === null, "Should return null for empty string");
|
|
127
|
+
});
|
|
128
|
+
// Test 7: Object mutation prevention
|
|
129
|
+
test("does not mutate original object", () => {
|
|
130
|
+
const key = (0, index_1.generateCookieKey)();
|
|
131
|
+
const original = { userId: "123", role: "admin" };
|
|
132
|
+
const originalCopy = { ...original };
|
|
133
|
+
(0, index_1.encodeCookie)(original, key);
|
|
134
|
+
assertEquals(original, originalCopy, "Original object should not be mutated");
|
|
135
|
+
});
|
|
136
|
+
// Test 8: Time validation
|
|
137
|
+
test("isValidCookieAge() functionality", () => {
|
|
138
|
+
const currentTime = Math.floor(Date.now() / 1000);
|
|
139
|
+
// Valid cookie (within age limit)
|
|
140
|
+
const validCookie = { time: currentTime - 30, userId: "123" };
|
|
141
|
+
assert((0, index_1.isValidCookieAge)(validCookie, 60), "Should be valid (30 seconds old, max 60)");
|
|
142
|
+
// Expired cookie
|
|
143
|
+
const expiredCookie = { time: currentTime - 120, userId: "123" };
|
|
144
|
+
assert(!(0, index_1.isValidCookieAge)(expiredCookie, 60), "Should be invalid (120 seconds old, max 60)");
|
|
145
|
+
// Cookie without time
|
|
146
|
+
const noTimeCookie = { userId: "123" };
|
|
147
|
+
assert(!(0, index_1.isValidCookieAge)(noTimeCookie, 60), "Should be invalid (no time)");
|
|
148
|
+
// Cookie with invalid time
|
|
149
|
+
const invalidTimeCookie = { time: "invalid", userId: "123" };
|
|
150
|
+
assert(!(0, index_1.isValidCookieAge)(invalidTimeCookie, 60), "Should be invalid (invalid time type)");
|
|
151
|
+
});
|
|
152
|
+
// Test 9: Large data handling
|
|
153
|
+
test("handles large data objects", () => {
|
|
154
|
+
const key = (0, index_1.generateCookieKey)();
|
|
155
|
+
const largeData = {
|
|
156
|
+
userId: "123",
|
|
157
|
+
data: "x".repeat(1000), // 1KB of data
|
|
158
|
+
nested: {
|
|
159
|
+
deep: {
|
|
160
|
+
structure: {
|
|
161
|
+
with: "values"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const encoded = (0, index_1.encodeCookie)(largeData, key);
|
|
167
|
+
assert(encoded !== null, "Should encode large data");
|
|
168
|
+
const decoded = (0, index_1.decodeCookie)(encoded, key);
|
|
169
|
+
assert(decoded !== null, "Should decode large data");
|
|
170
|
+
assert(decoded !== null && decoded.data === largeData.data, "Large data should match");
|
|
171
|
+
});
|
|
172
|
+
// Test 10: Key with different lengths
|
|
173
|
+
test("handles keys longer than 32 bytes", () => {
|
|
174
|
+
const longKey = crypto.randomBytes(64); // 64 bytes
|
|
175
|
+
const testData = { test: "data" };
|
|
176
|
+
const encoded = (0, index_1.encodeCookie)(testData, longKey);
|
|
177
|
+
assert(encoded !== null, "Should work with long key");
|
|
178
|
+
const decoded = (0, index_1.decodeCookie)(encoded, longKey);
|
|
179
|
+
assert(decoded !== null, "Should decode with long key");
|
|
180
|
+
assert(decoded !== null && decoded.test === testData.test, "Data should match");
|
|
181
|
+
});
|
|
182
|
+
// Summary
|
|
183
|
+
console.log(`\n📊 Test Results: ${passed} passed, ${failed} failed`);
|
|
184
|
+
if (failed === 0) {
|
|
185
|
+
console.log("🎉 All tests passed!");
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
console.log("💥 Some tests failed!");
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Run tests if this file is executed directly
|
|
194
|
+
if (require.main === module) {
|
|
195
|
+
const success = runTests();
|
|
196
|
+
process.exit(success ? 0 : 1);
|
|
197
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Pool } from "pg";
|
|
2
|
+
import { IServiceContainer } from "../services/ServiceContainer";
|
|
3
|
+
import { Config } from "../types";
|
|
4
|
+
import { WebSocket } from "ws";
|
|
5
|
+
export declare abstract class BaseMiddleware {
|
|
6
|
+
protected serviceContainer: IServiceContainer;
|
|
7
|
+
constructor(serviceContainer?: IServiceContainer);
|
|
8
|
+
protected get dbPool(): Pool;
|
|
9
|
+
protected get webSocket(): WebSocket | null;
|
|
10
|
+
protected get config(): Config;
|
|
11
|
+
protected get isWebSocketConnected(): boolean;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=BaseMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/BaseMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EACL,iBAAiB,EAElB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,8BAAsB,cAAc;IAClC,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;gBAElC,gBAAgB,CAAC,EAAE,iBAAiB;IAIhD,SAAS,KAAK,MAAM,IAAI,IAAI,CAE3B;IAED,SAAS,KAAK,SAAS,IAAI,SAAS,GAAG,IAAI,CAE1C;IAED,SAAS,KAAK,MAAM,IAAI,MAAM,CAE7B;IAED,SAAS,KAAK,oBAAoB,IAAI,OAAO,CAE5C;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseMiddleware = void 0;
|
|
4
|
+
const ServiceContainer_1 = require("../services/ServiceContainer");
|
|
5
|
+
class BaseMiddleware {
|
|
6
|
+
constructor(serviceContainer) {
|
|
7
|
+
this.serviceContainer = serviceContainer || ServiceContainer_1.ServiceContainer.getInstance();
|
|
8
|
+
}
|
|
9
|
+
get dbPool() {
|
|
10
|
+
return this.serviceContainer.getDatabaseService().getPool();
|
|
11
|
+
}
|
|
12
|
+
get webSocket() {
|
|
13
|
+
return this.serviceContainer.getWebSocketService().getWebSocket();
|
|
14
|
+
}
|
|
15
|
+
get config() {
|
|
16
|
+
return this.serviceContainer.getConfig();
|
|
17
|
+
}
|
|
18
|
+
get isWebSocketConnected() {
|
|
19
|
+
return this.serviceContainer.getWebSocketService().isConnected();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.BaseMiddleware = BaseMiddleware;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { IServiceContainer } from "../services/ServiceContainer";
|
|
3
|
+
import { BaseMiddleware } from "./BaseMiddleware";
|
|
4
|
+
export declare class AuthMiddleware extends BaseMiddleware {
|
|
5
|
+
constructor(serviceContainer?: IServiceContainer);
|
|
6
|
+
hmacAuth: (req: Request, res: Response, next: NextFunction) => void;
|
|
7
|
+
icebergAuth: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=authMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKlD,qBAAa,cAAe,SAAQ,cAAc;gBACpC,gBAAgB,CAAC,EAAE,iBAAiB;IAIzC,QAAQ,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAyKhE;IAEK,WAAW,GAChB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAAC,CAgFd;CACH"}
|
|
@@ -0,0 +1,287 @@
|
|
|
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 () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.AuthMiddleware = void 0;
|
|
40
|
+
const crypto = __importStar(require("crypto"));
|
|
41
|
+
const BaseMiddleware_1 = require("./BaseMiddleware");
|
|
42
|
+
const qs_1 = __importDefault(require("qs"));
|
|
43
|
+
const axios_1 = __importDefault(require("axios"));
|
|
44
|
+
class AuthMiddleware extends BaseMiddleware_1.BaseMiddleware {
|
|
45
|
+
constructor(serviceContainer) {
|
|
46
|
+
super(serviceContainer);
|
|
47
|
+
this.hmacAuth = (req, res, next) => {
|
|
48
|
+
try {
|
|
49
|
+
const signature = req.headers["x-hmac-signature"];
|
|
50
|
+
const timestamp = req.headers["x-hmac-timestamp"];
|
|
51
|
+
const nonce = req.headers["x-hmac-nonce"];
|
|
52
|
+
if (!signature || !timestamp || !nonce) {
|
|
53
|
+
const unauthorizedResponse = {
|
|
54
|
+
error: "UnauthorizedException",
|
|
55
|
+
code: 401,
|
|
56
|
+
message: [
|
|
57
|
+
"missing 'x-hmac-signature' or 'x-hmac-nonce' or 'x-hmac-timestamp' headers",
|
|
58
|
+
],
|
|
59
|
+
path: req.path,
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
};
|
|
62
|
+
res.status(401).json(unauthorizedResponse);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Validate timestamp format and convert to number
|
|
66
|
+
let requestTime;
|
|
67
|
+
try {
|
|
68
|
+
requestTime = parseInt(timestamp.toString());
|
|
69
|
+
if (isNaN(requestTime)) {
|
|
70
|
+
throw new Error("Invalid timestamp format");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (timestampError) {
|
|
74
|
+
const unauthorizedResponse = {
|
|
75
|
+
error: "UnauthorizedException",
|
|
76
|
+
code: 401,
|
|
77
|
+
message: ["invalid 'x-hmac-timestamp' format"],
|
|
78
|
+
path: req.path,
|
|
79
|
+
timestamp: new Date().toISOString(),
|
|
80
|
+
};
|
|
81
|
+
res.status(401).json(unauthorizedResponse);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
if (Math.abs(Date.now() - requestTime) > 5 * 60 * 1000) {
|
|
86
|
+
const unauthorizedResponse = {
|
|
87
|
+
error: "UnauthorizedException",
|
|
88
|
+
code: 401,
|
|
89
|
+
message: ["hmac-signature is expired"],
|
|
90
|
+
path: req.path,
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
};
|
|
93
|
+
res.status(401).json(unauthorizedResponse);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (timeError) {
|
|
98
|
+
console.error("Error checking timestamp validity:", timeError);
|
|
99
|
+
const unauthorizedResponse = {
|
|
100
|
+
error: "UnauthorizedException",
|
|
101
|
+
code: 401,
|
|
102
|
+
message: ["error validating request timestamp"],
|
|
103
|
+
path: req.path,
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
res.status(401).json(unauthorizedResponse);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let bodyHash;
|
|
110
|
+
try {
|
|
111
|
+
bodyHash = req.body
|
|
112
|
+
? crypto
|
|
113
|
+
.createHash("sha256")
|
|
114
|
+
.update(Buffer.from(JSON.stringify(req.body)))
|
|
115
|
+
.digest("hex")
|
|
116
|
+
: "";
|
|
117
|
+
}
|
|
118
|
+
catch (hashError) {
|
|
119
|
+
console.error("Error generating body hash:", hashError);
|
|
120
|
+
const unauthorizedResponse = {
|
|
121
|
+
error: "UnauthorizedException",
|
|
122
|
+
code: 401,
|
|
123
|
+
message: ["error processing request body"],
|
|
124
|
+
path: req.path,
|
|
125
|
+
timestamp: new Date().toISOString(),
|
|
126
|
+
};
|
|
127
|
+
res.status(401).json(unauthorizedResponse);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let message;
|
|
131
|
+
try {
|
|
132
|
+
message = [
|
|
133
|
+
req.method,
|
|
134
|
+
req.originalUrl,
|
|
135
|
+
timestamp,
|
|
136
|
+
nonce,
|
|
137
|
+
`content-type:application/json;host:${req.hostname}`,
|
|
138
|
+
bodyHash,
|
|
139
|
+
].join("\n");
|
|
140
|
+
}
|
|
141
|
+
catch (messageError) {
|
|
142
|
+
console.error("Error constructing HMAC message:", messageError);
|
|
143
|
+
const unauthorizedResponse = {
|
|
144
|
+
error: "UnauthorizedException",
|
|
145
|
+
code: 401,
|
|
146
|
+
message: ["error processing request data"],
|
|
147
|
+
path: req.path,
|
|
148
|
+
timestamp: new Date().toISOString(),
|
|
149
|
+
};
|
|
150
|
+
res.status(401).json(unauthorizedResponse);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
let expected;
|
|
154
|
+
try {
|
|
155
|
+
if (!this.config.icebergConfig.HMAC_SECRET) {
|
|
156
|
+
throw new Error("HMAC_SECRET is not configured");
|
|
157
|
+
}
|
|
158
|
+
expected = crypto
|
|
159
|
+
.createHmac("sha256", this.config.icebergConfig.HMAC_SECRET)
|
|
160
|
+
.update(message)
|
|
161
|
+
.digest("hex");
|
|
162
|
+
}
|
|
163
|
+
catch (hmacError) {
|
|
164
|
+
console.error("Error generating HMAC signature:", hmacError);
|
|
165
|
+
const unauthorizedResponse = {
|
|
166
|
+
error: "UnauthorizedException",
|
|
167
|
+
code: 401,
|
|
168
|
+
message: ["error validating request signature"],
|
|
169
|
+
path: req.path,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
res.status(401).json(unauthorizedResponse);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
if (signature !== expected) {
|
|
177
|
+
const unauthorizedResponse = {
|
|
178
|
+
error: "InvalidSignature",
|
|
179
|
+
code: 401,
|
|
180
|
+
message: ["x-hmac-signature is invalid"],
|
|
181
|
+
path: req.path,
|
|
182
|
+
timestamp: new Date().toISOString(),
|
|
183
|
+
};
|
|
184
|
+
res.status(401).json(unauthorizedResponse);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (comparisonError) {
|
|
189
|
+
console.error("Error comparing signatures:", comparisonError);
|
|
190
|
+
const unauthorizedResponse = {
|
|
191
|
+
error: "UnauthorizedException",
|
|
192
|
+
code: 401,
|
|
193
|
+
message: ["error validating request signature"],
|
|
194
|
+
path: req.path,
|
|
195
|
+
timestamp: new Date().toISOString(),
|
|
196
|
+
};
|
|
197
|
+
res.status(401).json(unauthorizedResponse);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
next();
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
console.error("Unexpected error in HMAC authentication:", error);
|
|
204
|
+
const unauthorizedResponse = {
|
|
205
|
+
error: "UnauthorizedException",
|
|
206
|
+
code: 401,
|
|
207
|
+
message: ["authentication failed due to internal error"],
|
|
208
|
+
path: req.path,
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
};
|
|
211
|
+
res.status(401).json(unauthorizedResponse);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
this.icebergAuth = async (req, res, next) => {
|
|
216
|
+
try {
|
|
217
|
+
const { access_token } = req.cookies;
|
|
218
|
+
if (!access_token) {
|
|
219
|
+
const unauthorizedResponse = {
|
|
220
|
+
error: "UnauthorizedException",
|
|
221
|
+
code: 401,
|
|
222
|
+
message: ["missing 'access_token' cookie"],
|
|
223
|
+
path: req.path,
|
|
224
|
+
timestamp: new Date().toISOString(),
|
|
225
|
+
};
|
|
226
|
+
res.status(401).json(unauthorizedResponse);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
let token = qs_1.default.stringify({
|
|
230
|
+
token: access_token,
|
|
231
|
+
});
|
|
232
|
+
try {
|
|
233
|
+
const introspect_result = await axios_1.default.post(this.config.icebergConfig.introspectEndpoint, token, {
|
|
234
|
+
headers: {
|
|
235
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
if (introspect_result.status != 200) {
|
|
239
|
+
const unauthorizedResponse = {
|
|
240
|
+
error: introspect_result.statusText,
|
|
241
|
+
code: introspect_result.status,
|
|
242
|
+
message: [introspect_result.data],
|
|
243
|
+
path: req.path,
|
|
244
|
+
timestamp: new Date().toISOString(),
|
|
245
|
+
};
|
|
246
|
+
res.status(401).json(unauthorizedResponse);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const token_data = introspect_result.data;
|
|
250
|
+
if (!token_data.active) {
|
|
251
|
+
const unauthorizedResponse = {
|
|
252
|
+
error: "UnauthorizedException",
|
|
253
|
+
code: 401,
|
|
254
|
+
message: ["access token is expired"],
|
|
255
|
+
path: req.path,
|
|
256
|
+
timestamp: new Date().toISOString(),
|
|
257
|
+
};
|
|
258
|
+
res.status(401).json(unauthorizedResponse);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
req.body.userId = token_data.user_id;
|
|
262
|
+
next();
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
console.error("Error validating access token:", error);
|
|
266
|
+
const errorResponse = {
|
|
267
|
+
error: error instanceof Error
|
|
268
|
+
? error.message
|
|
269
|
+
: "Failed to validate access token",
|
|
270
|
+
timestamp: new Date().toISOString(),
|
|
271
|
+
};
|
|
272
|
+
res.status(500).json(errorResponse);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
console.error("Error validating access token:", error);
|
|
278
|
+
const errorResponse = {
|
|
279
|
+
error: "Internal server error",
|
|
280
|
+
timestamp: new Date().toISOString(),
|
|
281
|
+
};
|
|
282
|
+
res.status(500).json(errorResponse);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.AuthMiddleware = AuthMiddleware;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { CorsOptions } from "cors";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import z from "zod";
|
|
5
|
+
export declare function validateData<T extends z.ZodObject>(schema: T): (req: Request, res: Response, next: NextFunction) => void;
|
|
6
|
+
export declare const requestLogger: (req: Request, res: Response, next: NextFunction) => void;
|
|
7
|
+
export declare const errorHandler: (error: Error, req: Request, res: Response, next: NextFunction) => void;
|
|
8
|
+
export declare const notFoundHandler: (req: Request, res: Response) => void;
|
|
9
|
+
export declare const setupMiddleware: (app: express.Application, corsOptions: CorsOptions) => void;
|
|
10
|
+
export declare const asyncHandler: (fn: Function) => (req: Request, res: Response, next: NextFunction) => void;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAa,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,IACnD,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAsDxD;AAED,eAAO,MAAM,aAAa,GACxB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,IAGF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,OAAO,KAAK,EACZ,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,IAwBF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,KAAG,IAO7D,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,KAAK,OAAO,CAAC,WAAW,EACxB,aAAa,WAAW,KACvB,IAUF,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,IAAI,QAAQ,MAC/B,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,SAcxD,CAAC"}
|