prostgles-server 2.0.178 → 2.0.179

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.
Files changed (98) hide show
  1. package/dist/AuthHandler.d.ts +4 -4
  2. package/dist/AuthHandler.d.ts.map +1 -1
  3. package/dist/DBSchemaBuilder.d.ts +6 -6
  4. package/dist/DBSchemaBuilder.d.ts.map +1 -1
  5. package/dist/DBSchemaBuilder.js +25 -8
  6. package/dist/DBSchemaBuilder.js.map +1 -1
  7. package/dist/DboBuilder.d.ts +20 -21
  8. package/dist/DboBuilder.d.ts.map +1 -1
  9. package/dist/DboBuilder.js +1 -1
  10. package/dist/DboBuilder.js.map +1 -1
  11. package/dist/Prostgles.d.ts +8 -10
  12. package/dist/Prostgles.d.ts.map +1 -1
  13. package/dist/Prostgles.js.map +1 -1
  14. package/dist/PublishParser.d.ts +37 -37
  15. package/dist/PublishParser.d.ts.map +1 -1
  16. package/dist/PublishParser.js.map +1 -1
  17. package/dist/index.d.ts +2 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/lib/AuthHandler.d.ts +148 -0
  21. package/lib/AuthHandler.d.ts.map +1 -0
  22. package/lib/AuthHandler.js +411 -0
  23. package/lib/AuthHandler.ts +3 -3
  24. package/lib/DBEventsManager.d.ts +38 -0
  25. package/lib/DBEventsManager.d.ts.map +1 -0
  26. package/lib/DBEventsManager.js +136 -0
  27. package/lib/DBSchemaBuilder.d.ts +11 -0
  28. package/lib/DBSchemaBuilder.d.ts.map +1 -0
  29. package/lib/DBSchemaBuilder.js +102 -0
  30. package/lib/DBSchemaBuilder.ts +62 -27
  31. package/lib/DboBuilder.d.ts +428 -0
  32. package/lib/DboBuilder.d.ts.map +1 -0
  33. package/lib/DboBuilder.js +3078 -0
  34. package/lib/DboBuilder.ts +25 -25
  35. package/lib/FileManager.d.ts +168 -0
  36. package/lib/FileManager.d.ts.map +1 -0
  37. package/lib/FileManager.js +474 -0
  38. package/lib/Filtering.d.ts +15 -0
  39. package/lib/Filtering.d.ts.map +1 -0
  40. package/lib/Filtering.js +299 -0
  41. package/lib/PostgresNotifListenManager.d.ts +27 -0
  42. package/lib/PostgresNotifListenManager.d.ts.map +1 -0
  43. package/lib/PostgresNotifListenManager.js +122 -0
  44. package/lib/Prostgles.d.ts +193 -0
  45. package/lib/Prostgles.d.ts.map +1 -0
  46. package/lib/Prostgles.js +579 -0
  47. package/lib/Prostgles.ts +6 -6
  48. package/lib/PubSubManager.d.ts +157 -0
  49. package/lib/PubSubManager.d.ts.map +1 -0
  50. package/lib/PubSubManager.js +1400 -0
  51. package/lib/PublishParser.d.ts +262 -0
  52. package/lib/PublishParser.d.ts.map +1 -0
  53. package/lib/PublishParser.js +390 -0
  54. package/lib/PublishParser.ts +39 -38
  55. package/lib/QueryBuilder.d.ts +124 -0
  56. package/lib/QueryBuilder.d.ts.map +1 -0
  57. package/lib/QueryBuilder.js +1349 -0
  58. package/lib/SyncReplication.d.ts +34 -0
  59. package/lib/SyncReplication.d.ts.map +1 -0
  60. package/lib/SyncReplication.js +411 -0
  61. package/lib/TableConfig.d.ts +175 -0
  62. package/lib/TableConfig.d.ts.map +1 -0
  63. package/lib/TableConfig.js +231 -0
  64. package/lib/index.d.ts +10 -0
  65. package/lib/index.d.ts.map +1 -0
  66. package/lib/index.js +45 -0
  67. package/lib/index.ts +3 -4
  68. package/lib/shortestPath.d.ts +10 -0
  69. package/lib/shortestPath.d.ts.map +1 -0
  70. package/lib/shortestPath.js +111 -0
  71. package/lib/utils.d.ts +2 -0
  72. package/lib/utils.d.ts.map +1 -0
  73. package/lib/utils.js +5 -0
  74. package/package.json +3 -3
  75. package/tests/client/PID.txt +1 -1
  76. package/tests/client/index.d.ts +1 -1
  77. package/tests/client/index.d.ts.map +1 -1
  78. package/tests/client_only_queries.d.ts +4 -0
  79. package/tests/client_only_queries.d.ts.map +1 -0
  80. package/tests/isomorphic_queries.d.ts +6 -0
  81. package/tests/isomorphic_queries.d.ts.map +1 -0
  82. package/tests/server/DBoGenerated.d.ts +97 -193
  83. package/tests/server/dboTypeCheck.d.ts +2 -0
  84. package/tests/server/dboTypeCheck.d.ts.map +1 -0
  85. package/tests/server/dboTypeCheck.js +14 -0
  86. package/tests/server/dboTypeCheck.ts +17 -0
  87. package/tests/server/index.d.ts +2 -0
  88. package/tests/server/index.d.ts.map +1 -0
  89. package/tests/server/index.js +11 -11
  90. package/tests/server/index.ts +23 -16
  91. package/tests/server/package-lock.json +5 -5
  92. package/tests/server/publishTypeCheck.d.ts +2 -0
  93. package/tests/server/publishTypeCheck.d.ts.map +1 -0
  94. package/tests/server/publishTypeCheck.js +120 -0
  95. package/tests/server/publishTypeCheck.ts +129 -0
  96. package/tests/server/tsconfig.json +4 -5
  97. package/tests/server_only_queries.d.ts +2 -0
  98. package/tests/server_only_queries.d.ts.map +1 -0
