import { Inject, Injectable } from "@nestjs/common"; import { AccountService } from "./account.service"; import * as tokenService from "../contracts/services/token.service"; import * as passwordService from "../contracts/services/password.service"; import * as sessionService from "../contracts/services/session.service"; import { ISignIn } from "../contracts/models/sign.in"; @Injectable() export class LoginService { constructor( @Inject("@apihub24/token_service") private readonly tokenService: tokenService.ITokenService, @Inject("@apihub24/password_service") private readonly passwordService: passwordService.IPasswordService, @Inject("@apihub24/session_service") private readonly sessionService: sessionService.ISessionService, @Inject(AccountService) private readonly accountService: AccountService ) {} /** * This asynchronous method authenticates a user and creates a JWT token for a new session. * It first finds an active account with the given `accountName`, verifies the password, and if successful, creates a new session and generates a signed token. * @param signIn An `ISignIn` object containing the `accountName` and `password`. * @param expires An optional string specifying the token's expiration duration (default: "1h"). * @param algorithm An optional string specifying the signing algorithm for the token (default: "HS512"). * @returns A Promise that resolves to a JWT token string. Returns an empty string if authentication fails. */ async signIn( signIn: ISignIn, expires: string = "1h", algorithm: tokenService.Algorithm = "HS512" ): Promise { const accounts = await this.accountService.getBy( (x) => x.accountName === signIn.accountName && x.active && !!x.passwordHash?.length ); if ( !accounts.length || !(await this.passwordService.verify( signIn.password, accounts[0].passwordHash )) ) { return ""; } const session = await this.sessionService.create(accounts[0]); const token = await this.tokenService.generate( session, signIn.accountName, expires, algorithm ); return token; } /** * This asynchronous method logs a user out by removing their active session. * It finds the account by its `id` and then locates and removes the corresponding session. * @param accountId The unique identifier (`id`) of the account to be logged out. * @returns A Promise that resolves to `void` after the operation is complete. */ async signOut(accountId: string): Promise { const accounts = await this.accountService.getBy((x) => x.id === accountId); if (!accounts.length) { return; } const sessions = await this.sessionService.getBy( (x) => x.id === accounts[0].id ); if (!sessions.length) { return; } await this.sessionService.remove(sessions[0].id); } }