mirror of
https://github.com/placeholder-soft/web.git
synced 2026-01-12 17:02:57 +08:00
check for frame ip safety (#1036)
* check for ip safety * add jest * add gh workflow * middleware->frame calls with dns lookup
This commit is contained in:
18
.github/workflows/main.yml
vendored
Normal file
18
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Unit Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
Jest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run Tests
|
||||
run: |
|
||||
yarn install
|
||||
yarn test
|
||||
@@ -1 +1,48 @@
|
||||
export { GET, POST } from '@frames.js/render/next';
|
||||
import { GET as getHandler, POST as postHandler } from '@frames.js/render/next';
|
||||
import { ipSafe } from 'apps/web/src/middleware/ipSafe';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
import { URL } from 'url';
|
||||
import dns from 'dns/promises';
|
||||
|
||||
function withIPCheck(handler: (req: NextRequest) => Promise<Response>) {
|
||||
return async function (req: NextRequest) {
|
||||
const searchParams = req.nextUrl.searchParams;
|
||||
const url = searchParams.get('url');
|
||||
|
||||
if (url) {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const hostname = parsedUrl.hostname;
|
||||
const resolvedAddresses = await dns.resolve(hostname);
|
||||
|
||||
let allSafe = true;
|
||||
|
||||
for (const address of resolvedAddresses) {
|
||||
if (ipaddr.isValid(address)) {
|
||||
if (!ipSafe(address)) {
|
||||
allSafe = false;
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
return NextResponse.json({ message: 'Invalid IP address resolution' }, { status: 400 });
|
||||
}
|
||||
}
|
||||
|
||||
if (!allSafe) {
|
||||
return NextResponse.json({ message: 'Forbidden: Unsafe IP' }, { status: 403 });
|
||||
}
|
||||
|
||||
return await handler(req);
|
||||
} catch (error) {
|
||||
return NextResponse.json({ message: 'Invalid URL format' }, { status: 400 });
|
||||
}
|
||||
}
|
||||
|
||||
return handler(req);
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
export const GET = withIPCheck(getHandler);
|
||||
export const POST = withIPCheck(postHandler);
|
||||
|
||||
17
apps/web/jest.config.js
Normal file
17
apps/web/jest.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const nextJest = require('next/jest');
|
||||
|
||||
const createJestConfig = nextJest({
|
||||
dir: './',
|
||||
});
|
||||
|
||||
const customJestConfig = {
|
||||
testEnvironment: 'jest-environment-jsdom',
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
||||
moduleDirectories: ['node_modules', '<rootDir>'],
|
||||
moduleNameMapper: {
|
||||
'^@/components/(.*)$': '<rootDir>/components/$1',
|
||||
'^@/pages/(.*)$': '<rootDir>/pages/$1',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = createJestConfig(customJestConfig);
|
||||
1
apps/web/jest.setup.js
Normal file
1
apps/web/jest.setup.js
Normal file
@@ -0,0 +1 @@
|
||||
require('@testing-library/jest-dom');
|
||||
@@ -5,6 +5,7 @@
|
||||
"scripts": {
|
||||
"start": "node --require ./tracer/initialize.js ./node_modules/.bin/next start",
|
||||
"build": "next build",
|
||||
"test": "jest",
|
||||
"analyze": "ANALYZE=true next build",
|
||||
"dev": "node --require ./tracer/initialize.js ./node_modules/.bin/next dev",
|
||||
"lint": "next lint",
|
||||
@@ -39,6 +40,7 @@
|
||||
"ethers": "5.7.2",
|
||||
"framer-motion": "^8.5.5",
|
||||
"hls.js": "^1.5.14",
|
||||
"ipaddr.js": "^2.2.0",
|
||||
"is-ipfs": "^8.0.4",
|
||||
"jose": "^5.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
@@ -67,6 +69,9 @@
|
||||
"wagmi": "^2.11.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^6.5.0",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@types/jest": "^29.5.13",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/pg": "^8.11.6",
|
||||
"@types/react": "^18",
|
||||
@@ -76,9 +81,11 @@
|
||||
"csv-parser": "^3.0.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint-config-next": "^13.1.6",
|
||||
"jest": "^29.7.0",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier-plugin-tailwindcss": "^0.2.5",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "5.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
148
apps/web/src/middleware/ipSafe.spec.ts
Normal file
148
apps/web/src/middleware/ipSafe.spec.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { ipSafe } from './ipSafe';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
|
||||
const badIps = [
|
||||
'127.0.0.1', // IPv4 loopback
|
||||
'::1', // IPv6 loopback
|
||||
'10.0.0.1', // 10.0.0.0/8 private IP
|
||||
'172.16.0.13', // 172.16.0.0/12 private IP
|
||||
'192.168.15.15', // 192.168.0.0/16 private IP
|
||||
'169.254.169.254', // AWS metadata endpoint
|
||||
'0.0.0.0', // IPv4 unspecified address
|
||||
'1.2.3.0/24', // IPv4 network CIDR (won't pass string-based IP checks)
|
||||
'::ffff:192.0.2.128', // IPv6 mapped address pointing to IPv4 private address
|
||||
'::ffff:172.16.0.0', // ditto
|
||||
'::ffff:10.0.0.0', // ditto
|
||||
'::ffff:169.254.169.254', // ditto, but pointing at AWS metadata address
|
||||
'::ffff:127.0.0.1', // ditto, but pointing at localhost
|
||||
'::ffff:c0a8:8b32', // mapped IP address in hex format (192.168.139.50)
|
||||
'fe80::c800:eff:fe74:8', // IPv6 link-local address
|
||||
'fd6d:8d64:af0c::', // IPv6 unique local address
|
||||
'nonsense', // nonsense IP
|
||||
];
|
||||
|
||||
jest.mock('ipaddr.js', () => ({
|
||||
parse: jest.fn(),
|
||||
IPv4: {
|
||||
subnetMaskFromPrefixLength: jest.fn(() => ({
|
||||
match: jest.fn(() => true),
|
||||
})),
|
||||
},
|
||||
IPv6: {
|
||||
subnetMaskFromPrefixLength: jest.fn(() => ({
|
||||
match: jest.fn(() => true),
|
||||
})),
|
||||
},
|
||||
}));
|
||||
describe('IP Safe Tests', () => {
|
||||
let originalEnv: string | undefined;
|
||||
|
||||
beforeAll(() => {
|
||||
originalEnv = process.env.NODE_ENV;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = originalEnv;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
badIps.forEach((badIp) => {
|
||||
test(`returns false for unsafe IP: ${badIp}`, () => {
|
||||
expect(ipSafe(badIp)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
test('returns false for invalid IP address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
(ipaddr.parse as jest.Mock).mockImplementationOnce(() => {
|
||||
throw new Error('Invalid IP');
|
||||
});
|
||||
|
||||
expect(ipSafe('invalid-ip')).toBe(false);
|
||||
});
|
||||
|
||||
test('returns false for unsafe IPv4 address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const mockIPv4 = {
|
||||
kind: () => 'ipv4',
|
||||
range: () => 'private',
|
||||
toString: () => '127.0.0.1',
|
||||
match: () => true,
|
||||
};
|
||||
(ipaddr.parse as jest.Mock).mockReturnValueOnce(mockIPv4);
|
||||
|
||||
expect(ipSafe('127.0.0.1')).toBe(false);
|
||||
});
|
||||
|
||||
test('returns true for safe IPv4 address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const mockIPv4 = {
|
||||
kind: () => 'ipv4',
|
||||
range: () => 'unicast',
|
||||
toString: () => '8.8.8.8',
|
||||
match: () => true,
|
||||
};
|
||||
(ipaddr.parse as jest.Mock).mockReturnValueOnce(mockIPv4);
|
||||
|
||||
expect(ipSafe('8.8.8.8')).toBe(true);
|
||||
});
|
||||
|
||||
test('returns false for unsafe IPv6 address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const mockIPv6 = {
|
||||
kind: () => 'ipv6',
|
||||
range: () => 'loopback',
|
||||
isIPv4MappedAddress: () => false,
|
||||
match: () => true,
|
||||
};
|
||||
(ipaddr.parse as jest.Mock).mockReturnValueOnce(mockIPv6);
|
||||
|
||||
expect(ipSafe('::1')).toBe(false);
|
||||
});
|
||||
|
||||
test('returns true for safe IPv6 address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const mockIPv6 = {
|
||||
kind: () => 'ipv6',
|
||||
range: () => 'unicast',
|
||||
isIPv4MappedAddress: () => false,
|
||||
match: () => true,
|
||||
};
|
||||
(ipaddr.parse as jest.Mock).mockReturnValueOnce(mockIPv6);
|
||||
|
||||
expect(ipSafe('2001:4860:4860::8888')).toBe(true);
|
||||
});
|
||||
|
||||
test('returns true for safe IPv6 mapped IPv4 address', () => {
|
||||
// @ts-expect-error this is ok I promise
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const mockIPv6 = {
|
||||
kind: () => 'ipv6',
|
||||
range: () => 'unicast',
|
||||
isIPv4MappedAddress: () => true,
|
||||
toIPv4Address: () => ({
|
||||
kind: () => 'ipv4',
|
||||
range: () => 'unicast',
|
||||
match: () => true,
|
||||
}),
|
||||
};
|
||||
(ipaddr.parse as jest.Mock).mockReturnValueOnce(mockIPv6);
|
||||
|
||||
expect(ipSafe('::ffff:8.8.8.8')).toBe(true);
|
||||
});
|
||||
});
|
||||
58
apps/web/src/middleware/ipSafe.ts
Normal file
58
apps/web/src/middleware/ipSafe.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import ipaddr from 'ipaddr.js';
|
||||
|
||||
export function ipSafe(ipStr: string): boolean {
|
||||
try {
|
||||
const ip = ipaddr.parse(ipStr);
|
||||
if (!ip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const kind = ip.kind();
|
||||
if (!kind || (kind !== 'ipv4' && kind !== 'ipv6')) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (kind === 'ipv6') {
|
||||
return ipv6Safe(ip as ipaddr.IPv6);
|
||||
}
|
||||
|
||||
return ipv4Safe(ip as ipaddr.IPv4);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function ipv4Safe(ip: ipaddr.IPv4): boolean {
|
||||
const range = ip.range();
|
||||
|
||||
// Reject private, link-local, loopback, or broadcast IPs
|
||||
if (['private', 'linkLocal', 'loopback', 'broadcast'].includes(range)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject special IPs like 0.0.0.0 and non-standard prefixes
|
||||
if (ip.toString() === '0.0.0.0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function ipv6Safe(ip: ipaddr.IPv6): boolean {
|
||||
// If IPv6 address is mapped to an IPv4 address, ensure it's safe
|
||||
if (ip.isIPv4MappedAddress()) {
|
||||
const ipv4 = ip.toIPv4Address();
|
||||
return ipv4Safe(ipv4);
|
||||
}
|
||||
|
||||
// Reject loopback, unspecified, link-local, or unique-local IPs
|
||||
const range = ip.range();
|
||||
if (['loopback', 'unspecified', 'linkLocal', 'uniqueLocal'].includes(range)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -18,7 +18,8 @@
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
"strictNullChecks": true,
|
||||
"types": ["jest", "@testing-library/jest-dom"]
|
||||
},
|
||||
"include": [
|
||||
"global.d.ts",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn workspaces foreach run build",
|
||||
"lint": "yarn workspaces foreach run lint",
|
||||
"test": "yarn workspaces foreach run test",
|
||||
"postinstall": "sh -c 'if [ command -v ./node_modules/.bin/husky ]; then ./node_modules/.bin/husky install; fi;'",
|
||||
"prepublishOnly": "pinst --disable",
|
||||
"postpublish": "pinst --enable"
|
||||
@@ -22,6 +23,7 @@
|
||||
"@graphql-eslint/eslint-plugin": "^3.10.4",
|
||||
"@swc/core": "^1.2.173",
|
||||
"@swc/jest": "0.2.20",
|
||||
"@testing-library/jest-dom": "^6.5.0",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "18.14.2",
|
||||
|
||||
137
yarn.lock
137
yarn.lock
@@ -5,6 +5,13 @@ __metadata:
|
||||
version: 6
|
||||
cacheKey: 8
|
||||
|
||||
"@adobe/css-tools@npm:^4.4.0":
|
||||
version: 4.4.0
|
||||
resolution: "@adobe/css-tools@npm:4.4.0"
|
||||
checksum: 1f08fb49bf17fc7f2d1a86d3e739f29ca80063d28168307f1b0a962ef37501c5667271f6771966578897f2e94e43c4770fd802728a6e6495b812da54112d506a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@adraffy/ens-normalize@npm:1.10.0":
|
||||
version: 1.10.0
|
||||
resolution: "@adraffy/ens-normalize@npm:1.10.0"
|
||||
@@ -368,6 +375,9 @@ __metadata:
|
||||
"@radix-ui/react-tooltip": ^1.1.2
|
||||
"@rainbow-me/rainbowkit": ^2.1.5
|
||||
"@tanstack/react-query": ^5
|
||||
"@testing-library/jest-dom": ^6.5.0
|
||||
"@testing-library/react": ^16.0.1
|
||||
"@types/jest": ^29.5.13
|
||||
"@types/jsonwebtoken": ^9.0.6
|
||||
"@types/node": 18.11.18
|
||||
"@types/pg": ^8.11.6
|
||||
@@ -389,7 +399,9 @@ __metadata:
|
||||
ethers: 5.7.2
|
||||
framer-motion: ^8.5.5
|
||||
hls.js: ^1.5.14
|
||||
ipaddr.js: ^2.2.0
|
||||
is-ipfs: ^8.0.4
|
||||
jest: ^29.7.0
|
||||
jose: ^5.4.1
|
||||
jsonwebtoken: ^9.0.2
|
||||
kysely: ^0.27.3
|
||||
@@ -412,6 +424,7 @@ __metadata:
|
||||
satori: ^0.10.14
|
||||
sharp: ^0.33.4
|
||||
tailwindcss: ^3.2.4
|
||||
ts-jest: ^29.2.5
|
||||
twemoji: ^14.0.2
|
||||
typed.js: ^2.1.0
|
||||
typescript: 5.0.4
|
||||
@@ -2018,6 +2031,7 @@ __metadata:
|
||||
"@radix-ui/react-tooltip": ^1.1.2
|
||||
"@swc/core": ^1.2.173
|
||||
"@swc/jest": 0.2.20
|
||||
"@testing-library/jest-dom": ^6.5.0
|
||||
"@testing-library/react": 14.0.0
|
||||
"@types/jest": ^29.4.0
|
||||
"@types/node": 18.14.2
|
||||
@@ -7687,6 +7701,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/jest-dom@npm:^6.5.0":
|
||||
version: 6.5.0
|
||||
resolution: "@testing-library/jest-dom@npm:6.5.0"
|
||||
dependencies:
|
||||
"@adobe/css-tools": ^4.4.0
|
||||
aria-query: ^5.0.0
|
||||
chalk: ^3.0.0
|
||||
css.escape: ^1.5.1
|
||||
dom-accessibility-api: ^0.6.3
|
||||
lodash: ^4.17.21
|
||||
redent: ^3.0.0
|
||||
checksum: c2d14103ebe3358852ec527ff7512f64207a39932b2f7b6dff7e73ba91296b01a71bad9a9584b6ee010681380a906c1740af50470adc6db660e1c7585d012ebf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@testing-library/react@npm:14.0.0"
|
||||
@@ -7715,6 +7744,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react@npm:^16.0.1":
|
||||
version: 16.0.1
|
||||
resolution: "@testing-library/react@npm:16.0.1"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.5
|
||||
peerDependencies:
|
||||
"@testing-library/dom": ^10.0.0
|
||||
"@types/react": ^18.0.0
|
||||
"@types/react-dom": ^18.0.0
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 1837db473ea018cf2b5d0cbfffb7a30d0d759e5a7f23aad431441c77bcc3d2533250cd003a61878fd908267df47404cedcb5914f12d79e413002c659652b37fd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tootallnate/once@npm:2":
|
||||
version: 2.0.0
|
||||
resolution: "@tootallnate/once@npm:2.0.0"
|
||||
@@ -8097,6 +8146,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jest@npm:^29.5.13":
|
||||
version: 29.5.13
|
||||
resolution: "@types/jest@npm:29.5.13"
|
||||
dependencies:
|
||||
expect: ^29.0.0
|
||||
pretty-format: ^29.0.0
|
||||
checksum: 875ac23c2398cdcf22aa56c6ba24560f11d2afda226d4fa23936322dde6202f9fdbd2b91602af51c27ecba223d9fc3c1e33c9df7e47b3bf0e2aefc6baf13ce53
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jsdom@npm:^20.0.0":
|
||||
version: 20.0.1
|
||||
resolution: "@types/jsdom@npm:20.0.1"
|
||||
@@ -10180,6 +10239,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aria-query@npm:^5.0.0":
|
||||
version: 5.3.2
|
||||
resolution: "aria-query@npm:5.3.2"
|
||||
checksum: d971175c85c10df0f6d14adfe6f1292409196114ab3c62f238e208b53103686f46cc70695a4f775b73bc65f6a09b6a092fd963c4f3a5a7d690c8fc5094925717
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aria-query@npm:^5.1.3":
|
||||
version: 5.3.0
|
||||
resolution: "aria-query@npm:5.3.0"
|
||||
@@ -11054,7 +11120,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bs-logger@npm:0.x":
|
||||
"bs-logger@npm:0.x, bs-logger@npm:^0.2.6":
|
||||
version: 0.2.6
|
||||
resolution: "bs-logger@npm:0.2.6"
|
||||
dependencies:
|
||||
@@ -11342,6 +11408,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "chalk@npm:3.0.0"
|
||||
dependencies:
|
||||
ansi-styles: ^4.1.0
|
||||
supports-color: ^7.1.0
|
||||
checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "chalk@npm:4.1.2"
|
||||
@@ -12422,6 +12498,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css.escape@npm:^1.5.1":
|
||||
version: 1.5.1
|
||||
resolution: "css.escape@npm:1.5.1"
|
||||
checksum: f6d38088d870a961794a2580b2b2af1027731bb43261cfdce14f19238a88664b351cc8978abc20f06cc6bbde725699dec8deb6fe9816b139fc3f2af28719e774
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssesc@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "cssesc@npm:3.0.0"
|
||||
@@ -13241,6 +13324,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dom-accessibility-api@npm:^0.6.3":
|
||||
version: 0.6.3
|
||||
resolution: "dom-accessibility-api@npm:0.6.3"
|
||||
checksum: c325b5144bb406df23f4affecffc117dbaec9af03daad9ee6b510c5be647b14d28ef0a4ea5ca06d696d8ab40bb777e5fed98b985976fdef9d8790178fa1d573f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dom-converter@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "dom-converter@npm:0.2.0"
|
||||
@@ -16625,7 +16715,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ipaddr.js@npm:^2.0.1":
|
||||
"ipaddr.js@npm:^2.0.1, ipaddr.js@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "ipaddr.js@npm:2.2.0"
|
||||
checksum: 770ba8451fd9bf78015e8edac0d5abd7a708cbf75f9429ca9147a9d2f3a2d60767cd5de2aab2b1e13ca6e4445bdeff42bf12ef6f151c07a5c6cf8a44328e2859
|
||||
@@ -17893,7 +17983,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest@npm:^29.4.1":
|
||||
"jest@npm:^29.4.1, jest@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "jest@npm:29.7.0"
|
||||
dependencies:
|
||||
@@ -18781,7 +18871,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"make-error@npm:1.x, make-error@npm:^1.1.1":
|
||||
"make-error@npm:1.x, make-error@npm:^1.1.1, make-error@npm:^1.3.6":
|
||||
version: 1.3.6
|
||||
resolution: "make-error@npm:1.3.6"
|
||||
checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402
|
||||
@@ -23421,7 +23511,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0":
|
||||
"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3":
|
||||
version: 7.6.3
|
||||
resolution: "semver@npm:7.6.3"
|
||||
bin:
|
||||
@@ -24946,6 +25036,43 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-jest@npm:^29.2.5":
|
||||
version: 29.2.5
|
||||
resolution: "ts-jest@npm:29.2.5"
|
||||
dependencies:
|
||||
bs-logger: ^0.2.6
|
||||
ejs: ^3.1.10
|
||||
fast-json-stable-stringify: ^2.1.0
|
||||
jest-util: ^29.0.0
|
||||
json5: ^2.2.3
|
||||
lodash.memoize: ^4.1.2
|
||||
make-error: ^1.3.6
|
||||
semver: ^7.6.3
|
||||
yargs-parser: ^21.1.1
|
||||
peerDependencies:
|
||||
"@babel/core": ">=7.0.0-beta.0 <8"
|
||||
"@jest/transform": ^29.0.0
|
||||
"@jest/types": ^29.0.0
|
||||
babel-jest: ^29.0.0
|
||||
jest: ^29.0.0
|
||||
typescript: ">=4.3 <6"
|
||||
peerDependenciesMeta:
|
||||
"@babel/core":
|
||||
optional: true
|
||||
"@jest/transform":
|
||||
optional: true
|
||||
"@jest/types":
|
||||
optional: true
|
||||
babel-jest:
|
||||
optional: true
|
||||
esbuild:
|
||||
optional: true
|
||||
bin:
|
||||
ts-jest: cli.js
|
||||
checksum: d60d1e1d80936f6002b1bb27f7e062408bc733141b9d666565503f023c340a3196d506c836a4316c5793af81a5f910ab49bb9c13f66e2dc66de4e0f03851dbca
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-node@npm:^10.9.1":
|
||||
version: 10.9.2
|
||||
resolution: "ts-node@npm:10.9.2"
|
||||
|
||||
Reference in New Issue
Block a user