Files
standardnotes-server/packages/auth/src/Infra/InversifyExpressUtils/InversifyExpressSubscriptionTokensController.ts
T
Karol SójkoandGitHub fea58029b9 feat(auth): move inversify express controllers to different structure (#610)
* wip: move valet token controller

* wip: move users controller

* wip: move admin controller

* wip: move subscription tokens controller

* wip: move subscription settings controller

* wip: move settings controller

* wip: move middleware

* wip: move session controller

* wip: move offline controller

* wip: move listed controller

* wip: move internal controller

* wip: move healthcheck controller

* wip: move features controller

* fix: bind inversify express controllers only for home server

* fix: inversify deps
2023-05-17 11:54:18 +02:00

117 lines
4.2 KiB
TypeScript

import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { ErrorTag } from '@standardnotes/responses'
import { SettingName } from '@standardnotes/settings'
import { Request, Response } from 'express'
import { inject } from 'inversify'
import {
BaseHttpController,
controller,
httpPost,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
results,
} from 'inversify-express-utils'
import TYPES from '../../Bootstrap/Types'
import { Role } from '../../Domain/Role/Role'
import { SettingServiceInterface } from '../../Domain/Setting/SettingServiceInterface'
import { AuthenticateSubscriptionToken } from '../../Domain/UseCase/AuthenticateSubscriptionToken/AuthenticateSubscriptionToken'
import { CreateSubscriptionToken } from '../../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
import { User } from '../../Domain/User/User'
import { ProjectorInterface } from '../../Projection/ProjectorInterface'
import { ControllerContainerInterface } from '@standardnotes/domain-core'
@controller('/subscription-tokens')
export class InversifyExpressSubscriptionTokensController extends BaseHttpController {
constructor(
@inject(TYPES.Auth_CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
@inject(TYPES.Auth_AuthenticateSubscriptionToken) private authenticateToken: AuthenticateSubscriptionToken,
@inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
@inject(TYPES.Auth_UserProjector) private userProjector: ProjectorInterface<User>,
@inject(TYPES.Auth_RoleProjector) private roleProjector: ProjectorInterface<Role>,
@inject(TYPES.Auth_CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
@inject(TYPES.Auth_AUTH_JWT_TTL) private jwtTTL: number,
@inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
) {
super()
this.controllerContainer.register('auth.subscription-tokens.create', this.createToken.bind(this))
}
@httpPost('/', TYPES.Auth_ApiGatewayAuthMiddleware)
async createToken(_request: Request, response: Response): Promise<results.JsonResult> {
if (response.locals.readOnlyAccess) {
return this.json(
{
error: {
tag: ErrorTag.ReadOnlyAccess,
message: 'Session has read-only access.',
},
},
401,
)
}
const result = await this.createSubscriptionToken.execute({
userUuid: response.locals.user.uuid,
})
return this.json({
token: result.subscriptionToken.token,
})
}
@httpPost('/:token/validate')
async validate(request: Request): Promise<results.JsonResult> {
const authenticateTokenResponse = await this.authenticateToken.execute({
token: request.params.token,
})
if (!authenticateTokenResponse.success) {
return this.json(
{
error: {
tag: 'invalid-auth',
message: 'Invalid login credentials.',
},
},
401,
)
}
const user = authenticateTokenResponse.user as User
let extensionKey = undefined
const extensionKeySetting = await this.settingService.findSettingWithDecryptedValue({
settingName: SettingName.create(SettingName.NAMES.ExtensionKey).getValue(),
userUuid: user.uuid,
})
if (extensionKeySetting !== null) {
extensionKey = extensionKeySetting.value as string
}
const roles = await user.roles
const authTokenData: CrossServiceTokenData = {
user: await this.projectUser(user),
roles: await this.projectRoles(roles),
extensionKey,
}
const authToken = this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL)
return this.json({ authToken })
}
private async projectUser(user: User): Promise<{ uuid: string; email: string }> {
return <{ uuid: string; email: string }>await this.userProjector.projectSimple(user)
}
private async projectRoles(roles: Array<Role>): Promise<Array<{ uuid: string; name: string }>> {
const roleProjections = []
for (const role of roles) {
roleProjections.push(<{ uuid: string; name: string }>await this.roleProjector.projectSimple(role))
}
return roleProjections
}
}