You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
5.4 KiB
146 lines
5.4 KiB
import {Controller} from '../../http/Controller'
|
|
import {Inject, Injectable} from '../../di'
|
|
import {ResponseObject, Route} from '../../http/routing/Route'
|
|
import {Request} from '../../http/lifecycle/Request'
|
|
import {view} from '../../http/response/ViewResponseFactory'
|
|
import {ResponseFactory} from '../../http/response/ResponseFactory'
|
|
import {SecurityContext} from '../SecurityContext'
|
|
import {BasicLoginFormRequest} from './BasicLoginFormRequest'
|
|
import {Routing} from '../../service/Routing'
|
|
import {Valid, ValidationError} from '../../forms'
|
|
import {AuthenticatableCredentials} from '../types'
|
|
import {BasicRegisterFormRequest} from './BasicRegisterFormRequest'
|
|
import {AuthenticatableAlreadyExistsError} from '../AuthenticatableAlreadyExistsError'
|
|
import {Session} from '../../http/session/Session'
|
|
import {temporary} from '../../http/response/TemporaryRedirectResponseFactory'
|
|
|
|
@Injectable()
|
|
export class BasicLoginController extends Controller {
|
|
public static routes({ enableRegistration = true } = {}): void {
|
|
Route.group('auth', () => {
|
|
Route.get('login', (request: Request) => {
|
|
const controller = <BasicLoginController> request.make(BasicLoginController)
|
|
return controller.getLogin()
|
|
})
|
|
.pre('@auth:guest')
|
|
.alias('@auth.login')
|
|
|
|
Route.post('login', (request: Request) => {
|
|
const controller = <BasicLoginController> request.make(BasicLoginController)
|
|
return controller.attemptLogin()
|
|
})
|
|
.pre('@auth:guest')
|
|
.alias('@auth.login.attempt')
|
|
|
|
Route.any('logout', (request: Request) => {
|
|
const controller = <BasicLoginController> request.make(BasicLoginController)
|
|
return controller.attemptLogout()
|
|
})
|
|
.pre('@auth:required')
|
|
.alias('@auth.logout')
|
|
|
|
if ( enableRegistration ) {
|
|
Route.get('register', (request: Request) => {
|
|
const controller = <BasicLoginController> request.make(BasicLoginController)
|
|
return controller.getRegistration()
|
|
})
|
|
.pre('@auth:guest')
|
|
.alias('@auth.register')
|
|
|
|
Route.post('register', (request: Request) => {
|
|
const controller = <BasicLoginController> request.make(BasicLoginController)
|
|
return controller.attemptRegister()
|
|
})
|
|
.pre('@auth:guest')
|
|
.alias('@auth.register.attempt')
|
|
}
|
|
}).pre('@auth:web')
|
|
}
|
|
|
|
@Inject()
|
|
protected readonly security!: SecurityContext
|
|
|
|
@Inject()
|
|
protected readonly routing!: Routing
|
|
|
|
@Inject()
|
|
protected readonly session!: Session
|
|
|
|
public getLogin(): ResponseFactory {
|
|
return this.getLoginView()
|
|
}
|
|
|
|
public getRegistration(): ResponseFactory {
|
|
return this.getRegistrationView()
|
|
}
|
|
|
|
public async attemptLogin(): Promise<ResponseObject> {
|
|
const form = <BasicLoginFormRequest> this.request.make(BasicLoginFormRequest)
|
|
|
|
try {
|
|
const data: Valid<AuthenticatableCredentials> = await form.get()
|
|
const user = await this.security.attempt(data)
|
|
if ( user ) {
|
|
const intention = this.session.get('auth.intention', '/')
|
|
this.session.forget('auth.intention')
|
|
return temporary(intention)
|
|
}
|
|
|
|
return this.getLoginView(['Invalid username/password.'])
|
|
} catch (e: unknown) {
|
|
if ( e instanceof ValidationError ) {
|
|
return this.getLoginView(e.errors.all())
|
|
}
|
|
|
|
throw e
|
|
}
|
|
}
|
|
|
|
public async attemptLogout(): Promise<ResponseObject> {
|
|
await this.security.flush()
|
|
return this.getMessageView('You have been logged out.')
|
|
}
|
|
|
|
public async attemptRegister(): Promise<ResponseObject> {
|
|
const form = <BasicRegisterFormRequest> this.request.make(BasicRegisterFormRequest)
|
|
|
|
try {
|
|
const data: Valid<AuthenticatableCredentials> = await form.get()
|
|
const user = await this.security.repository.createByCredentials(data)
|
|
await this.security.authenticate(user)
|
|
|
|
const intention = this.session.get('auth.intention', '/')
|
|
this.session.forget('auth.intention')
|
|
return temporary(intention)
|
|
} catch (e: unknown) {
|
|
if ( e instanceof ValidationError ) {
|
|
return this.getRegistrationView(e.errors.all())
|
|
} else if ( e instanceof AuthenticatableAlreadyExistsError ) {
|
|
return this.getRegistrationView(['A user with that username already exists.'])
|
|
}
|
|
|
|
throw e
|
|
}
|
|
}
|
|
|
|
protected getLoginView(errors?: string[]): ResponseFactory {
|
|
return view('@extollo:auth:login', {
|
|
formAction: this.routing.getNamedPath('@auth.login.attempt').toRemote,
|
|
errors,
|
|
})
|
|
}
|
|
|
|
protected getRegistrationView(errors?: string[]): ResponseFactory {
|
|
return view('@extollo:auth:register', {
|
|
formAction: this.routing.getNamedPath('@auth.register.attempt').toRemote,
|
|
errors,
|
|
})
|
|
}
|
|
|
|
protected getMessageView(message: string): ResponseFactory {
|
|
return view('@extollo:auth:message', {
|
|
message,
|
|
})
|
|
}
|
|
}
|