diff --git a/lib/Auth/AuthHandler.ts b/lib/Auth/AuthHandler.ts index b85e35c9..b2758592 100644 --- a/lib/Auth/AuthHandler.ts +++ b/lib/Auth/AuthHandler.ts @@ -3,7 +3,7 @@ import { LocalParams, PRGLIOSocket } from "../DboBuilder/DboBuilder"; import { DBOFullyTyped } from "../DBSchemaBuilder"; import { removeExpressRoute } from "../FileManager/FileManager"; import { DB, DBHandlerServer, Prostgles } from "../Prostgles"; -import { Auth, AuthClientRequest, AuthResult, BasicSession, ExpressReq, ExpressRes, LoginClientInfo } from "./AuthTypes" +import { Auth, AuthClientRequest, AuthResult, BasicSession, ExpressReq, ExpressRes, LoginClientInfo, LoginParams } from "./AuthTypes" import { getSafeReturnURL } from "./getSafeReturnURL"; import { setupAuthRoutes } from "./setupAuthRoutes"; import { getProviders } from "./setAuthProviders"; @@ -198,7 +198,7 @@ export class AuthHandler { }) } - loginThrottled = async (params: AnyObject, client: LoginClientInfo): Promise => { + loginThrottled = async (params: LoginParams, client: LoginClientInfo): Promise => { if (!this.opts?.login) throw "Auth login config missing"; const { responseThrottle = 500 } = this.opts; @@ -219,6 +219,26 @@ export class AuthHandler { return result; }, responseThrottle); + }; + + loginThrottledAndSetCookie = async (req: ExpressReq, res: ExpressRes, loginParams: LoginParams) => { + const start = Date.now(); + const { sid, expires } = await this.loginThrottled(loginParams, getLoginClientInfo({ httpReq: req })) || {}; + await this.prostgles.opts.onLog?.({ + type: "auth", + command: "login", + duration: Date.now() - start, + sid, + socketId: undefined, + }); + + if (sid) { + + this.setCookieAndGoToReturnURLIFSet({ sid, expires }, { req, res }); + + } else { + throw ("Internal error: no user or session") + } } @@ -401,50 +421,6 @@ export class AuthHandler { } } - - /** - * ARE THESE NEEDED?! - */ - // const { - // register, - // logout - // } = this.opts; - // const login = this.loginThrottled - // let handlers: { - // name: keyof Omit; - // ch: string; - // func: (...args: any) => any; - // }[] = [ - // { func: (params: any, dbo: any, db: DB, client: LoginClientInfo) => register?.(params, dbo, db), ch: CHANNELS.REGISTER, name: "register" as keyof Omit }, - // { func: (params: any, dbo: any, db: DB, client: LoginClientInfo) => login(params, client), ch: CHANNELS.LOGIN, name: "login" as keyof Omit }, - // { func: (params: any, dbo: any, db: DB, client: LoginClientInfo) => logout?.(this.getSID({ socket }), dbo, db), ch: CHANNELS.LOGOUT, name: "logout" as keyof Omit} - // ].filter(h => h.func); - - - // handlers.map(({ func, ch, name }) => { - // auth[name] = true; - - // socket.removeAllListeners(ch) - // socket.on(ch, async (params: any, cb = (..._callback: any) => { /** Empty */ }) => { - - // try { - // if (!socket) throw "socket missing??!!"; - // const id_address = (socket as any)?.conn?.remoteAddress; - // const user_agent = socket.handshake?.headers?.["user-agent"]; - // const res = await func(params, this.dbo as any, this.db, { user_agent, id_address }); - // if (name === "login" && res && res.sid) { - // /* TODO: Re-send schema to client */ - // } - - // cb(null, true); - - // } catch (err) { - // console.error(name + " err", err); - // cb(err) - // } - // }); - // }); - const userData = await this.getClientInfo(clientReq); const auth: AuthSocketSchema = { providers: getProviders.bind(this)(), diff --git a/lib/Auth/AuthTypes.ts b/lib/Auth/AuthTypes.ts index 57cc4c37..a57477b4 100644 --- a/lib/Auth/AuthTypes.ts +++ b/lib/Auth/AuthTypes.ts @@ -1,5 +1,5 @@ import { Express, NextFunction, Request, Response } from "express"; -import { AnyObject, EmailSignupType, FieldFilter, UserLike } from "prostgles-types"; +import { AnyObject, FieldFilter, UserLike } from "prostgles-types"; import { DB } from "../Prostgles"; import { DBOFullyTyped } from "../DBSchemaBuilder"; import { PRGLIOSocket } from "../DboBuilder/DboBuilderTypes"; @@ -73,14 +73,7 @@ type RegistrationProviders = ThirdPartyProviders & { }; } -type RegistrationData = -| { - provider: "email"; - profile: { - username: string; - password: string; - } -} +export type AuthProviderUserData = | { provider: "google"; profile: GoogleProfile; @@ -106,6 +99,16 @@ type RegistrationData = refreshToken: string; } +export type RegistrationData = +| { + provider: "email"; + profile: { + username: string; + password: string; + } +} +| AuthProviderUserData; + export type AuthRegistrationConfig = RegistrationProviders & { /** * Required for social login callback @@ -218,7 +221,7 @@ export type Auth = { */ getUser: (sid: string | undefined, dbo: DBOFullyTyped, db: DB, client: AuthClientRequest & LoginClientInfo) => Awaitable>; - login?: (params: AnyObject, dbo: DBOFullyTyped, db: DB, client: LoginClientInfo) => Awaitable | BasicSession; + login?: (params: LoginParams, dbo: DBOFullyTyped, db: DB, client: LoginClientInfo) => Awaitable | BasicSession; logout?: (sid: string | undefined, dbo: DBOFullyTyped, db: DB) => Awaitable; /** @@ -228,3 +231,8 @@ export type Auth = { getSession: (sid: string | undefined, dbo: DBOFullyTyped, db: DB) => Awaitable } } + + +export type LoginParams = +| { type: "username"; username: string; password: string; [key: string]: any } +| ({ type: "provider"; } & AuthProviderUserData) \ No newline at end of file diff --git a/lib/Auth/setAuthProviders.ts b/lib/Auth/setAuthProviders.ts index 321f26e6..e53e515f 100644 --- a/lib/Auth/setAuthProviders.ts +++ b/lib/Auth/setAuthProviders.ts @@ -10,6 +10,7 @@ import { AUTH_ROUTES_AND_PARAMS, AuthHandler } from "./AuthHandler"; import type e from "express"; import { RequestHandler } from "express"; import { removeExpressRouteByName } from "../FileManager/FileManager"; +import { getErrorAsObject } from "../DboBuilder/dboBuilderUtils"; export const upsertNamedExpressMiddleware = (app: e.Express, handler: RequestHandler, name: string) => { @@ -76,7 +77,7 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req async (accessToken, refreshToken, profile, done) => { // This callback is where you would normally store or retrieve user info from the database await onRegister({ provider: providerName as "google", accessToken, refreshToken, profile }); - return done(null, profile); + return done(null, profile, { accessToken, refreshToken, profile }); } ) ); @@ -87,9 +88,15 @@ export function setAuthProviders (this: AuthHandler, { registrations, app }: Req app.get(callbackPath, passport.authenticate(providerName, { session: false, failureRedirect: "/login" }), - (req, res) => { - // Successful authentication, redirect to main page - res.redirect("/"); + async (req, res) => { + this.loginThrottledAndSetCookie(req, res, { type: "provider", provider: providerName, ...req.authInfo as any }) + .then(() => { + // Successful authentication, redirect to main page + res.redirect("/"); + }) + .catch((e: any) => { + res.status(500).json(getErrorAsObject(e)); + }); } ); }); diff --git a/lib/Auth/setupAuthRoutes.ts b/lib/Auth/setupAuthRoutes.ts index 469ebe70..44bb7356 100644 --- a/lib/Auth/setupAuthRoutes.ts +++ b/lib/Auth/setupAuthRoutes.ts @@ -1,7 +1,7 @@ import { RequestHandler } from "express"; import { DBOFullyTyped } from "../DBSchemaBuilder"; import { AUTH_ROUTES_AND_PARAMS, AuthHandler, getLoginClientInfo, HTTPCODES } from "./AuthHandler"; -import { AuthClientRequest, ExpressReq, ExpressRes } from "./AuthTypes"; +import { AuthClientRequest, ExpressReq, ExpressRes, LoginParams } from "./AuthTypes"; import { setAuthProviders, upsertNamedExpressMiddleware } from "./setAuthProviders"; export async function setupAuthRoutes(this: AuthHandler) { @@ -74,22 +74,28 @@ export async function setupAuthRoutes(this: AuthHandler) { app.post(AUTH_ROUTES_AND_PARAMS.login, async (req: ExpressReq, res: ExpressRes) => { try { - const start = Date.now(); - const { sid, expires } = await this.loginThrottled(req.body || {}, getLoginClientInfo({ httpReq: req })) || {}; - await this.prostgles.opts.onLog?.({ - type: "auth", - command: "login", - duration: Date.now() - start, - sid, - socketId: undefined, - }) - if (sid) { - - this.setCookieAndGoToReturnURLIFSet({ sid, expires }, { req, res }); - - } else { - throw ("Internal error: no user or session") - } + // const start = Date.now(); + const loginParams: LoginParams = { + type: "username", + ...req.body, + }; + + await this.loginThrottledAndSetCookie(req, res, loginParams); + // const { sid, expires } = await this.loginThrottled(loginParams, getLoginClientInfo({ httpReq: req })) || {}; + // await this.prostgles.opts.onLog?.({ + // type: "auth", + // command: "login", + // duration: Date.now() - start, + // sid, + // socketId: undefined, + // }) + // if (sid) { + + // this.setCookieAndGoToReturnURLIFSet({ sid, expires }, { req, res }); + + // } else { + // throw ("Internal error: no user or session") + // } } catch (err) { console.log(err) res.status(HTTPCODES.AUTH_ERROR).json({ err }); diff --git a/package-lock.json b/package-lock.json index 84667eef..c251f64f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prostgles-server", - "version": "4.2.144", + "version": "4.2.145", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prostgles-server", - "version": "4.2.144", + "version": "4.2.145", "license": "MIT", "dependencies": { "body-parser": "^1.20.3", diff --git a/package.json b/package.json index 989fc1a9..287ad5bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prostgles-server", - "version": "4.2.144", + "version": "4.2.145", "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 4031a0ea..0260b1ee 100644 --- a/tests/server/package-lock.json +++ b/tests/server/package-lock.json @@ -21,7 +21,7 @@ }, "../..": { "name": "prostgles-server", - "version": "4.2.144", + "version": "4.2.145", "license": "MIT", "dependencies": { "body-parser": "^1.20.3",