Show lightbox for GIFs

This commit is contained in:
Fedor Indutny 2021-07-14 16:39:52 -07:00 committed by GitHub
parent 62ab66c1c8
commit c3bdf3d411
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 790 additions and 815 deletions

View file

@ -7,6 +7,7 @@ import * as Attachment from '../../types/Attachment';
import * as MIME from '../../types/MIME';
import { SignalService } from '../../protobuf';
import { stringToArrayBuffer } from '../../../js/modules/string_to_array_buffer';
import * as logger from '../../logging/log';
describe('Attachment', () => {
describe('getUploadSizeLimitKb', () => {
@ -36,7 +37,7 @@ describe('Attachment', () => {
describe('getFileExtension', () => {
it('should return file extension from content type', () => {
const input: Attachment.Attachment = {
const input: Attachment.AttachmentType = {
data: stringToArrayBuffer('foo'),
contentType: MIME.IMAGE_GIF,
};
@ -44,7 +45,7 @@ describe('Attachment', () => {
});
it('should return file extension for QuickTime videos', () => {
const input: Attachment.Attachment = {
const input: Attachment.AttachmentType = {
data: stringToArrayBuffer('foo'),
contentType: MIME.VIDEO_QUICKTIME,
};
@ -55,7 +56,7 @@ describe('Attachment', () => {
describe('getSuggestedFilename', () => {
context('for attachment with filename', () => {
it('should return existing filename if present', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'funny-cat.mov',
data: stringToArrayBuffer('foo'),
contentType: MIME.VIDEO_QUICKTIME,
@ -67,7 +68,7 @@ describe('Attachment', () => {
});
context('for attachment without filename', () => {
it('should generate a filename based on timestamp', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
data: stringToArrayBuffer('foo'),
contentType: MIME.VIDEO_QUICKTIME,
};
@ -82,7 +83,7 @@ describe('Attachment', () => {
});
context('for attachment with index', () => {
it('should generate a filename based on timestamp', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
data: stringToArrayBuffer('foo'),
contentType: MIME.VIDEO_QUICKTIME,
};
@ -100,7 +101,7 @@ describe('Attachment', () => {
describe('isVisualMedia', () => {
it('should return true for images', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'meme.gif',
data: stringToArrayBuffer('gif'),
contentType: MIME.IMAGE_GIF,
@ -109,7 +110,7 @@ describe('Attachment', () => {
});
it('should return true for videos', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'meme.mp4',
data: stringToArrayBuffer('mp4'),
contentType: MIME.VIDEO_MP4,
@ -118,7 +119,7 @@ describe('Attachment', () => {
});
it('should return false for voice message attachment', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'Voice Message.aac',
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
data: stringToArrayBuffer('voice message'),
@ -128,7 +129,7 @@ describe('Attachment', () => {
});
it('should return false for other attachments', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'foo.json',
data: stringToArrayBuffer('{"foo": "bar"}'),
contentType: MIME.APPLICATION_JSON,
@ -139,7 +140,7 @@ describe('Attachment', () => {
describe('isFile', () => {
it('should return true for JSON', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'foo.json',
data: stringToArrayBuffer('{"foo": "bar"}'),
contentType: MIME.APPLICATION_JSON,
@ -148,7 +149,7 @@ describe('Attachment', () => {
});
it('should return false for images', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'meme.gif',
data: stringToArrayBuffer('gif'),
contentType: MIME.IMAGE_GIF,
@ -157,7 +158,7 @@ describe('Attachment', () => {
});
it('should return false for videos', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'meme.mp4',
data: stringToArrayBuffer('mp4'),
contentType: MIME.VIDEO_MP4,
@ -166,7 +167,7 @@ describe('Attachment', () => {
});
it('should return false for voice message attachment', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'Voice Message.aac',
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
data: stringToArrayBuffer('voice message'),
@ -178,7 +179,7 @@ describe('Attachment', () => {
describe('isVoiceMessage', () => {
it('should return true for voice message attachment', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'Voice Message.aac',
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
data: stringToArrayBuffer('voice message'),
@ -188,7 +189,7 @@ describe('Attachment', () => {
});
it('should return true for legacy Android voice message attachment', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
data: stringToArrayBuffer('voice message'),
contentType: MIME.AUDIO_MP3,
};
@ -196,7 +197,7 @@ describe('Attachment', () => {
});
it('should return false for other attachments', () => {
const attachment: Attachment.Attachment = {
const attachment: Attachment.AttachmentType = {
fileName: 'foo.gif',
data: stringToArrayBuffer('foo'),
contentType: MIME.IMAGE_GIF,
@ -204,4 +205,222 @@ describe('Attachment', () => {
assert.isFalse(Attachment.isVoiceMessage(attachment));
});
});
describe('replaceUnicodeOrderOverrides', () => {
it('should sanitize left-to-right order override character', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\u202Dfig.exe',
size: 1111,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\uFFFDfig.exe',
size: 1111,
};
const actual = await Attachment.replaceUnicodeOrderOverrides(input);
assert.deepEqual(actual, expected);
});
it('should sanitize right-to-left order override character', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\u202Efig.exe',
size: 1111,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\uFFFDfig.exe',
size: 1111,
};
const actual = await Attachment.replaceUnicodeOrderOverrides(input);
assert.deepEqual(actual, expected);
});
it('should sanitize multiple override characters', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\u202e\u202dlol\u202efig.exe',
size: 1111,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
fileName: 'test\uFFFD\uFFFDlol\uFFFDfig.exe',
size: 1111,
};
const actual = await Attachment.replaceUnicodeOrderOverrides(input);
assert.deepEqual(actual, expected);
});
it('should ignore non-order-override characters', () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'abc',
size: 1111,
};
const actual = Attachment._replaceUnicodeOrderOverridesSync(input);
assert.deepEqual(actual, input);
});
it('should replace order-override characters', () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'abc\u202D\u202E',
size: 1111,
};
const actual = Attachment._replaceUnicodeOrderOverridesSync(input);
assert.deepEqual(actual, {
contentType: MIME.IMAGE_JPEG,
fileName: 'abc\uFFFD\uFFFD',
size: 1111,
});
});
});
describe('replaceUnicodeV2', () => {
it('should remove all bad characters', async () => {
const input = {
size: 1111,
contentType: MIME.IMAGE_JPEG,
fileName:
'file\u202A\u202B\u202C\u202D\u202E\u2066\u2067\u2068\u2069\u200E\u200F\u061C.jpeg',
};
const expected = {
fileName:
'file\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.jpeg',
contentType: MIME.IMAGE_JPEG,
size: 1111,
};
const actual = await Attachment.replaceUnicodeV2(input);
assert.deepEqual(actual, expected);
});
it('should should leave normal filename alone', async () => {
const input = {
fileName: 'normal.jpeg',
contentType: MIME.IMAGE_JPEG,
size: 1111,
};
const expected = {
fileName: 'normal.jpeg',
contentType: MIME.IMAGE_JPEG,
size: 1111,
};
const actual = await Attachment.replaceUnicodeV2(input);
assert.deepEqual(actual, expected);
});
it('should handle missing fileName', async () => {
const input = {
size: 1111,
contentType: MIME.IMAGE_JPEG,
};
const expected = {
size: 1111,
contentType: MIME.IMAGE_JPEG,
};
const actual = await Attachment.replaceUnicodeV2(input);
assert.deepEqual(actual, expected);
});
});
describe('removeSchemaVersion', () => {
it('should remove existing schema version', () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'foo.jpg',
size: 1111,
schemaVersion: 1,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
fileName: 'foo.jpg',
size: 1111,
};
const actual = Attachment.removeSchemaVersion({
attachment: input,
logger,
});
assert.deepEqual(actual, expected);
});
});
describe('migrateDataToFileSystem', () => {
it('should write data to disk and store relative path to it', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
data: stringToArrayBuffer('Above us only sky'),
fileName: 'foo.jpg',
size: 1111,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
path: 'abc/abcdefgh123456789',
fileName: 'foo.jpg',
size: 1111,
};
const expectedAttachmentData = stringToArrayBuffer('Above us only sky');
const writeNewAttachmentData = async (attachmentData: ArrayBuffer) => {
assert.deepEqual(attachmentData, expectedAttachmentData);
return 'abc/abcdefgh123456789';
};
const actual = await Attachment.migrateDataToFileSystem(input, {
writeNewAttachmentData,
});
assert.deepEqual(actual, expected);
});
it('should skip over (invalid) attachments without data', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
fileName: 'foo.jpg',
size: 1111,
};
const expected = {
contentType: MIME.IMAGE_JPEG,
fileName: 'foo.jpg',
size: 1111,
};
const writeNewAttachmentData = async () => 'abc/abcdefgh123456789';
const actual = await Attachment.migrateDataToFileSystem(input, {
writeNewAttachmentData,
});
assert.deepEqual(actual, expected);
});
it('should throw error if data is not valid', async () => {
const input = {
contentType: MIME.IMAGE_JPEG,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: 123 as any,
fileName: 'foo.jpg',
size: 1111,
};
const writeNewAttachmentData = async () => 'abc/abcdefgh123456789';
await assert.isRejected(
Attachment.migrateDataToFileSystem(input, {
writeNewAttachmentData,
}),
'Expected `attachment.data` to be an array buffer; got: number'
);
});
});
});