Skip to content

Commit

Permalink
improve login validation
Browse files Browse the repository at this point in the history
  • Loading branch information
prostgles committed Dec 25, 2024
1 parent 8fd0bed commit 968434c
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 31 deletions.
12 changes: 9 additions & 3 deletions lib/Auth/AuthHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AuthFailure,
AuthGuardLocation,
AuthGuardLocationResponse,
AuthResponse,
AuthSocketSchema,
CHANNELS,
} from "prostgles-types";
Expand All @@ -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 = {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -279,7 +282,7 @@ export class AuthHandler {

loginThrottledAndSetCookie = async (
req: ExpressReq,
res: ExpressRes,
res: LoginResponseHandler,
loginParams: LoginParams
) => {
const start = Date.now();
Expand All @@ -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",
Expand Down
12 changes: 8 additions & 4 deletions lib/Auth/AuthTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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<S, SUser extends SessionUser> = {
Expand Down
2 changes: 1 addition & 1 deletion lib/Auth/authProviders/setOAuthProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
Expand Down
67 changes: 61 additions & 6 deletions lib/Auth/endpoints/setLoginRequestHandler.ts
Original file line number Diff line number Diff line change
@@ -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;
};
13 changes: 5 additions & 8 deletions lib/Auth/endpoints/setMagicLinkRequestHandler.ts
Original file line number Diff line number Diff line change
@@ -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<ExpressConfig<void, SessionUser>>["onMagicLink"],
app: e.Express
) {
const result = async (
req: ExpressReq,
res: Response<AuthResponse.MagicLinkAuthFailure | AuthResponse.MagicLinkAuthSuccess>
) => {
const result = async (req: ExpressReq, res: LoginResponseHandler) => {
const { id } = req.params;

if (typeof id !== "string" || !id) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Auth/utils/getSidAndUserFromRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 2 additions & 4 deletions lib/DboBuilder/DboBuilderTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,9 @@ export type PRGLIOSocket = {
};

/** Used for session caching */
__prglCache?: {
__prglCache?: SessionUser & {
session: BasicSession;
// user: UserLike;
// clientUser: UserLike;
} & SessionUser;
};

_user?: AnyObject;

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion tests/server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 968434c

Please sign in to comment.