import { UserBeforeCreateEvent } from "./../events" ; import { Service , Inject , EventManager } from "@bluelibs/core" ; import * as ms from "ms" ; import { ISecurityService , IUser , ICreateSessionOptions , IFieldMap , FindAuthenticationStrategyResponse , ISession , UserId , } from "../defs" ; import { USER_PERSISTANCE_LAYER , SESSION_PERSISTANCE_LAYER , } from "../constants" ; import { IUserPersistance , ISessionPersistance } from "../defs" ; import { UserAfterLogoutEvent , SessionRetrievedEvent , SessionBeforeCreateEvent , } from "../events" ; import { UserDisabledException , SessionExpiredException , UserNotFoundException , } from "../exceptions" ; import { UserDisabledEvent , UserEnabledEvent } from "../events" ; import { SessionAfterCreateEvent , UserBeforeUpdateEvent , UserAfterUpdateEvent , UserBeforeLoginEvent , UserAfterLoginEvent , UserBeforeLogoutEvent , UserAfterCreateEvent , UserBeforeDeleteEvent , UserAfterDeleteEvent , } from "../events" ; @ Service ( ) export class SecurityService implements ISecurityService { constructor ( @ Inject ( USER_PERSISTANCE_LAYER ) public readonly userPersistanceLayer , @ Inject ( SESSION_PERSISTANCE_LAYER ) public readonly sessionPersistanceLayer , protected readonly eventManager ) { } param data async createUser ( data = { } ) { const user = Object . assign ( { } , { isEnabled : true , } , data ) ; await this . eventManager . emit ( new UserBeforeCreateEvent ( { user : data , } ) ) ; const userId = await this . userPersistanceLayer . insertUser ( user ) ; await this . eventManager . emit ( new UserAfterCreateEvent ( { userId } ) ) ; return userId ; } async updateUser ( userId , data ) { await this . eventManager . emit ( new UserBeforeUpdateEvent ( { userId , data , } ) ) ; await this . userPersistanceLayer . updateUser ( userId , data ) ; await this . eventManager . emit ( new UserAfterUpdateEvent ( { userId , data , } ) ) ; } param userId async deleteUser ( userId ) { await this . eventManager . emit ( new UserBeforeDeleteEvent ( { userId , } ) ) ; await this . userPersistanceLayer . deleteUser ( userId ) ; await this . eventManager . emit ( new UserAfterDeleteEvent ( { userId , } ) ) ; } param filters param fields async findUser ( filters , fields ? ) { return this . userPersistanceLayer . findUser ( filters , fields ) ; } param filters param fields async findUserById ( userId , fields ? ) { return this . userPersistanceLayer . findUserById ( userId , fields ) ; } param userId param options async createSession ( userId , options = { } ) { if ( ! options . expiresIn ) { options . expiresIn = "14d" ; } this . eventManager . emit ( new SessionBeforeCreateEvent ( { userId , options } ) ) ; const expiresAt = new Date ( Date . now ( ) + ms ( options . expiresIn ) ) ; const token = await this . sessionPersistanceLayer . newSession ( userId , expiresAt , options . data ) ; this . eventManager . emit ( new SessionAfterCreateEvent ( { userId , token , options } ) ) ; return token ; } param userId param options async login ( userId , options ) { if ( ! ( await this . isUserEnabled ( userId ) ) ) { throw new UserDisabledException ( ) ; } await this . eventManager . emit ( new UserBeforeLoginEvent ( { userId , authenticationStrategy : options . authenticationStrategy , } ) ) ; const token = await this . createSession ( userId , options ) ; await this . updateUser ( userId , { lastLoginAt : new Date ( ) , } ) ; await this . eventManager . emit ( new UserAfterLoginEvent ( { userId , authenticationStrategy : options . authenticationStrategy , } ) ) ; return token ; } param userId async logout ( token ) { const session = await this . sessionPersistanceLayer . getSession ( token ) ; if ( ! session ) { return null ; } const { userId } = session ; await this . eventManager . emit ( new UserBeforeLogoutEvent ( { userId , } ) ) ; await this . sessionPersistanceLayer . deleteSession ( token ) ; await this . eventManager . emit ( new UserAfterLogoutEvent ( { userId , } ) ) ; } param token async getSession ( token ) { const session = await this . sessionPersistanceLayer . getSession ( token ) ; if ( ! session ) { return null ; } await this . eventManager . emit ( new SessionRetrievedEvent ( { session } ) ) ; await this . validateSession ( session ) ; return session ; } param token returns async reissueSessionToken ( token , expiresAt ? ) { const session = await this . sessionPersistanceLayer . getSession ( token ) ; if ( ! session ) { throw new Error ( "Invalid token provided for reissuing session" ) ; } this . sessionPersistanceLayer . deleteSession ( token ) ; return this . sessionPersistanceLayer . newSession ( session . userId , expiresAt || session . expiresAt , session . data ) ; } param session protected async validateSession ( session ) { const { userId , expiresAt } = session ; if ( expiresAt . getTime ( ) < new Date ( ) . getTime ( ) ) { throw new SessionExpiredException ( ) ; } if ( ! this . isUserEnabled ( userId ) ) { throw new UserDisabledException ( ) ; } } param userId param authMethodName param data async updateAuthenticationStrategyData < T = any > ( userId , authMethodName , data ) { return this . userPersistanceLayer . updateAuthenticationStrategyData ( userId , authMethodName , data ) ; } param userId param methodName async getAuthenticationStrategyData < T = any > ( userId , methodName , fields ? ) { return this . userPersistanceLayer . getAuthenticationStrategyData < T > ( userId , methodName , fields ) ; } async findThroughAuthenticationStrategy < T = any > ( methodName , filters , fields ? ) { return this . userPersistanceLayer . findThroughAuthenticationStrategy < T > ( methodName , filters , fields ) ; } param userId param methodName async removeAuthenticationStrategyData ( userId , methodName ) { return this . userPersistanceLayer . removeAuthenticationStrategyData ( userId , methodName ) ; } param userId async disableUser ( userId ) { await this . sessionPersistanceLayer . deleteAllSessionsForUser ( userId ) ; await this . updateUser ( userId , { isEnabled : false , } ) ; await this . eventManager . emit ( new UserDisabledEvent ( { userId , } ) ) ; } param userId async enableUser ( userId ) { await this . updateUser ( userId , { isEnabled : true , } ) ; await this . eventManager . emit ( new UserEnabledEvent ( { userId , } ) ) ; } param userId async isUserEnabled ( userId ) { const user = await this . findUserById ( userId , { isEnabled : 1 , } ) ; return Boolean ( user ?. isEnabled ) ; } param userId returns async getRoles ( userId ) { const user = await this . findUserById ( userId , { roles : 1 , } ) ; if ( ! user ) { return [ ] ; } return user ?. roles || [ ] ; } param userId param roles returns async setRoles ( userId , roles ) { return this . updateUser ( userId , { roles , } ) ; } }