prostgles-server 3.0.69 → 3.0.71
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/dist/PubSubManager/PubSubManager.d.ts +4 -4
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +1 -1
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/initPubSubManager.js +52 -36
- package/dist/PubSubManager/initPubSubManager.js.map +1 -1
- package/lib/AuthHandler.js +213 -209
- package/lib/DBEventsManager.js +34 -31
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.js +163 -155
- package/lib/DboBuilder/TableHandler.js +21 -20
- package/lib/DboBuilder/ViewHandler.js +23 -8
- package/lib/DboBuilder/runSQL.js +5 -5
- package/lib/DboBuilder.js +85 -65
- package/lib/FileManager.js +369 -364
- package/lib/PostgresNotifListenManager.js +26 -20
- package/lib/Prostgles.js +194 -177
- package/lib/PubSubManager/PubSubManager.d.ts +4 -4
- package/lib/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/PubSubManager.js +250 -240
- package/lib/PubSubManager/PubSubManager.ts +2 -2
- package/lib/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/initPubSubManager.js +52 -36
- package/lib/PubSubManager/initPubSubManager.ts +53 -37
- package/lib/PublishParser.js +7 -2
- package/lib/SchemaWatch.js +2 -1
- package/lib/TableConfig.js +94 -91
- package/package.json +1 -1
- package/tests/client/PID.txt +1 -1
- package/tests/client/tsconfig.json +2 -2
- package/tests/server/package-lock.json +1 -1
- package/tests/server/tsconfig.json +2 -2
package/lib/AuthHandler.js
CHANGED
|
@@ -3,216 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const prostgles_types_1 = require("prostgles-types");
|
|
4
4
|
const FileManager_1 = require("./FileManager");
|
|
5
5
|
class AuthHandler {
|
|
6
|
+
opts;
|
|
7
|
+
dbo;
|
|
8
|
+
db;
|
|
9
|
+
sidKeyName;
|
|
10
|
+
routes = {
|
|
11
|
+
catchAll: "*"
|
|
12
|
+
};
|
|
6
13
|
constructor(prostgles) {
|
|
7
|
-
this.routes = {
|
|
8
|
-
catchAll: "*"
|
|
9
|
-
};
|
|
10
|
-
this.validateSid = (sid) => {
|
|
11
|
-
if (!sid)
|
|
12
|
-
return undefined;
|
|
13
|
-
if (typeof sid !== "string")
|
|
14
|
-
throw "sid missing or not a string";
|
|
15
|
-
return sid;
|
|
16
|
-
};
|
|
17
|
-
this.matchesRoute = (route, clientFullRoute) => {
|
|
18
|
-
return route && clientFullRoute && (route === clientFullRoute ||
|
|
19
|
-
clientFullRoute.startsWith(route) && ["/", "?", "#"].includes(clientFullRoute[route.length]));
|
|
20
|
-
};
|
|
21
|
-
this.isUserRoute = (pathname) => {
|
|
22
|
-
const pubRoutes = [
|
|
23
|
-
...this.opts?.expressConfig?.publicRoutes || [],
|
|
24
|
-
];
|
|
25
|
-
if (this.routes?.login)
|
|
26
|
-
pubRoutes.push(this.routes.login);
|
|
27
|
-
if (this.routes?.logoutGetPath)
|
|
28
|
-
pubRoutes.push(this.routes.logoutGetPath);
|
|
29
|
-
if (this.routes?.magicLinks?.route)
|
|
30
|
-
pubRoutes.push(this.routes.magicLinks.route);
|
|
31
|
-
return !pubRoutes.some(publicRoute => {
|
|
32
|
-
return this.matchesRoute(publicRoute, pathname); // publicRoute === pathname || pathname.startsWith(publicRoute) && ["/", "?", "#"].includes(pathname.slice(-1));
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
this.setCookieAndGoToReturnURLIFSet = (cookie, r) => {
|
|
36
|
-
const { sid, expires } = cookie;
|
|
37
|
-
const { res, req } = r;
|
|
38
|
-
if (sid) {
|
|
39
|
-
const maxAgeOneDay = 60 * 60 * 24; // 24 hours;
|
|
40
|
-
let cookieDuration = {
|
|
41
|
-
maxAge: maxAgeOneDay
|
|
42
|
-
};
|
|
43
|
-
if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
|
|
44
|
-
// const maxAge = (+new Date(expires)) - Date.now();
|
|
45
|
-
cookieDuration = { expires: new Date(expires) };
|
|
46
|
-
const days = (+cookieDuration.expires - Date.now()) / (24 * 60 * 60e3);
|
|
47
|
-
if (days >= 400) {
|
|
48
|
-
console.warn(`Cookie expiration higher the limit of 400 days for Chrome: ${days}days`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const cookieOpts = {
|
|
52
|
-
...cookieDuration,
|
|
53
|
-
httpOnly: true,
|
|
54
|
-
//signed: true // Indicates if the cookie should be signed
|
|
55
|
-
secure: true,
|
|
56
|
-
sameSite: "strict",
|
|
57
|
-
...(this.opts?.expressConfig?.cookieOptions || {})
|
|
58
|
-
};
|
|
59
|
-
const cookieData = sid;
|
|
60
|
-
if (!this.sidKeyName || !this.routes?.returnURL)
|
|
61
|
-
throw "sidKeyName or returnURL missing";
|
|
62
|
-
res.cookie(this.sidKeyName, cookieData, cookieOpts);
|
|
63
|
-
const successURL = getReturnUrl(req, this.routes.returnURL) || "/";
|
|
64
|
-
res.redirect(successURL);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
throw ("no user or session");
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
this.getUser = async (clientReq) => {
|
|
71
|
-
if (!this.sidKeyName || !this.opts?.getUser)
|
|
72
|
-
throw "sidKeyName or this.opts.getUser missing";
|
|
73
|
-
const sid = clientReq.httpReq?.cookies?.[this.sidKeyName];
|
|
74
|
-
if (!sid)
|
|
75
|
-
return undefined;
|
|
76
|
-
try {
|
|
77
|
-
return this.throttledFunc(async () => {
|
|
78
|
-
return this.opts.getUser(this.validateSid(sid), this.dbo, this.db, clientReq);
|
|
79
|
-
}, 50);
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
console.error(err);
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
};
|
|
86
|
-
this.destroy = () => {
|
|
87
|
-
const app = this.opts?.expressConfig?.app;
|
|
88
|
-
const { login, logoutGetPath, magicLinks } = this.routes;
|
|
89
|
-
(0, FileManager_1.removeExpressRoute)(app, [login, logoutGetPath, magicLinks?.expressRoute]);
|
|
90
|
-
};
|
|
91
|
-
this.throttledFunc = (func, throttle = 500) => {
|
|
92
|
-
return new Promise(async (resolve, reject) => {
|
|
93
|
-
let interval, result, error, finished = false;
|
|
94
|
-
/**
|
|
95
|
-
* Throttle response times to prevent timing attacks
|
|
96
|
-
*/
|
|
97
|
-
interval = setInterval(() => {
|
|
98
|
-
if (finished) {
|
|
99
|
-
clearInterval(interval);
|
|
100
|
-
if (error) {
|
|
101
|
-
reject(error);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
resolve(result);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}, throttle);
|
|
108
|
-
try {
|
|
109
|
-
result = await func();
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
console.log(err);
|
|
113
|
-
error = err;
|
|
114
|
-
}
|
|
115
|
-
finished = true;
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
this.loginThrottled = async (params, client) => {
|
|
119
|
-
if (!this.opts?.login)
|
|
120
|
-
throw "Auth login config missing";
|
|
121
|
-
const { responseThrottle = 500 } = this.opts;
|
|
122
|
-
return this.throttledFunc(async () => {
|
|
123
|
-
let result = await this.opts?.login?.(params, this.dbo, this.db, client);
|
|
124
|
-
const err = {
|
|
125
|
-
msg: "Bad login result type. \nExpecting: undefined | null | { sid: string; expires: number } but got: " + JSON.stringify(result)
|
|
126
|
-
};
|
|
127
|
-
if (!result)
|
|
128
|
-
throw err;
|
|
129
|
-
if (result && (typeof result.sid !== "string" || typeof result.expires !== "number") || !result && ![undefined, null].includes(result)) {
|
|
130
|
-
throw err;
|
|
131
|
-
}
|
|
132
|
-
if (result && result.expires < Date.now()) {
|
|
133
|
-
throw { msg: "auth.login() is returning an expired session. Can only login with a session.expires greater than Date.now()" };
|
|
134
|
-
}
|
|
135
|
-
return result;
|
|
136
|
-
}, responseThrottle);
|
|
137
|
-
};
|
|
138
|
-
this.isValidSocketSession = (socket, session) => {
|
|
139
|
-
const hasExpired = Boolean(session && session.expires <= Date.now());
|
|
140
|
-
if (this.opts?.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
141
|
-
const error = "Session has expired";
|
|
142
|
-
if (hasExpired) {
|
|
143
|
-
if (session.onExpiration === "redirect")
|
|
144
|
-
socket.emit(prostgles_types_1.CHANNELS.AUTHGUARD, {
|
|
145
|
-
shouldReload: session.onExpiration === "redirect",
|
|
146
|
-
error
|
|
147
|
-
});
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return Boolean(session && !hasExpired);
|
|
152
|
-
};
|
|
153
|
-
this.makeSocketAuth = async (socket) => {
|
|
154
|
-
if (!this.opts)
|
|
155
|
-
return {};
|
|
156
|
-
let auth = {};
|
|
157
|
-
if (this.opts.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
158
|
-
auth.pathGuard = true;
|
|
159
|
-
socket.removeAllListeners(prostgles_types_1.CHANNELS.AUTHGUARD);
|
|
160
|
-
socket.on(prostgles_types_1.CHANNELS.AUTHGUARD, async (params, cb = (err, res) => { }) => {
|
|
161
|
-
try {
|
|
162
|
-
const { pathname, origin } = typeof params === "string" ? JSON.parse(params) : (params || {});
|
|
163
|
-
if (pathname && typeof pathname !== "string") {
|
|
164
|
-
console.warn("Invalid pathname provided for AuthGuardLocation: ", pathname);
|
|
165
|
-
}
|
|
166
|
-
/** These origins */
|
|
167
|
-
const IGNORED_API_ORIGINS = ["file://"];
|
|
168
|
-
if (!IGNORED_API_ORIGINS.includes(origin) && pathname && typeof pathname === "string" && this.isUserRoute(pathname) && !(await this.getClientInfo({ socket }))?.user) {
|
|
169
|
-
cb(null, { shouldReload: true });
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
cb(null, { shouldReload: false });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
console.error("AUTHGUARD err: ", err);
|
|
177
|
-
cb(err);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
const { register, logout } = this.opts;
|
|
182
|
-
const login = this.loginThrottled;
|
|
183
|
-
let handlers = [
|
|
184
|
-
{ func: (params, dbo, db, client) => register?.(params, dbo, db), ch: prostgles_types_1.CHANNELS.REGISTER, name: "register" },
|
|
185
|
-
{ func: (params, dbo, db, client) => login(params, client), ch: prostgles_types_1.CHANNELS.LOGIN, name: "login" },
|
|
186
|
-
{ func: (params, dbo, db, client) => logout?.(this.getSID({ socket }), dbo, db), ch: prostgles_types_1.CHANNELS.LOGOUT, name: "logout" }
|
|
187
|
-
].filter(h => h.func);
|
|
188
|
-
const userData = await this.getClientInfo({ socket });
|
|
189
|
-
if (userData) {
|
|
190
|
-
auth.user = userData.clientUser;
|
|
191
|
-
handlers = handlers.filter(h => h.name === "logout");
|
|
192
|
-
}
|
|
193
|
-
handlers.map(({ func, ch, name }) => {
|
|
194
|
-
auth[name] = true;
|
|
195
|
-
socket.removeAllListeners(ch);
|
|
196
|
-
socket.on(ch, async (params, cb = (...callback) => { }) => {
|
|
197
|
-
try {
|
|
198
|
-
if (!socket)
|
|
199
|
-
throw "socket missing??!!";
|
|
200
|
-
const id_address = socket?.conn?.remoteAddress;
|
|
201
|
-
const user_agent = socket.handshake?.headers?.["user-agent"];
|
|
202
|
-
const res = await func(params, this.dbo, this.db, { user_agent, id_address });
|
|
203
|
-
if (name === "login" && res && res.sid) {
|
|
204
|
-
/* TODO: Re-send schema to client */
|
|
205
|
-
}
|
|
206
|
-
cb(null, true);
|
|
207
|
-
}
|
|
208
|
-
catch (err) {
|
|
209
|
-
console.error(name + " err", err);
|
|
210
|
-
cb(err);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
return { auth, userData };
|
|
215
|
-
};
|
|
216
14
|
this.opts = prostgles.opts.auth;
|
|
217
15
|
if (prostgles.opts.auth?.expressConfig) {
|
|
218
16
|
const { magicLinks, returnURL, loginRoute, logoutGetPath } = prostgles.opts.auth.expressConfig;
|
|
@@ -233,6 +31,82 @@ class AuthHandler {
|
|
|
233
31
|
this.dbo = prostgles.dbo;
|
|
234
32
|
this.db = prostgles.db;
|
|
235
33
|
}
|
|
34
|
+
validateSid = (sid) => {
|
|
35
|
+
if (!sid)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (typeof sid !== "string")
|
|
38
|
+
throw "sid missing or not a string";
|
|
39
|
+
return sid;
|
|
40
|
+
};
|
|
41
|
+
matchesRoute = (route, clientFullRoute) => {
|
|
42
|
+
return route && clientFullRoute && (route === clientFullRoute ||
|
|
43
|
+
clientFullRoute.startsWith(route) && ["/", "?", "#"].includes(clientFullRoute[route.length]));
|
|
44
|
+
};
|
|
45
|
+
isUserRoute = (pathname) => {
|
|
46
|
+
const pubRoutes = [
|
|
47
|
+
...this.opts?.expressConfig?.publicRoutes || [],
|
|
48
|
+
];
|
|
49
|
+
if (this.routes?.login)
|
|
50
|
+
pubRoutes.push(this.routes.login);
|
|
51
|
+
if (this.routes?.logoutGetPath)
|
|
52
|
+
pubRoutes.push(this.routes.logoutGetPath);
|
|
53
|
+
if (this.routes?.magicLinks?.route)
|
|
54
|
+
pubRoutes.push(this.routes.magicLinks.route);
|
|
55
|
+
return !pubRoutes.some(publicRoute => {
|
|
56
|
+
return this.matchesRoute(publicRoute, pathname); // publicRoute === pathname || pathname.startsWith(publicRoute) && ["/", "?", "#"].includes(pathname.slice(-1));
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
setCookieAndGoToReturnURLIFSet = (cookie, r) => {
|
|
60
|
+
const { sid, expires } = cookie;
|
|
61
|
+
const { res, req } = r;
|
|
62
|
+
if (sid) {
|
|
63
|
+
const maxAgeOneDay = 60 * 60 * 24; // 24 hours;
|
|
64
|
+
let cookieDuration = {
|
|
65
|
+
maxAge: maxAgeOneDay
|
|
66
|
+
};
|
|
67
|
+
if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
|
|
68
|
+
// const maxAge = (+new Date(expires)) - Date.now();
|
|
69
|
+
cookieDuration = { expires: new Date(expires) };
|
|
70
|
+
const days = (+cookieDuration.expires - Date.now()) / (24 * 60 * 60e3);
|
|
71
|
+
if (days >= 400) {
|
|
72
|
+
console.warn(`Cookie expiration higher the limit of 400 days for Chrome: ${days}days`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const cookieOpts = {
|
|
76
|
+
...cookieDuration,
|
|
77
|
+
httpOnly: true,
|
|
78
|
+
//signed: true // Indicates if the cookie should be signed
|
|
79
|
+
secure: true,
|
|
80
|
+
sameSite: "strict",
|
|
81
|
+
...(this.opts?.expressConfig?.cookieOptions || {})
|
|
82
|
+
};
|
|
83
|
+
const cookieData = sid;
|
|
84
|
+
if (!this.sidKeyName || !this.routes?.returnURL)
|
|
85
|
+
throw "sidKeyName or returnURL missing";
|
|
86
|
+
res.cookie(this.sidKeyName, cookieData, cookieOpts);
|
|
87
|
+
const successURL = getReturnUrl(req, this.routes.returnURL) || "/";
|
|
88
|
+
res.redirect(successURL);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw ("no user or session");
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
getUser = async (clientReq) => {
|
|
95
|
+
if (!this.sidKeyName || !this.opts?.getUser)
|
|
96
|
+
throw "sidKeyName or this.opts.getUser missing";
|
|
97
|
+
const sid = clientReq.httpReq?.cookies?.[this.sidKeyName];
|
|
98
|
+
if (!sid)
|
|
99
|
+
return undefined;
|
|
100
|
+
try {
|
|
101
|
+
return this.throttledFunc(async () => {
|
|
102
|
+
return this.opts.getUser(this.validateSid(sid), this.dbo, this.db, clientReq);
|
|
103
|
+
}, 50);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
console.error(err);
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
};
|
|
236
110
|
async init() {
|
|
237
111
|
if (!this.opts)
|
|
238
112
|
return;
|
|
@@ -369,6 +243,58 @@ class AuthHandler {
|
|
|
369
243
|
}
|
|
370
244
|
}
|
|
371
245
|
}
|
|
246
|
+
destroy = () => {
|
|
247
|
+
const app = this.opts?.expressConfig?.app;
|
|
248
|
+
const { login, logoutGetPath, magicLinks } = this.routes;
|
|
249
|
+
(0, FileManager_1.removeExpressRoute)(app, [login, logoutGetPath, magicLinks?.expressRoute]);
|
|
250
|
+
};
|
|
251
|
+
throttledFunc = (func, throttle = 500) => {
|
|
252
|
+
return new Promise(async (resolve, reject) => {
|
|
253
|
+
let interval, result, error, finished = false;
|
|
254
|
+
/**
|
|
255
|
+
* Throttle response times to prevent timing attacks
|
|
256
|
+
*/
|
|
257
|
+
interval = setInterval(() => {
|
|
258
|
+
if (finished) {
|
|
259
|
+
clearInterval(interval);
|
|
260
|
+
if (error) {
|
|
261
|
+
reject(error);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
resolve(result);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}, throttle);
|
|
268
|
+
try {
|
|
269
|
+
result = await func();
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
console.log(err);
|
|
273
|
+
error = err;
|
|
274
|
+
}
|
|
275
|
+
finished = true;
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
loginThrottled = async (params, client) => {
|
|
279
|
+
if (!this.opts?.login)
|
|
280
|
+
throw "Auth login config missing";
|
|
281
|
+
const { responseThrottle = 500 } = this.opts;
|
|
282
|
+
return this.throttledFunc(async () => {
|
|
283
|
+
let result = await this.opts?.login?.(params, this.dbo, this.db, client);
|
|
284
|
+
const err = {
|
|
285
|
+
msg: "Bad login result type. \nExpecting: undefined | null | { sid: string; expires: number } but got: " + JSON.stringify(result)
|
|
286
|
+
};
|
|
287
|
+
if (!result)
|
|
288
|
+
throw err;
|
|
289
|
+
if (result && (typeof result.sid !== "string" || typeof result.expires !== "number") || !result && ![undefined, null].includes(result)) {
|
|
290
|
+
throw err;
|
|
291
|
+
}
|
|
292
|
+
if (result && result.expires < Date.now()) {
|
|
293
|
+
throw { msg: "auth.login() is returning an expired session. Can only login with a session.expires greater than Date.now()" };
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}, responseThrottle);
|
|
297
|
+
};
|
|
372
298
|
/**
|
|
373
299
|
* Will return first sid value found in : http cookie or query params
|
|
374
300
|
* Based on sid names in auth
|
|
@@ -458,6 +384,84 @@ class AuthHandler {
|
|
|
458
384
|
}, 5);
|
|
459
385
|
return res;
|
|
460
386
|
}
|
|
387
|
+
isValidSocketSession = (socket, session) => {
|
|
388
|
+
const hasExpired = Boolean(session && session.expires <= Date.now());
|
|
389
|
+
if (this.opts?.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
390
|
+
const error = "Session has expired";
|
|
391
|
+
if (hasExpired) {
|
|
392
|
+
if (session.onExpiration === "redirect")
|
|
393
|
+
socket.emit(prostgles_types_1.CHANNELS.AUTHGUARD, {
|
|
394
|
+
shouldReload: session.onExpiration === "redirect",
|
|
395
|
+
error
|
|
396
|
+
});
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return Boolean(session && !hasExpired);
|
|
401
|
+
};
|
|
402
|
+
makeSocketAuth = async (socket) => {
|
|
403
|
+
if (!this.opts)
|
|
404
|
+
return {};
|
|
405
|
+
let auth = {};
|
|
406
|
+
if (this.opts.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
407
|
+
auth.pathGuard = true;
|
|
408
|
+
socket.removeAllListeners(prostgles_types_1.CHANNELS.AUTHGUARD);
|
|
409
|
+
socket.on(prostgles_types_1.CHANNELS.AUTHGUARD, async (params, cb = (err, res) => { }) => {
|
|
410
|
+
try {
|
|
411
|
+
const { pathname, origin } = typeof params === "string" ? JSON.parse(params) : (params || {});
|
|
412
|
+
if (pathname && typeof pathname !== "string") {
|
|
413
|
+
console.warn("Invalid pathname provided for AuthGuardLocation: ", pathname);
|
|
414
|
+
}
|
|
415
|
+
/** These origins */
|
|
416
|
+
const IGNORED_API_ORIGINS = ["file://"];
|
|
417
|
+
if (!IGNORED_API_ORIGINS.includes(origin) && pathname && typeof pathname === "string" && this.isUserRoute(pathname) && !(await this.getClientInfo({ socket }))?.user) {
|
|
418
|
+
cb(null, { shouldReload: true });
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
cb(null, { shouldReload: false });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
catch (err) {
|
|
425
|
+
console.error("AUTHGUARD err: ", err);
|
|
426
|
+
cb(err);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
const { register, logout } = this.opts;
|
|
431
|
+
const login = this.loginThrottled;
|
|
432
|
+
let handlers = [
|
|
433
|
+
{ func: (params, dbo, db, client) => register?.(params, dbo, db), ch: prostgles_types_1.CHANNELS.REGISTER, name: "register" },
|
|
434
|
+
{ func: (params, dbo, db, client) => login(params, client), ch: prostgles_types_1.CHANNELS.LOGIN, name: "login" },
|
|
435
|
+
{ func: (params, dbo, db, client) => logout?.(this.getSID({ socket }), dbo, db), ch: prostgles_types_1.CHANNELS.LOGOUT, name: "logout" }
|
|
436
|
+
].filter(h => h.func);
|
|
437
|
+
const userData = await this.getClientInfo({ socket });
|
|
438
|
+
if (userData) {
|
|
439
|
+
auth.user = userData.clientUser;
|
|
440
|
+
handlers = handlers.filter(h => h.name === "logout");
|
|
441
|
+
}
|
|
442
|
+
handlers.map(({ func, ch, name }) => {
|
|
443
|
+
auth[name] = true;
|
|
444
|
+
socket.removeAllListeners(ch);
|
|
445
|
+
socket.on(ch, async (params, cb = (...callback) => { }) => {
|
|
446
|
+
try {
|
|
447
|
+
if (!socket)
|
|
448
|
+
throw "socket missing??!!";
|
|
449
|
+
const id_address = socket?.conn?.remoteAddress;
|
|
450
|
+
const user_agent = socket.handshake?.headers?.["user-agent"];
|
|
451
|
+
const res = await func(params, this.dbo, this.db, { user_agent, id_address });
|
|
452
|
+
if (name === "login" && res && res.sid) {
|
|
453
|
+
/* TODO: Re-send schema to client */
|
|
454
|
+
}
|
|
455
|
+
cb(null, true);
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
console.error(name + " err", err);
|
|
459
|
+
cb(err);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
return { auth, userData };
|
|
464
|
+
};
|
|
461
465
|
}
|
|
462
466
|
exports.default = AuthHandler;
|
|
463
467
|
/**
|
package/lib/DBEventsManager.js
CHANGED
|
@@ -4,41 +4,44 @@ exports.DBEventsManager = void 0;
|
|
|
4
4
|
const PostgresNotifListenManager_1 = require("./PostgresNotifListenManager");
|
|
5
5
|
const prostgles_types_1 = require("prostgles-types");
|
|
6
6
|
class DBEventsManager {
|
|
7
|
+
notifies = {};
|
|
8
|
+
notice = {
|
|
9
|
+
socketChannel: prostgles_types_1.CHANNELS.NOTICE_EV,
|
|
10
|
+
socketUnsubChannel: prostgles_types_1.CHANNELS.NOTICE_EV + "unsubscribe",
|
|
11
|
+
sockets: []
|
|
12
|
+
};
|
|
13
|
+
notifManager;
|
|
14
|
+
db_pg;
|
|
15
|
+
pgp;
|
|
7
16
|
constructor(db_pg, pgp) {
|
|
8
|
-
this.notifies = {};
|
|
9
|
-
this.notice = {
|
|
10
|
-
socketChannel: prostgles_types_1.CHANNELS.NOTICE_EV,
|
|
11
|
-
socketUnsubChannel: prostgles_types_1.CHANNELS.NOTICE_EV + "unsubscribe",
|
|
12
|
-
sockets: []
|
|
13
|
-
};
|
|
14
|
-
this.onNotif = ({ channel, payload }) => {
|
|
15
|
-
// console.log(36, { channel, payload }, Object.keys(this.notifies));
|
|
16
|
-
Object.keys(this.notifies)
|
|
17
|
-
.filter(ch => ch === channel)
|
|
18
|
-
.map(ch => {
|
|
19
|
-
const sub = this.notifies[ch];
|
|
20
|
-
sub.sockets.map(s => {
|
|
21
|
-
s.emit(sub.socketChannel, payload);
|
|
22
|
-
});
|
|
23
|
-
sub.localFuncs.map(lf => {
|
|
24
|
-
lf(payload);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
this.onNotice = (notice) => {
|
|
29
|
-
if (this.notice && this.notice.sockets.length) {
|
|
30
|
-
this.notice.sockets.map(s => {
|
|
31
|
-
s.emit(this.notice.socketChannel, notice);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
this.getNotifChannelName = async (channel) => {
|
|
36
|
-
const c = await this.db_pg.one("SELECT quote_ident($1) as c", channel);
|
|
37
|
-
return c.c;
|
|
38
|
-
};
|
|
39
17
|
this.db_pg = db_pg;
|
|
40
18
|
this.pgp = pgp;
|
|
41
19
|
}
|
|
20
|
+
onNotif = ({ channel, payload }) => {
|
|
21
|
+
// console.log(36, { channel, payload }, Object.keys(this.notifies));
|
|
22
|
+
Object.keys(this.notifies)
|
|
23
|
+
.filter(ch => ch === channel)
|
|
24
|
+
.map(ch => {
|
|
25
|
+
const sub = this.notifies[ch];
|
|
26
|
+
sub.sockets.map(s => {
|
|
27
|
+
s.emit(sub.socketChannel, payload);
|
|
28
|
+
});
|
|
29
|
+
sub.localFuncs.map(lf => {
|
|
30
|
+
lf(payload);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
onNotice = (notice) => {
|
|
35
|
+
if (this.notice && this.notice.sockets.length) {
|
|
36
|
+
this.notice.sockets.map(s => {
|
|
37
|
+
s.emit(this.notice.socketChannel, notice);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
getNotifChannelName = async (channel) => {
|
|
42
|
+
const c = await this.db_pg.one("SELECT quote_ident($1) as c", channel);
|
|
43
|
+
return c.c;
|
|
44
|
+
};
|
|
42
45
|
async addNotify(query, socket, func) {
|
|
43
46
|
if (typeof query !== "string" || (!socket && !func)) {
|
|
44
47
|
throw "Expecting (query: string, socket?, localFunc?) But received: " + JSON.stringify({ query, socket, func });
|