From fb4b0f8cf332a5e74722623f0336cb99f84c7c30 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Wed, 16 Aug 2023 11:41:20 +0200 Subject: [PATCH] feat: get api tokens by name (#4507) --- src/lib/routes/admin-api/api-token.ts | 47 ++++++++++++++++++++ src/test/e2e/api/admin/api-token.e2e.test.ts | 12 ++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/lib/routes/admin-api/api-token.ts b/src/lib/routes/admin-api/api-token.ts index fca1b3a753..352fe9c79b 100644 --- a/src/lib/routes/admin-api/api-token.ts +++ b/src/lib/routes/admin-api/api-token.ts @@ -48,6 +48,9 @@ import { OperationDeniedError } from '../../error'; interface TokenParam { token: string; } +interface TokenNameParam { + name: string; +} export const tokenTypeToCreatePermission: ( tokenType: ApiTokenType, ) => string = (tokenType) => { @@ -168,6 +171,26 @@ export class ApiTokenController extends Controller { ], }); + this.route({ + method: 'get', + path: '/:name', + handler: this.getApiTokensByName, + permission: [ADMIN, READ_CLIENT_API_TOKEN, READ_FRONTEND_API_TOKEN], + middleware: [ + openApiService.validPath({ + tags: ['API tokens'], + operationId: 'getApiTokensByName', + summary: 'Get API tokens by name', + description: + 'Retrieves all API tokens that match a given token name. Because token names are not unique, this endpoint will always return a list. If no tokens with the provided name exist, the list will be empty. Otherwise, it will contain all the tokens with the given name.', + responses: { + 200: createResponseSchema('apiTokensSchema'), + ...getStandardResponses(401, 403), + }, + }), + ], + }); + this.route({ method: 'post', path: '', @@ -259,6 +282,22 @@ export class ApiTokenController extends Controller { ); } + async getApiTokensByName( + req: IAuthRequest, + res: Response, + ): Promise { + const { user } = req; + const { name } = req.params; + + const tokens = await this.accessibleTokensByName(name, user); + this.openApiService.respondWithValidation( + 200, + res, + apiTokensSchema.$id, + { tokens: serializeDates(tokens) }, + ); + } + async createApiToken( req: IAuthRequest, res: Response, @@ -361,6 +400,14 @@ export class ApiTokenController extends Controller { res.status(200).end(); } + private async accessibleTokensByName( + tokenName: string, + user: User, + ): Promise { + const allTokens = await this.accessibleTokens(user); + return allTokens.filter((token) => token.tokenName === tokenName); + } + private async accessibleTokens(user: User): Promise { const allTokens = await this.apiTokenService.getAllTokens(); diff --git a/src/test/e2e/api/admin/api-token.e2e.test.ts b/src/test/e2e/api/admin/api-token.e2e.test.ts index 900b883495..d1f0ca695b 100644 --- a/src/test/e2e/api/admin/api-token.e2e.test.ts +++ b/src/test/e2e/api/admin/api-token.e2e.test.ts @@ -157,8 +157,8 @@ test('creates a lot of client tokens', async () => { ); } await Promise.all(requests); - expect.assertions(2); - return app.request + expect.assertions(4); + await app.request .get('/api/admin/api-tokens') .expect('Content-Type', /json/) .expect(200) @@ -166,6 +166,14 @@ test('creates a lot of client tokens', async () => { expect(res.body.tokens.length).toBe(10); expect(res.body.tokens[2].type).toBe('client'); }); + await app.request + .get('/api/admin/api-tokens/default-client') + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + expect(res.body.tokens.length).toBe(10); + expect(res.body.tokens[2].type).toBe('client'); + }); }); test('removes api token', async () => {