mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-25 11:27:31 -07:00
[backend/web-api] Move auth code into handler
This commit is contained in:
parent
ba76c5e67b
commit
a168e4ec03
2 changed files with 48 additions and 34 deletions
|
@ -1,16 +1,10 @@
|
||||||
import { Controller, Get, Post, Body, CurrentUser, Flow } from "@iceshrimp/koa-openapi";
|
import { Controller, Get, Post, Body, CurrentUser, Flow } from "@iceshrimp/koa-openapi";
|
||||||
import type { ILocalUser } from "@/models/entities/user.js";
|
import type { ILocalUser } from "@/models/entities/user.js";
|
||||||
import { UserHandler } from "@/server/api/web/handlers/user.js";
|
|
||||||
import type { AuthRequest, AuthResponse } from "@/server/api/web/entities/auth.js";
|
import type { AuthRequest, AuthResponse } from "@/server/api/web/entities/auth.js";
|
||||||
import type { Session } from "@/models/entities/session.js";
|
import type { Session } from "@/models/entities/session.js";
|
||||||
import { RatelimitRouteMiddleware } from "@/server/api/web/middleware/rate-limit.js";
|
import { RatelimitRouteMiddleware } from "@/server/api/web/middleware/rate-limit.js";
|
||||||
import { CurrentSession } from "@/server/api/web/misc/decorators.js";
|
import { CurrentSession } from "@/server/api/web/misc/decorators.js";
|
||||||
import { Sessions, UserProfiles, Users } from "@/models/index.js";
|
import { AuthHandler } from "@/server/api/web/handlers/auth.js";
|
||||||
import { unauthorized, badRequest } from "@hapi/boom";
|
|
||||||
import { comparePassword } from "@/misc/password.js";
|
|
||||||
import { IsNull } from "typeorm";
|
|
||||||
import { genId } from "@/misc/gen-id.js";
|
|
||||||
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
|
||||||
|
|
||||||
@Controller('/auth')
|
@Controller('/auth')
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
|
@ -19,37 +13,12 @@ export class AuthController {
|
||||||
@CurrentUser() me: ILocalUser | null,
|
@CurrentUser() me: ILocalUser | null,
|
||||||
@CurrentSession() session: Session | null,
|
@CurrentSession() session: Session | null,
|
||||||
): Promise<AuthResponse> {
|
): Promise<AuthResponse> {
|
||||||
const user = me ? await UserHandler.getUser(me, me.id) : null;
|
return AuthHandler.getAuthStatus(me, session);
|
||||||
return {
|
|
||||||
status: !user ? 'guest' : session?.active ? 'authenticated' : '2fa',
|
|
||||||
token: session?.token ?? null,
|
|
||||||
user: user,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/')
|
@Post('/')
|
||||||
@Flow([RatelimitRouteMiddleware("auth", 10, 60000, true)])
|
@Flow([RatelimitRouteMiddleware("auth", 10, 60000, true)])
|
||||||
async login(@Body({ required: true }) request: AuthRequest): Promise<AuthResponse> {
|
async login(@Body({ required: true }) request: AuthRequest): Promise<AuthResponse> {
|
||||||
if (request.username == null || request.password == null) throw badRequest("Missing username or password");
|
return AuthHandler.login(request);
|
||||||
|
|
||||||
const user = await Users.findOneBy({ usernameLower: request.username.toLowerCase(), host: IsNull() });
|
|
||||||
if (!user) throw unauthorized("Invalid username or password");
|
|
||||||
|
|
||||||
const profile = await UserProfiles.findOneBy( { userId: user.id });
|
|
||||||
if (!profile || profile.password == null) throw unauthorized("Invalid username or password");
|
|
||||||
|
|
||||||
if (!await comparePassword(request.password, profile.password)) throw unauthorized("Invalid username or password");
|
|
||||||
|
|
||||||
const result = await Sessions.insert({
|
|
||||||
id: genId(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
active: !profile.twoFactorEnabled,
|
|
||||||
userId: user.id,
|
|
||||||
token: secureRndstr(32),
|
|
||||||
});
|
|
||||||
|
|
||||||
const session = await Sessions.findOneByOrFail(result.identifiers[0]);
|
|
||||||
|
|
||||||
return this.getAuthStatus(user as ILocalUser, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
packages/backend/src/server/api/web/handlers/auth.ts
Normal file
45
packages/backend/src/server/api/web/handlers/auth.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { ILocalUser } from "@/models/entities/user.js";
|
||||||
|
import { Session } from "@/models/entities/session.js";
|
||||||
|
import { AuthRequest, AuthResponse } from "@/server/api/web/entities/auth.js";
|
||||||
|
import { UserHandler } from "@/server/api/web/handlers/user.js";
|
||||||
|
import { Sessions, UserProfiles, Users } from "@/models/index.js";
|
||||||
|
import { comparePassword } from "@/misc/password.js";
|
||||||
|
import { genId } from "@/misc/gen-id.js";
|
||||||
|
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||||
|
import { unauthorized, badRequest } from "@hapi/boom";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
|
||||||
|
export class AuthHandler {
|
||||||
|
public static async getAuthStatus(me: ILocalUser | null, session: Session | null): Promise<AuthResponse> {
|
||||||
|
const user = me ? await UserHandler.getUser(me, me.id) : null;
|
||||||
|
return {
|
||||||
|
status: !user ? 'guest' : session?.active ? 'authenticated' : '2fa',
|
||||||
|
token: session?.token ?? null,
|
||||||
|
user: user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async login(request: AuthRequest): Promise<AuthResponse> {
|
||||||
|
if (request.username == null || request.password == null) throw badRequest("Missing username or password");
|
||||||
|
|
||||||
|
const user = await Users.findOneBy({ usernameLower: request.username.toLowerCase(), host: IsNull() });
|
||||||
|
if (!user) throw unauthorized("Invalid username or password");
|
||||||
|
|
||||||
|
const profile = await UserProfiles.findOneBy( { userId: user.id });
|
||||||
|
if (!profile || profile.password == null) throw unauthorized("Invalid username or password");
|
||||||
|
|
||||||
|
if (!await comparePassword(request.password, profile.password)) throw unauthorized("Invalid username or password");
|
||||||
|
|
||||||
|
const result = await Sessions.insert({
|
||||||
|
id: genId(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
active: !profile.twoFactorEnabled,
|
||||||
|
userId: user.id,
|
||||||
|
token: secureRndstr(32),
|
||||||
|
});
|
||||||
|
|
||||||
|
const session = await Sessions.findOneByOrFail(result.identifiers[0]);
|
||||||
|
|
||||||
|
return this.getAuthStatus(user as ILocalUser, session);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue