From f7f95cdcbc4abf7717b9238ec28c247ac84b71f1 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 2 Jan 2023 13:22:05 -0500 Subject: [PATCH] avoid passing final callback to pre hook, because calling the callback can mess up hook execution Fix Automattic/mongoose#12836 --- index.js | 3 +++ test/pre.test.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/index.js b/index.js index 69688f3..9c5aa16 100644 --- a/index.js +++ b/index.js @@ -84,6 +84,9 @@ Kareem.prototype.execPre = function(name, context, args, callback) { const args = [decorateNextFn(_next)]; const _args = arguments.length >= 2 ? arguments : [null].concat($args); for (let i = 1; i < _args.length; ++i) { + if (i === _args.length - 1 && typeof _args[i] === 'function') { + continue; // skip callbacks to avoid accidentally calling the callback from a hook + } args.push(_args[i]); } diff --git a/test/pre.test.js b/test/pre.test.js index 9308693..c212029 100644 --- a/test/pre.test.js +++ b/test/pre.test.js @@ -289,6 +289,41 @@ describe('execPre', function() { }); }); + it('avoids passing final callback to pre', function(done) { + const execed = {}; + + hooks.pre('cook', function(next) { + execed.first = true; + assert.equal(arguments.length, 1); + next(null, 'test'); + }); + + hooks.pre('cook', function(next, p, _cb) { + execed.second = true; + assert.equal(p, 'test'); + assert.equal(arguments.length, 2); + next(); + }); + + hooks.pre('cook', function(next, p) { + execed.third = true; + assert.ok(!p); + assert.equal(arguments.length, 1); + next(); + }); + + hooks.execPre('cook', null, [finalCb], function(err) { + assert.ifError(err); + assert.equal(3, Object.keys(execed).length); + assert.ok(execed.first); + assert.ok(execed.second); + assert.ok(execed.third); + done(); + }); + + function finalCb() {} + }); + it('handles sync errors in pre if there are more hooks', function(done) { const execed = {};