@@ -0,0 +1,148 @@
1
+ import { AnyObject } from "prostgles-types";
2
+ import { LocalParams, PRGLIOSocket } from "./DboBuilder";
3
+ import { DBOFullyTyped } from "./DBSchemaBuilder";
4
+ import { DB, DBHandlerServer, Prostgles } from "./Prostgles";
5
+ declare type Awaitable<T> = T | Promise<T>;
6
+ declare type AuthSocketSchema = {
7
+ user?: AnyObject;
8
+ register?: boolean;
9
+ login?: boolean;
10
+ logout?: boolean;
11
+ pathGuard?: boolean;
12
+ };
13
+ declare type ExpressReq = {
14
+ body?: AnyObject;
15
+ query?: AnyObject;
16
+ cookies?: AnyObject;
17
+ params?: AnyObject;
18
+ path: string;
19
+ originalUrl: string;
20
+ };
21
+ declare type ExpressRes = {
22
+ status: (code: number) => ({
23
+ json: (response: AnyObject) => any;
24
+ });
25
+ cookie: (name: string, value: string, options: AnyObject) => any;
26
+ sendFile: (filepath: string) => void;
27
+ redirect: (url: string) => void;
28
+ };
29
+ export declare type BasicSession = {
30
+ /** Must be hard to bruteforce */
31
+ sid: string;
32
+ /** UNIX millisecond timestamp */
33
+ expires: number;
34
+ };
35
+ export declare type AuthClientRequest = {
36
+ socket: any;
37
+ } | {
38
+ httpReq: ExpressReq;
39
+ };
40
+ export declare type Auth<S = void> = {
41
+ /**
42
+ * Name of the cookie or socket hadnshake query param that represents the session id.
43
+ * Defaults to "session_id"
44
+ */
45
+ sidKeyName?: string;
46
+ /**
47
+ * Response time rounding in milliseconds to prevent timing attacks on login. Login response time should always be a multiple of this value. Defaults to 500 milliseconds
48
+ */
49
+ responseThrottle?: number;
50
+ expressConfig?: {
51
+ /**
52
+ * Express app instance. If provided Prostgles will attempt to set sidKeyName to user cookie
53
+ */
54
+ app: any;
55
+ /**
56
+ * Used in allowing logging in through express. Defaults to /login
57
+ */
58
+ loginRoute?: string;
59
+ /**
60
+ * Used in allowing logging out through express. Defaults to /logout
61
+ */
62
+ logoutGetPath?: string;
63
+ /**
64
+ * Options used in setting the cookie after a successful login
65
+ */
66
+ cookieOptions?: AnyObject;
67
+ /**
68
+ * If provided, any client requests to NOT these routes (or their subroutes) will be redirected to loginRoute and then redirected back to the initial route after logging in
69
+ */
70
+ publicRoutes?: string[];
71
+ /**
72
+ * False by default. If false and userRoutes are provided then the socket will request window.location.reload if the current url is on a user route.
73
+ */
74
+ disableSocketAuthGuard?: boolean;
75
+ /**
76
+ * Will be called after a GET request is authorised
77
+ */
78
+ onGetRequestOK?: (req: ExpressReq, res: ExpressRes) => any;
79
+ /**
80
+ * Name of get url parameter used in redirecting user after successful login. Defaults to returnURL
81
+ */
82
+ returnURL?: string;
83
+ magicLinks?: {
84
+ /**
85
+ * Will default to /magic-link
86
+ */
87
+ route?: string;
88
+ /**
89
+ * Used in creating a session/logging in using a magic link
90
+ */
91
+ check: (magicId: string, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession | undefined>;
92
+ };
93
+ };
94
+ getUser: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB, client: AuthClientRequest) => Awaitable<{
95
+ /**
96
+ * User data used on server. Mainly used in http request auth
97
+ */
98
+ user: AnyObject;
99
+ /**
100
+ * User data sent to client. Mainly used in socket request auth
101
+ */
102
+ clientUser: AnyObject;
103
+ } | undefined>;
104
+ register?: (params: AnyObject, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession> | BasicSession;
105
+ login?: (params: AnyObject, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession> | BasicSession;
106
+ logout?: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<any>;
107
+ /**
108
+ * If provided then then session info will be saved on socket.__prglCache and reused from there
109
+ */
110
+ cacheSession?: {
111
+ getSession: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession>;
112
+ };
113
+ };
114
+ export declare type ClientInfo = {
115
+ user?: AnyObject;
116
+ clientUser?: AnyObject;
117
+ sid?: string;
118
+ };
119
+ export default class AuthHandler {
120
+ protected opts?: Auth;
121
+ dbo: DBHandlerServer;
122
+ db: DB;
123
+ sidKeyName?: string;
124
+ returnURL?: string;
125
+ loginRoute?: string;
126
+ logoutGetPath?: string;
127
+ constructor(prostgles: Prostgles);
128
+ validateSid: (sid: string | undefined) => string;
129
+ matchesRoute: (route: string | undefined, clientFullRoute: string) => boolean;
130
+ isUserRoute: (pathname: string) => boolean;
131
+ private setCookieAndGoToReturnURLIFSet;
132
+ getUser: (clientReq: AuthClientRequest) => Promise<AnyObject | undefined>;
133
+ init(): Promise<void>;
134
+ throttledFunc: <T>(func: () => Promise<T>, throttle?: number) => Promise<T>;
135
+ loginThrottled: (params: AnyObject) => Promise<BasicSession>;
136
+ /**
137
+ * Will return first sid value found in : http cookie or query params
138
+ * Based on sid names in auth
139
+ * @param localParams
140
+ * @returns string
141
+ */
142
+ getSID(localParams: LocalParams): string | undefined;
143
+ getClientInfo(localParams: Pick<LocalParams, "socket" | "httpReq">): Promise<ClientInfo | undefined>;
144
+ isValidSocketSession: (socket: PRGLIOSocket, session: BasicSession) => boolean;
145
+ makeSocketAuth: (socket: PRGLIOSocket) => Promise<AuthSocketSchema>;
146
+ }
147
+ export {};
148
+ //# sourceMappingURL=AuthHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthHandler.d.ts","sourceRoot":"","sources":["AuthHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,411 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const prostgles_types_1 = require("prostgles-types");
4
+ class AuthHandler {
5
+ constructor(prostgles) {
6
+ this.validateSid = (sid) => {
7
+ if (!sid)
8
+ return undefined;
9
+ if (typeof sid !== "string")
10
+ throw "sid missing or not a string";
11
+ return sid;
12
+ };
13
+ this.matchesRoute = (route, clientFullRoute) => {
14
+ return route && clientFullRoute && (route === clientFullRoute ||
15
+ clientFullRoute.startsWith(route) && ["/", "?", "#"].includes(clientFullRoute.slice(-1)));
16
+ };
17
+ this.isUserRoute = (pathname) => {
18
+ const pubRoutes = [
19
+ ...this.opts?.expressConfig?.publicRoutes || [],
20
+ ];
21
+ if (this.loginRoute)
22
+ pubRoutes.push(this.loginRoute);
23
+ if (this.logoutGetPath)
24
+ pubRoutes.push(this.logoutGetPath);
25
+ return Boolean(!pubRoutes.find(publicRoute => {
26
+ return this.matchesRoute(publicRoute, pathname); // publicRoute === pathname || pathname.startsWith(publicRoute) && ["/", "?", "#"].includes(pathname.slice(-1));
27
+ }));
28
+ };
29
+ this.setCookieAndGoToReturnURLIFSet = (cookie, r) => {
30
+ const { sid, expires } = cookie;
31
+ const { res, req } = r;
32
+ if (sid) {
33
+ let maxAge = 1000 * 60 * 60 * 24; // 24 hours
34
+ if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
35
+ maxAge = (+new Date(expires) - Date.now());
36
+ }
37
+ let options = {
38
+ maxAge,
39
+ httpOnly: true, // The cookie only accessible by the web server
40
+ //signed: true // Indicates if the cookie should be signed
41
+ };
42
+ const cookieOpts = { ...options, secure: true, sameSite: "strict", ...(this.opts?.expressConfig?.cookieOptions || {}) };
43
+ const cookieData = sid;
44
+ if (!this.sidKeyName || !this.returnURL)
45
+ throw "sidKeyName or returnURL missing";
46
+ res.cookie(this.sidKeyName, cookieData, cookieOpts);
47
+ const successURL = getReturnUrl(req, this.returnURL) || "/";
48
+ res.redirect(successURL);
49
+ }
50
+ else {
51
+ throw ("no user or session");
52
+ }
53
+ };
54
+ this.getUser = async (clientReq) => {
55
+ if (!this.sidKeyName || !this.opts?.getUser)
56
+ throw "sidKeyName or this.opts.getUser missing";
57
+ const sid = "httpReq" in clientReq ? clientReq.httpReq?.cookies?.[this.sidKeyName] : clientReq.socket;
58
+ if (!sid)
59
+ return undefined;
60
+ try {
61
+ return this.throttledFunc(async () => {
62
+ return this.opts.getUser(this.validateSid(sid), this.dbo, this.db, clientReq);
63
+ }, 50);
64
+ }
65
+ catch (err) {
66
+ console.error(err);
67
+ }
68
+ return undefined;
69
+ };
70
+ this.throttledFunc = (func, throttle = 500) => {
71
+ return new Promise(async (resolve, reject) => {
72
+ let interval, result, error, finished = false;
73
+ /**
74
+ * Throttle response times to prevent timing attacks
75
+ */
76
+ interval = setInterval(() => {
77
+ if (finished) {
78
+ clearInterval(interval);
79
+ if (error) {
80
+ reject(error);
81
+ }
82
+ else {
83
+ resolve(result);
84
+ }
85
+ }
86
+ }, throttle);
87
+ try {
88
+ result = await func();
89
+ }
90
+ catch (err) {
91
+ console.log(err);
92
+ error = err;
93
+ }
94
+ finished = true;
95
+ });
96
+ };
97
+ this.loginThrottled = async (params) => {
98
+ if (!this.opts?.login)
99
+ throw "Auth login config missing";
100
+ const { responseThrottle = 500 } = this.opts;
101
+ return this.throttledFunc(async () => {
102
+ let result = await this.opts?.login?.(params, this.dbo, this.db);
103
+ const err = {
104
+ msg: "Bad login result type. \nExpecting: undefined | null | { sid: string; expires: number } but got: " + JSON.stringify(result)
105
+ };
106
+ if (!result)
107
+ throw err;
108
+ if (result && (typeof result.sid !== "string" || typeof result.expires !== "number") || !result && ![undefined, null].includes(result)) {
109
+ throw err;
110
+ }
111
+ if (result && result.expires < Date.now()) {
112
+ throw { msg: "auth.login() is returning an expired session. Can only login with a session.expires greater than Date.now()" };
113
+ }
114
+ return result;
115
+ }, responseThrottle);
116
+ };
117
+ this.isValidSocketSession = (socket, session) => {
118
+ const hasExpired = Boolean(session && session.expires <= Date.now());
119
+ if (this.opts?.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
120
+ if (hasExpired) {
121
+ socket.emit(prostgles_types_1.CHANNELS.AUTHGUARD, { shouldReload: true });
122
+ throw "";
123
+ }
124
+ }
125
+ return Boolean(session && !hasExpired);
126
+ };
127
+ this.makeSocketAuth = async (socket) => {
128
+ if (!this.opts)
129
+ return {};
130
+ let auth = {};
131
+ if (this.opts.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
132
+ auth.pathGuard = true;
133
+ socket.removeAllListeners(prostgles_types_1.CHANNELS.AUTHGUARD);
134
+ socket.on(prostgles_types_1.CHANNELS.AUTHGUARD, async (params, cb = (err, res) => { }) => {
135
+ try {
136
+ const { pathname } = typeof params === "string" ? JSON.parse(params) : (params || {});
137
+ if (pathname && typeof pathname !== "string")
138
+ console.warn("Invalid pathname provided for AuthGuardLocation: ", pathname);
139
+ if (pathname && typeof pathname === "string" && this.isUserRoute(pathname) && !(await this.getClientInfo({ socket }))?.user) {
140
+ cb(null, { shouldReload: true });
141
+ }
142
+ else {
143
+ cb(null, { shouldReload: false });
144
+ }
145
+ }
146
+ catch (err) {
147
+ console.error("AUTHGUARD err: ", err);
148
+ cb(err);
149
+ }
150
+ });
151
+ }
152
+ const { register, logout } = this.opts;
153
+ const login = this.loginThrottled;
154
+ let handlers = [
155
+ { func: (params, dbo, db) => register?.(params, dbo, db), ch: prostgles_types_1.CHANNELS.REGISTER, name: "register" },
156
+ { func: (params, dbo, db) => login(params), ch: prostgles_types_1.CHANNELS.LOGIN, name: "login" },
157
+ { func: (params, dbo, db) => logout?.(this.getSID({ socket }), dbo, db), ch: prostgles_types_1.CHANNELS.LOGOUT, name: "logout" }
158
+ ].filter(h => h.func);
159
+ const usrData = await this.getClientInfo({ socket });
160
+ if (usrData) {
161
+ auth.user = usrData.clientUser;
162
+ handlers = handlers.filter(h => h.name === "logout");
163
+ }
164
+ handlers.map(({ func, ch, name }) => {
165
+ auth[name] = true;
166
+ socket.removeAllListeners(ch);
167
+ socket.on(ch, async (params, cb = (...callback) => { }) => {
168
+ try {
169
+ if (!socket)
170
+ throw "socket missing??!!";
171
+ const res = await func(params, this.dbo, this.db);
172
+ if (name === "login" && res && res.sid) {
173
+ /* TODO: Re-send schema to client */
174
+ }
175
+ cb(null, true);
176
+ }
177
+ catch (err) {
178
+ console.error(name + " err", err);
179
+ cb(err);
180
+ }
181
+ });
182
+ });
183
+ return auth;
184
+ };
185
+ this.opts = prostgles.opts.auth;
186
+ if (prostgles.opts.auth?.expressConfig) {
187
+ this.returnURL = prostgles.opts.auth?.expressConfig?.returnURL || "returnURL";
188
+ this.loginRoute = prostgles.opts.auth?.expressConfig?.loginRoute || "/login";
189
+ this.logoutGetPath = prostgles.opts.auth?.expressConfig?.logoutGetPath || "/logout";
190
+ }
191
+ if (!prostgles.dbo || !prostgles.db)
192
+ throw "dbo or db missing";
193
+ this.dbo = prostgles.dbo;
194
+ this.db = prostgles.db;
195
+ }
196
+ async init() {
197
+ if (!this.opts)
198
+ return;
199
+ this.opts.sidKeyName = this.opts.sidKeyName || "session_id";
200
+ const { sidKeyName, login, getUser, expressConfig } = this.opts;
201
+ this.sidKeyName = this.opts.sidKeyName;
202
+ if (typeof sidKeyName !== "string" && !login) {
203
+ throw "Invalid auth: Provide { sidKeyName: string } ";
204
+ }
205
+ /**
206
+ * Why ??? Collision with socket.io ???
207
+ */
208
+ if (this.sidKeyName === "sid")
209
+ throw "sidKeyName cannot be 'sid' please provide another name.";
210
+ if (!getUser)
211
+ throw "getUser missing from auth config";
212
+ if (expressConfig) {
213
+ const { app, publicRoutes = [], onGetRequestOK, magicLinks } = expressConfig;
214
+ if (publicRoutes.find(r => typeof r !== "string" || !r)) {
215
+ throw "Invalid or empty string provided within publicRoutes ";
216
+ }
217
+ if (app && magicLinks) {
218
+ const { route = "/magic-link", check } = magicLinks;
219
+ if (!check)
220
+ throw "Check must be defined for magicLinks";
221
+ app.get(`${route}/:id`, async (req, res) => {
222
+ const { id } = req.params ?? {};
223
+ if (typeof id !== "string" || !id) {
224
+ res.status(404).json({ msg: "Invalid magic-link id. Expecting a string" });
225
+ }
226
+ else {
227
+ try {
228
+ const session = await this.throttledFunc(async () => {
229
+ return check(id, this.dbo, this.db);
230
+ });
231
+ if (!session) {
232
+ res.status(404).json({ msg: "Invalid magic-link" });
233
+ }
234
+ else {
235
+ this.setCookieAndGoToReturnURLIFSet(session, { req, res });
236
+ }
237
+ }
238
+ catch (e) {
239
+ res.status(404).json({ msg: e });
240
+ }
241
+ }
242
+ });
243
+ }
244
+ if (app && this.loginRoute) {
245
+ app.post(this.loginRoute, async (req, res) => {
246
+ try {
247
+ const { sid, expires } = await this.loginThrottled(req.body || {}) || {};
248
+ if (sid) {
249
+ this.setCookieAndGoToReturnURLIFSet({ sid, expires }, { req, res });
250
+ }
251
+ else {
252
+ throw ("no user or session");
253
+ }
254
+ }
255
+ catch (err) {
256
+ console.log(err);
257
+ res.status(404).json({ err: "Invalid username or password" });
258
+ }
259
+ });
260
+ if (app && this.logoutGetPath && this.opts.logout) {
261
+ app.get(this.logoutGetPath, async (req, res) => {
262
+ const sid = this.validateSid(req?.cookies?.[sidKeyName]);
263
+ if (sid) {
264
+ try {
265
+ await this.throttledFunc(() => {
266
+ return this.opts.logout(req?.cookies?.[sidKeyName], this.dbo, this.db);
267
+ });
268
+ }
269
+ catch (err) {
270
+ console.error(err);
271
+ }
272
+ }
273
+ res.redirect("/");
274
+ });
275
+ }
276
+ if (app && Array.isArray(publicRoutes)) {
277
+ /* Redirect if not logged in and requesting non public content */
278
+ app.get('*', async (req, res) => {
279
+ const clientReq = { httpReq: req };
280
+ const getUser = this.getUser;
281
+ try {
282
+ const returnURL = getReturnUrl(req, this.returnURL);
283
+ /**
284
+ * Requesting a User route
285
+ */
286
+ if (this.isUserRoute(req.path)) {
287
+ /* Check auth. Redirect if unauthorized */
288
+ const u = await getUser(clientReq);
289
+ if (!u) {
290
+ res.redirect(`${this.loginRoute}?returnURL=${encodeURIComponent(req.originalUrl)}`);
291
+ return;
292
+ }
293
+ /* If authorized and going to returnUrl then redirect. Otherwise serve file */
294
+ }
295
+ else if (returnURL && (await getUser(clientReq))) {
296
+ res.redirect(returnURL);
297
+ return;
298
+ /** If Logged in and requesting login then redirect */
299
+ }
300
+ else if (this.matchesRoute(this.loginRoute, req.path) && (await getUser(clientReq))) {
301
+ res.redirect("/");
302
+ return;
303
+ }
304
+ if (onGetRequestOK) {
305
+ onGetRequestOK(req, res);
306
+ }
307
+ }
308
+ catch (error) {
309
+ console.error(error);
310
+ res.status(404).json({ msg: "Something went wrong", error });
311
+ }
312
+ });
313
+ }
314
+ }
315
+ }
316
+ }
317
+ /**
318
+ * Will return first sid value found in : http cookie or query params
319
+ * Based on sid names in auth
320
+ * @param localParams
321
+ * @returns string
322
+ */
323
+ getSID(localParams) {
324
+ if (!this.opts)
325
+ return undefined;
326
+ const { sidKeyName } = this.opts;
327
+ if (!sidKeyName || !localParams)
328
+ return undefined;
329
+ if (localParams.socket) {
330
+ const querySid = localParams.socket?.handshake?.query?.[sidKeyName];
331
+ let rawSid = querySid;
332
+ if (!rawSid) {
333
+ const cookie_str = localParams.socket?.handshake?.headers?.cookie;
334
+ const cookie = parseCookieStr(cookie_str);
335
+ rawSid = cookie[sidKeyName];
336
+ }
337
+ return this.validateSid(rawSid);
338
+ }
339
+ else if (localParams.httpReq) {
340
+ return this.validateSid(localParams.httpReq?.cookies?.[sidKeyName]);
341
+ }
342
+ else
343
+ throw "socket OR httpReq missing from localParams";
344
+ function parseCookieStr(cookie_str) {
345
+ if (!cookie_str || typeof cookie_str !== "string")
346
+ return {};
347
+ return cookie_str.replace(/\s/g, '').split(";").reduce((prev, current) => {
348
+ const [name, value] = current.split('=');
349
+ prev[name] = value;
350
+ return prev;
351
+ }, {});
352
+ }
353
+ }
354
+ async getClientInfo(localParams) {
355
+ if (!this.opts)
356
+ return {};
357
+ const getSession = this.opts.cacheSession?.getSession;
358
+ const isSocket = "socket" in localParams;
359
+ if (getSession && isSocket && localParams.socket?.__prglCache) {
360
+ const { session, user, clientUser } = localParams.socket.__prglCache;
361
+ const isValid = this.isValidSocketSession(localParams.socket, session);
362
+ if (isValid) {
363
+ return {
364
+ sid: session.sid,
365
+ user,
366
+ clientUser,
367
+ };
368
+ }
369
+ else
370
+ return {};
371
+ }
372
+ const res = await this.throttledFunc(async () => {
373
+ const { getUser } = this.opts ?? {};
374
+ if (getUser && localParams && (localParams.httpReq || localParams.socket)) {
375
+ const sid = this.getSID(localParams);
376
+ const clientReq = localParams.httpReq ? { httpReq: localParams.httpReq } : { socket: localParams.socket };
377
+ let user, clientUser;
378
+ if (sid) {
379
+ const res = await getUser(sid, this.dbo, this.db, clientReq);
380
+ user = res?.user;
381
+ clientUser = res?.clientUser;
382
+ }
383
+ if (getSession && isSocket) {
384
+ const session = await getSession(sid, this.dbo, this.db);
385
+ if (session?.expires && user && clientUser && localParams.socket) {
386
+ localParams.socket.__prglCache = {
387
+ session,
388
+ user,
389
+ clientUser,
390
+ };
391
+ }
392
+ }
393
+ if (sid) {
394
+ return { sid, user, clientUser };
395
+ }
396
+ }
397
+ return {};
398
+ }, 5);
399
+ return res;
400
+ }
401
+ }
402
+ exports.default = AuthHandler;
403
+ /**
404
+ * AUTH
405
+ */
406
+ function getReturnUrl(req, name) {
407
+ if (req?.query?.returnURL && name) {
408
+ return decodeURIComponent(req?.query?.[name]);
409
+ }
410
+ return null;
411
+ }
@@ -36,7 +36,7 @@ export type BasicSession = {
36
36
 
37
37
  };
38
38
  export type AuthClientRequest = { socket: any } | { httpReq: ExpressReq }
39
- export type Auth<S extends DBSchema | undefined = undefined> = {
39
+ export type Auth<S = void> = {
40
40
  /**
41
41
  * Name of the cookie or socket hadnshake query param that represents the session id.
42
42
  * Defaults to "session_id"
@@ -136,8 +136,8 @@ export type ClientInfo = {
136
136
  sid?: string;
137
137
  }
138
138
 
139
- export default class AuthHandler<S extends DBSchema | undefined = undefined> {
140
- protected opts?: Auth<S>;
139
+ export default class AuthHandler {
140
+ protected opts?: Auth;
141
141
  dbo: DBHandlerServer;
142
142
  db: DB;
143
143
  sidKeyName?: string;
@@ -0,0 +1,38 @@
1
+ import { PostgresNotifListenManager } from "./PostgresNotifListenManager";
2
+ import { DB, PGP } from "./Prostgles";
3
+ import { PRGLIOSocket } from "./DboBuilder";
4
+ export declare class DBEventsManager {
5
+ notifies: {
6
+ [key: string]: {
7
+ socketChannel: string;
8
+ sockets: any[];
9
+ localFuncs: ((payload: string) => void)[];
10
+ notifMgr: PostgresNotifListenManager;
11
+ };
12
+ };
13
+ notice: {
14
+ socketChannel: string;
15
+ socketUnsubChannel: string;
16
+ sockets: any[];
17
+ };
18
+ notifManager?: PostgresNotifListenManager;
19
+ db_pg: DB;
20
+ pgp: PGP;
21
+ constructor(db_pg: DB, pgp: PGP);
22
+ private onNotif;
23
+ onNotice: (notice: any) => void;
24
+ getNotifChannelName: (channel: string) => Promise<any>;
25
+ addNotify(query: string, socket?: PRGLIOSocket, func?: any): Promise<{
26
+ socketChannel: string;
27
+ socketUnsubChannel: string;
28
+ notifChannel: string;
29
+ unsubscribe?: () => void;
30
+ }>;
31
+ removeNotify(channel?: string, socket?: PRGLIOSocket, func?: any): void;
32
+ addNotice(socket: PRGLIOSocket): {
33
+ socketChannel: string;
34
+ socketUnsubChannel: string;
35
+ };
36
+ removeNotice(socket: PRGLIOSocket): void;
37
+ }
38
+ //# sourceMappingURL=DBEventsManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DBEventsManager.d.ts","sourceRoot":"","sources":["DBEventsManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAqB,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,eAAe;IAE1B,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,aAAa,EAAE,MAAM,CAAC;YACtB,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;YAC1C,QAAQ,EAAE,0BAA0B,CAAC;SACtC,CAAA;KACF,CAAM;IAEP,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,OAAO,EAAE,GAAG,EAAE,CAAC;KAChB,CAIC;IAEF,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAE1C,KAAK,EAAE,EAAE,CAAC;IACV,GAAG,EAAE,GAAG,CAAA;gBACI,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG;IAK/B,OAAO,CAAC,OAAO,CAgBd;IAED,QAAQ,WAAY,GAAG,UAMtB;IAED,mBAAmB,YAAmB,MAAM,kBAG3C;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC;QACzE,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;KAC1B,CAAC;IAmEF,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,GAAG;IAkBhE,SAAS,CAAC,MAAM,EAAE,YAAY;;;;IAiB9B,YAAY,CAAC,MAAM,EAAE,YAAY;CAIlC"}