This is an automated email from the ASF dual-hosted git repository. hsluoyz pushed a commit to branch fix/replace-axios-with-fetch in repository https://gitbox.apache.org/repos/asf/casbin-casbin.js.git
commit 6e2c277743661c33025712a6f6e82f332df4bf2a Author: Yang Luo <[email protected]> AuthorDate: Sat May 23 01:16:54 2026 +0800 fix: replace axios with native fetch to remove CVE-affected dependency Removes the [email protected] dependency (which triggered security scanners via its follow-redirects transitive dep) in favour of the native Fetch API available in Node.js 18+ and all modern browsers. Also adds a minimal custom jest environment to expose Node.js native fetch inside the jsdom test context, and loads basicPolicies into the test server so the integration test works without HTTP interception. Fixes #314 Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- jest.environment.js | 13 +++++++++++++ jestconfig.json | 2 +- package.json | 1 - src/Authorizer.ts | 11 +++++++---- src/__test__/index.test.ts | 13 ------------- src/__test__/server.ts | 10 +++++++++- yarn.lock | 9 +-------- 7 files changed, 31 insertions(+), 28 deletions(-) diff --git a/jest.environment.js b/jest.environment.js new file mode 100644 index 0000000..61f2094 --- /dev/null +++ b/jest.environment.js @@ -0,0 +1,13 @@ +const JsDOMEnvironment = require('jest-environment-jsdom').default; + +class FetchEnvironment extends JsDOMEnvironment { + async setup() { + await super.setup(); + this.global.fetch = fetch; + this.global.Headers = Headers; + this.global.Request = Request; + this.global.Response = Response; + } +} + +module.exports = FetchEnvironment; diff --git a/jestconfig.json b/jestconfig.json index 51bcb5e..f62c8b4 100644 --- a/jestconfig.json +++ b/jestconfig.json @@ -2,7 +2,7 @@ "transform": { "^.+\\.(t|j)sx?$": "ts-jest" }, - "testEnvironment": "jsdom", + "testEnvironment": "./jest.environment.js", "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], "coveragePathIgnorePatterns": [ diff --git a/package.json b/package.json index 67293da..f8f4670 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "dependencies": { "@babel/core": "^7.14.6", "@babel/preset-env": "^7.14.5", - "axios": "^0.21.1", "babel-loader": ">=8.1.0", "casbin-core": "^0.0.0-beta.2", "js-cookie": "^2.2.1" diff --git a/src/Authorizer.ts b/src/Authorizer.ts index 85e5556..a533a49 100644 --- a/src/Authorizer.ts +++ b/src/Authorizer.ts @@ -1,4 +1,3 @@ -import axios from 'axios'; import * as casbin from 'casbin-core'; import Permission from './Permission'; import { StringKV } from './types'; @@ -111,10 +110,14 @@ export class Authorizer { if (this.endpoint === undefined || this.endpoint === null) { throw Error("Endpoint is null or not specified."); } - const resp = await axios.get<BaseResponse>(`${this.endpoint}?subject=${this.user}`, { - headers: this.requestHeaders, + const resp = await fetch(`${this.endpoint}?subject=${this.user}`, { + headers: this.requestHeaders as unknown as HeadersInit, }); - return resp.data.data; + if (!resp.ok) { + throw new Error(`HTTP error: ${resp.status}`); + } + const body: BaseResponse = await resp.json(); + return body.data; } /** diff --git a/src/__test__/index.test.ts b/src/__test__/index.test.ts index 1a73dba..ce8dbe0 100644 --- a/src/__test__/index.test.ts +++ b/src/__test__/index.test.ts @@ -1,27 +1,14 @@ -import axios from 'axios'; import { Authorizer } from '../index'; import { basicModelStr } from './models'; import { basicPolicies } from './policies'; import { removeLocalStorage } from '../Cache'; import TestServer from './server'; -jest.mock('axios'); -const mockedAxios = axios as jest.Mocked<typeof axios>; - test('Mock functions', () => { - const respObj = { - m: basicModelStr, - p: basicPolicies - } - const resp = { data: { message: 'ok', data: JSON.stringify(respObj)}}; - // Specify the returned data of the mockedAxios once - mockedAxios.get.mockImplementationOnce(() => Promise.resolve(resp)); // TODO: Use mock function to get response object // const authorizer = new Authorizer('http://localhost:4000'); // authorizer.setUser('alice'); // expect(authorizer.getPermission()).toMatchObject(respObj); - - // expect(mockedAxios.get('http://localhost:4000/api/permissions?subject=alice')).toMatchObject(respObj); }); async function check(authorizer: Authorizer) { diff --git a/src/__test__/server.ts b/src/__test__/server.ts index c88bebd..090e559 100644 --- a/src/__test__/server.ts +++ b/src/__test__/server.ts @@ -2,7 +2,8 @@ import * as http from "http"; import express from 'express'; import { newEnforcer, Enforcer, Model } from 'casbin-core'; import { StringKV } from '../types'; -import { basicModelStr } from './models' +import { basicModelStr } from './models'; +import { basicPolicies } from './policies'; class CasbinService { private enforcer! : Enforcer; @@ -11,6 +12,13 @@ class CasbinService { // RBAC API doesn't support RBAC w/ domain. // this.enforcer = await newEnforcer('./src/__test__/example/rbac_with_domains_model.conf', './src/__test__/example/rbac_with_domains_policy.csv'); this.enforcer = await newEnforcer(new Model(basicModelStr)); + for (const policy of basicPolicies) { + const arr = policy.map(v => v.trim()); + const pType = arr.shift(); + if (pType === 'p') { + await this.enforcer.addPolicy(...arr); + } + } } public async getEnforcerConfig(sub: string): Promise<string> { diff --git a/yarn.lock b/yarn.lock index 1994c94..fe68c5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2099,13 +2099,6 @@ await-lock@^2.0.1: resolved "https://registry.yarnpkg.com/await-lock/-/await-lock-2.2.2.tgz#a95a9b269bfd2f69d22b17a321686f551152bcef" integrity sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw== -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -3802,7 +3795,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -follow-redirects@^1.0.0, follow-redirects@^1.14.0: +follow-redirects@^1.0.0: version "1.15.11" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
