diff --git a/lib/Auth/AuthHandler.ts b/lib/Auth/AuthHandler.ts index f96164f1..e9aa6209 100644 --- a/lib/Auth/AuthHandler.ts +++ b/lib/Auth/AuthHandler.ts @@ -3,6 +3,7 @@ import { AuthFailure, AuthGuardLocation, AuthGuardLocationResponse, + AuthResponse, AuthSocketSchema, CHANNELS, } from "prostgles-types"; @@ -27,6 +28,8 @@ import { setupAuthRoutes } from "./setupAuthRoutes"; import { getClientRequestIPsInfo } from "./utils/getClientRequestIPsInfo"; import { getReturnUrl } from "./utils/getReturnUrl"; import { getSidAndUserFromRequest } from "./utils/getSidAndUserFromRequest"; +import type { Response } from "express"; +import { LoginResponseHandler } from "./endpoints/setLoginRequestHandler"; export { getClientRequestIPsInfo }; export const HTTP_FAIL_CODES = { @@ -109,7 +112,7 @@ export class AuthHandler { setCookieAndGoToReturnURLIFSet = ( cookie: { sid: string; expires: number }, - r: { req: ExpressReq; res: ExpressRes } + r: { req: ExpressReq; res: LoginResponseHandler } ) => { const { sid, expires } = cookie; const { res, req } = r; @@ -279,7 +282,7 @@ export class AuthHandler { loginThrottledAndSetCookie = async ( req: ExpressReq, - res: ExpressRes, + res: LoginResponseHandler, loginParams: LoginParams ) => { const start = Date.now(); @@ -289,7 +292,10 @@ export class AuthHandler { ); const loginResponse = typeof errCodeOrSession === "string" ? - { session: undefined, response: { success: false, code: errCodeOrSession } } + { + session: undefined, + response: { success: false, code: errCodeOrSession } as const, + } : errCodeOrSession; await this.prostgles.opts.onLog?.({ type: "auth", diff --git a/lib/Auth/AuthTypes.ts b/lib/Auth/AuthTypes.ts index 634524b8..08a2a69d 100644 --- a/lib/Auth/AuthTypes.ts +++ b/lib/Auth/AuthTypes.ts @@ -13,12 +13,12 @@ import type { import type { MicrosoftStrategyOptions } from "passport-microsoft"; import { AnyObject, + AuthFailure, + AuthRequest, + AuthResponse, FieldFilter, IdentityProvider, - AuthResponse, UserLike, - AuthRequest, - AuthFailure, } from "prostgles-types"; import { DBOFullyTyped } from "../DBSchemaBuilder"; import { PRGLIOSocket } from "../DboBuilder/DboBuilderTypes"; @@ -327,7 +327,11 @@ export type LoginResponse = | AuthResponse.MagicLinkAuthFailure["code"]; export type LoginParams = - | ({ type: "username" } & AuthRequest.LoginData) + | ({ + type: "username"; + signupType: undefined | EmailProvider["signupType"]; + magicLinkUrlPath: undefined | string; + } & AuthRequest.LoginData) | ({ type: "provider" } & AuthProviderUserData); export type ExpressConfig = { diff --git a/lib/Auth/authProviders/setOAuthProviders.ts b/lib/Auth/authProviders/setOAuthProviders.ts index 9d256be8..c97cb434 100644 --- a/lib/Auth/authProviders/setOAuthProviders.ts +++ b/lib/Auth/authProviders/setOAuthProviders.ts @@ -80,9 +80,9 @@ export function setOAuthProviders( }); } else { this.loginThrottledAndSetCookie(req, res, { + ...authInfo, type: "provider", provider: providerName, - ...authInfo, }).catch((e: any) => { res.status(500).json(getErrorAsObject(e)); }); diff --git a/lib/Auth/endpoints/setLoginRequestHandler.ts b/lib/Auth/endpoints/setLoginRequestHandler.ts index 2ce33639..1ff43873 100644 --- a/lib/Auth/endpoints/setLoginRequestHandler.ts +++ b/lib/Auth/endpoints/setLoginRequestHandler.ts @@ -1,18 +1,73 @@ -import e from "express"; +import e, { Response } from "express"; import { AUTH_ROUTES_AND_PARAMS, AuthHandler, HTTP_FAIL_CODES } from "../AuthHandler"; -import { LoginParams } from "../AuthTypes"; +import { BasicSession, LoginParams } from "../AuthTypes"; +import { AuthFailure, AuthRequest, AuthResponse, isDefined, isObject } from "prostgles-types"; + +export type LoginResponseHandler = Response< + | { + session: BasicSession; + response?: AuthResponse.PasswordLoginSuccess | AuthResponse.MagicLinkAuthSuccess; + } + | AuthFailure + | AuthResponse.PasswordLoginFailure + | AuthResponse.MagicLinkAuthFailure +>; export function setLoginRequestHandler(this: AuthHandler, app: e.Express) { - app.post(AUTH_ROUTES_AND_PARAMS.login, async (req, res) => { + const { registrations } = this.opts.expressConfig ?? {}; + app.post(AUTH_ROUTES_AND_PARAMS.login, async (req, res: LoginResponseHandler) => { + const loginData = parseLoginData(req.body); + if ("error" in loginData) { + return res + .status(HTTP_FAIL_CODES.BAD_REQUEST) + .json({ success: false, code: "something-went-wrong", message: loginData.error }); + } try { const loginParams: LoginParams = { + ...loginData, + magicLinkUrlPath: + registrations?.websiteUrl && + `${registrations.websiteUrl}/${AUTH_ROUTES_AND_PARAMS.magicLinksRoute}`, + signupType: registrations?.email?.signupType, type: "username", - ...req.body, }; await this.loginThrottledAndSetCookie(req, res, loginParams); - } catch (error) { - res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({ error }); + } catch (_error) { + res.status(HTTP_FAIL_CODES.BAD_REQUEST).json({ success: false, code: "server-error" }); } }); } + +const parseLoginData = (bodyData: any): AuthRequest.LoginData | { error: string } => { + const loginData: AuthRequest.LoginData = { + username: "", + remember_me: !!bodyData?.remember_me, + }; + + (["username", "password", "totp_token", "totp_recovery_code"] as const).forEach((prop) => { + const valOrError = getStringOrUndefined(bodyData[prop], prop); + if (isObject(valOrError)) { + return valOrError; + } + if (prop === "username") { + if (!isDefined(valOrError)) { + return { error: "username error: Expected non-empty string" }; + } + loginData[prop] = valOrError; + } else { + loginData[prop] = valOrError; + } + }); + + return loginData; +}; + +const getStringOrUndefined = ( + val: any, + propName: string +): string | undefined | { error: string } => { + const isStringOrUndefined = typeof val === "string" || val === undefined; + if (!isStringOrUndefined) return { error: `${propName} error: Expected string or undefined` }; + return val; +}; diff --git a/lib/Auth/endpoints/setMagicLinkRequestHandler.ts b/lib/Auth/endpoints/setMagicLinkRequestHandler.ts index 87286a48..a672017a 100644 --- a/lib/Auth/endpoints/setMagicLinkRequestHandler.ts +++ b/lib/Auth/endpoints/setMagicLinkRequestHandler.ts @@ -1,23 +1,20 @@ -import e, { Response } from "express"; -import { ExpressConfig, ExpressReq, SessionUser } from "../AuthTypes"; -import { AuthResponse } from "prostgles-types"; +import e from "express"; +import { DBOFullyTyped } from "../../DBSchemaBuilder"; import { AUTH_ROUTES_AND_PARAMS, AuthHandler, getClientRequestIPsInfo, HTTP_FAIL_CODES, } from "../AuthHandler"; -import { DBOFullyTyped } from "../../DBSchemaBuilder"; +import { ExpressConfig, ExpressReq, SessionUser } from "../AuthTypes"; +import { LoginResponseHandler } from "./setLoginRequestHandler"; export function setMagicLinkRequestHandler( this: AuthHandler, onMagicLink: Required>["onMagicLink"], app: e.Express ) { - const result = async ( - req: ExpressReq, - res: Response - ) => { + const result = async (req: ExpressReq, res: LoginResponseHandler) => { const { id } = req.params; if (typeof id !== "string" || !id) { diff --git a/lib/Auth/utils/getSidAndUserFromRequest.ts b/lib/Auth/utils/getSidAndUserFromRequest.ts index d624b466..e4cafcf8 100644 --- a/lib/Auth/utils/getSidAndUserFromRequest.ts +++ b/lib/Auth/utils/getSidAndUserFromRequest.ts @@ -43,7 +43,7 @@ export async function getSidAndUserFromRequest( if (typeof clientInfoOrErr === "string") throw clientInfoOrErr; const clientInfo = clientInfoOrErr; if (getSession && clientReq.socket) { - const session = await getSession(sid, this.dbo as any, this.db); + const session = await getSession(sid, this.dbo as DBOFullyTyped, this.db); if (session && session.expires && clientInfo?.user) { clientReq.socket.__prglCache = { ...clientInfo, diff --git a/lib/DboBuilder/DboBuilderTypes.ts b/lib/DboBuilder/DboBuilderTypes.ts index c59b7211..dd17ff35 100644 --- a/lib/DboBuilder/DboBuilderTypes.ts +++ b/lib/DboBuilder/DboBuilderTypes.ts @@ -168,11 +168,9 @@ export type PRGLIOSocket = { }; /** Used for session caching */ - __prglCache?: { + __prglCache?: SessionUser & { session: BasicSession; - // user: UserLike; - // clientUser: UserLike; - } & SessionUser; + }; _user?: AnyObject; diff --git a/package-lock.json b/package-lock.json index 482c21eb..1ea4a316 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prostgles-server", - "version": "4.2.200", + "version": "4.2.201", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prostgles-server", - "version": "4.2.200", + "version": "4.2.201", "license": "MIT", "dependencies": { "@aws-sdk/client-ses": "^3.699.0", diff --git a/package.json b/package.json index e5abd825..8364373a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prostgles-server", - "version": "4.2.200", + "version": "4.2.201", "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/tests/server/package-lock.json b/tests/server/package-lock.json index 74e4f4a9..b3d24dd7 100644 --- a/tests/server/package-lock.json +++ b/tests/server/package-lock.json @@ -21,7 +21,7 @@ }, "../..": { "name": "prostgles-server", - "version": "4.2.200", + "version": "4.2.201", "license": "MIT", "dependencies": { "@aws-sdk/client-ses": "^3.699.0",