prostgles-server 4.2.202 → 4.2.204
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/Auth/AuthHandler.d.ts +9 -12
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js +39 -170
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/AuthTypes.d.ts +37 -48
- package/dist/Auth/AuthTypes.d.ts.map +1 -1
- package/dist/Auth/endpoints/setCatchAllRequestHandler.d.ts +1 -2
- package/dist/Auth/endpoints/setCatchAllRequestHandler.d.ts.map +1 -1
- package/dist/Auth/endpoints/setCatchAllRequestHandler.js +4 -4
- package/dist/Auth/endpoints/setCatchAllRequestHandler.js.map +1 -1
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.d.ts +3 -5
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.d.ts.map +1 -1
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.js +4 -5
- package/dist/Auth/endpoints/setConfirmEmailRequestHandler.js.map +1 -1
- package/dist/Auth/endpoints/setLoginRequestHandler.d.ts +5 -6
- package/dist/Auth/endpoints/setLoginRequestHandler.d.ts.map +1 -1
- package/dist/Auth/endpoints/setLoginRequestHandler.js +5 -8
- package/dist/Auth/endpoints/setLoginRequestHandler.js.map +1 -1
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.d.ts +2 -3
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.d.ts.map +1 -1
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.js +4 -4
- package/dist/Auth/endpoints/setMagicLinkRequestHandler.js.map +1 -1
- package/dist/Auth/endpoints/setOAuthRequestHandlers.d.ts +5 -0
- package/dist/Auth/endpoints/setOAuthRequestHandlers.d.ts.map +1 -0
- package/dist/Auth/{authProviders/setOAuthProviders.js → endpoints/setOAuthRequestHandlers.js} +19 -15
- package/dist/Auth/endpoints/setOAuthRequestHandlers.js.map +1 -0
- package/dist/Auth/endpoints/setRegisterRequestHandler.d.ts +2 -2
- package/dist/Auth/endpoints/setRegisterRequestHandler.d.ts.map +1 -1
- package/dist/Auth/endpoints/setRegisterRequestHandler.js +26 -44
- package/dist/Auth/endpoints/setRegisterRequestHandler.js.map +1 -1
- package/dist/Auth/getClientAuth.d.ts +8 -0
- package/dist/Auth/getClientAuth.d.ts.map +1 -0
- package/dist/Auth/getClientAuth.js +76 -0
- package/dist/Auth/getClientAuth.js.map +1 -0
- package/dist/Auth/login.d.ts +5 -0
- package/dist/Auth/login.d.ts.map +1 -0
- package/dist/Auth/login.js +111 -0
- package/dist/Auth/login.js.map +1 -0
- package/dist/Auth/sendEmail.d.ts +3 -5
- package/dist/Auth/sendEmail.d.ts.map +1 -1
- package/dist/Auth/sendEmail.js +27 -2
- package/dist/Auth/sendEmail.js.map +1 -1
- package/dist/Auth/setupAuthRoutes.d.ts.map +1 -1
- package/dist/Auth/setupAuthRoutes.js +15 -9
- package/dist/Auth/setupAuthRoutes.js.map +1 -1
- package/dist/Auth/utils/getSidAndUserFromRequest.d.ts.map +1 -1
- package/dist/Auth/utils/getSidAndUserFromRequest.js +2 -1
- package/dist/Auth/utils/getSidAndUserFromRequest.js.map +1 -1
- package/dist/Auth/utils/throttledReject.d.ts +5 -0
- package/dist/Auth/utils/throttledReject.d.ts.map +1 -0
- package/dist/Auth/utils/throttledReject.js +34 -0
- package/dist/Auth/utils/throttledReject.js.map +1 -0
- package/dist/Auth/utils/upsertNamedExpressMiddleware.d.ts +6 -0
- package/dist/Auth/utils/upsertNamedExpressMiddleware.d.ts.map +1 -0
- package/dist/Auth/utils/upsertNamedExpressMiddleware.js +12 -0
- package/dist/Auth/utils/upsertNamedExpressMiddleware.js.map +1 -0
- package/dist/DBSchemaBuilder.js.map +1 -1
- package/dist/Prostgles.d.ts +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +2 -2
- package/dist/Prostgles.js.map +1 -1
- package/dist/ProstglesTypes.d.ts +2 -2
- package/dist/ProstglesTypes.d.ts.map +1 -1
- package/lib/Auth/AuthHandler.ts +50 -218
- package/lib/Auth/AuthTypes.ts +72 -72
- package/lib/Auth/endpoints/setCatchAllRequestHandler.ts +8 -4
- package/lib/Auth/endpoints/setConfirmEmailRequestHandler.ts +9 -13
- package/lib/Auth/endpoints/setLoginRequestHandler.ts +8 -14
- package/lib/Auth/endpoints/setMagicLinkRequestHandler.ts +6 -6
- package/lib/Auth/{authProviders/setOAuthProviders.ts → endpoints/setOAuthRequestHandlers.ts} +24 -17
- package/lib/Auth/endpoints/setRegisterRequestHandler.ts +30 -54
- package/lib/Auth/getClientAuth.ts +100 -0
- package/lib/Auth/login.ts +139 -0
- package/lib/Auth/sendEmail.ts +31 -7
- package/lib/Auth/setupAuthRoutes.ts +22 -9
- package/lib/Auth/utils/getSidAndUserFromRequest.ts +2 -1
- package/lib/Auth/utils/throttledReject.ts +33 -0
- package/lib/Auth/utils/upsertNamedExpressMiddleware.ts +14 -0
- package/lib/DBSchemaBuilder.ts +2 -2
- package/lib/Prostgles.ts +1 -1
- package/lib/ProstglesTypes.ts +2 -2
- package/package.json +2 -2
- package/dist/Auth/authProviders/setEmailProvider.d.ts +0 -4
- package/dist/Auth/authProviders/setEmailProvider.d.ts.map +0 -1
- package/dist/Auth/authProviders/setEmailProvider.js +0 -26
- package/dist/Auth/authProviders/setEmailProvider.js.map +0 -1
- package/dist/Auth/authProviders/setOAuthProviders.d.ts +0 -5
- package/dist/Auth/authProviders/setOAuthProviders.d.ts.map +0 -1
- package/dist/Auth/authProviders/setOAuthProviders.js.map +0 -1
- package/dist/Auth/setAuthProviders.d.ts +0 -11
- package/dist/Auth/setAuthProviders.d.ts.map +0 -1
- package/dist/Auth/setAuthProviders.js +0 -41
- package/dist/Auth/setAuthProviders.js.map +0 -1
- package/lib/Auth/authProviders/setEmailProvider.ts +0 -26
- package/lib/Auth/setAuthProviders.ts +0 -47
package/lib/Auth/AuthHandler.ts
CHANGED
|
@@ -1,35 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnyObject,
|
|
3
|
-
AuthFailure,
|
|
4
|
-
AuthGuardLocation,
|
|
5
|
-
AuthGuardLocationResponse,
|
|
6
|
-
AuthResponse,
|
|
7
|
-
AuthSocketSchema,
|
|
8
|
-
CHANNELS,
|
|
9
|
-
} from "prostgles-types";
|
|
1
|
+
import { AnyObject, AuthResponse, CHANNELS } from "prostgles-types";
|
|
10
2
|
import { PRGLIOSocket } from "../DboBuilder/DboBuilder";
|
|
11
3
|
import { DBOFullyTyped } from "../DBSchemaBuilder";
|
|
12
4
|
import { removeExpressRoute } from "../FileManager/FileManager";
|
|
13
5
|
import { DB, DBHandlerServer, Prostgles } from "../Prostgles";
|
|
14
6
|
import {
|
|
15
|
-
|
|
7
|
+
AuthConfig,
|
|
16
8
|
AuthClientRequest,
|
|
17
9
|
AuthResult,
|
|
18
10
|
AuthResultWithSID,
|
|
19
11
|
BasicSession,
|
|
20
12
|
ExpressReq,
|
|
21
|
-
ExpressRes,
|
|
22
|
-
LoginClientInfo,
|
|
23
|
-
LoginParams,
|
|
24
|
-
LoginResponse,
|
|
25
13
|
} from "./AuthTypes";
|
|
26
|
-
import {
|
|
14
|
+
import { LoginResponseHandler } from "./endpoints/setLoginRequestHandler";
|
|
15
|
+
import { getClientAuth } from "./getClientAuth";
|
|
16
|
+
import { login } from "./login";
|
|
27
17
|
import { setupAuthRoutes } from "./setupAuthRoutes";
|
|
28
18
|
import { getClientRequestIPsInfo } from "./utils/getClientRequestIPsInfo";
|
|
29
19
|
import { getReturnUrl } from "./utils/getReturnUrl";
|
|
30
20
|
import { getSidAndUserFromRequest } from "./utils/getSidAndUserFromRequest";
|
|
31
|
-
import
|
|
32
|
-
import { LoginResponseHandler } from "./endpoints/setLoginRequestHandler";
|
|
21
|
+
import { throttledReject } from "./utils/throttledReject";
|
|
33
22
|
|
|
34
23
|
export { getClientRequestIPsInfo };
|
|
35
24
|
export const HTTP_FAIL_CODES = {
|
|
@@ -48,7 +37,7 @@ export const HTTP_SUCCESS_CODES = {
|
|
|
48
37
|
|
|
49
38
|
export const AUTH_ROUTES_AND_PARAMS = {
|
|
50
39
|
login: "/login",
|
|
51
|
-
loginWithProvider: "/
|
|
40
|
+
loginWithProvider: "/oauth",
|
|
52
41
|
emailRegistration: "/register",
|
|
53
42
|
returnUrlParamName: "returnURL",
|
|
54
43
|
sidKeyName: "session_id",
|
|
@@ -62,7 +51,7 @@ export const AUTH_ROUTES_AND_PARAMS = {
|
|
|
62
51
|
|
|
63
52
|
export class AuthHandler {
|
|
64
53
|
protected readonly prostgles: Prostgles;
|
|
65
|
-
protected readonly opts:
|
|
54
|
+
protected readonly opts: AuthConfig;
|
|
66
55
|
dbo: DBHandlerServer;
|
|
67
56
|
db: DB;
|
|
68
57
|
|
|
@@ -98,7 +87,7 @@ export class AuthHandler {
|
|
|
98
87
|
isUserRoute = (pathname: string) => {
|
|
99
88
|
const { login, logoutGetPath, magicLinksRoute, loginWithProvider } = AUTH_ROUTES_AND_PARAMS;
|
|
100
89
|
const pubRoutes = [
|
|
101
|
-
...(this.opts.
|
|
90
|
+
...(this.opts.loginSignupConfig?.publicRoutes || []),
|
|
102
91
|
login,
|
|
103
92
|
logoutGetPath,
|
|
104
93
|
magicLinksRoute,
|
|
@@ -116,42 +105,43 @@ export class AuthHandler {
|
|
|
116
105
|
) => {
|
|
117
106
|
const { sid, expires } = cookie;
|
|
118
107
|
const { res, req } = r;
|
|
119
|
-
if (sid) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
let cookieDuration: CD = {
|
|
123
|
-
maxAge: maxAgeOneDay,
|
|
124
|
-
};
|
|
125
|
-
if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
|
|
126
|
-
// const maxAge = (+new Date(expires)) - Date.now();
|
|
127
|
-
cookieDuration = { expires: new Date(expires) };
|
|
128
|
-
const days = (+cookieDuration.expires - Date.now()) / (24 * 60 * 60e3);
|
|
129
|
-
if (days >= 400) {
|
|
130
|
-
console.warn(`Cookie expiration is higher than the Chrome 400 day limit: ${days}days`);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
108
|
+
if (!sid) {
|
|
109
|
+
throw "no sid";
|
|
110
|
+
}
|
|
133
111
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
};
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
} else {
|
|
147
|
-
throw "no user or session";
|
|
112
|
+
const maxAgeOneDay = 60 * 60 * 24; // 24 hours;
|
|
113
|
+
type CD = { maxAge: number } | { expires: Date };
|
|
114
|
+
let cookieDuration: CD = {
|
|
115
|
+
maxAge: maxAgeOneDay,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
|
|
119
|
+
cookieDuration = { expires: new Date(expires) };
|
|
120
|
+
const days = (+cookieDuration.expires - Date.now()) / (24 * 60 * 60e3);
|
|
121
|
+
if (days >= 400) {
|
|
122
|
+
console.warn(`Cookie expiration is higher than the Chrome 400 day limit: ${days}days`);
|
|
123
|
+
}
|
|
148
124
|
}
|
|
125
|
+
|
|
126
|
+
const cookieOpts = {
|
|
127
|
+
...cookieDuration,
|
|
128
|
+
// The cookie only accessible by the web server
|
|
129
|
+
httpOnly: true,
|
|
130
|
+
//signed: true
|
|
131
|
+
secure: true,
|
|
132
|
+
sameSite: "strict" as const,
|
|
133
|
+
...(this.opts.loginSignupConfig?.cookieOptions ?? {}),
|
|
134
|
+
};
|
|
135
|
+
const cookieData = sid;
|
|
136
|
+
res.cookie(this.sidKeyName, cookieData, cookieOpts);
|
|
137
|
+
const successURL = getReturnUrl(req) || "/";
|
|
138
|
+
res.redirect(successURL);
|
|
149
139
|
};
|
|
150
140
|
|
|
151
141
|
getUserAndHandleError = async (localParams: AuthClientRequest): Promise<AuthResultWithSID> => {
|
|
152
142
|
const sid = this.getSID(localParams);
|
|
153
143
|
if (!sid) return { sid };
|
|
154
|
-
const handlerError = (code: AuthFailure["code"]) => {
|
|
144
|
+
const handlerError = (code: AuthResponse.AuthFailure["code"]) => {
|
|
155
145
|
if (localParams.httpReq) {
|
|
156
146
|
localParams.res
|
|
157
147
|
.status(HTTP_FAIL_CODES.BAD_REQUEST)
|
|
@@ -160,7 +150,7 @@ export class AuthHandler {
|
|
|
160
150
|
throw code;
|
|
161
151
|
};
|
|
162
152
|
try {
|
|
163
|
-
const userOrErrorCode = await
|
|
153
|
+
const userOrErrorCode = await throttledReject(async () => {
|
|
164
154
|
return this.opts.getUser(
|
|
165
155
|
this.validateSid(sid),
|
|
166
156
|
this.dbo as DBOFullyTyped,
|
|
@@ -186,7 +176,7 @@ export class AuthHandler {
|
|
|
186
176
|
init = setupAuthRoutes.bind(this);
|
|
187
177
|
|
|
188
178
|
destroy = () => {
|
|
189
|
-
const app = this.opts.
|
|
179
|
+
const app = this.opts.loginSignupConfig?.app;
|
|
190
180
|
const {
|
|
191
181
|
login,
|
|
192
182
|
logoutGetPath,
|
|
@@ -211,111 +201,13 @@ export class AuthHandler {
|
|
|
211
201
|
]);
|
|
212
202
|
};
|
|
213
203
|
|
|
214
|
-
|
|
215
|
-
return new Promise(async (resolve, reject) => {
|
|
216
|
-
let result: T,
|
|
217
|
-
error: any,
|
|
218
|
-
finished = false;
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Throttle reject response times to prevent timing attacks
|
|
222
|
-
*/
|
|
223
|
-
const interval = setInterval(() => {
|
|
224
|
-
if (finished) {
|
|
225
|
-
clearInterval(interval);
|
|
226
|
-
if (error) {
|
|
227
|
-
reject(error);
|
|
228
|
-
} else {
|
|
229
|
-
resolve(result);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}, throttle);
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
result = await func();
|
|
236
|
-
resolve(result);
|
|
237
|
-
clearInterval(interval);
|
|
238
|
-
} catch (err) {
|
|
239
|
-
console.log(err);
|
|
240
|
-
error = err;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
finished = true;
|
|
244
|
-
});
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
loginThrottledAndValidate = async (
|
|
248
|
-
params: LoginParams,
|
|
249
|
-
client: LoginClientInfo
|
|
250
|
-
): Promise<LoginResponse> => {
|
|
251
|
-
if (!this.opts.login) throw "Auth login config missing";
|
|
252
|
-
const { responseThrottle = 500 } = this.opts;
|
|
253
|
-
return this.throttledFunc(async () => {
|
|
254
|
-
const result = await this.opts.login?.(params, this.dbo as DBOFullyTyped, this.db, client);
|
|
255
|
-
|
|
256
|
-
if (!result) {
|
|
257
|
-
return "server-error";
|
|
258
|
-
}
|
|
259
|
-
if (typeof result === "string") return result;
|
|
260
|
-
|
|
261
|
-
const { sid, expires } = result.session;
|
|
262
|
-
if (!sid) {
|
|
263
|
-
// return withServerError("Invalid sid");
|
|
264
|
-
return "server-error";
|
|
265
|
-
}
|
|
266
|
-
if (sid && (typeof sid !== "string" || typeof expires !== "number")) {
|
|
267
|
-
// return withServerError(
|
|
268
|
-
// "Bad login result type. \nExpecting: undefined | null | { sid: string; expires: number }"
|
|
269
|
-
// );
|
|
270
|
-
return "server-error";
|
|
271
|
-
}
|
|
272
|
-
if (expires < Date.now()) {
|
|
273
|
-
// return withServerError(
|
|
274
|
-
// "auth.login() is returning an expired session. Can only login with a session.expires greater than Date.now()"
|
|
275
|
-
// );
|
|
276
|
-
return "server-error";
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return result;
|
|
280
|
-
}, responseThrottle);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
loginThrottledAndSetCookie = async (
|
|
284
|
-
req: ExpressReq,
|
|
285
|
-
res: LoginResponseHandler,
|
|
286
|
-
loginParams: LoginParams
|
|
287
|
-
) => {
|
|
288
|
-
const start = Date.now();
|
|
289
|
-
const errCodeOrSession = await this.loginThrottledAndValidate(
|
|
290
|
-
loginParams,
|
|
291
|
-
getClientRequestIPsInfo({ httpReq: req, res })
|
|
292
|
-
);
|
|
293
|
-
const loginResponse =
|
|
294
|
-
typeof errCodeOrSession === "string" ?
|
|
295
|
-
{
|
|
296
|
-
session: undefined,
|
|
297
|
-
response: { success: false, code: errCodeOrSession } as const,
|
|
298
|
-
}
|
|
299
|
-
: errCodeOrSession;
|
|
300
|
-
await this.prostgles.opts.onLog?.({
|
|
301
|
-
type: "auth",
|
|
302
|
-
command: "login",
|
|
303
|
-
success: !!loginResponse.session,
|
|
304
|
-
duration: Date.now() - start,
|
|
305
|
-
sid: loginResponse.session?.sid,
|
|
306
|
-
socketId: undefined,
|
|
307
|
-
});
|
|
308
|
-
if (!loginResponse.session) {
|
|
309
|
-
return res.status(HTTP_FAIL_CODES.BAD_REQUEST).json(loginResponse.response);
|
|
310
|
-
}
|
|
311
|
-
this.setCookieAndGoToReturnURLIFSet(loginResponse.session, { req, res });
|
|
312
|
-
};
|
|
204
|
+
login = login.bind(this);
|
|
313
205
|
|
|
314
206
|
/**
|
|
315
207
|
* Will return first sid value found in:
|
|
316
|
-
* Bearer header
|
|
317
|
-
* http cookie
|
|
318
|
-
* query params
|
|
208
|
+
* - Bearer header
|
|
209
|
+
* - http cookie
|
|
210
|
+
* - query params
|
|
319
211
|
* Based on sid names in auth
|
|
320
212
|
*/
|
|
321
213
|
getSID(maybeClientReq: AuthClientRequest | undefined): string | undefined {
|
|
@@ -385,7 +277,10 @@ export class AuthHandler {
|
|
|
385
277
|
session: BasicSession | undefined
|
|
386
278
|
): boolean => {
|
|
387
279
|
const hasExpired = Boolean(session && session.expires <= Date.now());
|
|
388
|
-
if (
|
|
280
|
+
if (
|
|
281
|
+
this.opts.loginSignupConfig?.publicRoutes &&
|
|
282
|
+
!this.opts.loginSignupConfig.disableSocketAuthGuard
|
|
283
|
+
) {
|
|
389
284
|
const error = "Session has expired";
|
|
390
285
|
if (hasExpired) {
|
|
391
286
|
if (session?.onExpiration === "redirect")
|
|
@@ -399,68 +294,5 @@ export class AuthHandler {
|
|
|
399
294
|
return Boolean(session && !hasExpired);
|
|
400
295
|
};
|
|
401
296
|
|
|
402
|
-
getClientAuth =
|
|
403
|
-
clientReq: AuthClientRequest
|
|
404
|
-
): Promise<{ auth: AuthSocketSchema; userData: AuthResultWithSID }> => {
|
|
405
|
-
let pathGuard = false;
|
|
406
|
-
if (this.opts.expressConfig?.publicRoutes && !this.opts.expressConfig.disableSocketAuthGuard) {
|
|
407
|
-
pathGuard = true;
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Due to SPA nature of some clients, we need to check if the connected client ends up on a protected route
|
|
411
|
-
*/
|
|
412
|
-
if (clientReq.socket) {
|
|
413
|
-
const { socket } = clientReq;
|
|
414
|
-
socket.removeAllListeners(CHANNELS.AUTHGUARD);
|
|
415
|
-
socket.on(
|
|
416
|
-
CHANNELS.AUTHGUARD,
|
|
417
|
-
async (
|
|
418
|
-
params: AuthGuardLocation,
|
|
419
|
-
cb = (_err: any, _res?: AuthGuardLocationResponse) => {
|
|
420
|
-
/** EMPTY */
|
|
421
|
-
}
|
|
422
|
-
) => {
|
|
423
|
-
try {
|
|
424
|
-
const { pathname, origin } =
|
|
425
|
-
typeof params === "string" ? (JSON.parse(params) as AuthGuardLocation) : params;
|
|
426
|
-
if (pathname && typeof pathname !== "string") {
|
|
427
|
-
console.warn("Invalid pathname provided for AuthGuardLocation: ", pathname);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/** These origins */
|
|
431
|
-
const IGNORED_API_ORIGINS = ["file://"];
|
|
432
|
-
if (
|
|
433
|
-
!IGNORED_API_ORIGINS.includes(origin) &&
|
|
434
|
-
pathname &&
|
|
435
|
-
typeof pathname === "string" &&
|
|
436
|
-
this.isUserRoute(pathname) &&
|
|
437
|
-
!(await this.getUserFromRequest({ socket }))
|
|
438
|
-
) {
|
|
439
|
-
cb(null, { shouldReload: true });
|
|
440
|
-
} else {
|
|
441
|
-
cb(null, { shouldReload: false });
|
|
442
|
-
}
|
|
443
|
-
} catch (err) {
|
|
444
|
-
console.error("AUTHGUARD err: ", err);
|
|
445
|
-
cb(err);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const userData = await this.getSidAndUserFromRequest(clientReq);
|
|
453
|
-
const { email } = this.opts.expressConfig?.registrations ?? {};
|
|
454
|
-
const auth: AuthSocketSchema = {
|
|
455
|
-
providers: getProviders.bind(this)(),
|
|
456
|
-
register: email && {
|
|
457
|
-
type: email.signupType,
|
|
458
|
-
url: AUTH_ROUTES_AND_PARAMS.emailRegistration,
|
|
459
|
-
},
|
|
460
|
-
user: userData.clientUser,
|
|
461
|
-
loginType: email?.signupType ?? "withPassword",
|
|
462
|
-
pathGuard,
|
|
463
|
-
};
|
|
464
|
-
return { auth, userData };
|
|
465
|
-
};
|
|
297
|
+
getClientAuth = getClientAuth.bind(this);
|
|
466
298
|
}
|
package/lib/Auth/AuthTypes.ts
CHANGED
|
@@ -13,12 +13,12 @@ import type {
|
|
|
13
13
|
import type { MicrosoftStrategyOptions } from "passport-microsoft";
|
|
14
14
|
import {
|
|
15
15
|
AnyObject,
|
|
16
|
-
AuthFailure,
|
|
17
16
|
AuthRequest,
|
|
18
17
|
AuthResponse,
|
|
19
18
|
FieldFilter,
|
|
20
19
|
IdentityProvider,
|
|
21
20
|
UserLike,
|
|
21
|
+
AuthSocketSchema,
|
|
22
22
|
} from "prostgles-types";
|
|
23
23
|
import { DBOFullyTyped } from "../DBSchemaBuilder";
|
|
24
24
|
import { PRGLIOSocket } from "../DboBuilder/DboBuilderTypes";
|
|
@@ -96,58 +96,43 @@ export type Email = {
|
|
|
96
96
|
attachments?: { filename: string; content: string }[] | Mail.Attachment[];
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
type EmailWithoutTo = Omit<Email, "to">;
|
|
100
|
-
|
|
101
|
-
type MagicLinkAuthResponse =
|
|
102
|
-
| AuthResponse.MagicLinkAuthFailure["code"]
|
|
103
|
-
| { response: AuthResponse.MagicLinkAuthSuccess; email: EmailWithoutTo };
|
|
104
|
-
|
|
105
99
|
type PasswordRegisterResponse =
|
|
106
|
-
| AuthResponse.PasswordRegisterFailure
|
|
107
|
-
|
|
|
100
|
+
| AuthResponse.PasswordRegisterFailure
|
|
101
|
+
| AuthResponse.PasswordRegisterSuccess;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Users have to provide an email and a password.
|
|
105
|
+
* Account should be activated after email confirmation
|
|
106
|
+
*/
|
|
107
|
+
export type SignupWithEmailAndPassword = {
|
|
108
|
+
/**
|
|
109
|
+
* Defaults to 8
|
|
110
|
+
*/
|
|
111
|
+
minPasswordLength?: number;
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
* Users have to provide an email and a password.
|
|
123
|
-
* Account should be activated after email confirmation
|
|
124
|
-
*/
|
|
125
|
-
signupType: "withPassword";
|
|
126
|
-
/**
|
|
127
|
-
* Defaults to 8
|
|
128
|
-
*/
|
|
129
|
-
minPasswordLength?: number;
|
|
130
|
-
/**
|
|
131
|
-
* Called when the user has registered
|
|
132
|
-
*/
|
|
133
|
-
onRegister: (data: {
|
|
134
|
-
email: string;
|
|
135
|
-
password: string;
|
|
136
|
-
confirmationUrlPath: string;
|
|
137
|
-
clientInfo: LoginClientInfo;
|
|
138
|
-
req: ExpressReq;
|
|
139
|
-
}) => Awaitable<PasswordRegisterResponse>;
|
|
140
|
-
smtp: SMTPConfig;
|
|
113
|
+
/**
|
|
114
|
+
* Called when the user has registered
|
|
115
|
+
*/
|
|
116
|
+
onRegister: (data: {
|
|
117
|
+
email: string;
|
|
118
|
+
/**
|
|
119
|
+
* Password after validation
|
|
120
|
+
*/
|
|
121
|
+
password: string;
|
|
122
|
+
clientInfo: LoginClientInfo;
|
|
123
|
+
confirmationUrlPath: string;
|
|
124
|
+
req: ExpressReq;
|
|
125
|
+
}) => Awaitable<PasswordRegisterResponse>;
|
|
141
126
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Called after the user has clicked the URL to confirm their email address
|
|
129
|
+
*/
|
|
130
|
+
onEmailConfirmation: (data: {
|
|
131
|
+
confirmationCode: string;
|
|
132
|
+
clientInfo: LoginClientInfo;
|
|
133
|
+
req: ExpressReq;
|
|
134
|
+
}) => Awaitable<AuthResponse.AuthFailure | (AuthResponse.AuthSuccess & { redirect_to?: string })>;
|
|
135
|
+
};
|
|
151
136
|
|
|
152
137
|
export type AuthProviderUserData =
|
|
153
138
|
| {
|
|
@@ -185,10 +170,8 @@ export type RegistrationData =
|
|
|
185
170
|
}
|
|
186
171
|
| AuthProviderUserData;
|
|
187
172
|
|
|
188
|
-
export type
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
OAuthProviders?: ThirdPartyProviders;
|
|
173
|
+
export type LoginWithOAuthConfig<S> = {
|
|
174
|
+
OAuthProviders: ThirdPartyProviders;
|
|
192
175
|
|
|
193
176
|
/**
|
|
194
177
|
* Required for social login callback
|
|
@@ -205,7 +188,9 @@ export type AuthRegistrationConfig<S> = {
|
|
|
205
188
|
req: ExpressReq;
|
|
206
189
|
res: ExpressRes;
|
|
207
190
|
clientInfo: LoginClientInfo;
|
|
208
|
-
}) => Promise<
|
|
191
|
+
}) => Promise<
|
|
192
|
+
AuthResponse.OAuthRegisterSuccess | AuthResponse.OAuthRegisterFailure | AuthResponse.AuthFailure
|
|
193
|
+
>;
|
|
209
194
|
|
|
210
195
|
/**
|
|
211
196
|
* Used to identify abuse
|
|
@@ -256,7 +241,7 @@ export type AuthResultWithSID<SU = SessionUser> =
|
|
|
256
241
|
});
|
|
257
242
|
|
|
258
243
|
export type AuthResult<SU = SessionUser> = SU | undefined;
|
|
259
|
-
export type AuthResultOrError<SU = SessionUser> = AuthFailure["code"] | AuthResult<SU>;
|
|
244
|
+
export type AuthResultOrError<SU = SessionUser> = AuthResponse.AuthFailure["code"] | AuthResult<SU>;
|
|
260
245
|
|
|
261
246
|
export type AuthRequestParams<S, SUser extends SessionUser> = {
|
|
262
247
|
db: DB;
|
|
@@ -264,7 +249,7 @@ export type AuthRequestParams<S, SUser extends SessionUser> = {
|
|
|
264
249
|
getUser: () => Promise<AuthResultWithSID<SUser>>;
|
|
265
250
|
};
|
|
266
251
|
|
|
267
|
-
export type
|
|
252
|
+
export type AuthConfig<S = void, SUser extends SessionUser = SessionUser> = {
|
|
268
253
|
/**
|
|
269
254
|
* Name of the cookie or socket hadnshake query param that represents the session id.
|
|
270
255
|
* Defaults to "session_id"
|
|
@@ -291,15 +276,7 @@ export type Auth<S = void, SUser extends SessionUser = SessionUser> = {
|
|
|
291
276
|
* /logout
|
|
292
277
|
* /magic-link/:id
|
|
293
278
|
*/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
login?: (
|
|
297
|
-
params: LoginParams,
|
|
298
|
-
dbo: DBOFullyTyped<S>,
|
|
299
|
-
db: DB,
|
|
300
|
-
client: LoginClientInfo
|
|
301
|
-
) => Awaitable<LoginResponse>;
|
|
302
|
-
logout?: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<any>;
|
|
279
|
+
loginSignupConfig?: LoginSignupConfig<S, SUser>;
|
|
303
280
|
|
|
304
281
|
/**
|
|
305
282
|
* 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
|
|
@@ -321,20 +298,23 @@ export type Auth<S = void, SUser extends SessionUser = SessionUser> = {
|
|
|
321
298
|
export type LoginResponse =
|
|
322
299
|
| {
|
|
323
300
|
session: BasicSession;
|
|
324
|
-
response?: AuthResponse.PasswordLoginSuccess | AuthResponse.
|
|
301
|
+
response?: AuthResponse.PasswordLoginSuccess | AuthResponse.OAuthRegisterSuccess;
|
|
325
302
|
}
|
|
303
|
+
| {
|
|
304
|
+
session?: undefined;
|
|
305
|
+
response: AuthResponse.MagicLinkAuthSuccess;
|
|
306
|
+
}
|
|
307
|
+
| AuthResponse.OAuthRegisterFailure["code"]
|
|
326
308
|
| AuthResponse.PasswordLoginFailure["code"]
|
|
327
309
|
| AuthResponse.MagicLinkAuthFailure["code"];
|
|
328
310
|
|
|
329
311
|
export type LoginParams =
|
|
330
312
|
| ({
|
|
331
313
|
type: "username";
|
|
332
|
-
signupType: undefined | EmailProvider["signupType"];
|
|
333
|
-
magicLinkUrlPath: undefined | string;
|
|
334
314
|
} & AuthRequest.LoginData)
|
|
335
|
-
| ({ type: "
|
|
315
|
+
| ({ type: "OAuth" } & AuthProviderUserData);
|
|
336
316
|
|
|
337
|
-
export type
|
|
317
|
+
export type LoginSignupConfig<S, SUser extends SessionUser> = {
|
|
338
318
|
/**
|
|
339
319
|
* Express app instance. If provided Prostgles will attempt to set sidKeyName to user cookie
|
|
340
320
|
*/
|
|
@@ -386,7 +366,27 @@ export type ExpressConfig<S, SUser extends SessionUser> = {
|
|
|
386
366
|
| { session?: undefined; response: AuthResponse.MagicLinkAuthFailure }
|
|
387
367
|
>;
|
|
388
368
|
|
|
389
|
-
|
|
369
|
+
signupWithEmailAndPassword?: SignupWithEmailAndPassword;
|
|
370
|
+
|
|
371
|
+
loginWithOAuth?: LoginWithOAuthConfig<S>;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Used to hint to the client which login mode is available
|
|
375
|
+
* Defaults to username and password
|
|
376
|
+
*/
|
|
377
|
+
localLoginMode?: AuthSocketSchema["loginType"];
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* If provided then the user will be able to login with a username and password
|
|
381
|
+
*/
|
|
382
|
+
login: (
|
|
383
|
+
params: LoginParams,
|
|
384
|
+
dbo: DBOFullyTyped<S>,
|
|
385
|
+
db: DB,
|
|
386
|
+
client: LoginClientInfo
|
|
387
|
+
) => Awaitable<LoginResponse>;
|
|
388
|
+
|
|
389
|
+
logout: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<void>;
|
|
390
390
|
};
|
|
391
391
|
|
|
392
392
|
type ExpressMiddleware<S, SUser extends SessionUser> = (
|
|
@@ -3,14 +3,19 @@ import { AuthClientRequest } from "../AuthTypes";
|
|
|
3
3
|
import { AUTH_ROUTES_AND_PARAMS, AuthHandler, HTTP_FAIL_CODES } from "../AuthHandler";
|
|
4
4
|
import { getReturnUrl } from "../utils/getReturnUrl";
|
|
5
5
|
import { DBOFullyTyped } from "../../DBSchemaBuilder";
|
|
6
|
+
import { throttledReject } from "../utils/throttledReject";
|
|
6
7
|
|
|
7
8
|
export function setCatchAllRequestHandler(this: AuthHandler, app: e.Express) {
|
|
8
9
|
const onLogout = async (req: Request, res: Response) => {
|
|
9
10
|
const sid = this.validateSid(req.cookies?.[this.sidKeyName]);
|
|
10
11
|
if (sid) {
|
|
11
12
|
try {
|
|
12
|
-
await
|
|
13
|
-
return this.opts.logout
|
|
13
|
+
await throttledReject(async () => {
|
|
14
|
+
return this.opts.loginSignupConfig?.logout(
|
|
15
|
+
req.cookies?.[this.sidKeyName],
|
|
16
|
+
this.dbo as DBOFullyTyped,
|
|
17
|
+
this.db
|
|
18
|
+
);
|
|
14
19
|
});
|
|
15
20
|
} catch (err) {
|
|
16
21
|
console.error(err);
|
|
@@ -20,7 +25,7 @@ export function setCatchAllRequestHandler(this: AuthHandler, app: e.Express) {
|
|
|
20
25
|
};
|
|
21
26
|
|
|
22
27
|
const requestHandler: RequestHandler = async (req, res, next) => {
|
|
23
|
-
const { onGetRequestOK } = this.opts.
|
|
28
|
+
const { onGetRequestOK } = this.opts.loginSignupConfig ?? {};
|
|
24
29
|
const clientReq: AuthClientRequest = { httpReq: req, res };
|
|
25
30
|
const getUser = async () => {
|
|
26
31
|
const userOrCode = await this.getUserAndHandleError(clientReq);
|
|
@@ -103,5 +108,4 @@ export function setCatchAllRequestHandler(this: AuthHandler, app: e.Express) {
|
|
|
103
108
|
};
|
|
104
109
|
|
|
105
110
|
app.get(AUTH_ROUTES_AND_PARAMS.catchAll, requestHandler);
|
|
106
|
-
return requestHandler;
|
|
107
111
|
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import type { Request, Response } from "express";
|
|
2
|
-
import
|
|
2
|
+
import e from "express";
|
|
3
|
+
import { AuthResponse } from "prostgles-types";
|
|
3
4
|
import { AUTH_ROUTES_AND_PARAMS, AuthHandler, HTTP_FAIL_CODES } from "../AuthHandler";
|
|
4
|
-
import {
|
|
5
|
+
import { SignupWithEmailAndPassword } from "../AuthTypes";
|
|
5
6
|
import { getClientRequestIPsInfo } from "../utils/getClientRequestIPsInfo";
|
|
6
|
-
import
|
|
7
|
+
import { throttledReject } from "../utils/throttledReject";
|
|
7
8
|
|
|
8
9
|
export function setConfirmEmailRequestHandler(
|
|
9
10
|
this: AuthHandler,
|
|
10
|
-
emailAuthConfig:
|
|
11
|
-
Required<AuthRegistrationConfig<void>>["email"],
|
|
12
|
-
{ signupType: "withPassword" }
|
|
13
|
-
>,
|
|
11
|
+
emailAuthConfig: SignupWithEmailAndPassword,
|
|
14
12
|
app: e.Express
|
|
15
13
|
) {
|
|
16
14
|
const requestHandler = async (
|
|
17
15
|
req: Request,
|
|
18
|
-
res: Response<AuthFailure | AuthResponse.AuthSuccess>
|
|
16
|
+
res: Response<AuthResponse.AuthFailure | AuthResponse.AuthSuccess>
|
|
19
17
|
) => {
|
|
20
18
|
const { id } = req.params;
|
|
21
19
|
try {
|
|
@@ -23,17 +21,15 @@ export function setConfirmEmailRequestHandler(
|
|
|
23
21
|
return res.send({ success: false, code: "something-went-wrong", message: "Invalid code" });
|
|
24
22
|
}
|
|
25
23
|
const { httpReq, ...clientInfo } = getClientRequestIPsInfo({ httpReq: req, res });
|
|
26
|
-
const response = await
|
|
24
|
+
const response = await throttledReject(async () =>
|
|
27
25
|
emailAuthConfig.onEmailConfirmation({
|
|
28
26
|
confirmationCode: id,
|
|
29
27
|
clientInfo,
|
|
30
28
|
req: httpReq,
|
|
31
29
|
})
|
|
32
30
|
);
|
|
33
|
-
if (
|
|
34
|
-
return res
|
|
35
|
-
.status(HTTP_FAIL_CODES.BAD_REQUEST)
|
|
36
|
-
.json({ success: false, code: "something-went-wrong" });
|
|
31
|
+
if (!response.success) {
|
|
32
|
+
return res.status(HTTP_FAIL_CODES.BAD_REQUEST).json(response);
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
/**
|