Switch from hashed to random attachment file names
Using hashes, we get the benefit of deduplication but if a user receives two messages with the same attachment, deleting one would delete it for both since they are only stored once. To avoid the complexity of tracking number of references, we simply generate random file names similar to iMessage on MacOS (?) and Signal Android.
This commit is contained in:
parent
d9de6dacba
commit
1283c77518
2 changed files with 17 additions and 31 deletions
|
@ -1,7 +1,6 @@
|
|||
const crypto = require('crypto');
|
||||
const FSE = require('fs-extra');
|
||||
const isArrayBuffer = require('lodash/isArrayBuffer');
|
||||
const isBuffer = require('lodash/isBuffer');
|
||||
const isString = require('lodash/isString');
|
||||
const Path = require('path');
|
||||
|
||||
|
@ -17,29 +16,20 @@ exports.writeAttachmentData = (root) => {
|
|||
}
|
||||
|
||||
const buffer = new Buffer(arrayBuffer);
|
||||
const path = Path.join(root, exports._getAttachmentPath(buffer));
|
||||
const path = Path.join(root, exports._getAttachmentPath());
|
||||
await FSE.ensureFile(path);
|
||||
await FSE.writeFile(path, buffer);
|
||||
return path;
|
||||
};
|
||||
};
|
||||
|
||||
exports._getAttachmentName = (buffer) => {
|
||||
if (!isBuffer(buffer)) {
|
||||
throw new TypeError('`buffer` must be a buffer');
|
||||
}
|
||||
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(buffer);
|
||||
return hash.digest('hex');
|
||||
exports._getAttachmentName = () => {
|
||||
const buffer = crypto.randomBytes(32);
|
||||
return buffer.toString('hex');
|
||||
};
|
||||
|
||||
exports._getAttachmentPath = (buffer) => {
|
||||
if (!isBuffer(buffer)) {
|
||||
throw new TypeError('`buffer` must be a buffer');
|
||||
}
|
||||
|
||||
const name = exports._getAttachmentName(buffer);
|
||||
exports._getAttachmentPath = () => {
|
||||
const name = exports._getAttachmentName();
|
||||
const prefix = name.slice(0, 3);
|
||||
return Path.join(prefix, name);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ const FSE = require('fs-extra');
|
|||
const isEqual = require('lodash/isEqual');
|
||||
const Path = require('path');
|
||||
const stringToArrayBuffer = require('string-to-arraybuffer');
|
||||
const tempy = require('tempy');
|
||||
const tmp = require('tmp');
|
||||
const { assert } = require('chai');
|
||||
|
||||
const {
|
||||
|
@ -12,11 +12,15 @@ const {
|
|||
} = require('../../../../app/types/attachment/write_attachment_data');
|
||||
|
||||
|
||||
const PREFIX_LENGTH = 3;
|
||||
const NUM_SEPARATORS = 1;
|
||||
const NAME_LENGTH = 64;
|
||||
const PATH_LENGTH = PREFIX_LENGTH + NUM_SEPARATORS + NAME_LENGTH;
|
||||
|
||||
describe('writeAttachmentData', () => {
|
||||
let TEMPORARY_DIRECTORY = null;
|
||||
before(() => {
|
||||
// Sync!
|
||||
TEMPORARY_DIRECTORY = tempy.directory();
|
||||
TEMPORARY_DIRECTORY = tmp.dirSync().name;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
@ -26,33 +30,25 @@ describe('writeAttachmentData', () => {
|
|||
it('should write file to disk and return path', async () => {
|
||||
const input = stringToArrayBuffer('test string');
|
||||
const tempDirectory = Path.join(TEMPORARY_DIRECTORY, 'writeAttachmentData');
|
||||
const expectedPath = Path.join(
|
||||
tempDirectory,
|
||||
'd55/d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'
|
||||
);
|
||||
|
||||
const outputPath = await writeAttachmentData(tempDirectory)(input);
|
||||
const output = await FSE.readFile(outputPath);
|
||||
|
||||
assert.strictEqual(outputPath, expectedPath);
|
||||
assert.lengthOf(Path.relative(tempDirectory, outputPath), PATH_LENGTH);
|
||||
|
||||
const inputBuffer = Buffer.from(input);
|
||||
assert.isTrue(isEqual(inputBuffer, output));
|
||||
});
|
||||
|
||||
describe('_getAttachmentName', () => {
|
||||
it('should return correct name', () => {
|
||||
const input = Buffer.from('test string', 'utf8');
|
||||
const expected = 'd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b';
|
||||
assert.strictEqual(_getAttachmentName(input), expected);
|
||||
it('should return random file name with correct length', () => {
|
||||
assert.lengthOf(_getAttachmentName(), NAME_LENGTH);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_getAttachmentPath', () => {
|
||||
it('should return correct path', () => {
|
||||
const input = Buffer.from('test string', 'utf8');
|
||||
const expected = 'd55/d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b';
|
||||
assert.strictEqual(_getAttachmentPath(input), expected);
|
||||
assert.lengthOf(_getAttachmentPath(), PATH_LENGTH);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue