Skip to content

Commit

Permalink
Merge pull request #226 from esek/fix/max-avatar-size
Browse files Browse the repository at this point in the history
[FIX] Add max to file uploads
  • Loading branch information
ginger51011 authored Aug 17, 2022
2 parents 8fcf2b4 + 196f566 commit 13540ff
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ DB_HOST=postgres://postgres:password@localhost:5432/ekorre_foot

# File settings
FILES_ENDPOINT=/files
MAX_AVATAR_SIZE_MB=5
MAX_FILE_UPLOAD_SIZE_MB=25

# EBrev settings
EBREV=http://localhost:8081
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Alla märkbara ändringar ska dokumenteras i denna fil.
Baserat på [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
och följer [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.3] - 2022-08-17

### Ändrat
- Lagt till maxstorlek på användares avatarer
- Lagt till allmän maxstorlek på filer

## [1.0.2] - 2022-08-16

### Ändrat
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ekorre-ts",
"version": "1.0.2",
"version": "1.0.3",
"description": "E-Sektionens backend",
"main": "src/index.ts",
"scripts": {
Expand Down
7 changes: 6 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import dotenv from 'dotenv';
import path from 'path';
import { BYTES_PER_MB } from './util';

// Read dot-env file
dotenv.config();
Expand All @@ -8,11 +9,15 @@ dotenv.config();
* Config for file-handling
* @param {string} ENDPOINT - The endpoint in Ekorre to expose with files (ex. https://api.esek.se/{endpoint})
* @param {string} ROOT - The root folder to save files in
* @param {number} MAX_AVATAR_SIZE_BYTES - Maximum size for users profile pictures (avatars) in bytes
* @param {number} MAX_FILE_UPLOAD_SIZE_BYTES - Maximum size for all uploaded files in bytes
*/

const FILES = {
ENDPOINT: process.env.FILES_ENDPOINT ?? '/files',
ROOT: `${path.dirname(__dirname)}/public`,
MAX_AVATAR_SIZE_BYTES: Number.parseInt(process.env.MAX_AVATAR_SIZE_MB ?? '1') * BYTES_PER_MB, // Default 1 MB
MAX_FILE_UPLOAD_SIZE_BYTES:
Number.parseInt(process.env.MAX_FILE_UPLOAD_SIZE_MB ?? '20') * BYTES_PER_MB, // Default 20 MB
};

/**
Expand Down
19 changes: 18 additions & 1 deletion src/routes/file.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import config from '@/config';
import RequestError from '@/errors/request.errors';
import { Logger } from '@/logger';
import { reduce } from '@/reducers';
import { BYTES_PER_MB } from '@/util';
import FileAPI from '@api/file';
import { UserAPI } from '@api/user';
import { AccessType } from '@generated/graphql';
Expand Down Expand Up @@ -51,6 +52,13 @@ filesRoute.post('/upload', upload(), verifyAuthenticated, async (req, res) => {
}

const file = files.file instanceof Array ? files.file[0] : files.file;

// Check file size (file.size is in bytes)
const maxSize = config.FILES.MAX_FILE_UPLOAD_SIZE_BYTES;
if (file.size > maxSize) {
return res.status(413).send(`File too big, max is ${maxSize / BYTES_PER_MB} MB`);
}

const accessType = body?.accessType ?? AccessType.Public;
const path = body?.path ?? '/';
const dbFile = await fileApi.saveFile(file, accessType, path, res.locals.user.username);
Expand All @@ -66,6 +74,16 @@ filesRoute.post('/upload/avatar', upload(), verifyAuthenticated, async (req, res
return res.status(400).send('File missing');
}

const file = files.file instanceof Array ? files.file[0] : files.file;

// Check if file is too big (file.size is in bytes)
const maxAvatarSize = config.FILES.MAX_AVATAR_SIZE_BYTES;
const maxSize = config.FILES.MAX_FILE_UPLOAD_SIZE_BYTES;
const sizeConstraint = Math.min(maxAvatarSize, maxSize);
if (file.size > sizeConstraint) {
return res.status(413).send(`Avatar too big, max is ${sizeConstraint / BYTES_PER_MB} MB`);
}

const { user } = res.locals;

const { username, photoUrl } = user;
Expand All @@ -87,7 +105,6 @@ filesRoute.post('/upload/avatar', upload(), verifyAuthenticated, async (req, res

const path = 'avatars';

const file = files.file instanceof Array ? files.file[0] : files.file;
const accessType = AccessType.Public;

const dbFile = await fileApi.saveFile(file, accessType, path, username);
Expand Down
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,6 @@ export const devGuard = (message = 'Cannot do that in production'): void => {
throw new ServerError(message);
}
};

// Number of bytes in a megabyte
export const BYTES_PER_MB = 1e6;
2 changes: 1 addition & 1 deletion test/integration/file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ describe('avatars', () => {
const res = await uploadFile(file1).attach('file', path(file2)).expect(200);

expect(res.body).toMatchObject({
accessType: AccessType.Authenticated,
accessType: AccessType.Public, // Public by default
name: file1,
});

Expand Down

0 comments on commit 13540ff

Please sign in to comment.