@entity-access/server-pages 1.0.28 → 1.0.30
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/.vscode/settings.json +1 -0
- package/dist/Content.d.ts +6 -6
- package/dist/Content.d.ts.map +1 -1
- package/dist/Content.js +21 -37
- package/dist/Content.js.map +1 -1
- package/dist/Page.d.ts +11 -40
- package/dist/Page.d.ts.map +1 -1
- package/dist/Page.js +5 -3
- package/dist/Page.js.map +1 -1
- package/dist/ServerPages.d.ts +11 -5
- package/dist/ServerPages.d.ts.map +1 -1
- package/dist/ServerPages.js +102 -81
- package/dist/ServerPages.js.map +1 -1
- package/dist/core/LocalFile.d.ts +2 -1
- package/dist/core/LocalFile.d.ts.map +1 -1
- package/dist/core/LocalFile.js +8 -0
- package/dist/core/LocalFile.js.map +1 -1
- package/dist/core/RouteTree.js +1 -1
- package/dist/core/RouteTree.js.map +1 -1
- package/dist/core/SessionUser.d.ts +2 -2
- package/dist/core/SessionUser.d.ts.map +1 -1
- package/dist/core/SessionUser.js.map +1 -1
- package/dist/core/Wrapped.d.ts +70 -0
- package/dist/core/Wrapped.d.ts.map +1 -0
- package/dist/core/Wrapped.js +253 -0
- package/dist/core/Wrapped.js.map +1 -0
- package/dist/core/cached.d.ts +2 -0
- package/dist/core/cached.d.ts.map +1 -0
- package/dist/core/cached.js +3 -0
- package/dist/core/cached.js.map +1 -0
- package/dist/decorators/Authorize.d.ts +2 -0
- package/dist/decorators/Authorize.d.ts.map +1 -0
- package/dist/decorators/Authorize.js +3 -0
- package/dist/decorators/Authorize.js.map +1 -0
- package/dist/parsers/json/jsonParser.d.ts +2 -0
- package/dist/parsers/json/jsonParser.d.ts.map +1 -0
- package/dist/parsers/json/jsonParser.js +3 -0
- package/dist/parsers/json/jsonParser.js.map +1 -0
- package/dist/services/CookieService.d.ts +3 -3
- package/dist/services/CookieService.d.ts.map +1 -1
- package/dist/services/CookieService.js +5 -7
- package/dist/services/CookieService.js.map +1 -1
- package/dist/services/TokenService.d.ts +1 -0
- package/dist/services/TokenService.d.ts.map +1 -1
- package/dist/services/TokenService.js.map +1 -1
- package/dist/services/UserSessionProvider.d.ts +2 -1
- package/dist/services/UserSessionProvider.d.ts.map +1 -1
- package/dist/services/UserSessionProvider.js +3 -3
- package/dist/services/UserSessionProvider.js.map +1 -1
- package/dist/ssl/SelfSigned.d.ts +7 -0
- package/dist/ssl/SelfSigned.d.ts.map +1 -0
- package/dist/ssl/SelfSigned.js +62 -0
- package/dist/ssl/SelfSigned.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -6
- package/self-signed/cert.crt +22 -0
- package/self-signed/key.pem +27 -0
- package/src/Content.tsx +28 -43
- package/src/Page.tsx +18 -62
- package/src/ServerPages.ts +114 -76
- package/src/core/LocalFile.ts +11 -2
- package/src/core/RouteTree.ts +1 -1
- package/src/core/SessionUser.ts +2 -2
- package/src/core/Wrapped.ts +359 -0
- package/src/core/cached.ts +3 -0
- package/src/decorators/Authorize.ts +3 -0
- package/src/parsers/json/jsonParser.ts +3 -0
- package/src/services/CookieService.ts +7 -9
- package/src/services/TokenService.ts +1 -0
- package/src/services/UserSessionProvider.ts +4 -2
- package/src/ssl/SelfSigned.ts +78 -0
- package/test.js +1 -3
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import busboy from "busboy";
|
|
2
|
+
import { IncomingMessage, OutgoingMessage, ServerResponse } from "http";
|
|
3
|
+
import { Http2ServerRequest, Http2ServerResponse } from "http2";
|
|
4
|
+
import SessionUser from "./SessionUser.js";
|
|
5
|
+
import { parse, serialize } from "cookie";
|
|
6
|
+
import TempFolder from "./TempFolder.js";
|
|
7
|
+
import { LocalFile } from "./LocalFile.js";
|
|
8
|
+
import { Writable } from "stream";
|
|
9
|
+
import { ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
|
|
10
|
+
import CookieService from "../services/CookieService.js";
|
|
11
|
+
import { stat } from "fs/promises";
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
type UnwrappedRequest = IncomingMessage | Http2ServerRequest;
|
|
15
|
+
|
|
16
|
+
export interface IFormData {
|
|
17
|
+
fields: { [key: string]: string};
|
|
18
|
+
files: LocalFile[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface IWrappedRequest {
|
|
22
|
+
|
|
23
|
+
get host(): string;
|
|
24
|
+
|
|
25
|
+
get path(): string;
|
|
26
|
+
|
|
27
|
+
get asyncSessionUser(): Promise<SessionUser>;
|
|
28
|
+
|
|
29
|
+
get asyncJsonBody(): Promise<any>;
|
|
30
|
+
|
|
31
|
+
get asyncForm(): Promise<IFormData>;
|
|
32
|
+
|
|
33
|
+
get query(): { [key: string]: string};
|
|
34
|
+
|
|
35
|
+
get cookies(): { [key: string]: string};
|
|
36
|
+
|
|
37
|
+
get URL(): URL;
|
|
38
|
+
|
|
39
|
+
get remoteIPAddress(): string;
|
|
40
|
+
|
|
41
|
+
accepts(): string[];
|
|
42
|
+
accepts(... types: string[]): boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface IWrappedResponse {
|
|
46
|
+
|
|
47
|
+
asyncEnd();
|
|
48
|
+
|
|
49
|
+
asyncWrite(buffer: Buffer): Promise<void>;
|
|
50
|
+
|
|
51
|
+
send(data: Buffer | string | Blob, status?: number): Promise<void>;
|
|
52
|
+
|
|
53
|
+
sendRedirect(url: string, permanent?: boolean): void;
|
|
54
|
+
|
|
55
|
+
cookie(name: string, value: string, options?: { secure?: boolean, httpOnly?: boolean, maxAge?: number });
|
|
56
|
+
|
|
57
|
+
// https://github.com/phoenixinfotech1984/node-content-range
|
|
58
|
+
sendFile(filePath: string, options?: {
|
|
59
|
+
acceptRanges?: boolean,
|
|
60
|
+
cacheControl?: boolean,
|
|
61
|
+
maxAge?: number,
|
|
62
|
+
etag?: boolean,
|
|
63
|
+
immutable?: boolean,
|
|
64
|
+
headers?: { [key: string]: string},
|
|
65
|
+
lastModified?: boolean
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type WrappedRequest = UnwrappedRequest & IWrappedRequest & {
|
|
71
|
+
scope: ServiceProvider;
|
|
72
|
+
response: WrappedResponse;
|
|
73
|
+
disposables: Disposable[];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
type UnwrappedResponse = ServerResponse | Http2ServerResponse;
|
|
77
|
+
|
|
78
|
+
export type WrappedResponse = UnwrappedResponse & IWrappedResponse & {
|
|
79
|
+
request: WrappedRequest
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const requestMethods: { [P in keyof IWrappedRequest]: (this: WrappedRequest) => any} = {
|
|
83
|
+
remoteIPAddress(this: UnwrappedRequest) {
|
|
84
|
+
return this.socket?.remoteAddress;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
accepts(this: UnwrappedRequest) {
|
|
88
|
+
const accepts = (this.headers.accept ?? "").split(";");
|
|
89
|
+
return (...types: string[]) => {
|
|
90
|
+
if (types.length > 0) {
|
|
91
|
+
for (const type of types) {
|
|
92
|
+
for (const iterator of accepts) {
|
|
93
|
+
if (iterator.includes(type)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return accepts;
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
URL(this: UnwrappedRequest) {
|
|
105
|
+
const w = this as WrappedRequest;
|
|
106
|
+
return new URL(this.url, `http://${w.host}`);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
path(this: WrappedRequest) {
|
|
110
|
+
return this.URL.pathname;
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
host(this: UnwrappedRequest) {
|
|
114
|
+
return this.headers[":authority"] ?? this.headers["host"];
|
|
115
|
+
},
|
|
116
|
+
query(this: WrappedRequest) {
|
|
117
|
+
const u = this.URL;
|
|
118
|
+
const items = {};
|
|
119
|
+
for (const [key, value] of u.searchParams.entries()) {
|
|
120
|
+
items[key] = value;
|
|
121
|
+
}
|
|
122
|
+
return items;
|
|
123
|
+
},
|
|
124
|
+
cookies(this: UnwrappedRequest) {
|
|
125
|
+
const cookie = this.headers.cookie;
|
|
126
|
+
const cookies = parse(cookie);
|
|
127
|
+
return cookies;
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
async asyncJsonBody(this: WrappedRequest) {
|
|
131
|
+
const req = this;
|
|
132
|
+
let buffer = null as Buffer;
|
|
133
|
+
let encoding = this.headers["content-encoding"] ?? "utf-8";
|
|
134
|
+
const contentType = this.headers["content-type"];
|
|
135
|
+
if (!/\/json/i.test(contentType)) {
|
|
136
|
+
throw new Error(`Content Type ${contentType} isn't json `);
|
|
137
|
+
}
|
|
138
|
+
await new Promise<void>((resolve, reject) => {
|
|
139
|
+
req.pipe(new Writable({
|
|
140
|
+
write(chunk, enc, callback) {
|
|
141
|
+
encoding ||= enc;
|
|
142
|
+
let b = typeof chunk === "string"
|
|
143
|
+
? Buffer.from(chunk)
|
|
144
|
+
: chunk as Buffer;
|
|
145
|
+
buffer = buffer
|
|
146
|
+
? Buffer.concat([buffer, b])
|
|
147
|
+
: b;
|
|
148
|
+
callback();
|
|
149
|
+
},
|
|
150
|
+
final(callback) {
|
|
151
|
+
resolve();
|
|
152
|
+
callback();
|
|
153
|
+
},
|
|
154
|
+
}), { end: true });
|
|
155
|
+
});
|
|
156
|
+
const text = buffer.toString(encoding as any);
|
|
157
|
+
return JSON.parse(text);
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
async asyncSessionUser(this: WrappedRequest) {
|
|
161
|
+
try {
|
|
162
|
+
const cookieService = this.scope.resolve(CookieService);
|
|
163
|
+
const cookie = this.cookies[cookieService.cookieName];
|
|
164
|
+
const sessionUser = await cookieService.createSessionUserFromCookie(cookie, this.remoteIPAddress, this.response);
|
|
165
|
+
return sessionUser;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error(error);
|
|
168
|
+
return new SessionUser(null, null, null);
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
async asyncForm(this: WrappedRequest) {
|
|
173
|
+
let tempFolder: TempFolder;
|
|
174
|
+
const result: IFormData = {
|
|
175
|
+
fields: {},
|
|
176
|
+
files: []
|
|
177
|
+
};
|
|
178
|
+
const req = this;
|
|
179
|
+
const bb = busboy({ headers: req.headers, defParamCharset: "utf8" });
|
|
180
|
+
const tasks = [];
|
|
181
|
+
await new Promise((resolve, reject) => {
|
|
182
|
+
|
|
183
|
+
bb.on("field", (name, value) => {
|
|
184
|
+
result.fields[name] = value;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
bb.on("file", (name, file, info) => {
|
|
188
|
+
if (!tempFolder) {
|
|
189
|
+
tempFolder = new TempFolder();
|
|
190
|
+
this.disposables.push(tempFolder);
|
|
191
|
+
}
|
|
192
|
+
const tf = tempFolder.get(info.filename, info.mimeType);
|
|
193
|
+
tasks.push(tf.writeAll(file).then(() => {
|
|
194
|
+
result.files.push(tf);
|
|
195
|
+
}));
|
|
196
|
+
});
|
|
197
|
+
bb.on("error", reject);
|
|
198
|
+
bb.on("close", resolve);
|
|
199
|
+
req.pipe(bb);
|
|
200
|
+
});
|
|
201
|
+
await Promise.all(tasks);
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const responseMethods: { [P in keyof IWrappedResponse]: (this: WrappedResponse) => any} = {
|
|
207
|
+
|
|
208
|
+
asyncEnd() {
|
|
209
|
+
return () => new Promise<void>((resolve) => this.end(resolve));
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
asyncWrite() {
|
|
213
|
+
return (buffer: Buffer, start?: number, length?: number) => {
|
|
214
|
+
return new Promise((resolve) =>
|
|
215
|
+
this.write(buffer, resolve)
|
|
216
|
+
);
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
cookie() {
|
|
221
|
+
return (name: string, value: string, options = {}) => {
|
|
222
|
+
const cv = this.getHeaders()["set-cookie"];
|
|
223
|
+
const cookies = Array.isArray(cv) ? cv : [cv];
|
|
224
|
+
const nk = cookies.filter((x) => x.startsWith(name + "="));
|
|
225
|
+
nk.push(serialize(name, value, options));
|
|
226
|
+
this.setHeader("set-cookie", nk);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
send(this: WrappedResponse) {
|
|
231
|
+
return async (data: Buffer | string, status: number = 200) => {
|
|
232
|
+
try {
|
|
233
|
+
this.statusCode = status;
|
|
234
|
+
this.writeHead(this.statusCode, this.getHeaders());
|
|
235
|
+
await new Promise<void>((resolve, reject) => {
|
|
236
|
+
this.write(data, (error) => error ? reject(error) : resolve());
|
|
237
|
+
});
|
|
238
|
+
return this.asyncEnd();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(error);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
sendRedirect() {
|
|
245
|
+
return (location: string, permanent = false) => {
|
|
246
|
+
this.statusCode = 301;
|
|
247
|
+
this.writeHead(this.statusCode, {
|
|
248
|
+
location
|
|
249
|
+
});
|
|
250
|
+
return this.asyncEnd();
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
sendFile() {
|
|
254
|
+
return async (filePath: string, options?: {
|
|
255
|
+
acceptRanges?: boolean,
|
|
256
|
+
cacheControl?: boolean,
|
|
257
|
+
maxAge?: number,
|
|
258
|
+
etag?: boolean,
|
|
259
|
+
immutable?: boolean,
|
|
260
|
+
headers?: { [key: string]: string},
|
|
261
|
+
lastModified?: boolean
|
|
262
|
+
}) => {
|
|
263
|
+
/** Calculate Size of file */
|
|
264
|
+
const { size } = await stat(filePath);
|
|
265
|
+
const range = this.request.headers.range;
|
|
266
|
+
|
|
267
|
+
const lf = new LocalFile(filePath);
|
|
268
|
+
|
|
269
|
+
/** Check for Range header */
|
|
270
|
+
if (!range) {
|
|
271
|
+
this.writeHead(200, {
|
|
272
|
+
"Content-Length": size,
|
|
273
|
+
"Content-Type": "video/mp4"
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
await lf.writeTo(this);
|
|
277
|
+
|
|
278
|
+
return this.asyncEnd();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Extracting Start and End value from Range Header */
|
|
282
|
+
let [start, end] = range.replace(/bytes=/, "").split("-") as any[];
|
|
283
|
+
start = parseInt(start, 10);
|
|
284
|
+
end = end ? parseInt(end, 10) : size - 1;
|
|
285
|
+
|
|
286
|
+
if (!isNaN(start) && isNaN(end)) {
|
|
287
|
+
start = start;
|
|
288
|
+
end = size - 1;
|
|
289
|
+
}
|
|
290
|
+
if (isNaN(start) && !isNaN(end)) {
|
|
291
|
+
start = size - end;
|
|
292
|
+
end = size - 1;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Handle unavailable range request
|
|
296
|
+
if (start >= size || end >= size) {
|
|
297
|
+
// Return the 416 Range Not Satisfiable.
|
|
298
|
+
this.writeHead(416, {
|
|
299
|
+
"Content-Range": `bytes */${size}`
|
|
300
|
+
});
|
|
301
|
+
return this.asyncEnd();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Sending Partial Content With HTTP Code 206 */
|
|
305
|
+
this.writeHead(206, {
|
|
306
|
+
"Content-Range": `bytes ${start}-${end}/${size}`,
|
|
307
|
+
"Accept-Ranges": "bytes",
|
|
308
|
+
"Content-Length": end - start + 1,
|
|
309
|
+
"Content-Type": "video/mp4"
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
await lf.writeTo(this, start, end);
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export const Wrapped = {
|
|
319
|
+
request: (req: UnwrappedRequest) => {
|
|
320
|
+
for (const key in requestMethods) {
|
|
321
|
+
if (Object.prototype.hasOwnProperty.call(requestMethods, key)) {
|
|
322
|
+
const element = requestMethods[key];
|
|
323
|
+
Object.defineProperty(req, key, {
|
|
324
|
+
get() {
|
|
325
|
+
const value = element.call(this);
|
|
326
|
+
Object.defineProperty(this, key, { value, enumerable: true, writable: false });
|
|
327
|
+
return value;
|
|
328
|
+
},
|
|
329
|
+
enumerable: true,
|
|
330
|
+
configurable: true
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const wr = req as WrappedRequest;
|
|
335
|
+
wr.disposables = [];
|
|
336
|
+
return wr;
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
response: (req: WrappedRequest, res: UnwrappedResponse) => {
|
|
340
|
+
for (const key in responseMethods) {
|
|
341
|
+
if (Object.prototype.hasOwnProperty.call(responseMethods, key)) {
|
|
342
|
+
const element = responseMethods[key];
|
|
343
|
+
Object.defineProperty(res, key, {
|
|
344
|
+
get() {
|
|
345
|
+
const value = element.call(this);
|
|
346
|
+
Object.defineProperty(this, key, { value, enumerable: true, writable: false });
|
|
347
|
+
return value;
|
|
348
|
+
},
|
|
349
|
+
enumerable: true,
|
|
350
|
+
configurable: true
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const wr = res as WrappedResponse;
|
|
355
|
+
wr.request = req;
|
|
356
|
+
req.response = wr;
|
|
357
|
+
return wr;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -2,10 +2,10 @@ import Inject, { RegisterScoped, RegisterSingleton, ServiceProvider } from "@ent
|
|
|
2
2
|
import TokenService, { IAuthCookie } from "./TokenService.js";
|
|
3
3
|
import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
|
|
4
4
|
import { BaseDriver } from "@entity-access/entity-access/dist/drivers/base/BaseDriver.js";
|
|
5
|
-
import { Request, Response } from "express";
|
|
6
5
|
import cluster from "cluster";
|
|
7
6
|
import SessionUser from "../core/SessionUser.js";
|
|
8
7
|
import UserSessionProvider from "./UserSessionProvider.js";
|
|
8
|
+
import { WrappedResponse } from "../core/Wrapped.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* This will track userID,cookie pair so we can
|
|
@@ -65,13 +65,11 @@ export default class CookieService {
|
|
|
65
65
|
|
|
66
66
|
public clearCache = clearCache;
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
cookieName ??= this.tokenService.authCookieName;
|
|
70
|
-
const sessionCookie = req.cookies[cookieName];
|
|
71
|
-
return req.user = await this.createSessionUserFromCookie(sessionCookie, req.ip, resp);
|
|
68
|
+
public get cookieName() {
|
|
69
|
+
return cookieName ??= this.tokenService.authCookieName;
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
async createSessionUserFromCookie(cookie: string, ip: string, resp?:
|
|
72
|
+
async createSessionUserFromCookie(cookie: string, ip: string, resp?: WrappedResponse) {
|
|
75
73
|
const user = new SessionUser(resp, cookieName, this.tokenService);
|
|
76
74
|
try {
|
|
77
75
|
user.ipAddress = ip;
|
|
@@ -120,13 +118,13 @@ export default class CookieService {
|
|
|
120
118
|
parsedCookie.expiry = new Date(parsedCookie.expiry);
|
|
121
119
|
}
|
|
122
120
|
|
|
123
|
-
const r = await this.createUserInfo(
|
|
121
|
+
const r = await this.createUserInfo(cookie, parsedCookie);
|
|
124
122
|
return r;
|
|
125
123
|
});
|
|
126
124
|
}
|
|
127
125
|
|
|
128
|
-
private async createUserInfo(
|
|
129
|
-
const r = await this.userSessionProvider.getUserSession(
|
|
126
|
+
private async createUserInfo(cookie: string, parsedCookie: IAuthCookie) {
|
|
127
|
+
const r = await this.userSessionProvider.getUserSession(parsedCookie);
|
|
130
128
|
if (r === null) {
|
|
131
129
|
return {};
|
|
132
130
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { RegisterScoped, RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
|
|
2
2
|
import SessionUser from "../core/SessionUser.js";
|
|
3
3
|
import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
|
|
4
|
+
import { IAuthCookie } from "./TokenService.js";
|
|
4
5
|
|
|
5
6
|
@RegisterScoped
|
|
6
7
|
export default class UserSessionProvider {
|
|
7
8
|
|
|
8
|
-
async getUserSession(id:
|
|
9
|
+
async getUserSession({ userID, id: sessionID, expiry}: IAuthCookie): Promise<Partial<SessionUser>> {
|
|
9
10
|
return {
|
|
10
|
-
|
|
11
|
+
sessionID,
|
|
12
|
+
userID,
|
|
11
13
|
expiry
|
|
12
14
|
}
|
|
13
15
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as forge from "node-forge";
|
|
2
|
+
import * as crypto from "crypto";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
|
|
5
|
+
export class SelfSigned {
|
|
6
|
+
public static setupSelfSigned(sslMode = "./") {
|
|
7
|
+
|
|
8
|
+
const selfSigned = `${sslMode}/self-signed/`;
|
|
9
|
+
|
|
10
|
+
mkdirSync(selfSigned, { recursive: true });
|
|
11
|
+
|
|
12
|
+
const certPath = `${selfSigned}/cert.crt`;
|
|
13
|
+
const keyPath = `${selfSigned}/key.pem`;
|
|
14
|
+
|
|
15
|
+
let key;
|
|
16
|
+
let cert;
|
|
17
|
+
|
|
18
|
+
if (existsSync(certPath) && existsSync(keyPath)) {
|
|
19
|
+
key = readFileSync(keyPath);
|
|
20
|
+
cert = readFileSync(certPath);
|
|
21
|
+
return { key, cert };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const pki = forge.default.pki;
|
|
25
|
+
|
|
26
|
+
// generate a key pair or use one you have already
|
|
27
|
+
const keys = pki.rsa.generateKeyPair(2048);
|
|
28
|
+
|
|
29
|
+
// create a new certificate
|
|
30
|
+
const crt = pki.createCertificate();
|
|
31
|
+
|
|
32
|
+
// fill the required fields
|
|
33
|
+
crt.publicKey = keys.publicKey;
|
|
34
|
+
crt.serialNumber = '01';
|
|
35
|
+
crt.validity.notBefore = new Date();
|
|
36
|
+
crt.validity.notAfter = new Date();
|
|
37
|
+
crt.validity.notAfter.setFullYear(crt.validity.notBefore.getFullYear() + 40);
|
|
38
|
+
|
|
39
|
+
// use your own attributes here, or supply a csr (check the docs)
|
|
40
|
+
const attrs = [
|
|
41
|
+
{
|
|
42
|
+
name: 'commonName',
|
|
43
|
+
value: 'dev.socialmail.in'
|
|
44
|
+
}, {
|
|
45
|
+
name: 'countryName',
|
|
46
|
+
value: 'IN'
|
|
47
|
+
}, {
|
|
48
|
+
shortName: 'ST',
|
|
49
|
+
value: 'Maharashtra'
|
|
50
|
+
}, {
|
|
51
|
+
name: 'localityName',
|
|
52
|
+
value: 'Navi Mumbai'
|
|
53
|
+
}, {
|
|
54
|
+
name: 'organizationName',
|
|
55
|
+
value: 'NeuroSpeech Technologies Pvt Ltd'
|
|
56
|
+
}, {
|
|
57
|
+
shortName: 'OU',
|
|
58
|
+
value: 'Test'
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// here we set subject and issuer as the same one
|
|
63
|
+
crt.setSubject(attrs);
|
|
64
|
+
crt.setIssuer(attrs);
|
|
65
|
+
|
|
66
|
+
// the actual certificate signing
|
|
67
|
+
crt.sign(keys.privateKey);
|
|
68
|
+
|
|
69
|
+
// now convert the Forge certificate to PEM format
|
|
70
|
+
cert = pki.certificateToPem(crt);
|
|
71
|
+
key = pki.privateKeyToPem(keys.privateKey);
|
|
72
|
+
|
|
73
|
+
writeFileSync(certPath, cert);
|
|
74
|
+
writeFileSync(keyPath, key);
|
|
75
|
+
|
|
76
|
+
return { key, cert };
|
|
77
|
+
}
|
|
78
|
+
}
|
package/test.js
CHANGED
|
@@ -7,6 +7,4 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
const sp = ServerPages.create();
|
|
8
8
|
sp.registerRoutes(join(dirname( fileURLToPath(import.meta.url)), "./dist/tests/logger"));
|
|
9
9
|
|
|
10
|
-
const app = sp.build();
|
|
11
|
-
|
|
12
|
-
app.listen(8080);
|
|
10
|
+
const app = sp.build({ createSocketService: false, protocol: "https2" });
|