Allow PSD uploads over 6MB

You can't currently upload PSD files over 6MB. This is because its
mimetype is `image/vnd.adobe.photoshop`. We think this is an image, and
non-GIF images have a limit of 6MB.

To fix this, we could do one of two things:

1. Add a special case for PSD files
2. Increase the size limit for unsupported image types such as this

I went with the second option.

Tested this by:

- adding automated tests
- uploading a ~9 MB PSD file
- uploading a ~1 MB PNG
- uploading a ~27 MB PNG (which worked because it's converted to a smaller JPEG)
- uploading a ~50 MB text file
- trying to upload a ~500 MB text file (which failed, as expected)

Addresses [DESKTOP-1168][].

[DESKTOP-1168]: https://signalmessenger.atlassian.net/browse/DESKTOP-1168
This commit is contained in:
Evan Hahn 2021-02-09 14:11:07 -06:00 committed by Scott Nonnenberg
parent 92e5ccd764
commit 4519aa4abf
7 changed files with 64 additions and 25 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2018-2020 Signal Messenger, LLC
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
const is = require('@sindresorhus/is');
@ -217,6 +217,7 @@ exports.isImage = AttachmentTS.isImage;
exports.isVideo = AttachmentTS.isVideo;
exports.isAudio = AttachmentTS.isAudio;
exports.isVoiceMessage = AttachmentTS.isVoiceMessage;
exports.getUploadSizeLimitKb = AttachmentTS.getUploadSizeLimitKb;
exports.save = AttachmentTS.save;
const THUMBNAIL_SIZE = 150;

View File

@ -1,4 +1,4 @@
// Copyright 2018-2020 Signal Messenger, LLC
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
@ -9,6 +9,31 @@ import { SignalService } from '../../protobuf';
import { stringToArrayBuffer } from '../../../js/modules/string_to_array_buffer';
describe('Attachment', () => {
describe('getUploadSizeLimitKb', () => {
const { getUploadSizeLimitKb } = Attachment;
it('returns 6000 kilobytes for supported non-GIF images', () => {
assert.strictEqual(getUploadSizeLimitKb(MIME.IMAGE_JPEG), 6000);
assert.strictEqual(getUploadSizeLimitKb(MIME.IMAGE_PNG), 6000);
assert.strictEqual(getUploadSizeLimitKb(MIME.IMAGE_WEBP), 6000);
});
it('returns 25000 kilobytes for GIFs', () => {
assert.strictEqual(getUploadSizeLimitKb(MIME.IMAGE_GIF), 25000);
});
it('returns 100000 for other file types', () => {
assert.strictEqual(getUploadSizeLimitKb(MIME.APPLICATION_JSON), 100000);
assert.strictEqual(getUploadSizeLimitKb(MIME.AUDIO_AAC), 100000);
assert.strictEqual(getUploadSizeLimitKb(MIME.AUDIO_MP3), 100000);
assert.strictEqual(getUploadSizeLimitKb(MIME.VIDEO_MP4), 100000);
assert.strictEqual(
getUploadSizeLimitKb('image/vnd.adobe.photoshop' as MIME.MIMEType),
100000
);
});
});
describe('getFileExtension', () => {
it('should return file extension from content type', () => {
const input: Attachment.Attachment = {

View File

@ -0,0 +1,19 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import * as MIME from '../../types/MIME';
describe('MIME', () => {
describe('isGif', () => {
it('returns true for GIFs', () => {
assert.isTrue(MIME.isGif('image/gif'));
});
it('returns false for non-GIFs', () => {
assert.isFalse(MIME.isGif('image/jpeg'));
assert.isFalse(MIME.isGif('text/plain'));
});
});
});

View File

@ -431,3 +431,13 @@ export const getFileExtension = (
return attachment.contentType.split('/')[1];
}
};
export const getUploadSizeLimitKb = (contentType: MIME.MIMEType): number => {
if (MIME.isGif(contentType)) {
return 25000;
}
if (isImageTypeSupported(contentType)) {
return 6000;
}
return 100000;
};

View File

@ -17,6 +17,8 @@ export const VIDEO_MP4 = 'video/mp4' as MIMEType;
export const VIDEO_QUICKTIME = 'video/quicktime' as MIMEType;
export const LONG_MESSAGE = 'text/x-signal-plain' as MIMEType;
export const isGif = (value: string): value is MIMEType =>
value === 'image/gif';
export const isJPEG = (value: string): value is MIMEType =>
value === 'image/jpeg';
export const isImage = (value: string): value is MIMEType =>

View File

@ -1695,29 +1695,9 @@ Whisper.ConversationView = Whisper.View.extend({
},
isSizeOkay(attachment: any) {
let limitKb = 1000000;
const type =
attachment.contentType === 'image/gif'
? 'gif'
: attachment.contentType.split('/')[0];
switch (type) {
case 'image':
limitKb = 6000;
break;
case 'gif':
limitKb = 25000;
break;
case 'audio':
limitKb = 100000;
break;
case 'video':
limitKb = 100000;
break;
default:
limitKb = 100000;
break;
}
const limitKb = window.Signal.Types.Attachment.getUploadSizeLimitKb(
attachment.contentType
);
// this needs to be cast properly
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore

2
ts/window.d.ts vendored
View File

@ -358,6 +358,8 @@ declare global {
isImage: typeof Attachment.isImage;
isVideo: typeof Attachment.isVideo;
isAudio: typeof Attachment.isAudio;
getUploadSizeLimitKb: typeof Attachment.getUploadSizeLimitKb;
};
MIME: typeof MIME;
Contact: typeof Contact;