Merge branch 'main' of https://github.com/whs-authz-authn-project/caido-plugin-test into sujin
This commit is contained in:
commit
e7f9d5684b
24 changed files with 2836 additions and 57 deletions
32
.github/workflows/main.yml
vendored
Normal file
32
.github/workflows/main.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
name: Build and Upload Caido Plugin
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: oven-sh/setup-bun@v1
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
bun install
|
||||||
|
|
||||||
|
- name: Build plugin
|
||||||
|
run: |
|
||||||
|
bun run build
|
||||||
|
|
||||||
|
- name: Upload plugin artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: caido-plugin
|
||||||
|
path: dist
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -215,10 +215,11 @@ $RECYCLE.BIN/
|
||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
!dist/
|
#!dist/
|
||||||
dist/*
|
dist/*
|
||||||
packages/frontend/dist
|
packages/frontend/dist
|
||||||
packages/backend/dist
|
packages/backend/dist
|
||||||
!dist/*.zip
|
#!dist/*.zip
|
||||||
|
dist/plugin_package.zip
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux
|
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux
|
||||||
|
|
@ -1 +1,6 @@
|
||||||
# caido-plugin-test
|
# caido-plugin-test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
pnpm run watch
|
||||||
|
```
|
||||||
|
|
|
||||||
532
bun.lock
Normal file
532
bun.lock
Normal file
|
|
@ -0,0 +1,532 @@
|
||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "caido-oauth",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@caido-community/dev": "^0.1.3",
|
||||||
|
"@caido/sdk-backend": "^0.48.1",
|
||||||
|
"typescript": "5.5.4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@caido-community/dev": ["@caido-community/dev@0.1.6", "", { "dependencies": { "@caido/plugin-manifest": "0.3.0", "chalk": "5.4.1", "chokidar": "4.0.3", "commander": "13.0.0", "express": "5.0.0", "glob": "11.0.1", "jiti": "2.4.2", "jszip": "3.10.1", "tsup": "8.3.5", "vite": "6.0.7", "ws": "8.18.0", "zod": "3.24.1" }, "bin": { "caido-dev": "dist/cli.js" } }, "sha512-WAWmPdEahh4e24sO4crt+nvqZryhKsy4yP5QYGoyUKqEYVAct5S/lI9fHdoIRQPJDSds3ayB6jgMKAlifd8BAg=="],
|
||||||
|
|
||||||
|
"@caido/plugin-manifest": ["@caido/plugin-manifest@0.3.0", "", { "dependencies": { "ajv": "^8.17.0" } }, "sha512-HRGHf65K2sfSdaEUwkCNDlurJ4zL0bOUg/Db4u6CrwjTTzmg2gOzP6SzLRj+69gWmxOm5LUjhInNHaMIRmQkHw=="],
|
||||||
|
|
||||||
|
"@caido/quickjs-types": ["@caido/quickjs-types@0.18.0", "", {}, "sha512-hRXUVdDvlhEhvkBoWWytoVS2j1KDVZa8dx2Q/KvWUQTR57U8EMSYE9iFgvPhu78gS8z+RF42Zcb7moNx4SDMlw=="],
|
||||||
|
|
||||||
|
"@caido/sdk-backend": ["@caido/sdk-backend@0.48.1", "", { "dependencies": { "@caido/quickjs-types": "0.18.0", "@caido/sdk-shared": "^0.1.0" } }, "sha512-JvFeOlSqAKbj3OenBn0LPtCNaOV0x6YtaAQijpvYfBJK32Nvbf924Z10bFVCu+Clc5A1qr7HcAvJ/8B/aRikWA=="],
|
||||||
|
|
||||||
|
"@caido/sdk-shared": ["@caido/sdk-shared@0.1.1", "", {}, "sha512-JAV5ajUqxZdXYPTmDEvIKBZon8I5uHq44ATj0Nj3BVpllRDUGY9kcBd+PXMD50+3lv1CvhR3/f6q24T0+4aVJQ=="],
|
||||||
|
|
||||||
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg=="],
|
||||||
|
|
||||||
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.24.2", "", { "os": "android", "cpu": "x64" }, "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.24.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.24.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.24.2", "", { "os": "none", "cpu": "x64" }, "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.24.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.24.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA=="],
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.24.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
|
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||||
|
|
||||||
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.41.1", "", { "os": "android", "cpu": "arm" }, "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.41.1", "", { "os": "android", "cpu": "arm64" }, "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.41.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.41.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.41.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.41.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.41.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.41.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.41.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.41.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.41.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw=="],
|
||||||
|
|
||||||
|
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||||
|
|
||||||
|
"@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.9", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ=="],
|
||||||
|
|
||||||
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@22.15.29", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ=="],
|
||||||
|
|
||||||
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||||
|
|
||||||
|
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||||
|
|
||||||
|
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||||
|
|
||||||
|
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
||||||
|
|
||||||
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
|
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
||||||
|
|
||||||
|
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
||||||
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||||
|
|
||||||
|
"bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
|
||||||
|
|
||||||
|
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||||
|
|
||||||
|
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
|
||||||
|
|
||||||
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
|
|
||||||
|
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||||
|
|
||||||
|
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
|
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||||
|
|
||||||
|
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||||
|
|
||||||
|
"commander": ["commander@13.0.0", "", {}, "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ=="],
|
||||||
|
|
||||||
|
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||||
|
|
||||||
|
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
||||||
|
|
||||||
|
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
|
||||||
|
|
||||||
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||||
|
|
||||||
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.3.6", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg=="],
|
||||||
|
|
||||||
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
|
|
||||||
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||||
|
|
||||||
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||||
|
|
||||||
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||||
|
|
||||||
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
|
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|
||||||
|
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||||
|
|
||||||
|
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||||
|
|
||||||
|
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||||
|
|
||||||
|
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||||
|
|
||||||
|
"esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="],
|
||||||
|
|
||||||
|
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||||
|
|
||||||
|
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||||
|
|
||||||
|
"express": ["express@5.0.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.0.1", "content-disposition": "^1.0.0", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "^1.2.1", "debug": "4.3.6", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "^2.0.0", "fresh": "2.0.0", "http-errors": "2.0.0", "merge-descriptors": "^2.0.0", "methods": "~1.1.2", "mime-types": "^3.0.0", "on-finished": "2.4.1", "once": "1.4.0", "parseurl": "~1.3.3", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "router": "^2.0.0", "safe-buffer": "5.2.1", "send": "^1.1.0", "serve-static": "^2.1.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "^2.0.0", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-V4UkHQc+B7ldh1YC84HCXHwf60M4BOMvp9rkvTUWCK5apqDC1Esnbid4wm6nFyVuDy8XMfETsJw5lsIGBWyo0A=="],
|
||||||
|
|
||||||
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
|
||||||
|
|
||||||
|
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
|
||||||
|
|
||||||
|
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
||||||
|
|
||||||
|
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||||
|
|
||||||
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||||
|
|
||||||
|
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
|
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||||
|
|
||||||
|
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||||
|
|
||||||
|
"glob": ["glob@11.0.1", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", "minimatch": "^10.0.0", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw=="],
|
||||||
|
|
||||||
|
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||||
|
|
||||||
|
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
|
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
||||||
|
|
||||||
|
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||||
|
|
||||||
|
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
|
||||||
|
|
||||||
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||||
|
|
||||||
|
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||||
|
|
||||||
|
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||||
|
|
||||||
|
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="],
|
||||||
|
|
||||||
|
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||||
|
|
||||||
|
"joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
|
||||||
|
|
||||||
|
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||||
|
|
||||||
|
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||||
|
|
||||||
|
"jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
|
||||||
|
|
||||||
|
"jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="],
|
||||||
|
|
||||||
|
"jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
|
||||||
|
|
||||||
|
"lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
|
||||||
|
|
||||||
|
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||||
|
|
||||||
|
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||||
|
|
||||||
|
"load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
|
||||||
|
|
||||||
|
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
|
||||||
|
|
||||||
|
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
|
||||||
|
|
||||||
|
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
|
||||||
|
|
||||||
|
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
|
||||||
|
|
||||||
|
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
|
||||||
|
|
||||||
|
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
|
||||||
|
|
||||||
|
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||||
|
|
||||||
|
"lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="],
|
||||||
|
|
||||||
|
"lru-cache": ["lru-cache@11.1.0", "", {}, "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A=="],
|
||||||
|
|
||||||
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||||
|
|
||||||
|
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||||
|
|
||||||
|
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
|
||||||
|
|
||||||
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
|
"minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="],
|
||||||
|
|
||||||
|
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
|
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
|
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||||
|
|
||||||
|
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||||
|
|
||||||
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||||
|
|
||||||
|
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
|
||||||
|
|
||||||
|
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||||
|
|
||||||
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="],
|
||||||
|
|
||||||
|
"path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
|
||||||
|
|
||||||
|
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
|
||||||
|
|
||||||
|
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||||
|
|
||||||
|
"postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
|
||||||
|
|
||||||
|
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||||
|
|
||||||
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||||
|
|
||||||
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||||
|
|
||||||
|
"qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
|
||||||
|
|
||||||
|
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||||
|
|
||||||
|
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
||||||
|
|
||||||
|
"readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
|
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||||
|
|
||||||
|
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||||
|
|
||||||
|
"rollup": ["rollup@4.41.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.41.1", "@rollup/rollup-android-arm64": "4.41.1", "@rollup/rollup-darwin-arm64": "4.41.1", "@rollup/rollup-darwin-x64": "4.41.1", "@rollup/rollup-freebsd-arm64": "4.41.1", "@rollup/rollup-freebsd-x64": "4.41.1", "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", "@rollup/rollup-linux-arm-musleabihf": "4.41.1", "@rollup/rollup-linux-arm64-gnu": "4.41.1", "@rollup/rollup-linux-arm64-musl": "4.41.1", "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-musl": "4.41.1", "@rollup/rollup-linux-s390x-gnu": "4.41.1", "@rollup/rollup-linux-x64-gnu": "4.41.1", "@rollup/rollup-linux-x64-musl": "4.41.1", "@rollup/rollup-win32-arm64-msvc": "4.41.1", "@rollup/rollup-win32-ia32-msvc": "4.41.1", "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw=="],
|
||||||
|
|
||||||
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
|
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
|
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
|
||||||
|
|
||||||
|
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
|
||||||
|
|
||||||
|
"setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="],
|
||||||
|
|
||||||
|
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||||
|
|
||||||
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
|
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||||
|
|
||||||
|
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
||||||
|
|
||||||
|
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||||
|
|
||||||
|
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||||
|
|
||||||
|
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||||
|
|
||||||
|
"source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="],
|
||||||
|
|
||||||
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
|
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
||||||
|
|
||||||
|
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||||
|
|
||||||
|
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
|
"string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||||
|
|
||||||
|
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
|
||||||
|
|
||||||
|
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
|
||||||
|
|
||||||
|
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
||||||
|
|
||||||
|
"tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
|
||||||
|
|
||||||
|
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
|
||||||
|
|
||||||
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
|
"tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
|
||||||
|
|
||||||
|
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
||||||
|
|
||||||
|
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
||||||
|
|
||||||
|
"tsup": ["tsup@8.3.5", "", { "dependencies": { "bundle-require": "^5.0.0", "cac": "^6.7.14", "chokidar": "^4.0.1", "consola": "^3.2.3", "debug": "^4.3.7", "esbuild": "^0.24.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.24.0", "source-map": "0.8.0-beta.0", "sucrase": "^3.35.0", "tinyexec": "^0.3.1", "tinyglobby": "^0.2.9", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA=="],
|
||||||
|
|
||||||
|
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.5.4", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
|
|
||||||
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
|
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||||
|
|
||||||
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
|
"vite": ["vite@6.0.7", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.4.49", "rollup": "^4.23.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ=="],
|
||||||
|
|
||||||
|
"webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="],
|
||||||
|
|
||||||
|
"whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="],
|
||||||
|
|
||||||
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||||
|
|
||||||
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
|
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||||
|
|
||||||
|
"zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
|
"body-parser/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
|
||||||
|
"body-parser/qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
||||||
|
|
||||||
|
"debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||||
|
|
||||||
|
"finalhandler/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
|
||||||
|
"readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||||
|
|
||||||
|
"router/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
|
||||||
|
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
|
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||||
|
|
||||||
|
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||||
|
|
||||||
|
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||||
|
|
||||||
|
"tsup/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||||
|
|
||||||
|
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
|
"sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
|
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
dist/plugin_package.zip
vendored
BIN
dist/plugin_package.zip
vendored
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "caido-oauth",
|
"name": "caido-oauth-dev",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -9,6 +9,11 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@caido-community/dev": "^0.1.3",
|
"@caido-community/dev": "^0.1.3",
|
||||||
|
"@caido/sdk-backend": "^0.48.1",
|
||||||
"typescript": "5.5.4"
|
"typescript": "5.5.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"jsonwebtoken": "^9.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
144
packages/backend/src/controller/PKCECheck.ts
Normal file
144
packages/backend/src/controller/PKCECheck.ts
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
import type { SDK } from "caido:plugin";
|
||||||
|
import { Body, RequestSpec, type Request } from "caido:utils";
|
||||||
|
|
||||||
|
export class PKCECheck {
|
||||||
|
async test(sdk: SDK, req: Request): Promise<boolean> {
|
||||||
|
const method = req.getMethod();
|
||||||
|
if (method !== "GET") {
|
||||||
|
sdk.console.log("[PKCEDowngradeCheck] Not a GET request. Skipping.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = req.getQuery();
|
||||||
|
const searchParams = new URLSearchParams(query);
|
||||||
|
const requiredKeys = ["client_id", "response_type", "code_challenge", "code_challenge_method"];
|
||||||
|
|
||||||
|
if (!requiredKeys.every((key) => searchParams.has(key))) {
|
||||||
|
sdk.console.log("[PKCEDowngradeCheck] Required PKCE parameters missing. Skipping.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = req.getUrl();
|
||||||
|
const isOpenID = searchParams.get("scope")?.includes("openid") || url.includes("id_token");
|
||||||
|
const methodVal = searchParams.get("code_challenge_method");
|
||||||
|
const challengeVal = searchParams.get("code_challenge");
|
||||||
|
|
||||||
|
if (!methodVal || !challengeVal) {
|
||||||
|
sdk.console.log("[PKCEDowngradeCheck] code_challenge or method missing. Skipping.");
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: isOpenID
|
||||||
|
? "[WARN] OpenID Flow PKCE Parameters Missing"
|
||||||
|
: "[WARN] OAuth2 Flow PKCE Parameters Missing",
|
||||||
|
description: `PKCE parameters are missing or incomplete for ${url}. This may indicate a misconfiguration.`,
|
||||||
|
request: req,
|
||||||
|
reporter: "PKCE Checker",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodVal === "plain") {
|
||||||
|
sdk.console.log("[PKCEDowngradeCheck] code_challenge_method is 'plain'. Skipping.");
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: isOpenID
|
||||||
|
? "[WARN] OpenID Flow PKCE Method is 'plain'"
|
||||||
|
: "[WARN] OAuth2 Flow PKCE Method is 'plain'",
|
||||||
|
description: `PKCE method is set to 'plain' for ${url}. This may indicate a downgrade vulnerability.`,
|
||||||
|
request: req,
|
||||||
|
reporter: "PKCE Checker",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove PKCE parameters to simulate a downgraded request
|
||||||
|
searchParams.delete("code_challenge");
|
||||||
|
searchParams.delete("code_challenge_method");
|
||||||
|
const downgradedQuery = searchParams.toString();
|
||||||
|
const scheme = req.getUrl().startsWith("https") ? "https" : "http";
|
||||||
|
const downgradedUrl = `${scheme}://${req.getHost()}:${req.getPort()}${req.getPath()}?${downgradedQuery}`;
|
||||||
|
|
||||||
|
sdk.console.log(`${req.getHost()} Original URL: ` + url);
|
||||||
|
sdk.console.log(`${req.getHost()} Downgraded URL: ` + downgradedUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use Caido Replay SDK to replay the original request
|
||||||
|
const spec = new RequestSpec(downgradedUrl);
|
||||||
|
spec.setBody(req.getBody() as Body);
|
||||||
|
for (const [key, value] of Object.entries(req.getHeaders())) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
spec.setHeader(key, value.join(', ')); // or another suitable delimiter
|
||||||
|
} else {
|
||||||
|
spec.setHeader(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spec.setHost(req.getHost());
|
||||||
|
spec.setMethod(req.getMethod());
|
||||||
|
spec.setPath(req.getPath());
|
||||||
|
spec.setQuery(downgradedQuery);
|
||||||
|
spec.setTls(req.getTls());
|
||||||
|
spec.setPort(req.getPort());
|
||||||
|
|
||||||
|
let sendDowngradedRequest = await sdk.requests.send(spec);
|
||||||
|
|
||||||
|
if (sendDowngradedRequest.response) {
|
||||||
|
let domain = spec.getHost();
|
||||||
|
let port = spec.getPort();
|
||||||
|
let path = spec.getPath();
|
||||||
|
let query = spec.getQuery();
|
||||||
|
let id = sendDowngradedRequest.response.getId();
|
||||||
|
let code = sendDowngradedRequest.response.getCode();
|
||||||
|
sdk.console.log(`REQ ${id}: ${domain}:${port}${path}${query} received a status code of ${code}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendDowngradedRequest.response?.getCode() === 302) {
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: isOpenID
|
||||||
|
? "[CRITICAL] OpenID Flow PKCE Downgrade Vulnerability"
|
||||||
|
: "[CRITICAL] OAuth2 Flow PKCE Downgrade Vulnerability",
|
||||||
|
description: `The request to ${url} is vulnerable to a PKCE downgrade attack. This may indicate a configuration error.`,
|
||||||
|
request: req,
|
||||||
|
reporter: "PKCE Checker",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
sdk.console.log(`${req.getHost()} Original Status: ` + resOriginal.status);
|
||||||
|
sdk.console.log(`${req.getHost()} Downgraded Status: ` + resDowngraded.status);
|
||||||
|
|
||||||
|
sdk.console.log(`${req.getHost()} Original Headers: ` + JSON.stringify(resOriginal.headers));
|
||||||
|
sdk.console.log(`${req.getHost()} Downgraded Headers: ` + JSON.stringify(resDowngraded.headers));
|
||||||
|
|
||||||
|
// Caido Dev Docs 기준으로, 리다이렉트된 URL은 Response 객체의 url 속성에 저장되어 있음
|
||||||
|
const locationOriginal = resOriginal.url ?? "";
|
||||||
|
const locationDowngraded = resDowngraded.url ?? "";
|
||||||
|
|
||||||
|
sdk.console.log(`${req.getHost()} Original Location: ` + locationOriginal);
|
||||||
|
sdk.console.log(`${req.getHost()} Downgraded Location: ` + locationDowngraded);
|
||||||
|
|
||||||
|
const statusEqual = resOriginal.status === resDowngraded.status;
|
||||||
|
const codeInRedirects = locationOriginal.includes("code=") && locationDowngraded.includes("code=");
|
||||||
|
|
||||||
|
if (statusEqual && codeInRedirects) {
|
||||||
|
const title = isOpenID
|
||||||
|
? "[CRITICAL] OpenID Flow PKCE Downgraded to Plaintext"
|
||||||
|
: "[CRITICAL] OAuth2 Flow PKCE Downgraded to Plaintext";
|
||||||
|
const reference = isOpenID
|
||||||
|
? "https://openid.net/specs/openid-igov-oauth2-1_0-02.html#rfc.section.3.1.7"
|
||||||
|
: "https://datatracker.ietf.org/doc/html/rfc7636";
|
||||||
|
|
||||||
|
await sdk.findings.create({
|
||||||
|
title,
|
||||||
|
description: `PKCE downgrade detected for ${url}.\n\nDowngraded URL: ${downgradedUrl}\n\nRedirect contained code=.\n\nReference: ${reference}`,
|
||||||
|
request: req,
|
||||||
|
reporter: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
} catch (err) {
|
||||||
|
sdk.console.error(`PKCE downgrade check failed for ${url}: ${String(err)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdk.console.log("[PKCEDowngradeCheck] No PKCE downgrade detected.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
170
packages/backend/src/controller/accessTokenDetector.ts
Normal file
170
packages/backend/src/controller/accessTokenDetector.ts
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
import type { Request, Response } from "caido:utils";
|
||||||
|
import type { SDK, DefineAPI } from "caido:plugin";
|
||||||
|
|
||||||
|
// 토큰 누출 검사 결과를 담는 구조
|
||||||
|
export interface TokenLeakResult {
|
||||||
|
found: boolean; // 토큰이 발견되었는지 여부 (true/false)
|
||||||
|
location: 'url' | 'body' | 'header'; // 토큰이 발견된 위치 (url, body, header 중 하나)
|
||||||
|
title: string; // 경고 제목
|
||||||
|
description: string; // 상세 설명
|
||||||
|
value?: string; // 실제 발견된 값 (선택적)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 액세스 토큰 누출 검사 클래스
|
||||||
|
export class AccessTokenLeakController {
|
||||||
|
async testReq(sdk: SDK<DefineAPI<{}>>, request: Request): Promise<void> {
|
||||||
|
const result = await this._scanRequest(request);
|
||||||
|
if (result) {
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: result.title,
|
||||||
|
description: result.description,
|
||||||
|
request,
|
||||||
|
reporter: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async testResp(sdk: SDK<DefineAPI<{}>>, response: Response, request: Request): Promise<void> {
|
||||||
|
const result = await this._scanResponse(response);
|
||||||
|
if (result) {
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: result.title,
|
||||||
|
description: result.description,
|
||||||
|
request,
|
||||||
|
reporter: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request - 검사할 HTTP 요청 객체
|
||||||
|
* @returns 토큰이 발견되면 결과 객체, 없으면 null
|
||||||
|
*/
|
||||||
|
async _scanRequest(request: Request): Promise<TokenLeakResult | null> {
|
||||||
|
|
||||||
|
// === 1. URL에서 토큰 검사 ===
|
||||||
|
const url = request.getUrl();
|
||||||
|
|
||||||
|
const extractedTokenFromUrl = this.extractTokenFromText(url);
|
||||||
|
|
||||||
|
if (extractedTokenFromUrl) {
|
||||||
|
return {
|
||||||
|
found: true,
|
||||||
|
location: 'url',
|
||||||
|
title: "Access Token Leak in URL",
|
||||||
|
description: `요청 URL에 토큰이 포함되어 있습니다. (토큰: ${extractedTokenFromUrl.substring(0, 20)}...)`,
|
||||||
|
value: url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 2. 요청 본문(Body)에서 토큰 검사 ===
|
||||||
|
const body = request.getBody();
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
const bodyText = await body.toText();
|
||||||
|
|
||||||
|
const extractedTokenFromBody = this.extractTokenFromText(bodyText);
|
||||||
|
|
||||||
|
if (extractedTokenFromBody) {
|
||||||
|
return {
|
||||||
|
found: true,
|
||||||
|
location: 'body',
|
||||||
|
title: "Access Token Leak in Request Body",
|
||||||
|
description: `요청 Body에 토큰이이 포함되어 있습니다. (토큰: ${extractedTokenFromBody.substring(0, 20)}...)`,
|
||||||
|
value: bodyText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP 응답에서 액세스 토큰 누출 검사
|
||||||
|
* @param response - 검사할 HTTP 응답 객체
|
||||||
|
* @returns 토큰이 발견되면 결과 객체, 없으면 null
|
||||||
|
*/
|
||||||
|
async _scanResponse(response: Response): Promise<TokenLeakResult | null> {
|
||||||
|
|
||||||
|
// === 1. Location 헤더에서 토큰 검사 ===
|
||||||
|
const locationHeader = response.getHeader("Location");
|
||||||
|
|
||||||
|
const locationHeaderStr = Array.isArray(locationHeader) ? locationHeader.join(', ') : locationHeader;
|
||||||
|
|
||||||
|
if (locationHeaderStr) {
|
||||||
|
const extractedTokenFromHeader = this.extractTokenFromText(locationHeaderStr);
|
||||||
|
|
||||||
|
if (extractedTokenFromHeader) {
|
||||||
|
return {
|
||||||
|
found: true,
|
||||||
|
location: 'header',
|
||||||
|
title: "Access Token Leak in Redirect URL",
|
||||||
|
description: `Location 헤더에 토큰이 노출되었습니다: ${locationHeaderStr} (토큰: ${extractedTokenFromHeader.substring(0, 20)}...)`,
|
||||||
|
value: locationHeaderStr
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 2. 응답 본문에서 토큰 검사 ===
|
||||||
|
const bodyBytes = response.getBody();
|
||||||
|
|
||||||
|
if (bodyBytes) {
|
||||||
|
const bodyText = await bodyBytes.toText();
|
||||||
|
|
||||||
|
const extractedTokenFromBody = this.extractTokenFromText(bodyText);
|
||||||
|
|
||||||
|
if (extractedTokenFromBody) {
|
||||||
|
return {
|
||||||
|
found: true,
|
||||||
|
location: 'body',
|
||||||
|
title: "Access Token Leak in Response Body",
|
||||||
|
description: `HTTP 응답 본문에 토큰이 노출되었습니다. (토큰: ${extractedTokenFromBody.substring(0, 20)}...)`,
|
||||||
|
value: bodyText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 텍스트에서 실제 토큰 값을 추출
|
||||||
|
* @param text - 검사할 텍스트
|
||||||
|
* @returns 토큰 값이 있으면 해당 값, 없으면 null
|
||||||
|
*/
|
||||||
|
private extractTokenFromText(text: string): string | null {
|
||||||
|
// 토큰 관련 키워드 리스트
|
||||||
|
const tokenKeys = [
|
||||||
|
'access_token',
|
||||||
|
'id_token',
|
||||||
|
'auth_token',
|
||||||
|
'token',
|
||||||
|
'jwt',
|
||||||
|
'session_token'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 정규표현식 패턴 리스트 생성
|
||||||
|
const tokenPatterns: RegExp[] = [];
|
||||||
|
|
||||||
|
for (const key of tokenKeys) {
|
||||||
|
// 1. key=token 또는 key: token
|
||||||
|
tokenPatterns.push(new RegExp(`${key}[=:]\\s*([a-zA-Z0-9\\-._~+/]+=*)`, 'i'));
|
||||||
|
|
||||||
|
// 2. JSON 형태의 "key": "token"
|
||||||
|
tokenPatterns.push(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`, 'i'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Authorization: Bearer <token> 형태
|
||||||
|
tokenPatterns.push(/bearer\s+([a-zA-Z0-9\-._~+/]+=*)/i);
|
||||||
|
|
||||||
|
// 모든 패턴에 대해 검사
|
||||||
|
for (const pattern of tokenPatterns) {
|
||||||
|
const match = pattern.exec(text);
|
||||||
|
if (match && match[1]) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
181
packages/backend/src/controller/csrfCheck.ts
Normal file
181
packages/backend/src/controller/csrfCheck.ts
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
import type { Request, Response } from "caido:utils";
|
||||||
|
import type { SDK, DefineAPI } from "caido:plugin";
|
||||||
|
import { HttpUtils } from "../utils/http";
|
||||||
|
|
||||||
|
const httpUtils = new HttpUtils();
|
||||||
|
|
||||||
|
export class CsrfCheck {
|
||||||
|
private isOauthUri(request: Request): boolean {
|
||||||
|
const query = request.getQuery() || "";
|
||||||
|
|
||||||
|
// Check if the request is an OAuth authorization request
|
||||||
|
if (
|
||||||
|
query.includes("client_id=") &&
|
||||||
|
(query.includes("response_type=") ||
|
||||||
|
query.includes("grant_type=") ||
|
||||||
|
query.includes("redirect_uri=") ||
|
||||||
|
query.includes("scope=") ||
|
||||||
|
query.includes("state="))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isOauthRedirectResponse(response: Response): boolean {
|
||||||
|
const status = response.getCode();
|
||||||
|
const locationHeader = httpUtils.getHeaderValue(
|
||||||
|
response.getHeaders(),
|
||||||
|
"location"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
status >= 300 &&
|
||||||
|
status < 400 &&
|
||||||
|
locationHeader &&
|
||||||
|
(locationHeader.includes("client_id=") ||
|
||||||
|
locationHeader.includes("response_type=") ||
|
||||||
|
locationHeader.includes("grant_type=") ||
|
||||||
|
locationHeader.includes("redirect_uri=") ||
|
||||||
|
locationHeader.includes("scope=") ||
|
||||||
|
locationHeader.includes("state=") ||
|
||||||
|
locationHeader.includes("code=")) // code is also common in OAuth redirects
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isStateInQuery(request: Request): boolean {
|
||||||
|
const query = request.getQuery();
|
||||||
|
const stateValue = httpUtils.getQueryParam(query || "", "state");
|
||||||
|
if (!stateValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkStateAtResponseLocationHeader(
|
||||||
|
request: Request,
|
||||||
|
response: Response
|
||||||
|
): string[] | 0 {
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
this.isOauthUri(request) &&
|
||||||
|
this.isStateInQuery(request) &&
|
||||||
|
this.isOauthRedirectResponse(response)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return 0; // Not a target, no CSRF risk
|
||||||
|
}
|
||||||
|
|
||||||
|
// 요청에서 보낸 state 추출
|
||||||
|
const query = request.getQuery() || "";
|
||||||
|
const originalState = httpUtils.getQueryParam(query, "state");
|
||||||
|
|
||||||
|
// 리다이렉트 URL에서 쿼리 부분만 추출
|
||||||
|
const locationHeader = httpUtils.getHeaderValue(
|
||||||
|
response.getHeaders(),
|
||||||
|
"location"
|
||||||
|
);
|
||||||
|
const responseState = httpUtils.getQueryParamFromURI(
|
||||||
|
locationHeader || "",
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
|
||||||
|
// state가 없거나, 요청값과 다르면 CSRF 위험
|
||||||
|
if (!responseState) {
|
||||||
|
// missing state
|
||||||
|
return ["state parameter is missing in the response location header"];
|
||||||
|
}
|
||||||
|
if (originalState !== responseState) {
|
||||||
|
// mismatch
|
||||||
|
return ["state parameter mismatch between request and response"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // no CSRF risk detected
|
||||||
|
}
|
||||||
|
|
||||||
|
// private async checkStateReuse(
|
||||||
|
// request: Request,
|
||||||
|
// originResponse: Response
|
||||||
|
// ): Promise<string[] | 0> {
|
||||||
|
// // uri에 oauth 관련 파라미터가 없지만, 응답이 oauth 리다이렉트 응답인지 확인
|
||||||
|
// // 즉, 처음으로 state를 발급한 요청인지 확인
|
||||||
|
// if (
|
||||||
|
// !(
|
||||||
|
// !this.isOauthUri(request) &&
|
||||||
|
// this.isOauthRedirectResponse(originResponse)
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// return 0; // Not a target, no CSRF risk
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const originResponseLocationHeader = httpUtils.getHeaderValue(
|
||||||
|
// originResponse.getHeaders(),
|
||||||
|
// "location"
|
||||||
|
// );
|
||||||
|
// const originState = httpUtils.getQueryParamFromURI(
|
||||||
|
// originResponseLocationHeader || "",
|
||||||
|
// "state"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const requestHeaders = request.getHeaders();
|
||||||
|
// const noCookieHeaders = httpUtils.removeHeaders(requestHeaders, ["cookie"]);
|
||||||
|
// const newResponse = await httpUtils.resend(request, {
|
||||||
|
// headers: noCookieHeaders,
|
||||||
|
// });
|
||||||
|
// const newLocationHeader = httpUtils.getHeaderValue(
|
||||||
|
// newResponse.getHeaders(),
|
||||||
|
// "location"
|
||||||
|
// );
|
||||||
|
// const newState = httpUtils.getQueryParamFromURI(
|
||||||
|
// newLocationHeader || "",
|
||||||
|
// "state"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (originState === newState) {
|
||||||
|
// return [
|
||||||
|
// "State parameter reused in the response location header, indicating a potential CSRF risk",
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return 0; // no CSRF risk detected
|
||||||
|
// }
|
||||||
|
|
||||||
|
async checker(
|
||||||
|
sdk: SDK<DefineAPI<{}>, {}>,
|
||||||
|
request: Request,
|
||||||
|
response: Response
|
||||||
|
): Promise<void> {
|
||||||
|
let result = ``;
|
||||||
|
|
||||||
|
// 쿼리에 state 파라미터가 없으면 CSRF 위험
|
||||||
|
if (this.isOauthUri(request) && !this.isStateInQuery(request)) {
|
||||||
|
result += "CSRF risk: missing state parameter"; // CSRF risk: missing state parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// location 헤더에 state 파라미터가 없거나, 요청에서 보낸 state와 다르면 CSRF 위험
|
||||||
|
const stateAtResponseLocationHeaderCheck =
|
||||||
|
this.checkStateAtResponseLocationHeader(request, response);
|
||||||
|
if (stateAtResponseLocationHeaderCheck !== 0) {
|
||||||
|
result += `, ${stateAtResponseLocationHeaderCheck.join(", ")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 처음으로 state를 발급한 요청에서 state 파라미터를 바꿔서 보내기
|
||||||
|
// const reusedStateCheck = await this.checkStateReuse(request, response);
|
||||||
|
// if (reusedStateCheck !== 0) {
|
||||||
|
// result += `, ${reusedStateCheck.join(", ")}`;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
await sdk.findings.create({
|
||||||
|
title: "csrf vuln",
|
||||||
|
description: `SSO-related parameters detected in response:\n\n${request.getMethod()} ${request.getUrl()} : ${result}`,
|
||||||
|
request,
|
||||||
|
reporter: "csrf reporter",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
packages/backend/src/controller/scopeDetection.ts
Normal file
83
packages/backend/src/controller/scopeDetection.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
import type { SDK } from "caido:plugin";
|
||||||
|
import { RequestSpec } from "caido:utils";
|
||||||
|
|
||||||
|
export class ScopeDetection {
|
||||||
|
async scan(
|
||||||
|
sdk: SDK,
|
||||||
|
url: string
|
||||||
|
): Promise<{ data: string }> {
|
||||||
|
sdk.console.log(`들어온 url : ${url}`); // url이 잘 들어왔는지 확인함요
|
||||||
|
|
||||||
|
// url이 string이 아니고 , 값이 없거나 그럴 때 유효한 값 넣으라고 출력.
|
||||||
|
if (!url || typeof url !== "string") {
|
||||||
|
sdk.console.log("이상한 url 입력함.");
|
||||||
|
return { data: "알맞은 URL을 입력하세요." };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const spec = new RequestSpec(url); // url에 GET 요청 보낼거긔.
|
||||||
|
spec.setMethod("GET");
|
||||||
|
spec.setHeader("User-Agent", "Caido Scanner");
|
||||||
|
spec.setHeader("Accept", "*/*");
|
||||||
|
sdk.console.log(`요청 URL: ${url}`);
|
||||||
|
|
||||||
|
const res = await sdk.requests.send(spec); // 요청 보내고 응답 받음.
|
||||||
|
sdk.console.log('[SCAN] 응답 :', res);
|
||||||
|
sdk.console.log(`[SCAN] 요청 성공:${(res as any).status}`);
|
||||||
|
sdk.console.log(`[SCAN] body: ${(res as any).body ? (res as any).body.toString().substring(0, 100) : "없음"}`);
|
||||||
|
|
||||||
|
const html = (res as any).body ? (res as any).body.toString() : "";
|
||||||
|
|
||||||
|
// <a href= 형태 링크 찾을거임.
|
||||||
|
const anchorRegex = /<a\s+[^>]*href="([^"]+)"[^>]*>/gi;
|
||||||
|
const anchors: string[] = [];
|
||||||
|
let match;
|
||||||
|
while ((match = anchorRegex.exec(html)) !== null) { // html에서 a href 찾아 배열에 저장함.
|
||||||
|
if (typeof match[1] === "string") {
|
||||||
|
anchors.push(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sdk.console.log(`찾아진 a href 개수: ${anchors.length}`);
|
||||||
|
|
||||||
|
// 5. scope 탐지
|
||||||
|
const results: string[] = [];
|
||||||
|
anchors.forEach((href) => { // 추출한 a href 링크 하나씩 검사드감.
|
||||||
|
try {
|
||||||
|
const absHref = new URL(href, url).href; // 상대경로라면 url 기준으로 절대 URL 바꿔줌줌
|
||||||
|
sdk.console.log(`[SCAN] 절대 URL 변환: ${href} -> ${absHref}`); //
|
||||||
|
|
||||||
|
if (/oauth|authorize|login|accounts|auth/i.test(absHref)) { // url에 이런 OAuth 키워드가 있는지 필터링.
|
||||||
|
let u: URL;
|
||||||
|
try {
|
||||||
|
u = new URL(absHref); // 필터링된 url을 url 객체로 파싱. 정식 url인 경우 변수 u에 저장.
|
||||||
|
} catch (err) { // 파싱 실패하면
|
||||||
|
sdk.console.log(
|
||||||
|
`URL 파싱 실패 : ${absHref} (${err instanceof Error ? err.message : err})`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const scope = u.searchParams.get("scope"); // url에 scope있긔?scope값 가져와.
|
||||||
|
if (scope && /all|\*/i.test(scope)) { // scope가 존재하고 all, *있다면.
|
||||||
|
results.push(`위험한 scope 발견: ${scope}\n -> ${absHref}`); // results에 경고 메시지 전달.
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
sdk.console.log(`searchParams.get 실패`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
sdk.console.log(
|
||||||
|
`URL 파싱 실패 (absHref 단계): ${href} (${e instanceof Error ? e.message : e})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const resultStr = results.join("\n") || "위험한 scope가 발견되지 않았습니다.";
|
||||||
|
return { data: resultStr }; // 성공했는지 실패했는지 App.vue한테 전달할 메시지.
|
||||||
|
} catch (e) {
|
||||||
|
sdk.console.log(`백엔드 에러: ${e instanceof Error ? e.message : e}`);
|
||||||
|
return { data: "백엔드 에러: " + (e instanceof Error ? e.message : String(e)) }; // App.vue에 전달할 메시지.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,60 +1,56 @@
|
||||||
import type { SDK, DefineAPI } from "caido:plugin";
|
import type { SDK, DefineAPI } from "caido:plugin";
|
||||||
import type { Request, Response } from "caido:utils";
|
import type { Request, Response } from "caido:utils";
|
||||||
import { ImplicitGrantController } from "./controller/implictGrant";
|
// import { ImplicitGrantController } from "./controller/implictGrant";
|
||||||
import { AuthZCodeGrantController } from "./controller/authZCodeGrant";
|
// import { AuthZCodeGrantController } from "./controller/authZCodeGrant";
|
||||||
import { NonceCheckController } from "./controller/nonceCheck";
|
import { CsrfCheck } from "./controller/csrfCheck";
|
||||||
|
import { PKCECheck } from "./controller/PKCECheck";
|
||||||
|
import { AccessTokenLeakController } from "./controller/accessTokenDetector";
|
||||||
|
import { ScopeDetection } from "./controller/scopeDetection";
|
||||||
|
|
||||||
export type API = DefineAPI<{}>;
|
export type API = DefineAPI<{}>;
|
||||||
|
|
||||||
const implicitGrantController = new ImplicitGrantController();
|
const csrfCheck = new CsrfCheck();
|
||||||
const authZCodeGrantController = new AuthZCodeGrantController();
|
// const implicitGrantController = new ImplicitGrantController();
|
||||||
const nonceCheckController = new NonceCheckController();
|
// const authZCodeGrantController = new AuthZCodeGrantController();
|
||||||
|
const pkceCheckController = new PKCECheck();
|
||||||
// function matchSSORequest(req: Request): boolean {
|
const tokenCheck = new AccessTokenLeakController();
|
||||||
// const raw = req.getRaw().toString();
|
const ScopeDetectionController = new ScopeDetection();
|
||||||
|
|
||||||
// // 조건 3: Raw request에 SAMLRequest 또는 SAMLResponse 포함
|
|
||||||
// if (raw.includes("SAMLRequest=") || raw.includes("SAMLResponse=")) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function matchAccessTokenResponse(resp: Response): boolean {
|
|
||||||
// const raw = resp.getRaw().toString();
|
|
||||||
|
|
||||||
// const match = /"access_token"\s*:\s*"([^"]+)"/.exec(raw);
|
|
||||||
// return !!match;
|
|
||||||
// }
|
|
||||||
|
|
||||||
export function init(sdk: SDK<API>) {
|
export function init(sdk: SDK<API>) {
|
||||||
// 요청 이벤트
|
// sdk.events.onInterceptRequest(async (sdk, req: Request) => {
|
||||||
sdk.events.onInterceptRequest(async (sdk, req) => {
|
// const result = csrfCheck.checker(req);
|
||||||
const result =
|
|
||||||
authZCodeGrantController.testReq(req) ||
|
|
||||||
implicitGrantController.testReq(req);
|
|
||||||
|
|
||||||
if (result) {
|
// if (result) {
|
||||||
await sdk.findings.create({
|
// await sdk.findings.create({
|
||||||
title: "Possible SSO Request Detected",
|
// title: "Possible SSO Request Detected",
|
||||||
description: `SSO-related parameters detected in request:\n\n${req.getMethod()} ${req.getUrl()} : ${result}`,
|
// description: `SSO-related parameters detected in request:\n\n${req.getMethod()} ${req.getUrl()} : ${result}`,
|
||||||
request: req,
|
// request: req,
|
||||||
reporter: "",
|
// reporter: "",
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 응답 이벤트
|
sdk.events.onInterceptResponse(
|
||||||
sdk.events.onInterceptResponse(async (sdk, req, res) => {
|
async (sdk: SDK<DefineAPI<{}>, {}>, req: Request, resp: Response) => {
|
||||||
|
await csrfCheck.checker(sdk, req, resp);
|
||||||
|
await pkceCheckController.test(sdk, req);
|
||||||
|
await tokenCheck.testReq(sdk, req);
|
||||||
|
await tokenCheck.testResp(sdk, resp, req);
|
||||||
|
await ScopeDetectionController.scan(sdk, req.getUrl());
|
||||||
|
// sdk.events.onInterceptRequest(async (sdk, req: Request) => {
|
||||||
|
// const result =
|
||||||
|
// authZCodeGrantController.testReq(req) ||
|
||||||
|
// implicitGrantController.testReq(req);
|
||||||
|
|
||||||
if (NonceCheckController.isOidcFlow(req, res)) {
|
// if (result) {
|
||||||
await sdk.findings.create({
|
// await pkceCheckController.test(sdk, req);
|
||||||
title: "OIDC Flow Detected",
|
|
||||||
description: "The request appears to be part of an OIDC flow.",
|
// await sdk.findings.create({
|
||||||
request: req,
|
// title: "Possible SSO Request Detected",
|
||||||
reporter: "",
|
// description: `SSO-related parameters detected in request:\n\n${req.getMethod()} ${req.getUrl()} : ${result}`,
|
||||||
});
|
// request: req,
|
||||||
|
// reporter: "",
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
210
packages/backend/src/utils/http.ts
Normal file
210
packages/backend/src/utils/http.ts
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
let instance: HttpUtils | null = null;
|
||||||
|
export class HttpUtils {
|
||||||
|
/**
|
||||||
|
* 싱글턴 인스턴스를 생성합니다.
|
||||||
|
*/
|
||||||
|
public constructor() {
|
||||||
|
if (instance) {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
instance = this;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URI 디코딩 후 소문자로 변환하는 헬퍼 함수
|
||||||
|
* @param value - 디코딩하고 소문자로 변환할 문자열
|
||||||
|
* @returns 디코딩 및 소문자 변환된 문자열
|
||||||
|
*/
|
||||||
|
decodeAndLower(value: string): string {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(value).toLowerCase();
|
||||||
|
} catch {
|
||||||
|
return value.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 헤더 객체의 키와 값을 전부 소문자로 변환합니다.
|
||||||
|
* @param headers - Record<string, string | string[]> 형태의 헤더 맵
|
||||||
|
* @returns - 키와 값이 모두 소문자로 변환된 새 헤더 맵
|
||||||
|
*/
|
||||||
|
lowerCaseAllHeaders(
|
||||||
|
headers: Record<string, string | string[]>
|
||||||
|
): Record<string, string | string[]> {
|
||||||
|
const result: Record<string, string | string[]> = {};
|
||||||
|
|
||||||
|
for (const [rawKey, rawValue] of Object.entries(headers)) {
|
||||||
|
const key = this.decodeAndLower(rawKey);
|
||||||
|
|
||||||
|
if (Array.isArray(rawValue)) {
|
||||||
|
result[key] = rawValue.map((v) => this.decodeAndLower(v));
|
||||||
|
} else {
|
||||||
|
result[key] = this.decodeAndLower(rawValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
getQueryParamFromURI(uri: string, key: string): string | null {
|
||||||
|
uri = uri.toLowerCase();
|
||||||
|
key = key.toLowerCase();
|
||||||
|
try {
|
||||||
|
const urlObj = new URL(uri);
|
||||||
|
return urlObj.searchParams.get(key);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query
|
||||||
|
/**
|
||||||
|
* 주어진 쿼리 문자열(query)에서 key에 해당하는 값을 반환합니다.
|
||||||
|
* @param query - "a=1&b=2..." 형태의 쿼리 문자열 (맨 앞 ? 는 없어야 합니다)
|
||||||
|
* @param key - 가져오고 싶은 파라미터 이름
|
||||||
|
* @returns - 해당 파라미터 값, 없으면 null
|
||||||
|
*/
|
||||||
|
getQueryParam(query: string, key: string): string | null {
|
||||||
|
query = query.toLowerCase();
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
|
const params = new URLSearchParams(query);
|
||||||
|
return params.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주어진 쿼리 문자열(query)에 key=value를 설정하고, 전체 쿼리 문자열을 반환합니다.
|
||||||
|
* - 이미 key가 있으면 덮어쓰기(set), 없으면 새로 추가합니다.
|
||||||
|
* @param query - "a=1&b=2..." 형태의 쿼리 문자열 (맨 앞 ? 는 없어야 합니다)
|
||||||
|
* @param key - 설정할 파라미터 이름
|
||||||
|
* @param value - 설정할 값
|
||||||
|
* @returns - "a=1&b=2&c=3..." 형태의 새로운 쿼리 문자열
|
||||||
|
*/
|
||||||
|
setQueryParam(query: string, key: string, value: string): string {
|
||||||
|
query = query.toLowerCase();
|
||||||
|
key = key.toLowerCase();
|
||||||
|
value = value.toLowerCase();
|
||||||
|
|
||||||
|
const params = new URLSearchParams(query);
|
||||||
|
params.set(key, value);
|
||||||
|
return params.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주어진 쿼리 문자열(query)에서 key에 해당하는 파라미터를 삭제(delete)하고,
|
||||||
|
* 전체 쿼리 문자열을 반환합니다.
|
||||||
|
* @param query - "a=1&b=2..." 형태의 쿼리 문자열 (맨 앞 ? 는 없어야 합니다)
|
||||||
|
* @param key - 삭제할 파라미터 이름
|
||||||
|
* @returns - 삭제된 상태의 새로운 쿼리 문자열
|
||||||
|
*/
|
||||||
|
removeQueryParam(query: string, key: string): string {
|
||||||
|
query = query.toLowerCase();
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
|
const params = new URLSearchParams(query);
|
||||||
|
params.delete(key);
|
||||||
|
return params.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
/**
|
||||||
|
* 주어진 헤더 맵에서 name에 해당하는 첫 번째 헤더 값을 반환합니다.
|
||||||
|
* @param headers - Response.getHeaders() 가 반환하는 객체
|
||||||
|
* @param name - 꺼내고 싶은 헤더 이름 (예: "location", "Content-Type")
|
||||||
|
* @returns - 해당 헤더의 첫 번째 값, 없으면 null
|
||||||
|
*/
|
||||||
|
getHeaderValue(
|
||||||
|
headers: Record<string, string | string[]>,
|
||||||
|
name: string
|
||||||
|
): string | null {
|
||||||
|
const normalized = this.lowerCaseAllHeaders(headers);
|
||||||
|
const target = name.toLowerCase();
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(normalized)) {
|
||||||
|
if (key === target) {
|
||||||
|
let rawValue: string | null = null;
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
rawValue = value.length > 0 && value[0] ? value[0] : null;
|
||||||
|
} else {
|
||||||
|
rawValue = value.length > 0 ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawValue !== null) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(rawValue);
|
||||||
|
} catch {
|
||||||
|
return rawValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주어진 헤더 맵에서 name에 해당하는 헤더 값을 value로 변경한 새 맵을 반환합니다.
|
||||||
|
* - 기존 헤더 이름의 대소문자를 보존합니다.
|
||||||
|
* - value가 string인 경우 [value] 형태로, string[]인 경우 그대로 사용합니다.
|
||||||
|
* - 기존에 해당 헤더가 없으면 새로 추가합니다.
|
||||||
|
*
|
||||||
|
* @param headers - 키가 헤더 이름, 값이 문자열 배열인 헤더 맵
|
||||||
|
* @param name - 변경할 헤더 이름 (예: "Authorization", "X-Custom-Header")
|
||||||
|
* @param value - 새로 설정할 값 (string 또는 string[])
|
||||||
|
* @returns - 지정된 헤더가 업데이트된 새로운 헤더 맵
|
||||||
|
*/
|
||||||
|
setHeaderValue(
|
||||||
|
headers: Record<string, string | string[]>,
|
||||||
|
name: string,
|
||||||
|
value: string | string[]
|
||||||
|
): Record<string, string[]> {
|
||||||
|
headers = this.lowerCaseAllHeaders(headers);
|
||||||
|
const lowerName = name.toLowerCase();
|
||||||
|
const newHeaders: Record<string, string[]> = {};
|
||||||
|
|
||||||
|
// 1) 기존 헤더 복사하되, name과 일치하는 항목은 value로 대체
|
||||||
|
for (const [key, vals] of Object.entries(headers)) {
|
||||||
|
if (key.toLowerCase() === lowerName) {
|
||||||
|
newHeaders[key] = Array.isArray(value) ? value : [value];
|
||||||
|
} else {
|
||||||
|
newHeaders[key] = Array.isArray(vals) ? vals : [vals];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) 해당 헤더가 원래 없었다면 새로 추가
|
||||||
|
const exists = Object.keys(newHeaders).some(
|
||||||
|
(k) => k.toLowerCase() === lowerName
|
||||||
|
);
|
||||||
|
if (!exists) {
|
||||||
|
newHeaders[name] = Array.isArray(value) ? value : [value];
|
||||||
|
}
|
||||||
|
|
||||||
|
return newHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주어진 헤더 맵에서 특정 이름(들)에 해당하는 헤더를 제거한 새 맵을 반환합니다.
|
||||||
|
* @param headers - 키가 헤더 이름, 값이 문자열 배열인 헤더 맵
|
||||||
|
* @param namesToRemove - 제거할 헤더 이름(하나 혹은 배열). 대소문자 구분 없이 매칭됩니다.
|
||||||
|
* @returns - 지정된 헤더가 제외된 새로운 헤더 맵
|
||||||
|
*/
|
||||||
|
removeHeaders(
|
||||||
|
headers: Record<string, string | string[]>,
|
||||||
|
namesToRemove: string | string[]
|
||||||
|
): Record<string, string[]> {
|
||||||
|
headers = this.lowerCaseAllHeaders(headers);
|
||||||
|
const toRemove = Array.isArray(namesToRemove)
|
||||||
|
? namesToRemove.map((n) => n.toLowerCase())
|
||||||
|
: [namesToRemove.toLowerCase()];
|
||||||
|
|
||||||
|
const filtered: Record<string, string[]> = {};
|
||||||
|
for (const [key, vals] of Object.entries(headers)) {
|
||||||
|
if (!toRemove.includes(key.toLowerCase())) {
|
||||||
|
filtered[key] = Array.isArray(vals) ? vals : [vals];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["@caido/sdk-backend"]
|
"types": ["@caido/sdk-backend"],
|
||||||
},
|
},
|
||||||
"include": ["./src/**/*.ts"]
|
"include": ["./src/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
playground/PKCEDowngrade/.env.example
Normal file
2
playground/PKCEDowngrade/.env.example
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
GITHUB_CLIENT_ID=
|
||||||
|
GITHUB_CLIENT_SECRET=
|
||||||
2
playground/PKCEDowngrade/.gitignore
vendored
Normal file
2
playground/PKCEDowngrade/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# deps
|
||||||
|
node_modules/
|
||||||
11
playground/PKCEDowngrade/README.md
Normal file
11
playground/PKCEDowngrade/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
To install dependencies:
|
||||||
|
```sh
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
```sh
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
open http://localhost:3000
|
||||||
25
playground/PKCEDowngrade/bun.lock
Normal file
25
playground/PKCEDowngrade/bun.lock
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "PKCEDowngrade",
|
||||||
|
"dependencies": {
|
||||||
|
"hono": "^4.7.10",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@types/bun": ["@types/bun@1.2.14", "", { "dependencies": { "bun-types": "1.2.14" } }, "sha512-VsFZKs8oKHzI7zwvECiAJ5oSorWndIWEVhfbYqZd4HI/45kzW7PN2Rr5biAzvGvRuNmYLSANY+H59ubHq8xw7Q=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@22.15.21", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.2.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-Kuh4Ub28ucMRWeiUUWMHsT9Wcbr4H3kLIO72RZZElSDxSu7vpetRvxIUDUaW6QtaIeixIpm7OXtNnZPf82EzwA=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.7.10", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
12
playground/PKCEDowngrade/package.json
Normal file
12
playground/PKCEDowngrade/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "PKCEDowngrade",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "bun run --hot src/index.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"hono": "^4.7.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
94
playground/PKCEDowngrade/src/index.ts
Normal file
94
playground/PKCEDowngrade/src/index.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
import { Hono } from 'hono'
|
||||||
|
import { randomBytes, createHash } from 'crypto'
|
||||||
|
import { Buffer } from 'buffer'
|
||||||
|
|
||||||
|
const app = new Hono()
|
||||||
|
|
||||||
|
// In-memory PKCE store (should use Redis or similar in production)
|
||||||
|
const pkceStore = new Map<string, string>()
|
||||||
|
|
||||||
|
const generateCodeVerifier = () => {
|
||||||
|
return randomBytes(32).toString('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateCodeChallenge = (verifier: string) => {
|
||||||
|
const hash = createHash('sha256').update(verifier).digest()
|
||||||
|
return hash.toString('base64url')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Redirect to GitHub with PKCE
|
||||||
|
app.get('/login', (c) => {
|
||||||
|
const codeVerifier = generateCodeVerifier()
|
||||||
|
const codeChallenge = generateCodeChallenge(codeVerifier)
|
||||||
|
const state = randomBytes(8).toString('hex')
|
||||||
|
|
||||||
|
pkceStore.set(state, codeVerifier)
|
||||||
|
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
client_id: process.env.GITHUB_CLIENT_ID!,
|
||||||
|
redirect_uri: 'http://localhost:8787/callback',
|
||||||
|
scope: 'read:user',
|
||||||
|
state,
|
||||||
|
response_type: 'code',
|
||||||
|
code_challenge: codeChallenge,
|
||||||
|
code_challenge_method: 'S256',
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.redirect(`https://github.com/login/oauth/authorize?${params}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Step 2: GitHub redirects back here
|
||||||
|
app.get('/callback', async (c) => {
|
||||||
|
const url = new URL(c.req.url)
|
||||||
|
const code = url.searchParams.get('code')
|
||||||
|
const state = url.searchParams.get('state')
|
||||||
|
|
||||||
|
if (!code || !state) {
|
||||||
|
return c.text('Missing code or state', 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeVerifier = pkceStore.get(state)
|
||||||
|
if (!codeVerifier) {
|
||||||
|
return c.text('Invalid or expired state', 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Exchange code + verifier for token
|
||||||
|
const tokenRes = await fetch('https://github.com/login/oauth/access_token', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
client_id: process.env.GITHUB_CLIENT_ID,
|
||||||
|
client_secret: process.env.GITHUB_CLIENT_SECRET,
|
||||||
|
code,
|
||||||
|
redirect_uri: 'http://localhost:8787/callback',
|
||||||
|
code_verifier: codeVerifier,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const tokenData = await tokenRes.json()
|
||||||
|
if (!tokenData.access_token) {
|
||||||
|
return c.text('Failed to get access token', 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Use token to fetch user profile
|
||||||
|
const userRes = await fetch('https://api.github.com/user', {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokenData.access_token}`,
|
||||||
|
'User-Agent': 'hono-app',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const user = await userRes.json()
|
||||||
|
return c.json({
|
||||||
|
message: 'GitHub login successful!',
|
||||||
|
user,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export default {
|
||||||
|
port: 8787,
|
||||||
|
fetch: app.fetch,
|
||||||
|
}
|
||||||
7
playground/PKCEDowngrade/tsconfig.json
Normal file
7
playground/PKCEDowngrade/tsconfig.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "hono/jsx"
|
||||||
|
}
|
||||||
|
}
|
||||||
65
playground/csrf/index.js
Normal file
65
playground/csrf/index.js
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
// app.js
|
||||||
|
const express = require("express");
|
||||||
|
const app = express();
|
||||||
|
const port = 8000;
|
||||||
|
|
||||||
|
// 콜백 엔드포인트 (정상 동작 시뮬레이션)
|
||||||
|
app.get("/callback", (req, res) => {
|
||||||
|
res.send(`
|
||||||
|
<h1>Callback Received</h1>
|
||||||
|
<p>Query Params:</p>
|
||||||
|
<pre>${JSON.stringify(req.query, null, 2)}</pre>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1) state 파라미터를 무시하는 취약한 /authorize 엔드포인트
|
||||||
|
* - 클라이언트가 state를 보내도 무시
|
||||||
|
* - 리디렉트 시 state를 포함하지 않음
|
||||||
|
*/
|
||||||
|
app.get("/authorize/no-state", (req, res) => {
|
||||||
|
const clientId = req.query.client_id || "unknown-client";
|
||||||
|
const redirectUri = encodeURIComponent(
|
||||||
|
req.query.redirect_uri || `http://localhost:${port}/callback`
|
||||||
|
);
|
||||||
|
const code = "authcode-12345";
|
||||||
|
|
||||||
|
// state를 전혀 포함하지 않은 채로 리디렉트
|
||||||
|
const location = `${redirectUri}?code=${code}&client_id=${clientId}`;
|
||||||
|
res.set("Location", location);
|
||||||
|
res.status(302).send(`Redirecting to ${location}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2) 클라이언트가 보낸 state와 다른 값을 넣는 취약한 /authorize 엔드포인트
|
||||||
|
* - 클라이언트가 보낸 state를 로그로 확인만 하고,
|
||||||
|
* 응답 Location에는 'wrong-state'를 삽입
|
||||||
|
*/
|
||||||
|
app.get("/authorize/mismatch-state", (req, res) => {
|
||||||
|
const clientId = req.query.client_id || "unknown-client";
|
||||||
|
const originalState = req.query.state;
|
||||||
|
const redirectUri = encodeURIComponent(
|
||||||
|
req.query.redirect_uri || `http://localhost:${port}/callback`
|
||||||
|
);
|
||||||
|
const code = "authcode-67890";
|
||||||
|
|
||||||
|
console.log(`[VULN] original state from client:`, originalState);
|
||||||
|
|
||||||
|
// 클라이언트 state와 다르게 'wrong-state'를 삽입
|
||||||
|
const wrongState = "wrong-state";
|
||||||
|
const location = `${redirectUri}?code=${code}&state=${wrongState}&client_id=${clientId}`;
|
||||||
|
res.set("Location", location);
|
||||||
|
res.status(302).send(`Redirecting to ${location}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(
|
||||||
|
`Vulnerable OAuth test server listening at http://localhost:${port}`
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`1) No-State: http://localhost:${port}/authorize/no-state?client_id=abc&redirect_uri=http://localhost:${port}/callback`
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`2) Mismatch-State: http://localhost:${port}/authorize/mismatch-state?client_id=abc&state=xyz&redirect_uri=http://localhost:${port}/callback`
|
||||||
|
);
|
||||||
|
});
|
||||||
1167
playground/csrf/package-lock.json
generated
Normal file
1167
playground/csrf/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
19
playground/csrf/package.json
Normal file
19
playground/csrf/package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "csrf",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "nodemon index.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^5.1.0"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"description": "",
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^3.1.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
|
|
@ -11,6 +11,9 @@ importers:
|
||||||
'@caido-community/dev':
|
'@caido-community/dev':
|
||||||
specifier: ^0.1.3
|
specifier: ^0.1.3
|
||||||
version: 0.1.5(postcss@8.5.3)(typescript@5.5.4)
|
version: 0.1.5(postcss@8.5.3)(typescript@5.5.4)
|
||||||
|
'@caido/sdk-backend':
|
||||||
|
specifier: ^0.48.1
|
||||||
|
version: 0.48.1
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.5.4
|
specifier: 5.5.4
|
||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
|
|
@ -34,9 +37,15 @@ packages:
|
||||||
'@caido/quickjs-types@0.17.2':
|
'@caido/quickjs-types@0.17.2':
|
||||||
resolution: {integrity: sha512-5kcucGORMNEbcdU91yKLYZG/TFDqsO6XmCZ1TnU6V48E61mmqrJg6kjrfOFP1WOugDm+ZcGd/Su3p3XkFXfaPg==}
|
resolution: {integrity: sha512-5kcucGORMNEbcdU91yKLYZG/TFDqsO6XmCZ1TnU6V48E61mmqrJg6kjrfOFP1WOugDm+ZcGd/Su3p3XkFXfaPg==}
|
||||||
|
|
||||||
|
'@caido/quickjs-types@0.18.0':
|
||||||
|
resolution: {integrity: sha512-hRXUVdDvlhEhvkBoWWytoVS2j1KDVZa8dx2Q/KvWUQTR57U8EMSYE9iFgvPhu78gS8z+RF42Zcb7moNx4SDMlw==}
|
||||||
|
|
||||||
'@caido/sdk-backend@0.46.0':
|
'@caido/sdk-backend@0.46.0':
|
||||||
resolution: {integrity: sha512-peUKW/4Nrw9WVxIahc+6KrVtxA7vsbpuJqOoBxudxq7tQJ+cV9IEqzvYoFFo8KlnrTkeUQUJvd0W4WsM3HgxEg==}
|
resolution: {integrity: sha512-peUKW/4Nrw9WVxIahc+6KrVtxA7vsbpuJqOoBxudxq7tQJ+cV9IEqzvYoFFo8KlnrTkeUQUJvd0W4WsM3HgxEg==}
|
||||||
|
|
||||||
|
'@caido/sdk-backend@0.48.1':
|
||||||
|
resolution: {integrity: sha512-JvFeOlSqAKbj3OenBn0LPtCNaOV0x6YtaAQijpvYfBJK32Nvbf924Z10bFVCu+Clc5A1qr7HcAvJ/8B/aRikWA==}
|
||||||
|
|
||||||
'@caido/sdk-shared@0.1.1':
|
'@caido/sdk-shared@0.1.1':
|
||||||
resolution: {integrity: sha512-JAV5ajUqxZdXYPTmDEvIKBZon8I5uHq44ATj0Nj3BVpllRDUGY9kcBd+PXMD50+3lv1CvhR3/f6q24T0+4aVJQ==}
|
resolution: {integrity: sha512-JAV5ajUqxZdXYPTmDEvIKBZon8I5uHq44ATj0Nj3BVpllRDUGY9kcBd+PXMD50+3lv1CvhR3/f6q24T0+4aVJQ==}
|
||||||
|
|
||||||
|
|
@ -1095,11 +1104,18 @@ snapshots:
|
||||||
|
|
||||||
'@caido/quickjs-types@0.17.2': {}
|
'@caido/quickjs-types@0.17.2': {}
|
||||||
|
|
||||||
|
'@caido/quickjs-types@0.18.0': {}
|
||||||
|
|
||||||
'@caido/sdk-backend@0.46.0':
|
'@caido/sdk-backend@0.46.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@caido/quickjs-types': 0.17.2
|
'@caido/quickjs-types': 0.17.2
|
||||||
'@caido/sdk-shared': 0.1.1
|
'@caido/sdk-shared': 0.1.1
|
||||||
|
|
||||||
|
'@caido/sdk-backend@0.48.1':
|
||||||
|
dependencies:
|
||||||
|
'@caido/quickjs-types': 0.18.0
|
||||||
|
'@caido/sdk-shared': 0.1.1
|
||||||
|
|
||||||
'@caido/sdk-shared@0.1.1': {}
|
'@caido/sdk-shared@0.1.1': {}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.24.2':
|
'@esbuild/aix-ppc64@0.24.2':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue