From 8c2752bab13bc5b7617f8c5c9f20b8d056c856af Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 11 Feb 2022 14:28:10 -0500 Subject: [PATCH] test: user uploads.js tests --- src/user/uploads.js | 9 ++++++--- test/user/uploads.js | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/user/uploads.js b/src/user/uploads.js index 3899c1d66f..0867e9b982 100644 --- a/src/user/uploads.js +++ b/src/user/uploads.js @@ -42,6 +42,8 @@ module.exports = function (User) { throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); } + await _validatePath(uploadNames); + const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), User.isAdminOrGlobalMod(callerUid), @@ -50,8 +52,6 @@ module.exports = function (User) { throw new Error('[[error:no-privileges]]'); } - await _validatePath(uploadNames); - await batch.processArray(uploadNames, async (uploadNames) => { const fullPaths = uploadNames.map(path => _getFullPath(path)); @@ -61,7 +61,10 @@ module.exports = function (User) { file.delete(fullPath), file.delete(file.appendToFileName(fullPath, '-resized')), ]); - await db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), + db.delete(`upload:${md5(uploadNames[idx])}`), + ]); })); }, { batch: 50 }); }; diff --git a/test/user/uploads.js b/test/user/uploads.js index 8aae511324..5d86afb633 100644 --- a/test/user/uploads.js +++ b/test/user/uploads.js @@ -9,6 +9,7 @@ const nconf = require('nconf'); const db = require('../mocks/databasemock'); const user = require('../../src/user'); +const file = require('../../src/file'); const utils = require('../../public/src/utils'); const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); @@ -85,27 +86,63 @@ describe('uploads.js', () => { }); it('should remove the upload from the user\'s uploads zset', async () => { + await user.deleteUpload(uid, uid, relativePath); + const uploads = await db.getSortedSetMembers(`uid:${uid}:uploads`); + assert.deepStrictEqual(uploads, []); }); it('should delete the file from disk', async () => { + let exists = await file.exists(`${nconf.get('upload_path')}/${relativePath}`); + assert.strictEqual(exists, true); + await user.deleteUpload(uid, uid, relativePath); + + exists = await file.exists(`${nconf.get('upload_path')}/${relativePath}`); + assert.strictEqual(exists, false); }); it('should clean up references to it from the database', async () => { + const hash = md5(relativePath); + let exists = await db.exists(`upload:${hash}`); + assert.strictEqual(exists, true); + await user.deleteUpload(uid, uid, relativePath); + exists = await db.exists(`upload:${hash}`); + assert.strictEqual(exists, false); }); it('should accept multiple paths', async () => { + const secondPath = `files/${utils.generateUUID()}`; + fs.closeSync(fs.openSync(path.join(nconf.get('upload_path'), secondPath), 'w')); + await user.associateUpload(uid, secondPath); + + assert.strictEqual(await db.sortedSetCard(`uid:${uid}:uploads`), 2); + await user.deleteUpload(uid, uid, [relativePath, secondPath]); + + assert.strictEqual(await db.sortedSetCard(`uid:${uid}:uploads`), 0); + assert.deepStrictEqual(await db.getSortedSetMembers(`uid:${uid}:uploads`), []); }); it('should throw an error on a non-existant file', async () => { - + try { + await user.deleteUpload(uid, uid, `${relativePath}asdbkas`); + } catch (e) { + assert(e); + assert.strictEqual(e.message, '[[error:invalid-path]]'); + } }); it('should guard against path traversal', async () => { + assert.strictEqual(await file.exists(path.resolve(nconf.get('upload_path'), '../../config.json')), true); + try { + await user.deleteUpload(uid, uid, `../../config.json`); + } catch (e) { + assert(e); + assert.strictEqual(e.message, '[[error:invalid-path]]'); + } }); }); });