move Attachments and Attachments_test to typescript

pull/1554/head
Audric Ackermann 4 years ago
parent 42f0d21740
commit ccf8a31ae3
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -1,5 +1,5 @@
const electron = require('electron');
const Attachments = require('./attachments');
const Attachments = require('../ts/attachments/attachments');
const rimraf = require('rimraf');
const { ipcMain } = electron;

@ -64,7 +64,7 @@ const appInstance = config.util.getEnv('NODE_APP_INSTANCE') || 0;
// We generally want to pull in our own modules after this point, after the user
// data directory has been set.
const attachments = require('./app/attachments');
const attachments = require('./ts/attachments/attachments');
const attachmentChannel = require('./app/attachment_channel');
const updater = require('./ts/updater/index');

@ -165,6 +165,7 @@
"@types/semver": "5.5.0",
"@types/sinon": "9.0.4",
"@types/styled-components": "^5.1.4",
"@types/tmp": "^0.2.0",
"@types/uuid": "3.4.4",
"arraybuffer-loader": "1.0.3",
"asar": "0.14.0",

@ -332,7 +332,7 @@ window.nodeSetImmediate = setImmediate;
const Signal = require('./js/modules/signal');
const i18n = require('./js/modules/i18n');
const Attachments = require('./app/attachments');
const Attachments = require('./ts/attachments/attachments');
window.Signal = Signal.setup({
Attachments,

@ -1,32 +0,0 @@
/* global Whisper */
describe('LastSeenIndicatorView', () => {
it('renders provided count', () => {
const view = new Whisper.LastSeenIndicatorView({ count: 10 });
assert.equal(view.count, 10);
view.render();
assert.match(view.$el.html(), /10 Unread Messages/);
});
it('renders count of 1', () => {
const view = new Whisper.LastSeenIndicatorView({ count: 1 });
assert.equal(view.count, 1);
view.render();
assert.match(view.$el.html(), /1 Unread Message/);
});
it('increments count', () => {
const view = new Whisper.LastSeenIndicatorView({ count: 4 });
assert.equal(view.count, 4);
view.render();
assert.match(view.$el.html(), /4 Unread Messages/);
view.increment(3);
assert.equal(view.count, 7);
view.render();
assert.match(view.$el.html(), /7 Unread Messages/);
});
});

@ -1,16 +1,19 @@
const crypto = require('crypto');
const path = require('path');
const pify = require('pify');
const glob = require('glob');
const fse = require('fs-extra');
const toArrayBuffer = require('to-arraybuffer');
const { map, isArrayBuffer, isString } = require('lodash');
const AttachmentTS = require('../ts/types/Attachment');
import crypto from 'crypto';
import path from 'path';
import pify from 'pify';
import { default as glob } from 'glob';
import fse from 'fs-extra';
import toArrayBuffer from 'to-arraybuffer';
import { isArrayBuffer, isString, map } from 'lodash';
import {
decryptAttachmentBuffer,
encryptAttachmentBuffer,
} from '../../ts/types/Attachment';
const PATH = 'attachments.noindex';
exports.getAllAttachments = async userDataPath => {
export const getAllAttachments = async (userDataPath: string) => {
const dir = exports.getPath(userDataPath);
const pattern = path.join(dir, '**', '*');
@ -19,7 +22,7 @@ exports.getAllAttachments = async userDataPath => {
};
// getPath :: AbsolutePath -> AbsolutePath
exports.getPath = userDataPath => {
export const getPath = (userDataPath: string) => {
if (!isString(userDataPath)) {
throw new TypeError("'userDataPath' must be a string");
}
@ -27,7 +30,7 @@ exports.getPath = userDataPath => {
};
// ensureDirectory :: AbsolutePath -> IO Unit
exports.ensureDirectory = async userDataPath => {
export const ensureDirectory = async (userDataPath: string) => {
if (!isString(userDataPath)) {
throw new TypeError("'userDataPath' must be a string");
}
@ -37,12 +40,12 @@ exports.ensureDirectory = async userDataPath => {
// createReader :: AttachmentsPath ->
// RelativePath ->
// IO (Promise ArrayBuffer)
exports.createReader = root => {
export const createReader = (root: string) => {
if (!isString(root)) {
throw new TypeError("'root' must be a path");
}
return async relativePath => {
return async (relativePath: string) => {
if (!isString(relativePath)) {
throw new TypeError("'relativePath' must be a string");
}
@ -52,9 +55,8 @@ exports.createReader = root => {
throw new Error('Invalid relative path');
}
const buffer = await fse.readFile(normalized);
const decryptedData = await AttachmentTS.decryptAttachmentBuffer(
toArrayBuffer(buffer)
);
const decryptedData = await decryptAttachmentBuffer(toArrayBuffer(buffer));
return decryptedData.buffer;
};
@ -63,12 +65,12 @@ exports.createReader = root => {
// createWriterForNew :: AttachmentsPath ->
// ArrayBuffer ->
// IO (Promise RelativePath)
exports.createWriterForNew = root => {
export const createWriterForNew = (root: string) => {
if (!isString(root)) {
throw new TypeError("'root' must be a path");
}
return async arrayBuffer => {
return async (arrayBuffer: ArrayBuffer) => {
if (!isArrayBuffer(arrayBuffer)) {
throw new TypeError("'arrayBuffer' must be an array buffer");
}
@ -85,12 +87,15 @@ exports.createWriterForNew = root => {
// createWriter :: AttachmentsPath ->
// { data: ArrayBuffer, path: RelativePath } ->
// IO (Promise RelativePath)
exports.createWriterForExisting = root => {
export const createWriterForExisting = (root: any) => {
if (!isString(root)) {
throw new TypeError("'root' must be a path");
}
return async ({ data: arrayBuffer, path: relativePath } = {}) => {
return async ({
data: arrayBuffer,
path: relativePath,
}: { data?: ArrayBuffer; path?: string } = {}) => {
if (!isString(relativePath)) {
throw new TypeError("'relativePath' must be a path");
}
@ -106,9 +111,9 @@ exports.createWriterForExisting = root => {
}
await fse.ensureFile(normalized);
const {
encryptedBufferWithHeader,
} = await AttachmentTS.encryptAttachmentBuffer(arrayBuffer);
const { encryptedBufferWithHeader } = await encryptAttachmentBuffer(
arrayBuffer
);
const buffer = Buffer.from(encryptedBufferWithHeader.buffer);
await fse.writeFile(normalized, buffer);
@ -120,12 +125,12 @@ exports.createWriterForExisting = root => {
// createDeleter :: AttachmentsPath ->
// RelativePath ->
// IO Unit
exports.createDeleter = root => {
export const createDeleter = (root: any) => {
if (!isString(root)) {
throw new TypeError("'root' must be a path");
}
return async relativePath => {
return async (relativePath: any) => {
if (!isString(relativePath)) {
throw new TypeError("'relativePath' must be a string");
}
@ -139,9 +144,10 @@ exports.createDeleter = root => {
};
};
exports.deleteAll = async ({ userDataPath, attachments }) => {
export const deleteAll = async ({ userDataPath, attachments }: any) => {
const deleteFromDisk = exports.createDeleter(exports.getPath(userDataPath));
// tslint:disable-next-line: one-variable-per-declaration
for (let index = 0, max = attachments.length; index < max; index += 1) {
const file = attachments[index];
// eslint-disable-next-line no-await-in-loop
@ -152,13 +158,13 @@ exports.deleteAll = async ({ userDataPath, attachments }) => {
};
// createName :: Unit -> IO String
exports.createName = () => {
export const createName = () => {
const buffer = crypto.randomBytes(32);
return buffer.toString('hex');
};
// getRelativePath :: String -> Path
exports.getRelativePath = name => {
export const getRelativePath = (name: any) => {
if (!isString(name)) {
throw new TypeError("'name' must be a string");
}
@ -168,7 +174,9 @@ exports.getRelativePath = name => {
};
// createAbsolutePathGetter :: RootPath -> RelativePath -> AbsolutePath
exports.createAbsolutePathGetter = rootPath => relativePath => {
export const createAbsolutePathGetter = (rootPath: string) => (
relativePath: string
) => {
const absolutePath = path.join(rootPath, relativePath);
const normalized = path.normalize(absolutePath);
if (!normalized.startsWith(rootPath)) {

@ -8,6 +8,7 @@ import { Lightbox } from './Lightbox';
import { Message } from './conversation/media-gallery/types/Message';
import { AttachmentType } from '../types/Attachment';
// tslint:disable-next-line: no-submodule-imports
import useKey from 'react-use/lib/useKey';
export interface MediaItemType {

@ -77,7 +77,6 @@ import { ToastUtils, UserUtils } from '../../session/utils';
import { ConversationController } from '../../session/conversations';
import { MessageRegularProps } from '../../models/messageType';
import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch';
import src from 'redux-promise-middleware';
// Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;

@ -41,3 +41,11 @@ export const fromBase64ToArray = (d: string) =>
export const fromArrayBufferToBase64 = (d: BufferType) => decode(d, 'base64');
export const fromUInt8ArrayToBase64 = (d: Uint8Array) => decode(d, 'base64');
export const stringToArrayBuffer = (str: string): ArrayBuffer => {
if (typeof str !== 'string') {
throw new TypeError("'string' must be a string");
}
return encode(str, 'binary');
};

@ -1,27 +1,38 @@
const fse = require('fs-extra');
const path = require('path');
const tmp = require('tmp');
const { assert } = require('chai');
const Attachments = require('../../app/attachments');
const {
stringToArrayBuffer,
} = require('../../js/modules/string_to_array_buffer');
import fse from 'fs-extra';
import path from 'path';
import tmp from 'tmp';
import { assert } from 'chai';
import * as Attachments from '../../../../attachments/attachments';
import { stringToArrayBuffer } from '../../../../session/utils/String';
import {
decryptAttachmentBuffer,
encryptAttachmentBuffer,
} from '../../../../types/Attachment';
import { TestUtils } from '../../../test-utils';
const PREFIX_LENGTH = 2;
const NUM_SEPARATORS = 1;
const NAME_LENGTH = 64;
const PATH_LENGTH = PREFIX_LENGTH + NUM_SEPARATORS + NAME_LENGTH;
// tslint:disable-next-line: max-func-body-length
describe('Attachments', () => {
describe('createWriterForNew', () => {
let tempRootDirectory = null;
let tempRootDirectory: any = null;
before(() => {
tempRootDirectory = tmp.dirSync().name;
TestUtils.stubWindow('textsecure', {
storage: {
get: () =>
'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
},
});
});
after(async () => {
await fse.remove(tempRootDirectory);
TestUtils.restoreStubs();
});
it('should write file to disk and return path', async () => {
@ -37,19 +48,30 @@ describe('Attachments', () => {
assert.lengthOf(outputPath, PATH_LENGTH);
const outputDecrypted = Buffer.from(
await decryptAttachmentBuffer(output.buffer)
);
const inputBuffer = Buffer.from(input);
assert.deepEqual(inputBuffer, output);
assert.deepEqual(inputBuffer, outputDecrypted);
});
});
describe('createWriterForExisting', () => {
let tempRootDirectory = null;
let tempRootDirectory: any = null;
before(() => {
tempRootDirectory = tmp.dirSync().name;
TestUtils.stubWindow('textsecure', {
storage: {
get: () =>
'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
},
});
});
after(async () => {
await fse.remove(tempRootDirectory);
TestUtils.restoreStubs();
});
it('should write file to disk on given path and return path', async () => {
@ -72,9 +94,11 @@ describe('Attachments', () => {
const output = await fse.readFile(path.join(tempDirectory, outputPath));
assert.equal(outputPath, relativePath);
const outputDecrypted = Buffer.from(
await decryptAttachmentBuffer(output.buffer)
);
const inputBuffer = Buffer.from(input);
assert.deepEqual(inputBuffer, output);
assert.deepEqual(inputBuffer, outputDecrypted);
});
it('throws if relative path goes higher than root', async () => {
@ -101,13 +125,20 @@ describe('Attachments', () => {
});
describe('createReader', () => {
let tempRootDirectory = null;
let tempRootDirectory: any = null;
before(() => {
tempRootDirectory = tmp.dirSync().name;
TestUtils.stubWindow('textsecure', {
storage: {
get: () =>
'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
},
});
});
after(async () => {
await fse.remove(tempRootDirectory);
TestUtils.restoreStubs();
});
it('should read file from disk', async () => {
@ -122,14 +153,15 @@ describe('Attachments', () => {
const fullPath = path.join(tempDirectory, relativePath);
const input = stringToArrayBuffer('test string');
const inputBuffer = Buffer.from(input);
const encryptedInput = await encryptAttachmentBuffer(input);
const inputBuffer = Buffer.from(encryptedInput.encryptedBufferWithHeader);
await fse.ensureFile(fullPath);
await fse.writeFile(fullPath, inputBuffer);
const output = await Attachments.createReader(tempDirectory)(
const outputDecrypted = await Attachments.createReader(tempDirectory)(
relativePath
);
assert.deepEqual(input, output);
assert.deepEqual(new Uint8Array(input), new Uint8Array(outputDecrypted));
});
it('throws if relative path goes higher than root', async () => {
@ -152,7 +184,7 @@ describe('Attachments', () => {
});
describe('createDeleter', () => {
let tempRootDirectory = null;
let tempRootDirectory: any = null;
before(() => {
tempRootDirectory = tmp.dirSync().name;
});
@ -178,7 +210,7 @@ describe('Attachments', () => {
await fse.writeFile(fullPath, inputBuffer);
await Attachments.createDeleter(tempDirectory)(relativePath);
const existsFile = await fse.exists(fullPath);
const existsFile = fse.existsSync(fullPath);
assert.isFalse(existsFile);
});

@ -10,9 +10,8 @@ import {
isVideoTypeSupported,
} from '../util/GoogleChrome';
import { LocalizerType } from './Util';
import { fromHexToArray, toHex } from '../session/utils/String';
import { fromHexToArray } from '../session/utils/String';
import { getSodium } from '../session/crypto';
import { fromHex } from 'bytebuffer';
const MAX_WIDTH = 300;
const MAX_HEIGHT = MAX_WIDTH * 1.5;
@ -455,8 +454,7 @@ export const encryptAttachmentBuffer = async (bufferIn: ArrayBuffer) => {
};
export const decryptAttachmentBuffer = async (
bufferIn: ArrayBuffer,
key: string = '0c5f7147b6d3239cbb5a418814cee1bfca2df5c94bffddf22ee37eea3ede972b'
bufferIn: ArrayBuffer
): Promise<Uint8Array> => {
if (!isArrayBuffer(bufferIn)) {
throw new TypeError("'bufferIn' must be an array buffer");
@ -469,6 +467,7 @@ export const decryptAttachmentBuffer = async (
const header = new Uint8Array(
bufferIn.slice(0, sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES)
);
const encryptedBuffer = new Uint8Array(
bufferIn.slice(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES)
);
@ -492,7 +491,7 @@ export const decryptAttachmentBuffer = async (
return messageTag.message;
}
} catch (e) {
window.log.warn('Failed to load the file as an encrypted one', e);
window?.log?.warn('Failed to load the file as an encrypted one', e);
}
return new Uint8Array();
};

@ -754,6 +754,11 @@
"@types/react-native" "*"
csstype "^3.0.2"
"@types/tmp@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.0.tgz#e3f52b4d7397eaa9193592ef3fdd44dc0af4298c"
integrity sha512-flgpHJjntpBAdJD43ShRosQvNC0ME97DCfGvZEDlAThQmnerRXrLbX6YgzRBQCZTthET9eAWFAMaYP0m0Y4HzQ==
"@types/trusted-types@*":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.4.tgz#922d092c84a776a59acb0bd6785fd82b59b9bad5"

Loading…
Cancel
Save