Skip to content

Commit 255c322

Browse files
committed
fix(media): remove application header requirement for getting public media
1 parent 9bd72c8 commit 255c322

File tree

5 files changed

+26
-15
lines changed

5 files changed

+26
-15
lines changed

src/auth/decorator/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './get-user.decorator';
22
export * from './require-permission.decorator';
33
export * from './public.decorator';
44
export * from './require-role.decorator';
5+
export * from './skip-application-check.decorator';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Reflector } from '@nestjs/core';
2+
3+
export const SkipApplicationCheck = Reflector.createDecorator();

src/auth/guard/jwt.guard.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
import { ExecutionContext, Injectable } from '@nestjs/common';
22
import { Reflector } from '@nestjs/core';
33
import { AuthGuard } from '@nestjs/passport';
4-
import { IsPublic } from '../decorator';
4+
import { IsPublic, SkipApplicationCheck } from '../decorator';
55
import { AppException, ERROR_CODE } from '../../exceptions';
66
import { RequestAuthData } from '../interfaces/request-auth-data.interface';
77
import { PrismaService } from '../../prisma/prisma.service';
88
import { PermissionManager } from '../../utils';
9+
import { RawApiApplication } from '../../prisma/types';
910

1011
@Injectable()
1112
export class JwtGuard extends AuthGuard('jwt') {
12-
constructor(private reflector: Reflector, private prisma: PrismaService) {
13+
constructor(
14+
private reflector: Reflector,
15+
private prisma: PrismaService,
16+
) {
1317
super();
1418
}
1519

1620
async canActivate(context: ExecutionContext) {
1721
const request = context.switchToHttp().getRequest() as { user: RequestAuthData };
22+
const canSkipApplicationHeader = this.reflector.get(SkipApplicationCheck, context.getHandler());
1823
const applicationId = context.switchToHttp().getRequest().headers['x-application'];
19-
if (!applicationId) throw new AppException(ERROR_CODE.APPLICATION_HEADER_MISSING);
20-
const application = await this.prisma.apiApplication.findUnique({
21-
where: { id: applicationId },
22-
});
23-
if (!application) {
24-
throw new AppException(ERROR_CODE.NO_SUCH_APPLICATION, applicationId);
24+
let application: RawApiApplication | null = null;
25+
if (!applicationId && !canSkipApplicationHeader) throw new AppException(ERROR_CODE.APPLICATION_HEADER_MISSING);
26+
else if (applicationId) {
27+
application = await this.prisma.apiApplication.findUnique({
28+
where: { id: applicationId },
29+
});
30+
if (!application) throw new AppException(ERROR_CODE.NO_SUCH_APPLICATION, applicationId);
2531
}
2632
// Check whether the user is logged in
2733
let loggedIn = true;

src/media/image/imagemedia.controller.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Controller, Get, Post, Query, Response } from '@nestjs/common';
22
import { ApiConsumes, ApiCreatedResponse, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
33
import { Response as ExpressResponse } from 'express';
44
import { FileSize, MulterWithMime, UploadRoute, UserFile } from '../../upload.interceptor';
5-
import { GetUser, IsPublic, RequireApiPermission } from '../../auth/decorator';
5+
import { GetUser, IsPublic, RequireApiPermission, SkipApplicationCheck } from '../../auth/decorator';
66
import { AppException, ERROR_CODE } from '../../exceptions';
77
import { ApiAppErrorResponse } from '../../app.dto';
88
import { ImageMediaService } from './imagemedia.service';
@@ -17,7 +17,8 @@ import ImageMediaUploadResDto from './dto/res/imagemedia-upload-res.dto';
1717
export class ImageMediaController {
1818
constructor(readonly imageMediaService: ImageMediaService) {}
1919

20-
@Get('/:mediaId')
20+
@Get('/:mediaId.webp')
21+
@SkipApplicationCheck()
2122
@IsPublic()
2223
@ApiOperation({ description: 'Retrieve a media by its id.' })
2324
@ApiOkResponse({ description: 'The media is contained in the body of the response' })

test/e2e/media/image/get-media.e2e-spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ export const GetMediaE2ESpec = e2eSuite('GET /media/image/:mediaId', (app) => {
2929
});
3030

3131
it('should return a 404 as the media does not exist', () =>
32-
pactum.spec().get(`/media/image/${Dummies.UUID}`).expectAppError(ERROR_CODE.NO_SUCH_MEDIA, Dummies.UUID));
32+
pactum.spec().get(`/media/image/${Dummies.UUID}.webp`).expectAppError(ERROR_CODE.NO_SUCH_MEDIA, Dummies.UUID));
3333

3434
it('should return a 401 as the media is not public', () =>
35-
pactum.spec().get(`/media/image/${nonPublicMedia.id}`).expectAppError(ERROR_CODE.NOT_LOGGED_IN));
35+
pactum.spec().get(`/media/image/${nonPublicMedia.id}.webp`).expectAppError(ERROR_CODE.NOT_LOGGED_IN));
3636

3737
it('should return a 200 and the media (public)', () =>
3838
pactum
3939
.spec()
40-
.get(`/media/image/${publicMedia.id}`)
40+
.get(`/media/image/${publicMedia.id}.webp`)
4141
.expectStatus(200)
4242
.expectHeader('content-type', 'image/webp')
4343
.expectBodyContains('RIFF'));
@@ -46,11 +46,11 @@ export const GetMediaE2ESpec = e2eSuite('GET /media/image/:mediaId', (app) => {
4646
pactum
4747
.spec()
4848
.withBearerToken(user.token)
49-
.get(`/media/image/${nonPublicMedia.id}`)
49+
.get(`/media/image/${nonPublicMedia.id}.webp`)
5050
.expectStatus(200)
5151
.expectHeader('content-type', 'image/webp')
5252
.expectBodyContains('RIFF'));
5353

5454
it('should return a 503 as there is an error reading the file', () =>
55-
pactum.spec().get(`/media/image/${publicMediaInError.id}`).expectAppError(ERROR_CODE.SERVER_DISK_ERROR));
55+
pactum.spec().get(`/media/image/${publicMediaInError.id}.webp`).expectAppError(ERROR_CODE.SERVER_DISK_ERROR));
5656
});

0 commit comments

Comments
 (0)