diff --git a/lib/command.ts b/lib/command.ts index ab0d5661..35e4a5e6 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -429,7 +429,7 @@ Command.setReplyTransformer("hgetall", function (result) { for (let i = 0; i < result.length; i += 2) { const key = result[i]; const value = result[i + 1]; - if (obj[key]) { + if (key in obj) { // can only be truthy if the property is special somehow, like '__proto__' or 'constructor' // https://github.com/luin/ioredis/issues/1267 Object.defineProperty(obj, key, { diff --git a/test/functional/hgetall.ts b/test/functional/hgetall.ts index f4a38d8d..344f702c 100644 --- a/test/functional/hgetall.ts +++ b/test/functional/hgetall.ts @@ -1,12 +1,37 @@ import Redis from "../../lib/redis"; import { expect } from "chai"; +const CUSTOM_PROPERTY = "_myCustomProperty"; + describe("hgetall", function () { - it("should handle __proto__", async function () { + beforeEach(function () { + Object.defineProperty(Object.prototype, CUSTOM_PROPERTY, { + value: false, + configurable: true, + enumerable: false, + writable: false, + }); + }); + + afterEach(function () { + delete (Object.prototype as any)[CUSTOM_PROPERTY]; + }); + + it("should handle special field names", async function () { const redis = new Redis(); - await redis.hset("test_key", "__proto__", "hello"); + await redis.hmset( + "test_key", + "__proto__", + "hello", + CUSTOM_PROPERTY, + "world" + ); const ret = await redis.hgetall("test_key"); expect(ret.__proto__).to.eql("hello"); - expect(Object.keys(ret)).to.eql(["__proto__"]); + expect(ret[CUSTOM_PROPERTY]).to.eql("world"); + expect(Object.keys(ret).sort()).to.eql( + ["__proto__", CUSTOM_PROPERTY].sort() + ); + expect(Object.getPrototypeOf(ret)).to.eql(Object.prototype); }); });