From 8e325f7a2b89ee598947ac1e23d9c2e744a0e814 Mon Sep 17 00:00:00 2001 From: Matthew Heroux Date: Wed, 21 Feb 2024 23:05:09 -0600 Subject: [PATCH] feat: user service auth (#835) Signed-off-by: Matthew Heroux --- middleware/api/.env.dist | 1 + middleware/api/openapi-spec.json | 9 ++- .../api/src/modules/router/route-url.dto.ts | 31 ++++++++++ .../src/modules/router/router.controller.ts | 10 +++- .../api/src/modules/router/router.service.ts | 56 +++++-------------- .../api/src/modules/router/routes.config.ts | 44 +++++++++++++++ .../__snapshots__/main.stack.test.ts.snap | 3 +- middleware/api/stacks/main.stack.ts | 27 ++++----- 8 files changed, 119 insertions(+), 62 deletions(-) create mode 100644 middleware/api/src/modules/router/route-url.dto.ts create mode 100644 middleware/api/src/modules/router/routes.config.ts diff --git a/middleware/api/.env.dist b/middleware/api/.env.dist index 3995326b2..2dafd44ef 100644 --- a/middleware/api/.env.dist +++ b/middleware/api/.env.dist @@ -1,3 +1,4 @@ +API_SVC_DOMAIN_NAME = api.sandbox.nekosgate.com CHARACTER_SHEETS_SVC_DOMAIN_NAME = character-sheets.sandbox.nekosgate.com EMAIL_SERVICE_SVC_DOMAIN_NAME = email-message.sandbox.nekosgate.com HTML_TO_PDF_SVC_DOMAIN_NAME = html-to-pdf.sandbox.nekosgate.com diff --git a/middleware/api/openapi-spec.json b/middleware/api/openapi-spec.json index 6c8554afe..8ed4ed345 100644 --- a/middleware/api/openapi-spec.json +++ b/middleware/api/openapi-spec.json @@ -1,13 +1,20 @@ { "openapi": "3.0.0", "paths": { - "/routes": { + "/": { "get": { "operationId": "RouterController_getRoutes", "parameters": [], "responses": { "200": { "description": "" } } } }, + "/debug": { + "get": { + "operationId": "RouterController_getConfig", + "parameters": [], + "responses": { "200": { "description": "" } } + } + }, "/*": { "get": { "operationId": "RouterController_getRoute", diff --git a/middleware/api/src/modules/router/route-url.dto.ts b/middleware/api/src/modules/router/route-url.dto.ts new file mode 100644 index 000000000..a3a040aa2 --- /dev/null +++ b/middleware/api/src/modules/router/route-url.dto.ts @@ -0,0 +1,31 @@ +import { IsString, IsUrl } from '@cats-cradle/validation-schemas'; + +export class RouteUrlsDto { + @IsString() + @IsUrl() + users_url: string; + + @IsString() + @IsUrl() + character_sheets_url: string; + + @IsString() + @IsUrl() + email_messages_url: string; + + @IsString() + @IsUrl() + html_to_pdf_url: string; + + @IsString() + @IsUrl() + instances_url: string; + + @IsString() + @IsUrl() + dice_url: string; + + @IsString() + @IsUrl() + player_achievements_url: string; +} diff --git a/middleware/api/src/modules/router/router.controller.ts b/middleware/api/src/modules/router/router.controller.ts index f6d62af8c..81af1e18a 100644 --- a/middleware/api/src/modules/router/router.controller.ts +++ b/middleware/api/src/modules/router/router.controller.ts @@ -11,16 +11,22 @@ import { VERSION_NEUTRAL, } from '@nestjs/common'; import { RouterService } from './router.service'; +import { RouteUrlsDto } from './route-url.dto'; @Controller({ path: '', version: ['1', VERSION_NEUTRAL] }) export class RouterController { constructor(private readonly routerService: RouterService) {} - @Get('routes') - getRoutes(): { [key: string]: { path: string; endpoint: string } } { + @Get('') + getRoutes(): RouteUrlsDto { return this.routerService.getRoutes(); } + @Get('debug') + getConfig(): { [key: string]: { path: string; endpoint: string } } { + return this.routerService.getConfig(); + } + @Get('*') async getRoute(@Req() req: any): Promise { const { path, query } = req; diff --git a/middleware/api/src/modules/router/router.service.ts b/middleware/api/src/modules/router/router.service.ts index b6b505930..d7c02212a 100644 --- a/middleware/api/src/modules/router/router.service.ts +++ b/middleware/api/src/modules/router/router.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@nestjs/common'; import axios, { AxiosResponse } from 'axios'; import { v4 as uuidv4 } from 'uuid'; +import { RouteUrlsDto } from './route-url.dto'; +import { routes, RouteDefinition } from './routes.config'; type TRoute = { path: string; @@ -11,45 +13,6 @@ type TRoute = { @Injectable() export class RouterService { - private readonly routes: TRoute[] = [ - { - name: 'users_url', - path: '/user', - endpoint: process.env.USER_SVC_DOMAIN_NAME || '', - }, - { - name: 'character_sheets_url', - path: '/character-sheets', - endpoint: process.env.CHARACTER_SHEETS_SVC_DOMAIN_NAME || '', - }, - { - name: 'email_messages_url', - path: '/email-message', - endpoint: process.env.EMAIL_MESSAGE_SVC_DOMAIN_NAME || '', - }, - { - name: 'html_to_pdf_url', - path: '/html-to-pdf', - endpoint: process.env.HTML_TO_PDF_SVC_DOMAIN_NAME || '', - }, - { - name: 'instances_url', - path: '/instances', - endpoint: process.env.INSTANCES_SVC_DOMAIN_NAME || '', - }, - { - name: 'dice_url', - path: '/dice', - endpoint: process.env.LUCK_BY_DICE_SVC_DOMAIN_NAME || '', - }, - { - name: 'player_achievements_url', - path: '/player-achievements', - endpoint: process.env.PLAYER_ACHIEVEMENTS_SVC_DOMAIN_NAME || '', - }, - // Add more routes as needed - ]; - async routeRequest(path: string, body: any, method: string): Promise { const route = this.getRouteForPath(path); // Find the route for the provided path if (!route) { @@ -111,10 +74,17 @@ export class RouterService { return response.data; } - // TODO remove endpoint - getRoutes(): { [key: string]: { path: string; endpoint: string } } { + getRoutes(): RouteUrlsDto { + const urls: { [key: string]: string } = {}; + routes.forEach((route: RouteDefinition) => { + urls[route.name] = `https://${process.env.API_SVC_DOMAIN_NAME}${route.path}`; + }); + return urls as any as RouteUrlsDto; + } + + getConfig(): { [key: string]: { path: string; endpoint: string } } { const urls: { [key: string]: { path: string; endpoint: string } } = {}; - this.routes.forEach((route: TRoute) => { + routes.forEach((route: RouteDefinition) => { urls[route.name] = { path: route.path, endpoint: route.endpoint }; }); return urls; @@ -123,7 +93,7 @@ export class RouterService { private getRouteForPath( path: string, ): { path: string; endpoint: string } | undefined { - return this.routes.find((route) => path.startsWith(route.path)); + return routes.find((route) => path.startsWith(route.path)); } private constructUrl(endpoint: string, path: string): string { diff --git a/middleware/api/src/modules/router/routes.config.ts b/middleware/api/src/modules/router/routes.config.ts new file mode 100644 index 000000000..5a2841de0 --- /dev/null +++ b/middleware/api/src/modules/router/routes.config.ts @@ -0,0 +1,44 @@ +export type RouteDefinition = { + path: string; + name: string; + endpoint: string; +}; + +export const routes: RouteDefinition[] = [ + { + name: 'users_url', + path: '/user', + endpoint: process.env.USER_SVC_DOMAIN_NAME || '', + }, + { + name: 'character_sheets_url', + path: '/character-sheets', + endpoint: process.env.CHARACTER_SHEETS_SVC_DOMAIN_NAME || '', + }, + { + name: 'email_messages_url', + path: '/email-message', + endpoint: process.env.EMAIL_MESSAGE_SVC_DOMAIN_NAME || '', + }, + { + name: 'html_to_pdf_url', + path: '/html-to-pdf', + endpoint: process.env.HTML_TO_PDF_SVC_DOMAIN_NAME || '', + }, + { + name: 'instances_url', + path: '/instances', + endpoint: process.env.INSTANCES_SVC_DOMAIN_NAME || '', + }, + { + name: 'dice_url', + path: '/dice', + endpoint: process.env.LUCK_BY_DICE_SVC_DOMAIN_NAME || '', + }, + { + name: 'player_achievements_url', + path: '/player-achievements', + endpoint: process.env.PLAYER_ACHIEVEMENTS_SVC_DOMAIN_NAME || '', + }, + // Add more routes as needed +]; diff --git a/middleware/api/stacks/__snapshots__/main.stack.test.ts.snap b/middleware/api/stacks/__snapshots__/main.stack.test.ts.snap index 7412ab4e2..b141d0884 100644 --- a/middleware/api/stacks/__snapshots__/main.stack.test.ts.snap +++ b/middleware/api/stacks/__snapshots__/main.stack.test.ts.snap @@ -627,10 +627,11 @@ exports[`MainStack should match snapshot test 1`] = ` S3Bucket: { Fn::Sub: cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}, }, - S3Key: 84733bfcc0860a158020056aeea6de14f9009718cf2a83659cde3585250b04a6.zip, + S3Key: 696402484aadd93c03efb231f3a270bfd8656a85eed0051095cb57022377084a.zip, }, Environment: { Variables: { + API_SVC_DOMAIN_NAME: {{resolve:ssm:/API_SVC_DOMAIN_NAME}}, AWS_ACCOUNT_ID: { Ref: AWS::AccountId, }, diff --git a/middleware/api/stacks/main.stack.ts b/middleware/api/stacks/main.stack.ts index 2f1cdcf44..8e86ca76a 100644 --- a/middleware/api/stacks/main.stack.ts +++ b/middleware/api/stacks/main.stack.ts @@ -11,6 +11,7 @@ interface Secret { export class MainStack extends cdk.Stack { secrets: Secret[] = [ + { key: 'API_SVC_DOMAIN_NAME' }, { key: 'USER_SVC_DOMAIN_NAME' }, { key: 'CHARACTER_SHEETS_SVC_DOMAIN_NAME' }, { key: 'EMAIL_SERVICE_SVC_DOMAIN_NAME' }, @@ -23,20 +24,6 @@ export class MainStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); - const healthCheckLambda = this.setupLambda(`${id}-health-check-lambda`); - - const lambdaDomainName = new LambdaDomainName(this, `${id}-dns-domain`, { - subdomainName: 'api', - proxyLambda: healthCheckLambda, - stageName: 'default', - }); - - new cdk.CfnOutput(this, 'Endpoint', { - value: lambdaDomainName.getBaseUrl(), - }); - } - - setupLambda(lambdaId: string): lambda.Function { const environment: { [key: string]: string } = {}; for (const secret of this.secrets) { @@ -49,6 +36,16 @@ export class MainStack extends cdk.Stack { environment: environment, }); - return lambdaFunction.getNodeJsFunction(); + const lambdaDomainName = new LambdaDomainName(this, `${id}-dns-domain`, { + subdomainName: 'api', + proxyLambda: lambdaFunction.getNodeJsFunction(), + stageName: 'default', + }); + + lambdaDomainName.domainName; + + new cdk.CfnOutput(this, 'Endpoint', { + value: lambdaDomainName.getBaseUrl(), + }); } }