From d21ee1eac0edd70921dbdfac2c11858e4ba2b2ce Mon Sep 17 00:00:00 2001 From: James Date: Mon, 19 May 2025 11:02:40 +0900 Subject: [PATCH 01/14] Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4cb6778 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# caido-plugin-test \ No newline at end of file From 889d7cfbf2bb7d0078eb0508a222a9d336385a68 Mon Sep 17 00:00:00 2001 From: "tv0924@icloud.com" Date: Mon, 19 May 2025 11:08:20 +0900 Subject: [PATCH 02/14] [Add] is authZ|implict grant type --- .gitignore | 218 ++ LICENSE | 9 + caido.config.ts | 18 + package.json | 14 + packages/backend/package.json | 13 + .../backend/src/controller/authZCodeGrant.ts | 48 + .../backend/src/controller/implictGrant.ts | 40 + packages/backend/src/index.ts | 44 + packages/backend/tsconfig.json | 7 + pnpm-lock.yaml | 2000 +++++++++++++++++ pnpm-workspace.yaml | 2 + tsconfig.json | 24 + 12 files changed, 2437 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 caido.config.ts create mode 100644 package.json create mode 100644 packages/backend/package.json create mode 100644 packages/backend/src/controller/authZCodeGrant.ts create mode 100644 packages/backend/src/controller/implictGrant.ts create mode 100644 packages/backend/src/index.ts create mode 100644 packages/backend/tsconfig.json create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1657979 --- /dev/null +++ b/.gitignore @@ -0,0 +1,218 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,linux + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a9767d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2024 [Author] + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/caido.config.ts b/caido.config.ts new file mode 100644 index 0000000..4299bd9 --- /dev/null +++ b/caido.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "@caido-community/dev"; + +export default defineConfig({ + id: "caido-oauth", + name: "Caido OAuth", + description: "Plugin for OAuth", + version: "0.0.0", + author: { + name: "WHS Safe Us Team", + }, + plugins: [ + { + kind: "backend", + id: "backend", + root: "packages/backend", + }, + ], +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..67a5d31 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "caido-oauth", + "version": "0.0.0", + "private": true, + "scripts": { + "typecheck": "pnpm -r typecheck", + "build": "caido-dev build", + "watch": "caido-dev watch" + }, + "devDependencies": { + "@caido-community/dev": "^0.1.3", + "typescript": "5.5.4" + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json new file mode 100644 index 0000000..840a266 --- /dev/null +++ b/packages/backend/package.json @@ -0,0 +1,13 @@ +{ + "name": "backend", + "version": "0.0.0", + "type": "module", + "types": "src/index.ts", + "scripts": { + "typecheck": "tsc --noEmit", + "build": "vite build" + }, + "devDependencies": { + "@caido/sdk-backend": "^0.46.0" + } +} diff --git a/packages/backend/src/controller/authZCodeGrant.ts b/packages/backend/src/controller/authZCodeGrant.ts new file mode 100644 index 0000000..731b3da --- /dev/null +++ b/packages/backend/src/controller/authZCodeGrant.ts @@ -0,0 +1,48 @@ +import type { Request } from "caido:utils"; + +export class AuthZCodeGrantController { + constructor() {} + + isAuthZReq(req: Request) { + // const path = req.getPath(); + const query = req.getQuery(); + // const raw = req.getRaw().toString(); + + // 쿼리에 client_id and response_type=code 포함 확인 + if (query.includes("client_id=") && query.includes("response_type=code")) { + return true; + } + + return false; + } + + isSendCodeToClient(req: Request) { + const path = req.getPath(); + const query = req.getQuery(); + + // code & state 쌍 또는 path에 &code= 또는 쿼리로 code= 유사 일치 확인 + if ( + (query.includes("code=") && query.includes("state=")) || + path.includes("&code=") || + /code=%/i.test(query) + ) { + return true; + } + + return false; + } + + testReq(req: Request) { + if (this.isAuthZReq(req)) { + return "isAuthZReq"; + } + if (this.isSendCodeToClient(req)) { + return "isSendCodeToClient"; + } + return false; + } + + // isAccessTokenReq(req: Response) { + + // } +} diff --git a/packages/backend/src/controller/implictGrant.ts b/packages/backend/src/controller/implictGrant.ts new file mode 100644 index 0000000..2c65449 --- /dev/null +++ b/packages/backend/src/controller/implictGrant.ts @@ -0,0 +1,40 @@ +import type { Request } from "caido:utils"; + +export class ImplicitGrantController { + isImplicitGrantReq(req: Request) { + const query = req.getQuery(); + // const raw = req.getRaw().toString(); + + // 쿼리에 client_id and response_type=token 포함 확인 + if (query.includes("client_id=") && query.includes("response_type=token")) { + return true; + } + + return false; + } + + isSendTokenToClient(req: Request) { + const path = req.getPath(); + const query = req.getQuery(); + + if ( + (query.includes("access_token=") && query.includes("state=")) || + path.includes("&access_token=") || + /access_token=%/i.test(query) + ) { + return true; + } + + return false; + } + + testReq(req: Request) { + if (this.isImplicitGrantReq(req)) { + return "isImplicitGrantReq"; + } + if (this.isSendTokenToClient(req)) { + return "isSendTokenToClient"; + } + return false; + } +} diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts new file mode 100644 index 0000000..8ba813f --- /dev/null +++ b/packages/backend/src/index.ts @@ -0,0 +1,44 @@ +import type { SDK, DefineAPI } from "caido:plugin"; +import type { Request } from "caido:utils"; +import { ImplicitGrantController } from "./controller/implictGrant"; +import { AuthZCodeGrantController } from "./controller/authZCodeGrant"; + +export type API = DefineAPI<{}>; + +const implicitGrantController = new ImplicitGrantController(); +const authZCodeGrantController = new AuthZCodeGrantController(); + +// function matchSSORequest(req: Request): boolean { +// const raw = req.getRaw().toString(); + +// // 조건 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) { + sdk.events.onInterceptRequest(async (sdk, req: Request) => { + const result = + authZCodeGrantController.testReq(req) || + implicitGrantController.testReq(req); + + if (result) { + await sdk.findings.create({ + title: "Possible SSO Request Detected", + description: `SSO-related parameters detected in request:\n\n${req.getMethod()} ${req.getUrl()} : ${result}`, + request: req, + reporter: "", + }); + } + }); +} diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json new file mode 100644 index 0000000..9dec401 --- /dev/null +++ b/packages/backend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "types": ["@caido/sdk-backend"] + }, + "include": ["./src/**/*.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..67de64e --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2000 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@caido-community/dev': + specifier: ^0.1.3 + version: 0.1.5(postcss@8.5.3)(typescript@5.5.4) + typescript: + specifier: 5.5.4 + version: 5.5.4 + + packages/backend: + devDependencies: + '@caido/sdk-backend': + specifier: ^0.46.0 + version: 0.46.0 + +packages: + + '@caido-community/dev@0.1.5': + resolution: {integrity: sha512-mM+komusTlKNViTlAR055KS9pQJk+jKzbFlUb+MKaFuopMG6qS93z6PSz/08uc7u7/i+U7YiiQvaa7c1IXvl6Q==} + engines: {node: '>=20', pnpm: '>=9'} + hasBin: true + + '@caido/plugin-manifest@0.3.0': + resolution: {integrity: sha512-HRGHf65K2sfSdaEUwkCNDlurJ4zL0bOUg/Db4u6CrwjTTzmg2gOzP6SzLRj+69gWmxOm5LUjhInNHaMIRmQkHw==} + + '@caido/quickjs-types@0.17.2': + resolution: {integrity: sha512-5kcucGORMNEbcdU91yKLYZG/TFDqsO6XmCZ1TnU6V48E61mmqrJg6kjrfOFP1WOugDm+ZcGd/Su3p3XkFXfaPg==} + + '@caido/sdk-backend@0.46.0': + resolution: {integrity: sha512-peUKW/4Nrw9WVxIahc+6KrVtxA7vsbpuJqOoBxudxq7tQJ+cV9IEqzvYoFFo8KlnrTkeUQUJvd0W4WsM3HgxEg==} + + '@caido/sdk-shared@0.1.1': + resolution: {integrity: sha512-JAV5ajUqxZdXYPTmDEvIKBZon8I5uHq44ATj0Nj3BVpllRDUGY9kcBd+PXMD50+3lv1CvhR3/f6q24T0+4aVJQ==} + + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rollup/rollup-android-arm-eabi@4.41.0': + resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.41.0': + resolution: {integrity: sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.41.0': + resolution: {integrity: sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.41.0': + resolution: {integrity: sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.41.0': + resolution: {integrity: sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.41.0': + resolution: {integrity: sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.41.0': + resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.41.0': + resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.41.0': + resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.41.0': + resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.41.0': + resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.41.0': + resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.41.0': + resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.41.0': + resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.41.0': + resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.41.0': + resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.41.0': + resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.41.0': + resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.41.0': + resolution: {integrity: sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.41.0': + resolution: {integrity: sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@13.0.0: + resolution: {integrity: sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==} + engines: {node: '>=18'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + express@5.0.0: + resolution: {integrity: sha512-V4UkHQc+B7ldh1YC84HCXHwf60M4BOMvp9rkvTUWCK5apqDC1Esnbid4wm6nFyVuDy8XMfETsJw5lsIGBWyo0A==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.1: + resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} + engines: {node: 20 || >=22} + hasBin: true + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.1.0: + resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==} + engines: {node: 20 || >=22} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + rollup@4.41.0: + resolution: {integrity: sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsup@8.3.5: + resolution: {integrity: sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite@6.0.7: + resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + 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 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + +snapshots: + + '@caido-community/dev@0.1.5(postcss@8.5.3)(typescript@5.5.4)': + 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(jiti@2.4.2)(postcss@8.5.3)(typescript@5.5.4) + vite: 6.0.7(jiti@2.4.2) + ws: 8.18.0 + zod: 3.24.1 + transitivePeerDependencies: + - '@microsoft/api-extractor' + - '@swc/core' + - '@types/node' + - bufferutil + - less + - lightningcss + - postcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - utf-8-validate + - yaml + + '@caido/plugin-manifest@0.3.0': + dependencies: + ajv: 8.17.1 + + '@caido/quickjs-types@0.17.2': {} + + '@caido/sdk-backend@0.46.0': + dependencies: + '@caido/quickjs-types': 0.17.2 + '@caido/sdk-shared': 0.1.1 + + '@caido/sdk-shared@0.1.1': {} + + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@rollup/rollup-android-arm-eabi@4.41.0': + optional: true + + '@rollup/rollup-android-arm64@4.41.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.41.0': + optional: true + + '@rollup/rollup-darwin-x64@4.41.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.41.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.41.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.41.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.41.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.41.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.41.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.41.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.41.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.41.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.41.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.41.0': + optional: true + + '@types/estree@1.0.7': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + balanced-match@1.0.2: {} + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.1 + 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.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + bundle-require@5.1.0(esbuild@0.24.2): + dependencies: + esbuild: 0.24.2 + load-tsconfig: 0.2.5 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chalk@5.4.1: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@13.0.0: {} + + commander@4.1.1: {} + + consola@3.4.2: {} + + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.6.0: {} + + core-util-is@1.0.3: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.3.6: + dependencies: + ms: 2.1.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + depd@2.0.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + 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 + + escape-html@1.0.3: {} + + etag@1.8.1: {} + + express@5.0.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.6.0 + cookie-signature: 1.2.2 + debug: 4.3.6 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + methods: 1.1.2 + mime-types: 3.0.1 + 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.2.0 + safe-buffer: 5.2.1 + send: 1.2.0 + serve-static: 2.2.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-uri@3.0.6: {} + + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + finalhandler@2.1.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + 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 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@11.0.1: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.0 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + 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 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + immediate@3.0.6: {} + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-promise@4.0.0: {} + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.1.0: + dependencies: + '@isaacs/cliui': 8.0.2 + + jiti@2.4.2: {} + + joycon@3.1.1: {} + + json-schema-traverse@1.0.0: {} + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + load-tsconfig@0.2.5: {} + + lodash.sortby@4.7.0: {} + + lru-cache@10.4.3: {} + + lru-cache@11.1.0: {} + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + methods@1.1.2: {} + + mime-db@1.54.0: {} + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minipass@7.1.2: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + negotiator@1.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + package-json-from-dist@1.0.1: {} + + pako@1.0.11: {} + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + + path-to-regexp@8.2.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.2: {} + + pirates@4.0.7: {} + + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.4.2 + postcss: 8.5.3 + + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + process-nextick-args@2.0.1: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readdirp@4.1.2: {} + + require-from-string@2.0.2: {} + + resolve-from@5.0.0: {} + + rollup@4.41.0: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.41.0 + '@rollup/rollup-android-arm64': 4.41.0 + '@rollup/rollup-darwin-arm64': 4.41.0 + '@rollup/rollup-darwin-x64': 4.41.0 + '@rollup/rollup-freebsd-arm64': 4.41.0 + '@rollup/rollup-freebsd-x64': 4.41.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.41.0 + '@rollup/rollup-linux-arm-musleabihf': 4.41.0 + '@rollup/rollup-linux-arm64-gnu': 4.41.0 + '@rollup/rollup-linux-arm64-musl': 4.41.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.41.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.41.0 + '@rollup/rollup-linux-riscv64-gnu': 4.41.0 + '@rollup/rollup-linux-riscv64-musl': 4.41.0 + '@rollup/rollup-linux-s390x-gnu': 4.41.0 + '@rollup/rollup-linux-x64-gnu': 4.41.0 + '@rollup/rollup-linux-x64-musl': 4.41.0 + '@rollup/rollup-win32-arm64-msvc': 4.41.0 + '@rollup/rollup-win32-ia32-msvc': 4.41.0 + '@rollup/rollup-win32-x64-msvc': 4.41.0 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + send@1.2.0: + dependencies: + debug: 4.3.6 + 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 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + + setimmediate@1.0.5: {} + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + statuses@2.0.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + ts-interface-checker: 0.1.13 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinyexec@0.3.2: {} + + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + + toidentifier@1.0.1: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + tsup@8.3.5(jiti@2.4.2)(postcss@8.5.3)(typescript@5.5.4): + dependencies: + bundle-require: 5.1.0(esbuild@0.24.2) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.1 + esbuild: 0.24.2 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3) + resolve-from: 5.0.0 + rollup: 4.41.0 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.3 + typescript: 5.5.4 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + + typescript@5.5.4: {} + + unpipe@1.0.0: {} + + util-deprecate@1.0.2: {} + + utils-merge@1.0.1: {} + + vary@1.1.2: {} + + vite@6.0.7(jiti@2.4.2): + dependencies: + esbuild: 0.24.2 + postcss: 8.5.3 + rollup: 4.41.0 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.4.2 + + webidl-conversions@4.0.2: {} + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + ws@8.18.0: {} + + zod@3.24.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..18ec407 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f986f70 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "lib": ["ESNext"], + + "jsx": "preserve", + "noImplicitAny": true, + "noUncheckedIndexedAccess": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + + "moduleResolution": "bundler", + "esModuleInterop": true, + "sourceMap": true, + "noUnusedLocals": true, + + "useDefineForClassFields": true, + "isolatedModules": true, + + "baseUrl": "." + } +} From cc52c85fd5eb2399e177d91a5f91b90789328098 Mon Sep 17 00:00:00 2001 From: "tv0924@icloud.com" Date: Mon, 19 May 2025 11:12:18 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[File]=20caido=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B0=94=EB=A1=9C=20=EC=82=AC=EC=9A=A9=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20zip=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++ dist/plugin_package.zip | Bin 0 -> 2892 bytes packages/backend/dist/index.js | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 dist/plugin_package.zip create mode 100644 packages/backend/dist/index.js diff --git a/.gitignore b/.gitignore index 1657979..7118b70 100644 --- a/.gitignore +++ b/.gitignore @@ -215,4 +215,8 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +!dist/ +dist/* +!dist/*.zip + # End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file diff --git a/dist/plugin_package.zip b/dist/plugin_package.zip new file mode 100644 index 0000000000000000000000000000000000000000..31ab81ad9d2c3ea5abed9c5c5d2b92488e7cd63a GIT binary patch literal 2892 zcmWIWW@h1H0D&cZo1;K940A9rFeD`=XQ$?+=tES2M9@_UAgRjCOG&NJ%PQ8_S13qK z&Q45EE!KybP+XL(pPZjpQk0*QlUk&onOl&PnOx#tl$ckdS5nMXmRO|V2^PzQ2s*>n zD%dI{=Oh*vD^znSC}b9+s0vCg)F?_V)C9{ZC?x0S6_+R!mZla}D%dI%r55U?rhg*{Or^`B~6%>3JOK3C8b4q3MECQsSrDA!8SpK(-L!v!Qvp%%;MnGyp#}- z2_gB;U~4g*UyxXmfpC35Vo3(f@#J|gF*!N4xHul{ZX7-=E=ep&1?6eH1ZO{Y<@*)Z!9IxRMtzApK}@35uzbjLc#^98r!D0ZNz(m5?I@$w2I}fXze< zl_*AH#&NAR7Z(x9Ke4nVBg#2HB^4zDIHHK+$N}I)P*j>+l3%0&aWN!ifii+@O!fUWq?OD)G$Ie>~rP~Cx=p-{38NH;jBKwbprH-t1uds=B;a!F=>oRg=qkzNzDC!{P87Ph+=0ltcN*0ObiJ2t|#VOfF zdTE(?DVcfc#d^s_sfi`28lZX;q(niXB(o$Z)k;ArAiuacGbtxkAvoAy0qP|Mm(-Hf ztf3JP#L!aaf&f)mqH6+(*@ zLQ)fRLH@4=g^W^8W?ptNNCSjh05%pR5Dg9@kOx4q2=xTCB?fj8SU5W~59~V(37GFN zBvSKAiYg28GxJJ7-hfK$LvnFeF~a1c(!7#PNC;&mmL){S@ literal 0 HcmV?d00001 diff --git a/packages/backend/dist/index.js b/packages/backend/dist/index.js new file mode 100644 index 0000000..4a8c39f --- /dev/null +++ b/packages/backend/dist/index.js @@ -0,0 +1,81 @@ +// packages/backend/src/controller/implictGrant.ts +var ImplicitGrantController = class { + isImplicitGrantReq(req) { + const query = req.getQuery(); + if (query.includes("client_id=") && query.includes("response_type=token")) { + return true; + } + return false; + } + isSendTokenToClient(req) { + const path = req.getPath(); + const query = req.getQuery(); + if (query.includes("access_token=") && query.includes("state=") || path.includes("&access_token=") || /access_token=%/i.test(query)) { + return true; + } + return false; + } + testReq(req) { + if (this.isImplicitGrantReq(req)) { + return "isImplicitGrantReq"; + } + if (this.isSendTokenToClient(req)) { + return "isSendTokenToClient"; + } + return false; + } +}; + +// packages/backend/src/controller/authZCodeGrant.ts +var AuthZCodeGrantController = class { + constructor() { + } + isAuthZReq(req) { + const query = req.getQuery(); + if (query.includes("client_id=") && query.includes("response_type=code")) { + return true; + } + return false; + } + isSendCodeToClient(req) { + const path = req.getPath(); + const query = req.getQuery(); + if (query.includes("code=") && query.includes("state=") || path.includes("&code=") || /code=%/i.test(query)) { + return true; + } + return false; + } + testReq(req) { + if (this.isAuthZReq(req)) { + return "isAuthZReq"; + } + if (this.isSendCodeToClient(req)) { + return "isSendCodeToClient"; + } + return false; + } + // isAccessTokenReq(req: Response) { + // } +}; + +// packages/backend/src/index.ts +var implicitGrantController = new ImplicitGrantController(); +var authZCodeGrantController = new AuthZCodeGrantController(); +function init(sdk) { + sdk.events.onInterceptRequest(async (sdk2, req) => { + const result = authZCodeGrantController.testReq(req) || implicitGrantController.testReq(req); + if (result) { + await sdk2.findings.create({ + title: "Possible SSO Request Detected", + description: `SSO-related parameters detected in request: + +${req.getMethod()} ${req.getUrl()} : ${result}`, + request: req, + reporter: "" + }); + } + }); +} +export { + init +}; From b41b0869804e1f627625a40daacf545e3917f32d Mon Sep 17 00:00:00 2001 From: "tv0924@icloud.com" Date: Mon, 19 May 2025 12:13:43 +0900 Subject: [PATCH 04/14] [Remove] backend build file --- .gitignore | 1 + packages/backend/dist/index.js | 81 ---------------------------------- 2 files changed, 1 insertion(+), 81 deletions(-) delete mode 100644 packages/backend/dist/index.js diff --git a/.gitignore b/.gitignore index 7118b70..d00ddb0 100644 --- a/.gitignore +++ b/.gitignore @@ -217,6 +217,7 @@ $RECYCLE.BIN/ !dist/ dist/* +packages/*/dist/* !dist/*.zip # End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file diff --git a/packages/backend/dist/index.js b/packages/backend/dist/index.js deleted file mode 100644 index 4a8c39f..0000000 --- a/packages/backend/dist/index.js +++ /dev/null @@ -1,81 +0,0 @@ -// packages/backend/src/controller/implictGrant.ts -var ImplicitGrantController = class { - isImplicitGrantReq(req) { - const query = req.getQuery(); - if (query.includes("client_id=") && query.includes("response_type=token")) { - return true; - } - return false; - } - isSendTokenToClient(req) { - const path = req.getPath(); - const query = req.getQuery(); - if (query.includes("access_token=") && query.includes("state=") || path.includes("&access_token=") || /access_token=%/i.test(query)) { - return true; - } - return false; - } - testReq(req) { - if (this.isImplicitGrantReq(req)) { - return "isImplicitGrantReq"; - } - if (this.isSendTokenToClient(req)) { - return "isSendTokenToClient"; - } - return false; - } -}; - -// packages/backend/src/controller/authZCodeGrant.ts -var AuthZCodeGrantController = class { - constructor() { - } - isAuthZReq(req) { - const query = req.getQuery(); - if (query.includes("client_id=") && query.includes("response_type=code")) { - return true; - } - return false; - } - isSendCodeToClient(req) { - const path = req.getPath(); - const query = req.getQuery(); - if (query.includes("code=") && query.includes("state=") || path.includes("&code=") || /code=%/i.test(query)) { - return true; - } - return false; - } - testReq(req) { - if (this.isAuthZReq(req)) { - return "isAuthZReq"; - } - if (this.isSendCodeToClient(req)) { - return "isSendCodeToClient"; - } - return false; - } - // isAccessTokenReq(req: Response) { - // } -}; - -// packages/backend/src/index.ts -var implicitGrantController = new ImplicitGrantController(); -var authZCodeGrantController = new AuthZCodeGrantController(); -function init(sdk) { - sdk.events.onInterceptRequest(async (sdk2, req) => { - const result = authZCodeGrantController.testReq(req) || implicitGrantController.testReq(req); - if (result) { - await sdk2.findings.create({ - title: "Possible SSO Request Detected", - description: `SSO-related parameters detected in request: - -${req.getMethod()} ${req.getUrl()} : ${result}`, - request: req, - reporter: "" - }); - } - }); -} -export { - init -}; From f901464c3a5c24be74cfdb5927a0ad6960d3b92a Mon Sep 17 00:00:00 2001 From: "tv0924@icloud.com" Date: Mon, 19 May 2025 12:15:33 +0900 Subject: [PATCH 05/14] [Remove] backend build file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d00ddb0..029ef11 100644 --- a/.gitignore +++ b/.gitignore @@ -217,7 +217,8 @@ $RECYCLE.BIN/ !dist/ dist/* -packages/*/dist/* +packages/frontend/dist +packages/backend/dist !dist/*.zip # End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file From c355038288d11aaa8c62280fd074f4400dfda242 Mon Sep 17 00:00:00 2001 From: sultanofdisco Date: Sat, 24 May 2025 14:25:44 +0900 Subject: [PATCH 06/14] nonce check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oidc flow인지 check하고, nonce 유무를 체크한다 --- packages/backend/src/controller/nonceCheck.ts | 33 +++++++++++++++ .../backend/src/controller/tokenLeakCheck.ts | 42 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 packages/backend/src/controller/nonceCheck.ts create mode 100644 packages/backend/src/controller/tokenLeakCheck.ts diff --git a/packages/backend/src/controller/nonceCheck.ts b/packages/backend/src/controller/nonceCheck.ts new file mode 100644 index 0000000..383ca90 --- /dev/null +++ b/packages/backend/src/controller/nonceCheck.ts @@ -0,0 +1,33 @@ +import type { Request } from "caido:utils"; +import { TokenLeakCheck } from "./tokenLeakCheck"; + +export class NonceCheckController{ + /** + * 응답이 OIDC(OpenID Connect) 플로우인지 확인하는 메서드 + */ + + public static isOidcFlow(req: Request): boolean { + if(TokenLeakCheck.extractIdToken(req)) { + return true; + } + return false; + } + + + public static isNonceCheckRequest(req: Request): boolean { + const id_token = decodeIdToken(req); + + // 1. nonce 파라미터가 포함된 요청인지 확인 + if (id_token.includes("nonce=")) { + return true; + } + + return false; + } +} + +function decodeIdToken(req: Request): string { + // Implement actual decoding logic here. For now, return an empty string or mock value. + return ""; +} + diff --git a/packages/backend/src/controller/tokenLeakCheck.ts b/packages/backend/src/controller/tokenLeakCheck.ts new file mode 100644 index 0000000..2248b49 --- /dev/null +++ b/packages/backend/src/controller/tokenLeakCheck.ts @@ -0,0 +1,42 @@ +import type { Request } from "caido:utils"; +import jwt from "jsonwebtoken"; + +export class TokenLeakCheck { + public static extractIdToken(req: Request): string | null { + // 1. Authorization 헤더 확인\\ + const header = req.getHeaders() as Record; + const authHeader = header["authorization"] || header["Authorization"]; + if (typeof authHeader === "string" && authHeader.startsWith("Bearer ")) { + return authHeader.slice(7).trim(); + } + + // 2. 쿼리 파라미터 + const query = req.getQuery(); + if (query && typeof query === "object" && "id_token" in query) { + return (query as Record).id_token; + } + + // 3. POST 바디 안에 id_token이 있을 경우 + const rawBody = req.getRaw(); + const body = rawBody ? rawBody.toString() : ""; + const match = body.match(/id_token=([^&\s]+)/); + if (match && typeof match[1] === "string") { + return decodeURIComponent(match[1]); + } + + return null; + } + + public static decodeIdToken(req: Request): Record | null { + const token = this.extractIdToken(req); + if (!token) return null; + + const decoded = jwt.decode(token, { complete: true }); + if (!decoded || typeof decoded !== "object") return null; + + return { + header: decoded.header, + payload: decoded.payload, + }; + } +} From 12f635c77be748b4c0825fa9e31a60312866e1bf Mon Sep 17 00:00:00 2001 From: imnyang Date: Sun, 25 May 2025 16:59:51 +0900 Subject: [PATCH 07/14] What's happening!! --- bun.lock | 502 ++++++++++++++++++ dist/plugin_package.zip | Bin 2892 -> 7047 bytes package.json | 1 + .../src/controller/PKCEDowngradeCheck.ts | 108 ++++ packages/backend/src/index.ts | 5 + packages/backend/tsconfig.json | 2 +- 6 files changed, 617 insertions(+), 1 deletion(-) create mode 100644 bun.lock create mode 100644 packages/backend/src/controller/PKCEDowngradeCheck.ts diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..289e8aa --- /dev/null +++ b/bun.lock @@ -0,0 +1,502 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "caido-oauth", + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "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.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.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "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=="], + + "body-parser/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "finalhandler/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "router/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "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=="], + + "tsup/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "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=="], + } +} diff --git a/dist/plugin_package.zip b/dist/plugin_package.zip index 31ab81ad9d2c3ea5abed9c5c5d2b92488e7cd63a..34b70e1f07a90b3eacf3581195e7e40a421828dc 100644 GIT binary patch literal 7047 zcmWIWW@h1H009TvolzhfhB+7*7?Ki`vs3d@^dYK1BIv3FkW^*nrKDEqWfkk|D-Jrfa}tY-6{@)u6f%oZR0X9LY80gwYJ%ky6q57vic1sJrXQVaFcQ%eFt zTn$ZYE(HYzh0HVs4Y0gkW?phmX-aCbhEj4)W@=tZd}fNRlBR;18bm*md{Js~L4ICw zYJ5p$L8@&@es*e}k|xYb1%;y2lG36)g_5GuREQn5V4I-AX^A<-U~!OWW^r(8UP=ha zgphn^u(g=ZFGwuOK)602u_OcLc=EiLn4FwiTpSN}Hx3^bmn4>?g5+vy6hPJ^d0q`& zdrggkK8l#Cex_bYYH;MV|`sD_Yb3rK`OFqY!3t-wnsUOUyeX2)^P)JOJN-$`eQ_3uc zDL_e*XsH|{aIqN#O6152Q4ECIhfnmgyJA%sEf0l2}}sm#hFPeKd+wvUNaJ2E^$K(7Gfy zwIm}y1(A7t!F=KiZUJy0&p&q>wG$xqivh{kkLtOCSTD+QHmh<&vQ(CUgf?cf{@ z(haWJ;F>{60b-tlqOGlhlDlh&63llB3g|{FVRe~beu+Y&g1c)7C}==Iucr{4omo(j znU}7o1a&053WTQ-1qD!<1gUKm!HzTR1*r8cD7PtTDqvFxl8R5xNX*Ge z%}a;XUl_)rs)~n%h%IuFMO;vT(pqLwYKj6V1{DetixP8FOHzx96>>9+i$UQ*O2~lH zM2SLaQ4S($g%;(YrmM_i|AN#!PZtGSND+<{hQ-PG1*x|A1*v(NDUiTH59Q1hNR1DR zBy>MwPl%yGKA?0|T9gA%MZ{@@xfP@v#)caK@hl|ZeG^NPLCqV8dvifN4SnoUq!Asb z7OSPH4^3teQ{d4}gh94wCV(=8BC<0;i3-&~Qu7C@%N6pA6i`K=$qkl96f*OmaY=e& zfjB%Y5tL+7QbE>)26;N?=N9DWrRJ4rK%~K;5^Wf(U~jLWL|WW~Ohn`+sKY_=2{Ab= z5s@Z90SOmXumu$^1v!bCc_bGvSnX8EELH#;M^ae>NglcRDVb@RsVU$h5uS01QVVht zlT&deG;lgov)9)F1(_ZW#kM$9Mcb>zsz9_tTAL7uq`>O3lu&RcPf)3b_D8_^T(7tw zC$mID$x2^eNi*6Yw$@5tAFje9zqmw0v(^eO5RhL45m1-3K)+Rt)KwOrE z*S0AN&}@(5W_a!`DXN5auV9rTxH9%H%1qD91EN34TZbxE7Xz(-&sYfXkes)M5;iAQ=ENz_77_c4Pq|O#r&ckd433}$iZBVdP0O^MFQ*i4iE*XQ&w*^&Yu#5x>JCGp4#Yn+N zqM3-qi!c@LbR=Uzbr4c~fd+0+oq!O5Ye&@Xu%If*EXhe#uvLJySrqIQl%TCHx19WP zNLvrCKSiM=Um*Zg(}ChlNx@1%$sg1UGg2U|7?v_&HW#I)r52^;C8OI8>bw+N>FYxp zcY1lLCHln$smaAq0o}~>{4(8q&;Wvwu3@}^u7QzWMoDgta#32cUU6!2NoIbYp0S>x zo;lcgFw;^JOAG~=8$@(C@`bBBU=4Qrb(0(7Nmq}ctfm_1x z2vbN&ElEu-Nlj5ya4t$sECCg@X_dl0oWIH9#YLAQd1C zju{>BP#TD)fLIMt}71HvH6jZ7~4Ol%cE~JRVTE%g31;Jtgl-S@= zQk#HmF|?Mj0u`pH;-JoHYLS(Kk`mmVh*}QbEkcY8!umzE3dx{`uYyJ@B1MA2160z0 zdWxwq3Tlu?_2j>U)&oT*QzUs2~N634_u(VxSBmuK;N+fHEI8 zX_)qc?BrBS5-H0%i(Ljb8Zf({_q+Cdvkp!h5SRf45CC7{9|$M_z2_!K&Z0`BSJ2r?9P zkn#jn3Kpdnm*$i}oC?Y+ko<+|b+C3McS1~1fL3M2DcMGPxHBX;J6b6y1>_eOXC~#O zDg+1n!-r#Bpc!8Ykv&jzYjCi?Zc%DZVo7QWa?cr7V1VipST5t@f;V#^!y+1*wF+<{ zaO1gF0hHz;-bT) z`hZB3r4|)u=I4Rr4D<~23?QON;Ruom$SFY5nxR3xv5X81AROS$$RxsmdkzaSp9Pwy0Ug? jWcPql14Ji?)RII?8v)*|Y#<3{24;r!3=9m1q(D3X{e-ks delta 170 zcmZoSKO@E);LXg!#Q*|J_%=`ERc2now|S$n7u)1evDV4F;%7E { + const method = req.getMethod(); + const query = req.getQuery(); + + sdk.console.log(`[PKCEDowngradeCheck] Method: ${method}`); + sdk.console.log(`[PKCEDowngradeCheck] Query: ${query}`); + + if (method !== "GET") { + sdk.console.log("[PKCEDowngradeCheck] Not a GET request. Skipping."); + return false; + } + + if ( + !query.includes("client_id=") || + !query.includes("response_type=code") || + !query.includes("code_challenge=") || + !query.includes("code_challenge_method=") + ) { + sdk.console.log("[PKCEDowngradeCheck] Required PKCE parameters missing. Skipping."); + return false; + } + + const url = req.getUrl(); + const isOpenID = + query.includes("scope=openid") || query.includes("id_token"); + + sdk.console.log(`[PKCEDowngradeCheck] URL: ${url}`); + sdk.console.log(`[PKCEDowngradeCheck] isOpenID: ${isOpenID}`); + + const methodMatch = query.match(/code_challenge_method=([^&]*)/); + const challengeMatch = query.match(/code_challenge=([^&]*)/); + if (!methodMatch || !challengeMatch) { + sdk.console.log("[PKCEDowngradeCheck] code_challenge or code_challenge_method missing in query. Skipping."); + return false; + } + + const methodVal = decodeURIComponent(methodMatch[1] ?? ""); + sdk.console.log(`[PKCEDowngradeCheck] code_challenge_method: ${methodVal}`); + if (methodVal === "plain") { + sdk.console.log("[PKCEDowngradeCheck] code_challenge_method is plain. Skipping."); + return false; + } + + const modifiedQuery = query + .replace(/code_challenge_method=[^&]*&?/, "") + .replace(/code_challenge=[^&]*&?/, "") + .replace(/[?&]$/, ""); + + const downgradedUrl = `${req.getUrl().split("://")[0]}://${req.getHost()}:${req.getPort()}${req.getPath()}?${modifiedQuery}`; + sdk.console.log(`[PKCEDowngradeCheck] Downgraded URL: ${downgradedUrl}`); + + try { + const fetchOriginal = new FetchRequest(url, { method: "GET" }); + const fetchDowngraded = new FetchRequest(downgradedUrl, { method: "GET" }); + + sdk.console.log("[PKCEDowngradeCheck] Sending original request..."); + const resOriginal = await fetch(fetchOriginal); + sdk.console.log(`[PKCEDowngradeCheck] Original response status: ${resOriginal.status}`); + + sdk.console.log("[PKCEDowngradeCheck] Sending downgraded request..."); + const resDowngraded = await fetch(fetchDowngraded); + sdk.console.log(`[PKCEDowngradeCheck] Downgraded response status: ${resDowngraded.status}`); + + const statusEqual = resOriginal.status === resDowngraded.status; + sdk.console.log(`[PKCEDowngradeCheck] Status equal: ${statusEqual}`); + + const bodyOriginal = await resOriginal.text(); + const bodyDowngraded = await resDowngraded.text(); + + const codeInOriginal = bodyOriginal.includes("code="); + const codeInDowngrade = bodyDowngraded.includes("code="); + + sdk.console.log(`[PKCEDowngradeCheck] code= in original: ${codeInOriginal}`); + sdk.console.log(`[PKCEDowngradeCheck] code= in downgraded: ${codeInDowngrade}`); + + if (statusEqual && codeInOriginal && codeInDowngrade) { + const title = isOpenID + ? "OpenID Flow PKCE Downgraded to Plaintext" + : "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"; + + sdk.console.log(`[PKCEDowngradeCheck] PKCE downgrade detected! Creating finding.`); + + await sdk.findings.create({ + title, + description: `PKCE downgrade detected for ${url}.\n\nDowngraded URL: ${downgradedUrl}\n\nReference: ${reference}`, + request: req, + reporter: "", + }); + + return true; + } + } catch (e) { + sdk.console.error(`PKCE downgrade check failed for ${url}: ${String(e)}`); + } + + sdk.console.log("[PKCEDowngradeCheck] No PKCE downgrade detected."); + return false; + } +} diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 8ba813f..8eafcc4 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -2,11 +2,13 @@ import type { SDK, DefineAPI } from "caido:plugin"; import type { Request } from "caido:utils"; import { ImplicitGrantController } from "./controller/implictGrant"; import { AuthZCodeGrantController } from "./controller/authZCodeGrant"; +import { PKCEDowngradeCheck } from "./controller/PKCEDowngradeCheck"; export type API = DefineAPI<{}>; const implicitGrantController = new ImplicitGrantController(); const authZCodeGrantController = new AuthZCodeGrantController(); +const pkceDowngradeCheck = new PKCEDowngradeCheck(); // function matchSSORequest(req: Request): boolean { // const raw = req.getRaw().toString(); @@ -33,6 +35,8 @@ export function init(sdk: SDK) { implicitGrantController.testReq(req); if (result) { + await pkceDowngradeCheck.test(sdk, req); + await sdk.findings.create({ title: "Possible SSO Request Detected", description: `SSO-related parameters detected in request:\n\n${req.getMethod()} ${req.getUrl()} : ${result}`, @@ -40,5 +44,6 @@ export function init(sdk: SDK) { reporter: "", }); } + }); } diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 9dec401..022c0b2 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "types": ["@caido/sdk-backend"] + "types": ["@caido/sdk-backend"], }, "include": ["./src/**/*.ts"] } From 2601997ed5ed86cbbd8790df2c036cefa6fb30c0 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sun, 25 May 2025 20:37:18 +0900 Subject: [PATCH 08/14] =?UTF-8?q?GitHub=20Actions,=20PKCE=20Downgrade=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20PlayGround=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 43 +++++++++++++++++++++++++ .gitignore | 4 +-- dist/plugin_package.zip | Bin 7047 -> 0 bytes playground/.gitignore | 34 +++++++++++++++++++ playground/README.md | 15 +++++++++ playground/bun.lock | 25 ++++++++++++++ playground/package.json | 10 ++++++ playground/src/PKCEDowngradeExpress.js | 31 ++++++++++++++++++ playground/tsconfig.json | 29 +++++++++++++++++ 9 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 dist/plugin_package.zip create mode 100644 playground/.gitignore create mode 100644 playground/README.md create mode 100644 playground/bun.lock create mode 100644 playground/package.json create mode 100644 playground/src/PKCEDowngradeExpress.js create mode 100644 playground/tsconfig.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..30cddc7 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,43 @@ +name: Build and Upload Caido Plugin + +on: + push: + branches: + - main + pull_request: + branches: + - main + +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: Archive built plugin + run: | + mkdir -p dist-artifact + cp -r dist/* dist-artifact/ + # 만약 manifest.json도 포함되어야 한다면 + cp manifest.json dist-artifact/ + + - name: Upload plugin artifact + uses: actions/upload-artifact@v4 + with: + name: caido-plugin + path: dist-artifact diff --git a/.gitignore b/.gitignore index 029ef11..648628f 100644 --- a/.gitignore +++ b/.gitignore @@ -215,10 +215,10 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -!dist/ +#!dist/ dist/* packages/frontend/dist packages/backend/dist -!dist/*.zip +#!dist/*.zip # End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file diff --git a/dist/plugin_package.zip b/dist/plugin_package.zip deleted file mode 100644 index 34b70e1f07a90b3eacf3581195e7e40a421828dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7047 zcmWIWW@h1H009TvolzhfhB+7*7?Ki`vs3d@^dYK1BIv3FkW^*nrKDEqWfkk|D-Jrfa}tY-6{@)u6f%oZR0X9LY80gwYJ%ky6q57vic1sJrXQVaFcQ%eFt zTn$ZYE(HYzh0HVs4Y0gkW?phmX-aCbhEj4)W@=tZd}fNRlBR;18bm*md{Js~L4ICw zYJ5p$L8@&@es*e}k|xYb1%;y2lG36)g_5GuREQn5V4I-AX^A<-U~!OWW^r(8UP=ha zgphn^u(g=ZFGwuOK)602u_OcLc=EiLn4FwiTpSN}Hx3^bmn4>?g5+vy6hPJ^d0q`& zdrggkK8l#Cex_bYYH;MV|`sD_Yb3rK`OFqY!3t-wnsUOUyeX2)^P)JOJN-$`eQ_3uc zDL_e*XsH|{aIqN#O6152Q4ECIhfnmgyJA%sEf0l2}}sm#hFPeKd+wvUNaJ2E^$K(7Gfy zwIm}y1(A7t!F=KiZUJy0&p&q>wG$xqivh{kkLtOCSTD+QHmh<&vQ(CUgf?cf{@ z(haWJ;F>{60b-tlqOGlhlDlh&63llB3g|{FVRe~beu+Y&g1c)7C}==Iucr{4omo(j znU}7o1a&053WTQ-1qD!<1gUKm!HzTR1*r8cD7PtTDqvFxl8R5xNX*Ge z%}a;XUl_)rs)~n%h%IuFMO;vT(pqLwYKj6V1{DetixP8FOHzx96>>9+i$UQ*O2~lH zM2SLaQ4S($g%;(YrmM_i|AN#!PZtGSND+<{hQ-PG1*x|A1*v(NDUiTH59Q1hNR1DR zBy>MwPl%yGKA?0|T9gA%MZ{@@xfP@v#)caK@hl|ZeG^NPLCqV8dvifN4SnoUq!Asb z7OSPH4^3teQ{d4}gh94wCV(=8BC<0;i3-&~Qu7C@%N6pA6i`K=$qkl96f*OmaY=e& zfjB%Y5tL+7QbE>)26;N?=N9DWrRJ4rK%~K;5^Wf(U~jLWL|WW~Ohn`+sKY_=2{Ab= z5s@Z90SOmXumu$^1v!bCc_bGvSnX8EELH#;M^ae>NglcRDVb@RsVU$h5uS01QVVht zlT&deG;lgov)9)F1(_ZW#kM$9Mcb>zsz9_tTAL7uq`>O3lu&RcPf)3b_D8_^T(7tw zC$mID$x2^eNi*6Yw$@5tAFje9zqmw0v(^eO5RhL45m1-3K)+Rt)KwOrE z*S0AN&}@(5W_a!`DXN5auV9rTxH9%H%1qD91EN34TZbxE7Xz(-&sYfXkes)M5;iAQ=ENz_77_c4Pq|O#r&ckd433}$iZBVdP0O^MFQ*i4iE*XQ&w*^&Yu#5x>JCGp4#Yn+N zqM3-qi!c@LbR=Uzbr4c~fd+0+oq!O5Ye&@Xu%If*EXhe#uvLJySrqIQl%TCHx19WP zNLvrCKSiM=Um*Zg(}ChlNx@1%$sg1UGg2U|7?v_&HW#I)r52^;C8OI8>bw+N>FYxp zcY1lLCHln$smaAq0o}~>{4(8q&;Wvwu3@}^u7QzWMoDgta#32cUU6!2NoIbYp0S>x zo;lcgFw;^JOAG~=8$@(C@`bBBU=4Qrb(0(7Nmq}ctfm_1x z2vbN&ElEu-Nlj5ya4t$sECCg@X_dl0oWIH9#YLAQd1C zju{>BP#TD)fLIMt}71HvH6jZ7~4Ol%cE~JRVTE%g31;Jtgl-S@= zQk#HmF|?Mj0u`pH;-JoHYLS(Kk`mmVh*}QbEkcY8!umzE3dx{`uYyJ@B1MA2160z0 zdWxwq3Tlu?_2j>U)&oT*QzUs2~N634_u(VxSBmuK;N+fHEI8 zX_)qc?BrBS5-H0%i(Ljb8Zf({_q+Cdvkp!h5SRf45CC7{9|$M_z2_!K&Z0`BSJ2r?9P zkn#jn3Kpdnm*$i}oC?Y+ko<+|b+C3McS1~1fL3M2DcMGPxHBX;J6b6y1>_eOXC~#O zDg+1n!-r#Bpc!8Ykv&jzYjCi?Zc%DZVo7QWa?cr7V1VipST5t@f;V#^!y+1*wF+<{ zaO1gF0hHz;-bT) z`hZB3r4|)u=I4Rr4D<~23?QON;Ruom$SFY5nxR3xv5X81AROS$$RxsmdkzaSp9Pwy0Ug? jWcPql14Ji?)RII?8v)*|Y#<3{24;r!3=9m1q(D3X{e-ks diff --git a/playground/.gitignore b/playground/.gitignore new file mode 100644 index 0000000..a14702c --- /dev/null +++ b/playground/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/playground/README.md b/playground/README.md new file mode 100644 index 0000000..4a3109f --- /dev/null +++ b/playground/README.md @@ -0,0 +1,15 @@ +# playground + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run +``` + +This project was created using `bun init` in bun v1.2.14. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/playground/bun.lock b/playground/bun.lock new file mode 100644 index 0000000..0a70737 --- /dev/null +++ b/playground/bun.lock @@ -0,0 +1,25 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "playground", + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "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=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + } +} diff --git a/playground/package.json b/playground/package.json new file mode 100644 index 0000000..0bbbfb8 --- /dev/null +++ b/playground/package.json @@ -0,0 +1,10 @@ +{ + "name": "playground", + "private": true, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + } +} diff --git a/playground/src/PKCEDowngradeExpress.js b/playground/src/PKCEDowngradeExpress.js new file mode 100644 index 0000000..61cf737 --- /dev/null +++ b/playground/src/PKCEDowngradeExpress.js @@ -0,0 +1,31 @@ +const express = require("express"); +const app = express(); + +app.get("/auth", (req, res) => { + const { + client_id, + response_type, + code_challenge, + code_challenge_method, + scope + } = req.query; + + console.log("Incoming request:", req.query); + + if (!client_id || response_type !== "code") { + return res.status(400).send("Missing required parameters"); + } + + // Simulate issuing an authorization code + const code = "dummy-auth-code"; + + // Simulate PKCE check (normally you'd validate here) + // We deliberately allow the downgrade here to simulate the vulnerability + const responseBody = `Authorization successful. code=${code}`; + return res.status(200).send(responseBody); +}); + +const PORT = 5050; +app.listen(PORT, () => { + console.log(`Test PKCE server running on http://localhost:${PORT}`); +}); diff --git a/playground/tsconfig.json b/playground/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/playground/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From a5e48ed3742ff1fb6d205528f62e0804865f81c1 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sun, 25 May 2025 20:38:36 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[Add]=20=EB=AA=A8=EB=93=A0=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=EB=A1=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30cddc7..7b46d5d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,12 +1,8 @@ name: Build and Upload Caido Plugin on: - push: - branches: - - main - pull_request: - branches: - - main + push: + pull_request: jobs: build: From 2e1eb7a3abff2d98cfd8d982213363147eb59432 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sun, 25 May 2025 20:55:19 +0900 Subject: [PATCH 10/14] =?UTF-8?q?PKCE=20Downgrade=EB=A7=8C=20=EC=B2=B4?= =?UTF-8?q?=ED=82=B9=ED=95=9C=EB=8B=A4=EA=B3=A0=EC=9A=94=3F=20=EC=95=84?= =?UTF-8?q?=EB=87=A8=20=EC=9D=B4=EC=A0=9C=20PKCE=EA=B0=80=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=EC=A7=80=EB=8F=84=20=ED=99=95=EC=9D=B8=ED=95=A0?= =?UTF-8?q?=EA=B2=81=EB=8B=88=EB=8B=A4.=20=EC=9D=B4=EA=B1=B0=EB=8F=84=20?= =?UTF-8?q?=EC=A2=80=20=EC=A4=84=EC=9D=B4=EA=B3=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 9 +- packages/backend/src/controller/PKCECheck.ts | 98 ++++++++++++++++ .../src/controller/PKCEDowngradeCheck.ts | 108 ------------------ packages/backend/src/index.ts | 6 +- 4 files changed, 102 insertions(+), 119 deletions(-) create mode 100644 packages/backend/src/controller/PKCECheck.ts delete mode 100644 packages/backend/src/controller/PKCEDowngradeCheck.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7b46d5d..9071b63 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,15 +25,8 @@ jobs: run: | bun run build - - name: Archive built plugin - run: | - mkdir -p dist-artifact - cp -r dist/* dist-artifact/ - # 만약 manifest.json도 포함되어야 한다면 - cp manifest.json dist-artifact/ - - name: Upload plugin artifact uses: actions/upload-artifact@v4 with: name: caido-plugin - path: dist-artifact + path: dist diff --git a/packages/backend/src/controller/PKCECheck.ts b/packages/backend/src/controller/PKCECheck.ts new file mode 100644 index 0000000..3e41154 --- /dev/null +++ b/packages/backend/src/controller/PKCECheck.ts @@ -0,0 +1,98 @@ +import type { SDK } from "caido:plugin"; +import type { Request } from "caido:utils"; +import { fetch, Request as FetchRequest } from "caido:http"; + +export class PKCECheck { + async test(sdk: SDK, req: Request): Promise { + const method = req.getMethod(); + if (method !== "GET") { + sdk.console.log("[PKCEDowngradeCheck] Not a GET request. Skipping."); + return false; + } + + const query = req.getQuery(); + const requiredParams = ["client_id=", "response_type=code", "code_challenge=", "code_challenge_method="]; + if (!requiredParams.every(param => query.includes(param))) { + sdk.console.log("[PKCEDowngradeCheck] Required PKCE parameters missing. Skipping."); + return false; + } + + const url = req.getUrl(); + const isOpenID = query.includes("scope=openid") || query.includes("id_token"); + const methodMatch = query.match(/code_challenge_method=([^&]*)/); + const challengeMatch = query.match(/code_challenge=([^&]*)/); + + if (!methodMatch || !challengeMatch) { + 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: "", + }); + return false; + } + + const methodVal = decodeURIComponent(methodMatch[1]!); + 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: "", + }); + + return false; + } + + const downgradedQuery = query + .replace(/code_challenge_method=[^&]*&?/, "") + .replace(/code_challenge=[^&]*&?/, "") + .replace(/[?&]$/, ""); + + const downgradedUrl = `${req.getUrl().split("://")[0]}://${req.getHost()}:${req.getPort()}${req.getPath()}?${downgradedQuery}`; + + try { + const [resOriginal, resDowngraded] = await Promise.all([ + fetch(new FetchRequest(url, { method: "GET" })), + fetch(new FetchRequest(downgradedUrl, { method: "GET" })) + ]); + + const [bodyOriginal, bodyDowngraded] = await Promise.all([ + resOriginal.text(), + resDowngraded.text() + ]); + + const statusEqual = resOriginal.status === resDowngraded.status; + const codeInBoth = bodyOriginal.includes("code=") && bodyDowngraded.includes("code="); + + if (statusEqual && codeInBoth) { + 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\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; + } +} diff --git a/packages/backend/src/controller/PKCEDowngradeCheck.ts b/packages/backend/src/controller/PKCEDowngradeCheck.ts deleted file mode 100644 index 5d9e5e4..0000000 --- a/packages/backend/src/controller/PKCEDowngradeCheck.ts +++ /dev/null @@ -1,108 +0,0 @@ -import type { SDK } from "caido:plugin"; -import type { Request, Response } from "caido:utils"; -import { fetch, Request as FetchRequest } from "caido:http"; - -export class PKCEDowngradeCheck { - async test(sdk: SDK, req: Request): Promise { - const method = req.getMethod(); - const query = req.getQuery(); - - sdk.console.log(`[PKCEDowngradeCheck] Method: ${method}`); - sdk.console.log(`[PKCEDowngradeCheck] Query: ${query}`); - - if (method !== "GET") { - sdk.console.log("[PKCEDowngradeCheck] Not a GET request. Skipping."); - return false; - } - - if ( - !query.includes("client_id=") || - !query.includes("response_type=code") || - !query.includes("code_challenge=") || - !query.includes("code_challenge_method=") - ) { - sdk.console.log("[PKCEDowngradeCheck] Required PKCE parameters missing. Skipping."); - return false; - } - - const url = req.getUrl(); - const isOpenID = - query.includes("scope=openid") || query.includes("id_token"); - - sdk.console.log(`[PKCEDowngradeCheck] URL: ${url}`); - sdk.console.log(`[PKCEDowngradeCheck] isOpenID: ${isOpenID}`); - - const methodMatch = query.match(/code_challenge_method=([^&]*)/); - const challengeMatch = query.match(/code_challenge=([^&]*)/); - if (!methodMatch || !challengeMatch) { - sdk.console.log("[PKCEDowngradeCheck] code_challenge or code_challenge_method missing in query. Skipping."); - return false; - } - - const methodVal = decodeURIComponent(methodMatch[1] ?? ""); - sdk.console.log(`[PKCEDowngradeCheck] code_challenge_method: ${methodVal}`); - if (methodVal === "plain") { - sdk.console.log("[PKCEDowngradeCheck] code_challenge_method is plain. Skipping."); - return false; - } - - const modifiedQuery = query - .replace(/code_challenge_method=[^&]*&?/, "") - .replace(/code_challenge=[^&]*&?/, "") - .replace(/[?&]$/, ""); - - const downgradedUrl = `${req.getUrl().split("://")[0]}://${req.getHost()}:${req.getPort()}${req.getPath()}?${modifiedQuery}`; - sdk.console.log(`[PKCEDowngradeCheck] Downgraded URL: ${downgradedUrl}`); - - try { - const fetchOriginal = new FetchRequest(url, { method: "GET" }); - const fetchDowngraded = new FetchRequest(downgradedUrl, { method: "GET" }); - - sdk.console.log("[PKCEDowngradeCheck] Sending original request..."); - const resOriginal = await fetch(fetchOriginal); - sdk.console.log(`[PKCEDowngradeCheck] Original response status: ${resOriginal.status}`); - - sdk.console.log("[PKCEDowngradeCheck] Sending downgraded request..."); - const resDowngraded = await fetch(fetchDowngraded); - sdk.console.log(`[PKCEDowngradeCheck] Downgraded response status: ${resDowngraded.status}`); - - const statusEqual = resOriginal.status === resDowngraded.status; - sdk.console.log(`[PKCEDowngradeCheck] Status equal: ${statusEqual}`); - - const bodyOriginal = await resOriginal.text(); - const bodyDowngraded = await resDowngraded.text(); - - const codeInOriginal = bodyOriginal.includes("code="); - const codeInDowngrade = bodyDowngraded.includes("code="); - - sdk.console.log(`[PKCEDowngradeCheck] code= in original: ${codeInOriginal}`); - sdk.console.log(`[PKCEDowngradeCheck] code= in downgraded: ${codeInDowngrade}`); - - if (statusEqual && codeInOriginal && codeInDowngrade) { - const title = isOpenID - ? "OpenID Flow PKCE Downgraded to Plaintext" - : "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"; - - sdk.console.log(`[PKCEDowngradeCheck] PKCE downgrade detected! Creating finding.`); - - await sdk.findings.create({ - title, - description: `PKCE downgrade detected for ${url}.\n\nDowngraded URL: ${downgradedUrl}\n\nReference: ${reference}`, - request: req, - reporter: "", - }); - - return true; - } - } catch (e) { - sdk.console.error(`PKCE downgrade check failed for ${url}: ${String(e)}`); - } - - sdk.console.log("[PKCEDowngradeCheck] No PKCE downgrade detected."); - return false; - } -} diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 8eafcc4..7633932 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -2,13 +2,13 @@ import type { SDK, DefineAPI } from "caido:plugin"; import type { Request } from "caido:utils"; import { ImplicitGrantController } from "./controller/implictGrant"; import { AuthZCodeGrantController } from "./controller/authZCodeGrant"; -import { PKCEDowngradeCheck } from "./controller/PKCEDowngradeCheck"; +import { PKCECheck } from "./controller/PKCECheck"; export type API = DefineAPI<{}>; const implicitGrantController = new ImplicitGrantController(); const authZCodeGrantController = new AuthZCodeGrantController(); -const pkceDowngradeCheck = new PKCEDowngradeCheck(); +const pkceCheck = new PKCECheck(); // function matchSSORequest(req: Request): boolean { // const raw = req.getRaw().toString(); @@ -35,7 +35,7 @@ export function init(sdk: SDK) { implicitGrantController.testReq(req); if (result) { - await pkceDowngradeCheck.test(sdk, req); + await pkceCheck.test(sdk, req); await sdk.findings.create({ title: "Possible SSO Request Detected", From ba20dd9007280235e871632ba86d9cd66eaae129 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sun, 25 May 2025 22:28:56 +0900 Subject: [PATCH 11/14] =?UTF-8?q?=EC=A0=9C=EA=B0=80=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=ED=86=B5=EC=9D=BC=EC=84=B1=EC=9D=B4=20=EC=97=86=EC=97=88?= =?UTF-8?q?=EB=84=A4=EC=9A=94...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 7633932..2eccd6d 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -8,7 +8,7 @@ export type API = DefineAPI<{}>; const implicitGrantController = new ImplicitGrantController(); const authZCodeGrantController = new AuthZCodeGrantController(); -const pkceCheck = new PKCECheck(); +const pkceCheckController = new PKCECheck(); // function matchSSORequest(req: Request): boolean { // const raw = req.getRaw().toString(); @@ -35,7 +35,7 @@ export function init(sdk: SDK) { implicitGrantController.testReq(req); if (result) { - await pkceCheck.test(sdk, req); + await pkceCheckController.test(sdk, req); await sdk.findings.create({ title: "Possible SSO Request Detected", From 0a24c5594d7b4b9f52c6470888fb4bc00cb11782 Mon Sep 17 00:00:00 2001 From: imnyang Date: Mon, 26 May 2025 00:56:03 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[Add]=20PKCE=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84,=20Playground=20=EB=94=94=EB=A0=89=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++++- packages/backend/src/controller/PKCECheck.ts | 29 +++--- playground/.gitignore | 34 ------- playground/PKCEDowngrade/.gitignore | 2 + playground/PKCEDowngrade/README.md | 11 +++ playground/{ => PKCEDowngrade}/bun.lock | 10 +-- playground/PKCEDowngrade/package.json | 12 +++ playground/PKCEDowngrade/src/index.ts | 94 ++++++++++++++++++++ playground/PKCEDowngrade/tsconfig.json | 7 ++ playground/README.md | 15 ---- playground/package.json | 10 --- playground/src/PKCEDowngradeExpress.js | 31 ------- playground/tsconfig.json | 29 ------ 13 files changed, 164 insertions(+), 140 deletions(-) delete mode 100644 playground/.gitignore create mode 100644 playground/PKCEDowngrade/.gitignore create mode 100644 playground/PKCEDowngrade/README.md rename playground/{ => PKCEDowngrade}/bun.lock (75%) create mode 100644 playground/PKCEDowngrade/package.json create mode 100644 playground/PKCEDowngrade/src/index.ts create mode 100644 playground/PKCEDowngrade/tsconfig.json delete mode 100644 playground/README.md delete mode 100644 playground/package.json delete mode 100644 playground/src/PKCEDowngradeExpress.js delete mode 100644 playground/tsconfig.json diff --git a/README.md b/README.md index 4cb6778..c5497cc 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ -# caido-plugin-test \ No newline at end of file +# caido-plugin-test + +## To-Do +- [ ] PKCE 다운그래이드 https에서 작동 안하는 이슈 고치기 + +```log +2025-05-25T15:52:40.757475Z INFO actix-rt|system:0|arbiter:6 proxy|connect: Client connection (29e74afd-9006-445e-88a9-3fc5d4796af9) +2025-05-25T15:52:40.757530Z INFO actix-rt|system:0|arbiter:6 proxy|connect: Client connected for http://localhost:8787 (29e74afd-9006-445e-88a9-3fc5d4796af9) +2025-05-25T15:52:40.757562Z INFO actix-rt|system:0|arbiter:6 proxy|http1|logger: GET http://localhost/login (29e74afd-9006-445e-88a9-3fc5d4796af9) +2025-05-25T15:52:40.767186Z INFO actix-rt|system:0|arbiter:6 proxy|http1|logger: GET http://localhost:8787/login -> 302 361 (29e74afd-9006-445e-88a9-3fc5d4796af9) +2025-05-25T15:52:40.768696Z INFO actix-rt|system:0|arbiter:9 proxy|http1|logger: GET https://github.com/login/oauth/authorize?client_id=Ov23lixietSCQOHxPvcr&redirect_uri=http%3A%2F%2Flocalhost%3A8787%2Fcallback&scope=read%3Auser&state=bc11db571a4737d0&response_type=code&code_challenge=FtSdQsWI342PKH6BGgKYR6AOzW95LaS0jeVcwTmHaro&code_challenge_method=S256 (90f314dc-9480-4bd8-b7b6-5acba6b8bc7b) +2025-05-25T15:52:41.103596Z INFO actix-rt|system:0|arbiter:9 proxy|http1|logger: GET https://github.com/login/oauth/authorize?client_id=Ov23lixietSCQOHxPvcr&redirect_uri=http%3A%2F%2Flocalhost%3A8787%2Fcallback&scope=read%3Auser&state=bc11db571a4737d0&response_type=code&code_challenge=FtSdQsWI342PKH6BGgKYR6AOzW95LaS0jeVcwTmHaro&code_challenge_method=S256 -> 302 4927 (90f314dc-9480-4bd8-b7b6-5acba6b8bc7b) +2025-05-25T15:52:41.105944Z INFO actix-rt|system:0|arbiter:7 proxy|connect: Client connection (34585a00-9f9f-4c72-b087-2e9e92418dad) +2025-05-25T15:52:41.105993Z INFO actix-rt|system:0|arbiter:7 proxy|connect: Client connected for http://localhost:8787 (34585a00-9f9f-4c72-b087-2e9e92418dad) +2025-05-25T15:52:41.106023Z INFO actix-rt|system:0|arbiter:7 proxy|http1|logger: GET http://localhost/callback?code=10c34dcc4d3f7302e707&state=bc11db571a4737d0 (34585a00-9f9f-4c72-b087-2e9e92418dad) +2025-05-25T15:52:41.108270Z INFO plugin:65ad3a87-0257-4408-a9c7-e0885e04c162 js|sdk: [PKCEDowngradeCheck] Required PKCE parameters missing. Skipping. +2025-05-25T15:52:41.277387Z INFO plugin:65ad3a87-0257-4408-a9c7-e0885e04c162 js|sdk: [PKCEDowngradeCheck] No PKCE downgrade detected. +2025-05-25T15:52:41.686109Z INFO actix-rt|system:0|arbiter:7 proxy|http1|logger: GET http://localhost:8787/callback?code=10c34dcc4d3f7302e707&state=bc11db571a4737d0 -> 200 1582 (34585a00-9f9f-4c72-b087-2e9e92418dad) +``` \ No newline at end of file diff --git a/packages/backend/src/controller/PKCECheck.ts b/packages/backend/src/controller/PKCECheck.ts index 3e41154..1d3525d 100644 --- a/packages/backend/src/controller/PKCECheck.ts +++ b/packages/backend/src/controller/PKCECheck.ts @@ -11,18 +11,20 @@ export class PKCECheck { } const query = req.getQuery(); - const requiredParams = ["client_id=", "response_type=code", "code_challenge=", "code_challenge_method="]; - if (!requiredParams.every(param => query.includes(param))) { + 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 = query.includes("scope=openid") || query.includes("id_token"); - const methodMatch = query.match(/code_challenge_method=([^&]*)/); - const challengeMatch = query.match(/code_challenge=([^&]*)/); + 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 (!methodMatch || !challengeMatch) { + if (!methodVal || !challengeVal) { sdk.console.log("[PKCEDowngradeCheck] code_challenge or method missing. Skipping."); await sdk.findings.create({ title: isOpenID @@ -35,7 +37,6 @@ export class PKCECheck { return false; } - const methodVal = decodeURIComponent(methodMatch[1]!); if (methodVal === "plain") { sdk.console.log("[PKCEDowngradeCheck] code_challenge_method is 'plain'. Skipping."); await sdk.findings.create({ @@ -46,26 +47,24 @@ export class PKCECheck { request: req, reporter: "", }); - return false; } - const downgradedQuery = query - .replace(/code_challenge_method=[^&]*&?/, "") - .replace(/code_challenge=[^&]*&?/, "") - .replace(/[?&]$/, ""); - + // Remove PKCE parameters to simulate a downgraded request + searchParams.delete("code_challenge"); + searchParams.delete("code_challenge_method"); + const downgradedQuery = searchParams.toString(); const downgradedUrl = `${req.getUrl().split("://")[0]}://${req.getHost()}:${req.getPort()}${req.getPath()}?${downgradedQuery}`; try { const [resOriginal, resDowngraded] = await Promise.all([ fetch(new FetchRequest(url, { method: "GET" })), - fetch(new FetchRequest(downgradedUrl, { method: "GET" })) + fetch(new FetchRequest(downgradedUrl, { method: "GET" })), ]); const [bodyOriginal, bodyDowngraded] = await Promise.all([ resOriginal.text(), - resDowngraded.text() + resDowngraded.text(), ]); const statusEqual = resOriginal.status === resDowngraded.status; diff --git a/playground/.gitignore b/playground/.gitignore deleted file mode 100644 index a14702c..0000000 --- a/playground/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# dependencies (bun install) -node_modules - -# output -out -dist -*.tgz - -# code coverage -coverage -*.lcov - -# logs -logs -_.log -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# caches -.eslintcache -.cache -*.tsbuildinfo - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store diff --git a/playground/PKCEDowngrade/.gitignore b/playground/PKCEDowngrade/.gitignore new file mode 100644 index 0000000..506e4c3 --- /dev/null +++ b/playground/PKCEDowngrade/.gitignore @@ -0,0 +1,2 @@ +# deps +node_modules/ diff --git a/playground/PKCEDowngrade/README.md b/playground/PKCEDowngrade/README.md new file mode 100644 index 0000000..6dd13e7 --- /dev/null +++ b/playground/PKCEDowngrade/README.md @@ -0,0 +1,11 @@ +To install dependencies: +```sh +bun install +``` + +To run: +```sh +bun run dev +``` + +open http://localhost:3000 diff --git a/playground/bun.lock b/playground/PKCEDowngrade/bun.lock similarity index 75% rename from playground/bun.lock rename to playground/PKCEDowngrade/bun.lock index 0a70737..ec75146 100644 --- a/playground/bun.lock +++ b/playground/PKCEDowngrade/bun.lock @@ -2,13 +2,13 @@ "lockfileVersion": 1, "workspaces": { "": { - "name": "playground", + "name": "PKCEDowngrade", + "dependencies": { + "hono": "^4.7.10", + }, "devDependencies": { "@types/bun": "latest", }, - "peerDependencies": { - "typescript": "^5", - }, }, }, "packages": { @@ -18,7 +18,7 @@ "bun-types": ["bun-types@1.2.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-Kuh4Ub28ucMRWeiUUWMHsT9Wcbr4H3kLIO72RZZElSDxSu7vpetRvxIUDUaW6QtaIeixIpm7OXtNnZPf82EzwA=="], - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "hono": ["hono@4.7.10", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], } diff --git a/playground/PKCEDowngrade/package.json b/playground/PKCEDowngrade/package.json new file mode 100644 index 0000000..00ae1aa --- /dev/null +++ b/playground/PKCEDowngrade/package.json @@ -0,0 +1,12 @@ +{ + "name": "PKCEDowngrade", + "scripts": { + "dev": "bun run --hot src/index.ts" + }, + "dependencies": { + "hono": "^4.7.10" + }, + "devDependencies": { + "@types/bun": "latest" + } +} \ No newline at end of file diff --git a/playground/PKCEDowngrade/src/index.ts b/playground/PKCEDowngrade/src/index.ts new file mode 100644 index 0000000..4c61f36 --- /dev/null +++ b/playground/PKCEDowngrade/src/index.ts @@ -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() + +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, +} \ No newline at end of file diff --git a/playground/PKCEDowngrade/tsconfig.json b/playground/PKCEDowngrade/tsconfig.json new file mode 100644 index 0000000..c442b33 --- /dev/null +++ b/playground/PKCEDowngrade/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "strict": true, + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx" + } +} \ No newline at end of file diff --git a/playground/README.md b/playground/README.md deleted file mode 100644 index 4a3109f..0000000 --- a/playground/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# playground - -To install dependencies: - -```bash -bun install -``` - -To run: - -```bash -bun run -``` - -This project was created using `bun init` in bun v1.2.14. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/playground/package.json b/playground/package.json deleted file mode 100644 index 0bbbfb8..0000000 --- a/playground/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "playground", - "private": true, - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5" - } -} diff --git a/playground/src/PKCEDowngradeExpress.js b/playground/src/PKCEDowngradeExpress.js deleted file mode 100644 index 61cf737..0000000 --- a/playground/src/PKCEDowngradeExpress.js +++ /dev/null @@ -1,31 +0,0 @@ -const express = require("express"); -const app = express(); - -app.get("/auth", (req, res) => { - const { - client_id, - response_type, - code_challenge, - code_challenge_method, - scope - } = req.query; - - console.log("Incoming request:", req.query); - - if (!client_id || response_type !== "code") { - return res.status(400).send("Missing required parameters"); - } - - // Simulate issuing an authorization code - const code = "dummy-auth-code"; - - // Simulate PKCE check (normally you'd validate here) - // We deliberately allow the downgrade here to simulate the vulnerability - const responseBody = `Authorization successful. code=${code}`; - return res.status(200).send(responseBody); -}); - -const PORT = 5050; -app.listen(PORT, () => { - console.log(`Test PKCE server running on http://localhost:${PORT}`); -}); diff --git a/playground/tsconfig.json b/playground/tsconfig.json deleted file mode 100644 index bfa0fea..0000000 --- a/playground/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - // Environment setup & latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "Preserve", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false - } -} From b64c8cc4e42e97e4441a6088d0592944ac380040 Mon Sep 17 00:00:00 2001 From: imnyang Date: Wed, 28 May 2025 23:28:31 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[Add]=20PKCE=20=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/controller/PKCECheck.ts | 81 ++++++++++++++++---- playground/PKCEDowngrade/.env.example | 2 + 2 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 playground/PKCEDowngrade/.env.example diff --git a/packages/backend/src/controller/PKCECheck.ts b/packages/backend/src/controller/PKCECheck.ts index 1d3525d..8fc5671 100644 --- a/packages/backend/src/controller/PKCECheck.ts +++ b/packages/backend/src/controller/PKCECheck.ts @@ -1,6 +1,5 @@ import type { SDK } from "caido:plugin"; -import type { Request } from "caido:utils"; -import { fetch, Request as FetchRequest } from "caido:http"; +import { Body, RequestSpec, type Request } from "caido:utils"; export class PKCECheck { async test(sdk: SDK, req: Request): Promise { @@ -32,7 +31,7 @@ export class PKCECheck { : "[WARN] OAuth2 Flow PKCE Parameters Missing", description: `PKCE parameters are missing or incomplete for ${url}. This may indicate a misconfiguration.`, request: req, - reporter: "", + reporter: "PKCE Checker", }); return false; } @@ -45,7 +44,7 @@ export class PKCECheck { : "[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: "", + reporter: "PKCE Checker", }); return false; } @@ -54,23 +53,71 @@ export class PKCECheck { searchParams.delete("code_challenge"); searchParams.delete("code_challenge_method"); const downgradedQuery = searchParams.toString(); - const downgradedUrl = `${req.getUrl().split("://")[0]}://${req.getHost()}:${req.getPort()}${req.getPath()}?${downgradedQuery}`; + 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 { - const [resOriginal, resDowngraded] = await Promise.all([ - fetch(new FetchRequest(url, { method: "GET" })), - fetch(new FetchRequest(downgradedUrl, { method: "GET" })), - ]); + // 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()); - const [bodyOriginal, bodyDowngraded] = await Promise.all([ - resOriginal.text(), - resDowngraded.text(), - ]); + 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 codeInBoth = bodyOriginal.includes("code=") && bodyDowngraded.includes("code="); + const codeInRedirects = locationOriginal.includes("code=") && locationDowngraded.includes("code="); - if (statusEqual && codeInBoth) { + if (statusEqual && codeInRedirects) { const title = isOpenID ? "[CRITICAL] OpenID Flow PKCE Downgraded to Plaintext" : "[CRITICAL] OAuth2 Flow PKCE Downgraded to Plaintext"; @@ -80,13 +127,13 @@ export class PKCECheck { await sdk.findings.create({ title, - description: `PKCE downgrade detected for ${url}.\n\nDowngraded URL: ${downgradedUrl}\n\nReference: ${reference}`, + 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)}`); } diff --git a/playground/PKCEDowngrade/.env.example b/playground/PKCEDowngrade/.env.example new file mode 100644 index 0000000..13f5f37 --- /dev/null +++ b/playground/PKCEDowngrade/.env.example @@ -0,0 +1,2 @@ +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= From dcd03435692fed71aa9ef401be91627be3d39815 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sat, 31 May 2025 11:57:52 +0900 Subject: [PATCH 14/14] Dist conflicts resolve --- .gitignore | 225 ++++++++++++++++++++- dist/plugin_package.zip | Bin 3712 -> 0 bytes dist/plugin_package/manifest.json | 21 -- dist/plugin_package/oauth-backend/index.js | 83 -------- 4 files changed, 224 insertions(+), 105 deletions(-) delete mode 100644 dist/plugin_package.zip delete mode 100644 dist/plugin_package/manifest.json delete mode 100644 dist/plugin_package/oauth-backend/index.js diff --git a/.gitignore b/.gitignore index 3c3629e..648628f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,224 @@ -node_modules +# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,linux + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +#!dist/ +dist/* +packages/frontend/dist +packages/backend/dist +#!dist/*.zip + +# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,linux \ No newline at end of file diff --git a/dist/plugin_package.zip b/dist/plugin_package.zip deleted file mode 100644 index 9573ba39c2928d42322ad80411c36ddf032212da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3712 zcmWIWW@h1H;9y{2*ub?9^vsfs z(j<@q{cMZ+a5!Q}z&wE=k(yUhR9TRpnO6ex3MBlYiu5z{Qc^4QvWgMr7nSCfWI|#hE3qsQ z61YlW2i9^aD8zEr26(e`Twb>F&RIqV1`vj%15os%rvp9)1_o67AZoFt88HmCFt_RJ zD-@U0jq5b$dxMS7vTOeo=`+wL(Erer{%QYOz9Mu|it0LajntQGTw1 zQd+T+HB6BfNUk8UBm*i3Vj^Voi=o2#AT4EyMG8f!g{7&*CBBIT3bqRRS_%&F@d2Sh zuJQ2-TKWokspSg3i3J*()?8_&dC8y@rjVJJS)x&#lC24j&*GG9z0|VQypm$Q{5;RR zlGLK))Pj;Ah@l#Z#g%!<3Lw=+Iv|@g6>ROm+7uK@iYlQj1%>4Nyy6mt(xRN;lA_GK zbOl?GTD|ntlF*_YklmofgQQBq7VNOlARi659!+a-3@RuTr(_%Hfeg&gN!82APuEC@ z24|H3aAJ&AfV(j@1!N1z?^X&b)o_Dq6W~T=rYUGBmKNpcfx-}!`t&mMl5 zF<1cZAc(G_)RfGk)Z~)TqD%!_s2QNZ(ollQ#FrLjD#3Muy#bR7Ey~31mZH=`&lE(+ zd!`@)9+5=!ic?E8z$!t}33mqEDu@G>g%=FB>#GLrjq8uwkk_8oi&{PWce0*k#l>)@Wo+$`P zSS)}d$Vvgm3oXh-R)XY3kQxXV6d2GHUJDB@oCfgu7#K_Rg`F|$M=tyr(TD6=HhEi)%o17@s_ zf>*G=pI$LIpJt|2YCwWWMT2rZp@k5I;L6VSU1}(Z`4GcgvCse>j!34sG`4rhgh&Pc^ zFeFYul{d%{>9AS}TCtSoW#{FW=OHQ6{8d zzs$KA7(h6{n~_O`0nuSYZo-2)Y@h}_0;6=_U|K=a*xL9YaRvqf1_lNWCd?K;s { - try { - const urlString = req.getUrl(); - const url = new URL(urlString); - sdk2.console.log(`[OAuthPlugin] Intercepted request: ${urlString}`); - if (!url.pathname.includes("/authorize") && !url.pathname.includes("/auth")) return; - const params = new URLSearchParams(url.search); - const redirectUri = params.get("redirect_uri"); - if (!redirectUri) return; - const reqId = req.getId(); - requestMap.set(reqId, redirectUri); - const clientId = params.get("client_id") ?? "(missing)"; - const responseType = params.get("response_type") ?? "(missing)"; - const isScan = params.has("scan"); - if (isScan) return; - const output = { - original_url: urlString, - client_id: clientId, - redirect_uri: redirectUri, - response_type: responseType - }; - try { - const filePath = path.join(os.tmpdir(), "oauth-fuzz-input.json"); - await fs.writeFile(filePath, JSON.stringify(output, null, 2)); - } catch (err) { - await sdk2.findings.create({ - title: "[fs] Write Failed", - description: `Could not write to file: ${err}`, - request: req, - reporter: "oauth-open-redirect-detector" - }); - } - await sdk2.findings.create({ - title: "[ ] OAuth2 Authorization Request Collected", - description: `client_id: ${clientId} -redirect_uri: ${redirectUri} -response_type: ${responseType}`, - request: req, - reporter: "oauth-open-redirect-detector" - }); - } catch (err) { - sdk2.console.error(`Error in onInterceptRequest: ${err}`); - } - }); - sdk.events.onInterceptResponse(async (sdk2, req, resp) => { - try { - const reqId = req.getId(); - const url = new URL(req.getUrl()); - const status = resp.getCode(); - const location = resp.getHeader("location")?.[0]; - const params = new URLSearchParams(url.search); - const isScan = params.has("scan"); - if (!isScan) { - requestMap.delete(reqId); - return; - } - if (status >= 300 && status < 400 && location) { - const redirectUri = requestMap.get(reqId) ?? "(unknown)"; - await sdk2.findings.create({ - title: "[+] Redirect URI Misconfiguration Detected", - description: `Status: ${status} -Location: ${location} -Original Redirect URI: ${redirectUri} -Request URL: ${url.href}`, - request: req, - reporter: "oauth-open-redirect-detector" - }); - } - requestMap.delete(reqId); - } catch (err) { - sdk2.console.error(`Error in onInterceptResponse: ${err}`); - } - }); -} -export { - init -};