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.
144 lines
5.2 KiB
144 lines
5.2 KiB
import {Controller} from '../../../http/Controller'
|
|
import {Inject, Injectable} from '../../../di'
|
|
import {SecurityContext} from '../../context/SecurityContext'
|
|
import {Session} from '../../../http/session/Session'
|
|
import {ResponseFactory} from '../../../http/response/ResponseFactory'
|
|
import {redirectToGet, view} from '../../../http/response/ViewResponseFactory'
|
|
import {Routing} from '../../../service/Routing'
|
|
import {ResponseObject, Route} from '../../../http/routing/Route'
|
|
import {BasicLoginFormData, BasicLoginFormRequest} from './BasicLoginFormRequest'
|
|
import {Valid, ValidationError} from '../../../forms'
|
|
import {BasicRegisterFormData, BasicRegisterFormRequest} from './BasicRegisterFormRequest'
|
|
import {AuthenticatableAlreadyExistsError} from '../../AuthenticatableAlreadyExistsError'
|
|
import {Request} from '../../../http/lifecycle/Request'
|
|
|
|
@Injectable()
|
|
export class BasicLoginController extends Controller {
|
|
public static routes({ enableRegistration = true } = {}): void {
|
|
const controller = (request: Request) => {
|
|
return <BasicLoginController> request.make(BasicLoginController)
|
|
}
|
|
|
|
Route.group('auth', () => {
|
|
Route.get('login', (request: Request) =>
|
|
controller(request).getLogin())
|
|
.pre('@auth:guest')
|
|
.alias('@auth.login')
|
|
|
|
Route.post('login', (request: Request) =>
|
|
controller(request).attemptLogin())
|
|
.pre('@auth:guest')
|
|
.alias('@auth.login.attempt')
|
|
|
|
Route.any('logout', (request: Request) =>
|
|
controller(request).attemptLogout())
|
|
.pre('@auth:required')
|
|
.alias('@auth.logout')
|
|
|
|
if ( enableRegistration ) {
|
|
Route.get('register', (request: Request) =>
|
|
controller(request).getRegistration())
|
|
.pre('@auth:guest')
|
|
.alias('@auth.register')
|
|
|
|
Route.post('register', (request: Request) =>
|
|
controller(request).attemptRegister())
|
|
.pre('@auth:guest')
|
|
.alias('@auth.register.attempt')
|
|
}
|
|
}).pre('@auth:web')
|
|
}
|
|
|
|
@Inject()
|
|
protected readonly security!: SecurityContext
|
|
|
|
@Inject()
|
|
protected readonly session!: Session
|
|
|
|
@Inject()
|
|
protected readonly routing!: Routing
|
|
|
|
public getLogin(): ResponseFactory {
|
|
return this.getLoginView()
|
|
}
|
|
|
|
public getRegistration(): ResponseFactory {
|
|
if ( !this.security.repository.supportsRegistration() ) {
|
|
return redirectToGet('/')
|
|
}
|
|
|
|
return this.getRegistrationView()
|
|
}
|
|
|
|
public async attemptLogin(): Promise<ResponseObject> {
|
|
const form = <BasicLoginFormRequest> this.request.make(BasicLoginFormRequest)
|
|
|
|
try {
|
|
const data: Valid<BasicLoginFormData> = await form.get()
|
|
const user = await this.security.repository.getByIdentifier(data.username)
|
|
if ( user && (await user.validateCredential(data.password)) ) {
|
|
await this.security.authenticate(user)
|
|
|
|
const intention = this.session.get('@extollo:auth.intention', '/')
|
|
this.session.forget('@extollo:auth.intention')
|
|
return redirectToGet(intention)
|
|
}
|
|
|
|
return this.getLoginView(['Invalid username/password.'])
|
|
} catch (e: unknown) {
|
|
if ( e instanceof ValidationError ) {
|
|
return this.getLoginView(e.errors.all())
|
|
}
|
|
|
|
throw e
|
|
}
|
|
}
|
|
|
|
public async attemptRegister(): Promise<ResponseObject> {
|
|
const form = <BasicRegisterFormRequest> this.request.make(BasicRegisterFormRequest)
|
|
|
|
try {
|
|
const data: Valid<BasicRegisterFormData> = await form.get()
|
|
const user = await this.security.repository.createFromCredentials(data.username, data.password)
|
|
await this.security.authenticate(user)
|
|
|
|
const intention = this.session.get('@extollo:auth.intention', '/')
|
|
this.session.forget('@extollo:auth.intention')
|
|
return redirectToGet(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
|
|
}
|
|
}
|
|
|
|
public async attemptLogout(): Promise<ResponseObject> {
|
|
await this.security.flush()
|
|
return this.getMessageView('You have been logged out.')
|
|
}
|
|
|
|
protected getRegistrationView(errors?: string[]): ResponseFactory {
|
|
return view('@extollo:auth:register', {
|
|
formAction: this.routing.getNamedPath('@auth.register.attempt').toRemote,
|
|
errors,
|
|
})
|
|
}
|
|
|
|
protected getLoginView(errors?: string[]): ResponseFactory {
|
|
return view('@extollo:auth:login', {
|
|
formAction: this.routing.getNamedPath('@auth.login.attempt').toRemote,
|
|
errors,
|
|
})
|
|
}
|
|
|
|
protected getMessageView(message: string): ResponseFactory {
|
|
return view('@extollo:auth:message', {
|
|
message,
|
|
})
|
|
}
|
|
}
|