jsonwebtoken 9.0.0 – 在尝试存根时出现错误:TypeError: 无法重新定义属性:decode

huangapple go评论95阅读模式
英文:

jsonwebtoken 9.0.0 - getting error: TypeError: Cannot redefine property: decode - when trying to stub

问题

npm audit 刚刚发现 jsonwebtoken 存在安全漏洞。解决方案 是升级到版本 9.0.0 - 我已经这样做了。

然而,我的 mocha 测试现在无法通过。在 beforeEach 中,我试图使用 sinon.stub 来存根 decode 函数,但现在抛出以下 TypeError:

TypeError: 无法重新定义属性: decode

beforeEach 代码段如下:

const jwt = require('jsonwebtoken');

beforeEach(function () {
  this.sinon.stub(jwt, 'verify').returns({ email: 'email@email.com' });
  this.sinon.stub(jwt, 'decode').returns({ header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });
  this.sinon.stub(jwks, 'getKey').returns('some mock certificate');
  this.sinon.stub(T, 'expired');
});

我假设存根 verify 仍然有效,因为错误仅在下一行尝试存根 decode 时抛出。

是的,有一个类似问题的帖子,但它已经两年了,被接受的答案是“这很快会在未来版本中修复”。所以不太相关了。

英文:

so npm audit just found jsonwebtoken to have a security vulnerbility. The solution is to update to version 9.0.0 - which I did.

However, my mocha tests are not passing now. During a beforeEach, I am trying to stub the decode function using sinon.stub, which now throws this TypeError:

TypeError: Cannot redefine property: decode

The beforeEach:

const jwt = require('jsonwebtoken');

beforeEach(function () {
  this.sinon.stub(jwt, 'verify').returns({ email: 'email@email.com' });
  this.sinon.stub(jwt, 'decode').returns({ header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });
  this.sinon.stub(jwks, 'getKey').returns('some mock certificate');
  this.sinon.stub(T, 'expired');
});

I assume that stubbing verify still works, since the error only throws on the next line when I try to stub decode

Yes, there is a post with similar question, but it's two years old, and the accepted answer is that "this is soon to be fixed in a future version". So not really relevant anymore.

答案1

得分: 3

因为jsonwebtoken v9.0.0将decode函数设置为不可枚举和不可配置,请参见v9.0.0/index.js#L9

index.js

module.exports = {
  verify: require('./verify'),
  sign: require('./sign'),
  JsonWebTokenError: require('./lib/JsonWebTokenError'),
  NotBeforeError: require('./lib/NotBeforeError'),
  TokenExpiredError: require('./lib/TokenExpiredError'),
};

Object.defineProperty(module.exports, 'decode', {
  enumerable: false,
  value: require('./decode'),
});

根据文档Object.defineProperty创建的不可配置属性

如果您未将其配置为可配置属性,则Object.defineProperty()将创建不可配置属性。

这意味着configurable: false是默认值。这就是为什么sinon.stub(jwt, 'decode')不再起作用的原因。

并且有一个PR试图修复它以允许对decode函数进行存根。该PR将decode设置为可配置:

Object.defineProperty(module.exports, 'decode', {
  enumerable: false,
  configurable: true,
  value: require('./decode'),
});

有一个临时解决方案,您可以创建自己的jwt工具模块并对自己的jwt工具进行存根。

例如:

jwt-repack.js

const jwt = require('jsonwebtoken');
const decode = require('jsonwebtoken').decode;

module.exports = {
  ...jwt,
  decode
};

index.test.js

const sinon = require('sinon');
const jwt = require('./jwt-repack');

it('should pass', () => {
  sinon.stub(jwt, 'decode').returns({ header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });

  const actual = jwt.decode();
  sinon.assert.match(actual, { header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });
});

包版本:

"jsonwebtoken9": "npm:jsonwebtoken@^9.0.0",
"sinon": "^8.1.1",
英文:

Because jsonwebtoken v9.0.0 makes the decode function non-enumerable and non-configurable, see v9.0.0/index.js#L9

index.js:

module.exports = {
  verify: require('./verify'),
  sign: require('./sign'),
  JsonWebTokenError: require('./lib/JsonWebTokenError'),
  NotBeforeError: require('./lib/NotBeforeError'),
  TokenExpiredError: require('./lib/TokenExpiredError'),
};

Object.defineProperty(module.exports, 'decode', {
  enumerable: false,
  value: require('./decode'),
});

From the documentation Non-configurable properties created by Object.defineProperty

> The Object.defineProperty() creates non-configurable properties if you haven't specified them as configurable.

Which means the configurable: false is the default. That's why sinon.stub(jwt, 'decode') doesn't work anymore.

And there is PR trying to fix it to allow the decode function to be stubbed. This PR makes the decode configurable:

Object.defineProperty(module.exports, 'decode', {
  enumerable: false,
  configurable: true,
  value: require('./decode'),
});

There is a temporary solution, you can create your own jwt utils module and stub your own jwt utils.

E.g.

jwt-repack.js:

const jwt = require('jsonwebtoken');
const decode = require('jsonwebtoken').decode;

module.exports = {
  ...jwt,
  decode
};

index.test.js:

const sinon = require('sinon');
const jwt = require('./jwt-repack');

it('should pass', () => {
  sinon.stub(jwt, 'decode').returns({ header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });

  const actual = jwt.decode();
  sinon.assert.match(actual, { header: { alg: 'RS256', typ: 'JWT', kid: 'MOCKKID' } });
});

package versions:

"jsonwebtoken9": "npm:jsonwebtoken@^9.0.0",
"sinon": "^8.1.1",

huangapple
  • 本文由 发表于 2023年1月10日 22:12:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75071217.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定