Skip to content

Commit 93cd789

Browse files
committed
fix: remove redundant delete by id route
1 parent 0e2ad57 commit 93cd789

3 files changed

Lines changed: 43 additions & 122 deletions

File tree

‎packages/api-gateway/src/modules/auth/auth.controller.ts‎

Lines changed: 23 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,24 @@ export class AuthController implements OnModuleInit {
237237
type: 'string',
238238
},
239239
})
240+
@ApiHeader({
241+
name: 'x-user-jwt',
242+
description: "The user's ID token",
243+
required: true,
244+
schema: {
245+
type: 'string',
246+
},
247+
})
240248
@ApiBearerAuth('API_Key')
241249
@HttpCode(HttpStatus.NO_CONTENT)
242250
@Delete('/key')
243251
async deleteApiKey(
244252
@User() user: CommonProto.User,
245253
@Headers('Authorization') apiKey?: string,
246254
) {
255+
if (!user) {
256+
throw new UnauthorizedException('User ID token is required');
257+
}
247258
const key = apiKey?.replace('Bearer ', '');
248259
if (key === undefined) {
249260
throw new UnauthorizedException('API Key is required');
@@ -288,85 +299,6 @@ export class AuthController implements OnModuleInit {
288299
return;
289300
}
290301

291-
@ApiOperation({
292-
summary: 'Deletes an API key by ID.',
293-
})
294-
@ApiResponse({
295-
status: HttpStatus.BAD_REQUEST,
296-
description: 'Invalid API Key ID',
297-
})
298-
@ApiResponse({
299-
status: HttpStatus.NOT_FOUND,
300-
description: 'API Key not found',
301-
})
302-
@ApiResponse({
303-
status: HttpStatus.UNAUTHORIZED,
304-
description: 'Invalid API Key or insufficient permissions',
305-
})
306-
@ApiResponse({
307-
status: HttpStatus.NO_CONTENT,
308-
description: 'Successful API Key deletion',
309-
})
310-
@ApiParam({
311-
name: 'id',
312-
required: true,
313-
description: 'ID of the API key to delete',
314-
type: String,
315-
})
316-
@ApiHeader({
317-
name: 'Authorization',
318-
description: 'A valid API key',
319-
required: true,
320-
schema: {
321-
type: 'string',
322-
},
323-
})
324-
@ApiBearerAuth('API_Key')
325-
@HttpCode(HttpStatus.NO_CONTENT)
326-
@Delete('/key/:id')
327-
async deleteApiKeyById(
328-
@User() user: CommonProto.User,
329-
@Param('id') idStr: string,
330-
) {
331-
const id = +idStr;
332-
if (Number.isNaN(id)) {
333-
throw new HttpException('Invalid API Key ID', HttpStatus.BAD_REQUEST);
334-
}
335-
336-
const response = await lastValueFrom(this.apiKeyService.getApiKey({ id }));
337-
338-
if (!response.key) {
339-
throw new HttpException('API Key not found', HttpStatus.NOT_FOUND);
340-
}
341-
342-
if (!response.key.project) {
343-
throw new HttpException(
344-
'API Key has no associated project',
345-
HttpStatus.INTERNAL_SERVER_ERROR,
346-
);
347-
}
348-
349-
const projectId = response.key.project.id;
350-
const linked = await userLinkedToProject({
351-
project: { id: projectId },
352-
user,
353-
projectClient: this.projectService,
354-
});
355-
356-
if (!linked || user.type == CommonProto.UserType.USER) {
357-
throw new UnauthorizedException(
358-
'Only Superadmins & Linked Admins can delete API Keys',
359-
);
360-
}
361-
const deleteResponse = await lastValueFrom(
362-
this.apiKeyService.deleteApiKey({ id }),
363-
);
364-
if (!deleteResponse.success) {
365-
throw new HttpException('API Key deletion failed', 500);
366-
}
367-
return;
368-
}
369-
370302
@ApiOperation({
371303
summary: 'Lists all API keys',
372304
})
@@ -400,14 +332,25 @@ export class AuthController implements OnModuleInit {
400332
type: 'string',
401333
},
402334
})
335+
@ApiHeader({
336+
name: 'x-user-jwt',
337+
description: "The user's ID token",
338+
required: true,
339+
schema: {
340+
type: 'string',
341+
},
342+
})
403343
@ApiBearerAuth('API_Key')
404344
@Get('key/all')
405345
async getAllApiKeys(
406346
@User() user: CommonProto.User,
407347
@Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number,
408348
@Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
409349
) {
410-
console.debug('User ', user);
350+
if (!user) {
351+
throw new UnauthorizedException('User ID token is required');
352+
}
353+
411354
let obs: Observable<GetAllApiKeysResponse>;
412355
if (user.type == CommonProto.UserType.SUPERADMIN) {
413356
// superadmins can list all projects

‎packages/api-gateway/src/modules/auth/auth.module.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export class AuthModule implements NestModule {
9999
.apply(ApiKeyMiddleware)
100100
.forRoutes(
101101
{ path: 'auth/key/all', method: RequestMethod.GET },
102-
{ path: 'auth/key/:id', method: RequestMethod.DELETE },
102+
{ path: 'auth/key', method: RequestMethod.DELETE },
103103
);
104104
}
105105
}

‎packages/api-gateway/test/auth.e2e-spec.ts‎

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ describe('List API Keys - GET /auth/key/all', () => {
325325
const response = await request(app.getHttpServer())
326326
.get('/auth/key/all')
327327
.set('Authorization', `Bearer ${apiKey}`)
328+
.set('x-user-jwt', regularUserJwt)
328329
.expect(200);
329330

330331
expect(response.body.keys).toBeDefined();
@@ -393,6 +394,7 @@ describe('List API Keys - GET /auth/key/all', () => {
393394
const response = await request(app.getHttpServer())
394395
.get(`/auth/key/all`)
395396
.set('Authorization', `Bearer ${apiKey}`)
397+
.set('x-user-jwt', adminJwt)
396398
.expect(200);
397399

398400
expect(response.body.keys).toBeDefined();
@@ -402,10 +404,10 @@ describe('List API Keys - GET /auth/key/all', () => {
402404

403405
it('should support offset and limit query parameters', async () => {
404406
const adminJwt = await getJwtForUser(ADMIN_EMAIL, ADMIN_PASSWORD);
405-
407+
const keys = [];
406408
// Create multiple API keys
407409
for (let i = 0; i < 3; i++) {
408-
await request(app.getHttpServer())
410+
const key = await request(app.getHttpServer())
409411
.post('/auth/key')
410412
.set('Authorization', `Bearer ${adminJwt}`)
411413
.send({
@@ -414,24 +416,27 @@ describe('List API Keys - GET /auth/key/all', () => {
414416
description: `pagination-key-${i}`,
415417
})
416418
.expect(201);
419+
keys.push(key);
417420
}
418421

422+
const apiKey = keys.at(0).body['apiKey'];
419423
const response = await request(app.getHttpServer())
420424
.get('/auth/key/all?offset=0&limit=2')
421-
.set('Authorization', `Bearer ${adminJwt}`)
425+
.set('Authorization', `Bearer ${apiKey}`)
426+
.set('x-user-jwt', adminJwt)
422427
.expect(200);
423428

424429
expect(response.body.keys).toBeDefined();
425430
expect(response.body.keys.length).toBeLessThanOrEqual(2);
426431
});
427432
});
428433

429-
describe('Delete API Key by ID - DELETE /auth/key/:id', () => {
430-
it('should delete an existing API key by its ID', async () => {
434+
describe('Delete API Key - DELETE /auth/key', () => {
435+
it('should delete an existing API key', async () => {
431436
const adminJwt = await getJwtForUser(ADMIN_EMAIL, ADMIN_PASSWORD);
432437

433438
// Create an API key
434-
const createResp = await request(app.getHttpServer())
439+
const key = await request(app.getHttpServer())
435440
.post('/auth/key')
436441
.set('Authorization', `Bearer ${adminJwt}`)
437442
.send({
@@ -440,46 +445,19 @@ describe('Delete API Key by ID - DELETE /auth/key/:id', () => {
440445
description: 'delete-by-id-test',
441446
})
442447
.expect(201);
448+
const apiKey = key.body['apiKey'];
449+
expect(apiKey).toBeDefined();
443450

444-
expect(createResp.body.apiKey).toBeDefined();
445-
446-
// List keys to find the created key's ID
447-
const listResp = await request(app.getHttpServer())
448-
.get('/auth/key/all?projectId=0')
449-
.set('Authorization', `Bearer ${adminJwt}`)
450-
.expect(200);
451-
452-
const createdKey = listResp.body.keys.find(
453-
(k: any) => k.description === 'delete-by-id-test',
454-
);
455-
expect(createdKey).toBeDefined();
456-
const keyId = createdKey.id;
457-
458-
// Delete the key by ID
451+
// Delete the key
459452
await request(app.getHttpServer())
460-
.delete(`/auth/key/${keyId}`)
461-
.set('Authorization', `Bearer ${adminJwt}`)
462-
.expect(200);
463-
});
464-
465-
it('should return 400 for a non-numeric ID', async () => {
466-
const adminJwt = await getJwtForUser(ADMIN_EMAIL, ADMIN_PASSWORD);
467-
return request(app.getHttpServer())
468-
.delete('/auth/key/abc')
469-
.set('Authorization', `Bearer ${adminJwt}`)
470-
.expect(400);
471-
});
472-
473-
it('should return an error for a non-existent API key ID', async () => {
474-
const adminJwt = await getJwtForUser(ADMIN_EMAIL, ADMIN_PASSWORD);
475-
return request(app.getHttpServer())
476-
.delete('/auth/key/999999')
477-
.set('Authorization', `Bearer ${adminJwt}`)
478-
.expect(404);
453+
.delete(`/auth/key`)
454+
.set('Authorization', `Bearer ${apiKey}`)
455+
.set('x-user-jwt', adminJwt)
456+
.expect(204);
479457
});
480458

481459
it('should not be accessible without authentication', () => {
482-
return request(app.getHttpServer()).delete('/auth/key/1').expect(401);
460+
return request(app.getHttpServer()).delete('/auth/key').expect(401);
483461
});
484462
});
485463

0 commit comments

Comments
 (0)