Skip to content

Commit

Permalink
Merge pull request #242 from opendatakit/issa/fix-enc
Browse files Browse the repository at this point in the history
bug c#114: strip .enc extension suffix when decrypting attachments.
  • Loading branch information
issa-tseng authored Nov 22, 2019
2 parents c0ec7e3 + bcbe161 commit 1c64bb8
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
9 changes: 8 additions & 1 deletion lib/data/attachments.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@


const { join } = require('path');
const { compose, identity } = require('ramda');
const { Writable, pipeline } = require('stream');
const { rejectIfError } = require('../util/promise');
const { zipPart } = require('../util/zip');
const sanitize = require('sanitize-filename');

// encrypted files have a .enc extension that needs to be stripped. we will only
// do so if decryption is actually in progress.
const stripEnc = (decryptor) =>
((decryptor == null) ? identity : ((name) => name.replace(/\.enc$/i, '')));

// Given the Postgres rowstream returned by SubmissionAttachment.streamForExport
// here we use the util/zip multifile zipstreamer to archive all attachments into
// the archive. Will decrypt contents with the decryptor if necessary.
const streamAttachments = (inStream, decryptor) => {
const archive = zipPart();
const processName = compose(sanitize, stripEnc(decryptor));

const writable = new Writable({
objectMode: true,
Expand All @@ -31,7 +38,7 @@ const streamAttachments = (inStream, decryptor) => {
? att.content
: decryptor(att.content, att.keyId, att.localKey, att.instanceId, att.index);

archive.append(content, { name: join('media', sanitize(att.name)) }, done);
archive.append(content, { name: join('media', processName(att.name)) }, done);
},
final(done) {
archive.finalize();
Expand Down
21 changes: 21 additions & 0 deletions test/integration/other/encryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,27 @@ describe('managed encryption', () => {
done();
}))))));

it('should strip .enc suffix from decrypted attachments', testService((service) =>
service.login('alice', (asAlice) =>
asAlice.post('/v1/projects/1/key')
.send({ passphrase: 'supersecret', hint: 'it is a secret' })
.expect(200)
.then(() => asAlice.get('/v1/projects/1/forms/simple.xml')
.expect(200)
.then(({ text }) => sendEncrypted(asAlice, extractVersion(text), extractPubkey(text)))
.then((send) => send(testData.instances.simple.one, { 'testfile.jpg.enc': 'hello this is a suffixed file' }))
.then(() => asAlice.get('/v1/projects/1/forms/simple/submissions/keys')
.expect(200)
.then(({ body }) => body[0].id))
.then((keyId) => new Promise((done) =>
zipStreamToFiles(asAlice.get(`/v1/projects/1/forms/simple/submissions.csv.zip?${keyId}=supersecret`), (result) => {
result.filenames.length.should.equal(2);
result.filenames.should.containDeep([ 'simple.csv', 'media/testfile.jpg' ]);

result['media/testfile.jpg'].should.equal('hello this is a suffixed file');
done();
})))))));

it('should handle mixed [plaintext/encrypted] attachments (not decrypting)', testService((service) =>
service.login('alice', (asAlice) =>
asAlice.post('/v1/projects/1/forms')
Expand Down
20 changes: 20 additions & 0 deletions test/unit/data/attachments.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,25 @@ describe('.zip attachments streaming', () => {
done();
});
});

it('should not strip .enc unless decryption is happening', (done) => {
const inStream = streamTest.fromObjects([
{ instanceId: 'subone', name: 'firstfile.ext.enc', content: 'this is my first file' }
]);
zipStreamToFiles(zipStreamFromParts(streamAttachments(inStream)), (result) => {
result.filenames.should.eql([ 'media/firstfile.ext.enc' ]);
done();
});
});
});

it('should strip .enc if decryption is happening', (done) => {
const inStream = streamTest.fromObjects([
{ instanceId: 'subone', name: 'firstfile.ext.enc', content: 'this is my first file' }
]);
zipStreamToFiles(zipStreamFromParts(streamAttachments(inStream, () => {})), (result) => {
result.filenames.should.eql([ 'media/firstfile.ext' ]);
done();
});
});

0 comments on commit 1c64bb8

Please sign in to comment.