Refactor event bus and queue system; detect cycles in DI realization and make
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import {Inject, Injectable} from '../../di'
|
||||
import {EventBus} from '../../event/EventBus'
|
||||
import {Awaitable, Maybe} from '../../util'
|
||||
import {Authenticatable, AuthenticatableRepository} from '../types'
|
||||
import {Logging} from '../../service/Logging'
|
||||
import {UserAuthenticatedEvent} from '../event/UserAuthenticatedEvent'
|
||||
import {UserFlushedEvent} from '../event/UserFlushedEvent'
|
||||
import {Bus} from '../../support/bus'
|
||||
|
||||
/**
|
||||
* Base-class for a context that authenticates users and manages security.
|
||||
@@ -12,7 +12,7 @@ import {UserFlushedEvent} from '../event/UserFlushedEvent'
|
||||
@Injectable()
|
||||
export abstract class SecurityContext {
|
||||
@Inject()
|
||||
protected readonly bus!: EventBus
|
||||
protected readonly bus!: Bus
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
@@ -40,7 +40,7 @@ export abstract class SecurityContext {
|
||||
*/
|
||||
async authenticateOnce(user: Authenticatable): Promise<void> {
|
||||
this.authenticatedUser = user
|
||||
await this.bus.dispatch(new UserAuthenticatedEvent(user, this))
|
||||
await this.bus.push(new UserAuthenticatedEvent(user, this))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ export abstract class SecurityContext {
|
||||
async authenticate(user: Authenticatable): Promise<void> {
|
||||
this.authenticatedUser = user
|
||||
await this.persist()
|
||||
await this.bus.dispatch(new UserAuthenticatedEvent(user, this))
|
||||
await this.bus.push(new UserAuthenticatedEvent(user, this))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ export abstract class SecurityContext {
|
||||
const user = this.authenticatedUser
|
||||
if ( user ) {
|
||||
this.authenticatedUser = undefined
|
||||
await this.bus.dispatch(new UserFlushedEvent(user, this))
|
||||
await this.bus.push(new UserFlushedEvent(user, this))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export abstract class SecurityContext {
|
||||
if ( user ) {
|
||||
this.authenticatedUser = undefined
|
||||
await this.persist()
|
||||
await this.bus.dispatch(new UserFlushedEvent(user, this))
|
||||
await this.bus.push(new UserFlushedEvent(user, this))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export class SessionSecurityContext extends SecurityContext {
|
||||
const user = await this.repository.getByIdentifier(identifier)
|
||||
if ( user ) {
|
||||
this.authenticatedUser = user
|
||||
await this.bus.dispatch(new UserAuthenticationResumedEvent(user, this))
|
||||
await this.bus.push(new UserAuthenticationResumedEvent(user, this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,12 @@
|
||||
import {Event} from '../../event/Event'
|
||||
import {SecurityContext} from '../context/SecurityContext'
|
||||
import {Awaitable, JSONState} from '../../util'
|
||||
import {Authenticatable} from '../types'
|
||||
import {BaseEvent} from '../../support/bus'
|
||||
|
||||
/**
|
||||
* Event fired when a user is authenticated.
|
||||
*/
|
||||
export class AuthenticationEvent extends Event {
|
||||
export abstract class AuthenticationEvent extends BaseEvent {
|
||||
constructor(
|
||||
public readonly user: Authenticatable,
|
||||
public readonly context: SecurityContext,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async dehydrate(): Promise<JSONState> {
|
||||
return {
|
||||
user: await this.user.dehydrate(),
|
||||
contextName: this.context.name,
|
||||
}
|
||||
}
|
||||
|
||||
rehydrate(state: JSONState): Awaitable<void> { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
// TODO fill this in
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@ import {AuthenticationEvent} from './AuthenticationEvent'
|
||||
/**
|
||||
* Event fired when a user is authenticated.
|
||||
*/
|
||||
export class UserAuthenticatedEvent extends AuthenticationEvent {}
|
||||
export class UserAuthenticatedEvent extends AuthenticationEvent {
|
||||
public readonly eventName = '@extollo/lib:UserAuthenticatedEvent'
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@ import {AuthenticationEvent} from './AuthenticationEvent'
|
||||
/**
|
||||
* Event raised when a user is re-authenticated to a security context
|
||||
*/
|
||||
export class UserAuthenticationResumedEvent extends AuthenticationEvent {}
|
||||
export class UserAuthenticationResumedEvent extends AuthenticationEvent {
|
||||
public readonly eventName = '@extollo/lib:UserAuthenticationResumedEvent'
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@ import {AuthenticationEvent} from './AuthenticationEvent'
|
||||
/**
|
||||
* Event fired when a user is unauthenticated.
|
||||
*/
|
||||
export class UserFlushedEvent extends AuthenticationEvent {}
|
||||
export class UserFlushedEvent extends AuthenticationEvent {
|
||||
public readonly eventName = '@extollo/lib:UserFlushedEvent'
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ export * from './event/UserAuthenticatedEvent'
|
||||
export * from './event/UserAuthenticationResumedEvent'
|
||||
export * from './event/UserFlushedEvent'
|
||||
|
||||
export * from './serial/AuthenticationEventSerializer'
|
||||
|
||||
export * from './repository/orm/ORMUser'
|
||||
export * from './repository/orm/ORMUserRepository'
|
||||
|
||||
|
||||
54
src/auth/serial/AuthenticationEventSerializer.ts
Normal file
54
src/auth/serial/AuthenticationEventSerializer.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {BaseSerializer, ObjectSerializer, SerialPayload} from '../../support/bus'
|
||||
import {AuthenticationEvent} from '../event/AuthenticationEvent'
|
||||
import {ErrorWithContext, JSONState} from '../../util'
|
||||
import {Authenticatable} from '../types'
|
||||
import {StaticInstantiable} from '../../di'
|
||||
import {SecurityContext} from '../context/SecurityContext'
|
||||
import {UserAuthenticatedEvent} from '../event/UserAuthenticatedEvent'
|
||||
import {UserAuthenticationResumedEvent} from '../event/UserAuthenticationResumedEvent'
|
||||
import {UserFlushedEvent} from '../event/UserFlushedEvent'
|
||||
|
||||
export interface AuthenticationEventSerialPayload extends JSONState {
|
||||
user: SerialPayload<Authenticatable, JSONState>
|
||||
eventName: string
|
||||
}
|
||||
|
||||
@ObjectSerializer()
|
||||
export class AuthenticationEventSerializer extends BaseSerializer<AuthenticationEvent, AuthenticationEventSerialPayload> {
|
||||
protected async decodeSerial(serial: AuthenticationEventSerialPayload): Promise<AuthenticationEvent> {
|
||||
const user = await this.getSerialization().decode(serial.user)
|
||||
const context = await this.getRequest().make(SecurityContext)
|
||||
|
||||
const EventClass = this.getEventClass(serial.eventName)
|
||||
return new EventClass(user, context)
|
||||
}
|
||||
|
||||
protected async encodeActual(actual: AuthenticationEvent): Promise<AuthenticationEventSerialPayload> {
|
||||
return {
|
||||
eventName: actual.eventName,
|
||||
user: await this.getSerialization().encode(actual.user),
|
||||
}
|
||||
}
|
||||
|
||||
protected getName(): string {
|
||||
return '@extollo/lib:AuthenticationEventSerializer'
|
||||
}
|
||||
|
||||
matchActual(some: AuthenticationEvent): boolean {
|
||||
return some instanceof AuthenticationEvent
|
||||
}
|
||||
|
||||
protected getEventClass(name: string): StaticInstantiable<AuthenticationEvent> {
|
||||
if ( name === '@extollo/lib:UserAuthenticatedEvent' ) {
|
||||
return UserAuthenticatedEvent
|
||||
} else if ( name === '@extollo/lib:UserAuthenticationResumedEvent' ) {
|
||||
return UserAuthenticationResumedEvent
|
||||
} else if ( name === '@extollo/lib:UserFlushedEvent' ) {
|
||||
return UserFlushedEvent
|
||||
}
|
||||
|
||||
throw new ErrorWithContext('Unable to map event name to AuthenticationEvent implementation', {
|
||||
eventName: name,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user