mirror of
https://github.com/tinyauthapp/tinyauth.git
synced 2026-08-25 23:03:35 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8624bb9562 |
@@ -235,8 +235,6 @@ TINYAUTH_LDAP_GROUPCACHETTL=900
|
||||
|
||||
# Enable the OAuth bridge, uses a new way to format OAuth user information.
|
||||
TINYAUTH_EXPERIMENTAL_OAUTHBRIDGEENABLED=false
|
||||
# Disable the fallback to forward_auth modules when auth_request or ext_authz fail.
|
||||
TINYAUTH_EXPERIMENTAL_DISABLEAUTHMODULEFALLBACK=false
|
||||
|
||||
# tailscale config
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
name: Run e2e tests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# pull_request:
|
||||
# branches:
|
||||
# - main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
@@ -38,6 +38,6 @@ jobs:
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
|
||||
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ COPY ./frontend/vite.config.ts ./
|
||||
RUN pnpm run build
|
||||
|
||||
# Builder
|
||||
FROM golang:1.26-alpine3.23 AS builder
|
||||
FROM golang:1.27-alpine3.23 AS builder
|
||||
|
||||
ARG VERSION
|
||||
ARG COMMIT_HASH
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.26-alpine3.23
|
||||
FROM golang:1.27-alpine3.23
|
||||
|
||||
WORKDIR /tinyauth
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ COPY ./frontend/vite.config.ts ./
|
||||
RUN pnpm run build
|
||||
|
||||
# Builder
|
||||
FROM golang:1.26-alpine3.23 AS builder
|
||||
FROM golang:1.27-alpine3.23 AS builder
|
||||
|
||||
ARG VERSION
|
||||
ARG COMMIT_HASH
|
||||
|
||||
@@ -81,6 +81,7 @@ A huge thank you to [selfh.st](https://selfh.st) for their generous donation to
|
||||
|
||||
- [JetBrains for Open-Source](https://jb.gg/OpenSource)
|
||||
- [CodeRabbit AI](https://www.coderabbit.ai)
|
||||
- [Dosu](https://dosu.dev/)
|
||||
- [InstaPods](https://instapods.com) - [Deploy Tinyauth from 3$/month](https://app.instapods.com/dashboard/pods/create?app=tinyauth&ref=tinyauth)
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"packageManager": "pnpm@11.1.2",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.9.1",
|
||||
"@hookform/resolvers": "^5.9.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-label": "^2.1.15",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
@@ -23,16 +23,16 @@
|
||||
"axios": "^1.19.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"i18next": "^26.4.0",
|
||||
"i18next": "^26.3.6",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"i18next-resources-to-backend": "^1.2.3",
|
||||
"lucide-react": "^1.33.0",
|
||||
"lucide-react": "^1.31.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.6.7",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-hook-form": "^7.86.0",
|
||||
"react-i18next": "^17.0.12",
|
||||
"react-hook-form": "^7.85.0",
|
||||
"react-i18next": "^17.0.11",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^8.3.0",
|
||||
"sonner": "^2.0.8",
|
||||
@@ -46,8 +46,8 @@
|
||||
"@types/node": "^26.2.0",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.4",
|
||||
"@vitejs/plugin-react": "^6.1.0",
|
||||
"eslint": "^10.9.0",
|
||||
"@vitejs/plugin-react": "^6.0.5",
|
||||
"eslint": "^10.8.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.4",
|
||||
"globals": "^17.11.0",
|
||||
@@ -55,6 +55,6 @@
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~6.0.2",
|
||||
"typescript-eslint": "^8.67.0",
|
||||
"vite": "^8.2.2"
|
||||
"vite": "^8.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+152
-165
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@hookform/resolvers':
|
||||
specifier: ^5.9.1
|
||||
version: 5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.4.3)
|
||||
specifier: ^5.9.0
|
||||
version: 5.9.0(react-hook-form@7.85.0(react@19.2.8))(zod@4.4.3)
|
||||
'@radix-ui/react-dropdown-menu':
|
||||
specifier: ^2.1.24
|
||||
version: 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
@@ -28,7 +28,7 @@ importers:
|
||||
version: 1.3.3(@types/react@19.2.18)(react@19.2.8)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0))
|
||||
version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.101.4
|
||||
version: 5.101.4(react@19.2.8)
|
||||
@@ -42,8 +42,8 @@ importers:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
i18next:
|
||||
specifier: ^26.4.0
|
||||
version: 26.4.0(typescript@6.0.3)
|
||||
specifier: ^26.3.6
|
||||
version: 26.3.6(typescript@6.0.3)
|
||||
i18next-browser-languagedetector:
|
||||
specifier: ^8.2.1
|
||||
version: 8.2.1
|
||||
@@ -51,8 +51,8 @@ importers:
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
lucide-react:
|
||||
specifier: ^1.33.0
|
||||
version: 1.33.0(react@19.2.8)
|
||||
specifier: ^1.31.0
|
||||
version: 1.31.0(react@19.2.8)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
@@ -66,11 +66,11 @@ importers:
|
||||
specifier: ^19.2.8
|
||||
version: 19.2.8(react@19.2.8)
|
||||
react-hook-form:
|
||||
specifier: ^7.86.0
|
||||
version: 7.86.0(react@19.2.8)
|
||||
specifier: ^7.85.0
|
||||
version: 7.85.0(react@19.2.8)
|
||||
react-i18next:
|
||||
specifier: ^17.0.12
|
||||
version: 17.0.12(i18next@26.4.0(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3)
|
||||
specifier: ^17.0.11
|
||||
version: 17.0.11(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3)
|
||||
react-markdown:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0(@types/react@19.2.18)(react@19.2.8)
|
||||
@@ -92,10 +92,10 @@ importers:
|
||||
devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^10.0.1
|
||||
version: 10.0.1(eslint@10.9.0(jiti@2.7.0))
|
||||
version: 10.0.1(eslint@10.8.1(jiti@2.7.0))
|
||||
'@tanstack/eslint-plugin-query':
|
||||
specifier: ^5.101.4
|
||||
version: 5.101.4(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
version: 5.101.4(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@types/node':
|
||||
specifier: ^26.2.0
|
||||
version: 26.2.0
|
||||
@@ -106,23 +106,23 @@ importers:
|
||||
specifier: ^19.2.4
|
||||
version: 19.2.4(@types/react@19.2.18)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0))
|
||||
specifier: ^6.0.5
|
||||
version: 6.0.5(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))
|
||||
eslint:
|
||||
specifier: ^10.9.0
|
||||
version: 10.9.0(jiti@2.7.0)
|
||||
specifier: ^10.8.1
|
||||
version: 10.8.1(jiti@2.7.0)
|
||||
eslint-plugin-react-hooks:
|
||||
specifier: ^7.0.1
|
||||
version: 7.1.1(eslint@10.9.0(jiti@2.7.0))
|
||||
version: 7.1.1(eslint@10.8.1(jiti@2.7.0))
|
||||
eslint-plugin-react-refresh:
|
||||
specifier: ^0.5.4
|
||||
version: 0.5.4(eslint@10.9.0(jiti@2.7.0))
|
||||
version: 0.5.4(eslint@10.8.1(jiti@2.7.0))
|
||||
globals:
|
||||
specifier: ^17.11.0
|
||||
version: 17.11.0
|
||||
rollup-plugin-visualizer:
|
||||
specifier: ^7.1.1
|
||||
version: 7.1.1(rolldown@1.2.5)
|
||||
version: 7.1.1(rolldown@1.2.3)
|
||||
tw-animate-css:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
@@ -131,10 +131,10 @@ importers:
|
||||
version: 6.0.3
|
||||
typescript-eslint:
|
||||
specifier: ^8.67.0
|
||||
version: 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
version: 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
vite:
|
||||
specifier: ^8.2.2
|
||||
version: 8.2.2(@types/node@26.2.0)(jiti@2.7.0)
|
||||
specifier: ^8.2.1
|
||||
version: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -267,8 +267,8 @@ packages:
|
||||
'@floating-ui/utils@0.2.12':
|
||||
resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
|
||||
|
||||
'@hookform/resolvers@5.9.1':
|
||||
resolution: {integrity: sha512-7b7vsbraJxKgjVSA1Nur9tLwj539WGJUBLA7QNvXnFoT2pM5Z7G+6rlukk4B2/QrTZy6huRtH6wKeESPKuIr6w==}
|
||||
'@hookform/resolvers@5.9.0':
|
||||
resolution: {integrity: sha512-8sNo1IklGaONrsKzXjwZJNsPbccAXLXGX//G+VFEcQOviMtbvR8/fM6HWyA0qrjgpOYauwoodda53CQIWOZ7Ag==}
|
||||
peerDependencies:
|
||||
'@sinclair/typebox': '>=0.25.24'
|
||||
'@standard-schema/spec': ^1.0.0
|
||||
@@ -381,8 +381,8 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
|
||||
'@oxc-project/types@0.146.0':
|
||||
resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==}
|
||||
'@oxc-project/types@0.143.0':
|
||||
resolution: {integrity: sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==}
|
||||
|
||||
'@radix-ui/number@1.1.3':
|
||||
resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==}
|
||||
@@ -1074,98 +1074,92 @@ packages:
|
||||
'@radix-ui/rect@1.1.3':
|
||||
resolution: {integrity: sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==}
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.5':
|
||||
resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==}
|
||||
'@rolldown/binding-android-arm64@1.2.3':
|
||||
resolution: {integrity: sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==}
|
||||
'@rolldown/binding-darwin-arm64@1.2.3':
|
||||
resolution: {integrity: sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.5':
|
||||
resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==}
|
||||
'@rolldown/binding-darwin-x64@1.2.3':
|
||||
resolution: {integrity: sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.5':
|
||||
resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==}
|
||||
'@rolldown/binding-freebsd-x64@1.2.3':
|
||||
resolution: {integrity: sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.5':
|
||||
resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==}
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.3':
|
||||
resolution: {integrity: sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==}
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.3':
|
||||
resolution: {integrity: sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.5':
|
||||
resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==}
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.3':
|
||||
resolution: {integrity: sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==}
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.3':
|
||||
resolution: {integrity: sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==}
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.3':
|
||||
resolution: {integrity: sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==}
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.3':
|
||||
resolution: {integrity: sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.5':
|
||||
resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==}
|
||||
'@rolldown/binding-linux-x64-musl@1.2.3':
|
||||
resolution: {integrity: sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==}
|
||||
'@rolldown/binding-openharmony-arm64@1.2.3':
|
||||
resolution: {integrity: sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.5':
|
||||
resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==}
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.3':
|
||||
resolution: {integrity: sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.5':
|
||||
resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==}
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.3':
|
||||
resolution: {integrity: sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -1427,21 +1421,18 @@ packages:
|
||||
'@ungap/structured-clone@1.3.1':
|
||||
resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==}
|
||||
|
||||
'@vitejs/plugin-react@6.1.0':
|
||||
resolution: {integrity: sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==}
|
||||
'@vitejs/plugin-react@6.0.5':
|
||||
resolution: {integrity: sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
|
||||
babel-plugin-react-compiler: ^1.0.0
|
||||
oxc-transform-react: ^0.145.0
|
||||
vite: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
'@rolldown/plugin-babel':
|
||||
optional: true
|
||||
babel-plugin-react-compiler:
|
||||
optional: true
|
||||
oxc-transform-react:
|
||||
optional: true
|
||||
|
||||
acorn-jsx@5.3.2:
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
@@ -1662,8 +1653,8 @@ packages:
|
||||
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
eslint@10.9.0:
|
||||
resolution: {integrity: sha512-5KeEOJZBfEVA47boFiBsf+6MmmJpffM7qEBg4pLla2e4nlKgdKlqCW0oSLOGsT8Wl5uCGJptLV1bkaiShj90Gw==}
|
||||
eslint@10.8.1:
|
||||
resolution: {integrity: sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1831,8 +1822,8 @@ packages:
|
||||
i18next-resources-to-backend@1.2.3:
|
||||
resolution: {integrity: sha512-8Y/LLAm5fqZc2ckQxtTWbu75ndjNLzF7mcYl6rhc4g+WBopIsG3YhdYqF5qhJy64tlYhlU2KSSnEgW3gGHLqwg==}
|
||||
|
||||
i18next@26.4.0:
|
||||
resolution: {integrity: sha512-rsmK5bFqsD1AetSFSIa43wtNR4WpvvH4p0tLEsTxkC7QTrfdFm06nbQ95bh8Og4wwaCnUEcm9DVYL2cgxitiQg==}
|
||||
i18next@26.3.6:
|
||||
resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==}
|
||||
peerDependencies:
|
||||
typescript: ^5 || ^6 || ^7
|
||||
peerDependenciesMeta:
|
||||
@@ -2090,8 +2081,8 @@ packages:
|
||||
lru-cache@5.1.1:
|
||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
|
||||
lucide-react@1.33.0:
|
||||
resolution: {integrity: sha512-MTRwMy0ZlL8Ur/vOAiJ9XGHE+kFPC7brq6MxAm0GiGXEBj0qy0jA/pG4N675oSzciO/UCdX8T+5yUQdmDeTLxg==}
|
||||
lucide-react@1.31.0:
|
||||
resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==}
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
@@ -2300,14 +2291,14 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^19.2.8
|
||||
|
||||
react-hook-form@7.86.0:
|
||||
resolution: {integrity: sha512-4kbWJrh5jPZt1+YqVcXcGKffGcXV/XVbozknLh0Yjh0KhpoAkus21TAQhzRYqNwFkkObmnSvRlZZ3GT+ehoIrA==}
|
||||
react-hook-form@7.85.0:
|
||||
resolution: {integrity: sha512-U2MTriFXnclmV4rOE20p2DcRFv5WEg3FIcBFOKcOLFHDVvGIMPvLTkTWefUsonmlaVy23khVDxDWym6uJVGOzw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17 || ^18 || ^19
|
||||
|
||||
react-i18next@17.0.12:
|
||||
resolution: {integrity: sha512-lFWPEGkxQ6RhusdUkysFBD58VHfSSzvHBzqMgN0SvfVpdQGfwtNkStTqdy08/sJd7s807qqutgx93fRpD0DJ3Q==}
|
||||
react-i18next@17.0.11:
|
||||
resolution: {integrity: sha512-cDtkXgxjuFTWUH6V+aQn1Ve5vDiUztCNPWW5GtSHDccsgRXO1nE6QFWCEmc1KAutrb3OUv87wFShJL5RhUwPXg==}
|
||||
peerDependencies:
|
||||
i18next: '>= 26.2.0'
|
||||
react: '>= 16.8.0'
|
||||
@@ -2378,8 +2369,8 @@ packages:
|
||||
remark-rehype@11.1.2:
|
||||
resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
|
||||
|
||||
rolldown@1.2.5:
|
||||
resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==}
|
||||
rolldown@1.2.3:
|
||||
resolution: {integrity: sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
@@ -2571,13 +2562,13 @@ packages:
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
vite@8.2.2:
|
||||
resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==}
|
||||
vite@8.2.1:
|
||||
resolution: {integrity: sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
'@vitejs/devtools': ^0.4.0 || ^0.5.0
|
||||
'@vitejs/devtools': ^0.4.0
|
||||
esbuild: ^0.27.0 || ^0.28.0
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
@@ -2768,9 +2759,9 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@eslint-community/eslint-utils@4.10.1(eslint@10.9.0(jiti@2.7.0))':
|
||||
'@eslint-community/eslint-utils@4.10.1(eslint@10.8.1(jiti@2.7.0))':
|
||||
dependencies:
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
@@ -2791,9 +2782,9 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.15
|
||||
|
||||
'@eslint/js@10.0.1(eslint@10.9.0(jiti@2.7.0))':
|
||||
'@eslint/js@10.0.1(eslint@10.8.1(jiti@2.7.0))':
|
||||
optionalDependencies:
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
|
||||
'@eslint/object-schema@3.0.5': {}
|
||||
|
||||
@@ -2819,10 +2810,10 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.12': {}
|
||||
|
||||
'@hookform/resolvers@5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.4.3)':
|
||||
'@hookform/resolvers@5.9.0(react-hook-form@7.85.0(react@19.2.8))(zod@4.4.3)':
|
||||
dependencies:
|
||||
'@standard-schema/utils': 0.3.0
|
||||
react-hook-form: 7.86.0(react@19.2.8)
|
||||
react-hook-form: 7.85.0(react@19.2.8)
|
||||
optionalDependencies:
|
||||
zod: 4.4.3
|
||||
|
||||
@@ -2861,7 +2852,7 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@oxc-project/types@0.146.0': {}
|
||||
'@oxc-project/types@0.143.0': {}
|
||||
|
||||
'@radix-ui/number@1.1.3': {}
|
||||
|
||||
@@ -3610,49 +3601,46 @@ snapshots:
|
||||
|
||||
'@radix-ui/rect@1.1.3': {}
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.5':
|
||||
'@rolldown/binding-android-arm64@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.5':
|
||||
'@rolldown/binding-darwin-arm64@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.5':
|
||||
'@rolldown/binding-darwin-x64@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.5':
|
||||
'@rolldown/binding-freebsd-x64@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.5':
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.5':
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.5':
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-x64-musl@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.5':
|
||||
'@rolldown/binding-openharmony-arm64@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.5':
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.5':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.5':
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.3':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.1': {}
|
||||
@@ -3720,17 +3708,17 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.3.3
|
||||
|
||||
'@tailwindcss/vite@4.3.3(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0))':
|
||||
'@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.3.3
|
||||
'@tailwindcss/oxide': 4.3.3
|
||||
tailwindcss: 4.3.3
|
||||
vite: 8.2.2(@types/node@26.2.0)(jiti@2.7.0)
|
||||
vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
|
||||
|
||||
'@tanstack/eslint-plugin-query@5.101.4(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@tanstack/eslint-plugin-query@5.101.4(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.65.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
'@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
optionalDependencies:
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -3783,15 +3771,15 @@ snapshots:
|
||||
|
||||
'@types/unist@3.0.3': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/scope-manager': 8.67.0
|
||||
'@typescript-eslint/type-utils': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/type-utils': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.67.0
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
ignore: 7.0.6
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
@@ -3799,14 +3787,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.67.0
|
||||
'@typescript-eslint/types': 8.67.0
|
||||
'@typescript-eslint/typescript-estree': 8.67.0(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.67.0
|
||||
debug: 4.4.3
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -3847,13 +3835,13 @@ snapshots:
|
||||
dependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/type-utils@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.67.0
|
||||
'@typescript-eslint/typescript-estree': 8.67.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
debug: 4.4.3
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -3893,24 +3881,24 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.65.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/utils@8.65.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.0(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0))
|
||||
'@typescript-eslint/scope-manager': 8.65.0
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/typescript-estree': 8.65.0(typescript@6.0.3)
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.0(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0))
|
||||
'@typescript-eslint/scope-manager': 8.67.0
|
||||
'@typescript-eslint/types': 8.67.0
|
||||
'@typescript-eslint/typescript-estree': 8.67.0(typescript@6.0.3)
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -3927,10 +3915,10 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.3.1': {}
|
||||
|
||||
'@vitejs/plugin-react@6.1.0(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0))':
|
||||
'@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
vite: 8.2.2(@types/node@26.2.0)(jiti@2.7.0)
|
||||
vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.18.0):
|
||||
dependencies:
|
||||
@@ -4105,20 +4093,20 @@ snapshots:
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
eslint-plugin-react-hooks@7.1.1(eslint@10.9.0(jiti@2.7.0)):
|
||||
eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/parser': 7.29.3
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
hermes-parser: 0.25.1
|
||||
zod: 4.4.3
|
||||
zod-validation-error: 4.0.2(zod@4.4.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-react-refresh@0.5.4(eslint@10.9.0(jiti@2.7.0)):
|
||||
eslint-plugin-react-refresh@0.5.4(eslint@10.8.1(jiti@2.7.0)):
|
||||
dependencies:
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
|
||||
eslint-scope@9.1.2:
|
||||
dependencies:
|
||||
@@ -4131,9 +4119,9 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@5.0.1: {}
|
||||
|
||||
eslint@10.9.0(jiti@2.7.0):
|
||||
eslint@10.8.1(jiti@2.7.0):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.0(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.23.5
|
||||
'@eslint/config-helpers': 0.7.0
|
||||
@@ -4326,7 +4314,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
|
||||
i18next@26.4.0(typescript@6.0.3):
|
||||
i18next@26.3.6(typescript@6.0.3):
|
||||
optionalDependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
@@ -4502,7 +4490,7 @@ snapshots:
|
||||
dependencies:
|
||||
yallist: 3.1.1
|
||||
|
||||
lucide-react@1.33.0(react@19.2.8):
|
||||
lucide-react@1.31.0(react@19.2.8):
|
||||
dependencies:
|
||||
react: 19.2.8
|
||||
|
||||
@@ -4887,15 +4875,15 @@ snapshots:
|
||||
react: 19.2.8
|
||||
scheduler: 0.27.0
|
||||
|
||||
react-hook-form@7.86.0(react@19.2.8):
|
||||
react-hook-form@7.85.0(react@19.2.8):
|
||||
dependencies:
|
||||
react: 19.2.8
|
||||
|
||||
react-i18next@17.0.12(i18next@26.4.0(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3):
|
||||
react-i18next@17.0.11(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
html-parse-stringify: 4.0.1
|
||||
i18next: 26.4.0(typescript@6.0.3)
|
||||
i18next: 26.3.6(typescript@6.0.3)
|
||||
react: 19.2.8
|
||||
use-sync-external-store: 1.6.0(react@19.2.8)
|
||||
optionalDependencies:
|
||||
@@ -4973,35 +4961,34 @@ snapshots:
|
||||
unified: 11.0.5
|
||||
vfile: 6.0.3
|
||||
|
||||
rolldown@1.2.5:
|
||||
rolldown@1.2.3:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.146.0
|
||||
'@oxc-project/types': 0.143.0
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-android-arm-eabi': 1.2.5
|
||||
'@rolldown/binding-android-arm64': 1.2.5
|
||||
'@rolldown/binding-darwin-arm64': 1.2.5
|
||||
'@rolldown/binding-darwin-x64': 1.2.5
|
||||
'@rolldown/binding-freebsd-x64': 1.2.5
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.2.5
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-arm64-musl': 1.2.5
|
||||
'@rolldown/binding-linux-ppc64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-s390x-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-x64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-x64-musl': 1.2.5
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.5
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.5
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.5
|
||||
'@rolldown/binding-android-arm64': 1.2.3
|
||||
'@rolldown/binding-darwin-arm64': 1.2.3
|
||||
'@rolldown/binding-darwin-x64': 1.2.3
|
||||
'@rolldown/binding-freebsd-x64': 1.2.3
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.2.3
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.2.3
|
||||
'@rolldown/binding-linux-arm64-musl': 1.2.3
|
||||
'@rolldown/binding-linux-ppc64-gnu': 1.2.3
|
||||
'@rolldown/binding-linux-s390x-gnu': 1.2.3
|
||||
'@rolldown/binding-linux-x64-gnu': 1.2.3
|
||||
'@rolldown/binding-linux-x64-musl': 1.2.3
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.3
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.3
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.3
|
||||
|
||||
rollup-plugin-visualizer@7.1.1(rolldown@1.2.5):
|
||||
rollup-plugin-visualizer@7.1.1(rolldown@1.2.3):
|
||||
dependencies:
|
||||
open: 11.0.1
|
||||
picomatch: 4.0.5
|
||||
source-map: 0.8.0
|
||||
yargs: 18.1.0
|
||||
optionalDependencies:
|
||||
rolldown: 1.2.5
|
||||
rolldown: 1.2.3
|
||||
|
||||
run-applescript@7.1.0: {}
|
||||
|
||||
@@ -5085,13 +5072,13 @@ snapshots:
|
||||
dependencies:
|
||||
prelude-ls: 1.2.1
|
||||
|
||||
typescript-eslint@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3):
|
||||
typescript-eslint@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.67.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.9.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.9.0(jiti@2.7.0)
|
||||
'@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.8.1(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5172,12 +5159,12 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0):
|
||||
vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0):
|
||||
dependencies:
|
||||
lightningcss: 1.33.0
|
||||
picomatch: 4.0.5
|
||||
postcss: 8.5.26
|
||||
rolldown: 1.2.5
|
||||
rolldown: 1.2.3
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 26.2.0
|
||||
|
||||
@@ -28,9 +28,9 @@ require (
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/tools v0.49.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.36.4
|
||||
k8s.io/client-go v0.36.4
|
||||
modernc.org/sqlite v1.57.0
|
||||
k8s.io/apimachinery v0.36.3
|
||||
k8s.io/client-go v0.36.3
|
||||
modernc.org/sqlite v1.56.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -380,12 +380,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
k8s.io/api v0.36.4 h1:RxrvqCL6vgH5/+UnTeu1IIFqYmGfy0hnyrod1rn35Oo=
|
||||
k8s.io/api v0.36.4/go.mod h1:S2B3orCFBDhrgyWbLeuKcT2QdHIpQesBkCYSlWtwUOw=
|
||||
k8s.io/apimachinery v0.36.4 h1:PT2UzkupGuAx/+xT5XjiMJ1WGpY3fn9/hdAvjweRet4=
|
||||
k8s.io/apimachinery v0.36.4/go.mod h1:p2I2dipt7JHG+quVwQ1d02d28O4GdDi77RByQ13MTpk=
|
||||
k8s.io/client-go v0.36.4 h1:MDvfDNvMSt0Br94SK8neviVlwL9qifw9B26hJCpD1K0=
|
||||
k8s.io/client-go v0.36.4/go.mod h1:pNK4WKELbwlEDvtbE8l22lEZL5THYF61H5EealokZmA=
|
||||
k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w=
|
||||
k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg=
|
||||
k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM=
|
||||
k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE=
|
||||
k8s.io/client-go v0.36.3 h1:M4JdVzXxYcZk4fGpfDdYnxSwhLKWCFoQsHW6t+z8Hfg=
|
||||
k8s.io/client-go v0.36.3/go.mod h1:gcPwr0c87vjjG6HB6pWEqOeuYVoXSsREjzux2j6GF30=
|
||||
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
|
||||
@@ -414,8 +414,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
||||
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.57.0 h1:qNQP6xnx5M0ISNtlnxoOX0+cD5bJ0/gr9aMmndFczzg=
|
||||
modernc.org/sqlite v1.57.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/sqlite v1.56.0 h1:/D8e2RfFqoy/Zc6PuC76U28zFwmI/sYx1Kjm4yEn9e0=
|
||||
modernc.org/sqlite v1.56.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
@@ -294,9 +294,7 @@ func (controller *OAuthController) getCookieDomain() string {
|
||||
|
||||
func (controller *OAuthController) isRedirectSafe(redirectURI string) bool {
|
||||
v := validators.NewDomainValidator(validators.DomainValidatorOptions{
|
||||
WithPort: true,
|
||||
WithScheme: true,
|
||||
AllowedSchemes: []string{"https", "http"},
|
||||
WithPort: true,
|
||||
})
|
||||
|
||||
_, err := v.SafeHostname(controller.runtime.AppURL)
|
||||
|
||||
@@ -57,7 +57,6 @@ type ProxyContext struct {
|
||||
type ProxyController struct {
|
||||
log *logger.Logger
|
||||
runtime *model.RuntimeConfig
|
||||
config *model.Config
|
||||
acls *service.AccessControlsService
|
||||
auth *service.AuthService
|
||||
policyEngine *service.PolicyEngine
|
||||
@@ -68,7 +67,6 @@ type ProxyControllerInput struct {
|
||||
|
||||
Log *logger.Logger
|
||||
RuntimeConfig *model.RuntimeConfig
|
||||
Config *model.Config
|
||||
RouterGroup *gin.RouterGroup `name:"apiRouterGroup"`
|
||||
ACLsService *service.AccessControlsService
|
||||
AuthService *service.AuthService
|
||||
@@ -79,7 +77,6 @@ func NewProxyController(i ProxyControllerInput) *ProxyController {
|
||||
controller := &ProxyController{
|
||||
log: i.Log,
|
||||
runtime: i.RuntimeConfig,
|
||||
config: i.Config,
|
||||
acls: i.ACLsService,
|
||||
auth: i.AuthService,
|
||||
policyEngine: i.PolicyEngine,
|
||||
@@ -468,10 +465,6 @@ func (controller *ProxyController) getExtAuthzContext(c *gin.Context) (ProxyCont
|
||||
// We get the path from the query string
|
||||
path := c.Query("path")
|
||||
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return ProxyContext{}, errors.New("path not found")
|
||||
}
|
||||
|
||||
// For envoy we need to support every method
|
||||
method := c.Request.Method
|
||||
|
||||
@@ -484,22 +477,14 @@ func (controller *ProxyController) getExtAuthzContext(c *gin.Context) (ProxyCont
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (controller *ProxyController) determineAuthModules(proxy ProxyType, fallbacks bool) []AuthModuleType {
|
||||
func (controller *ProxyController) determineAuthModules(proxy ProxyType) []AuthModuleType {
|
||||
switch proxy {
|
||||
case Traefik, Caddy:
|
||||
return []AuthModuleType{ForwardAuth}
|
||||
case Envoy:
|
||||
authModules := []AuthModuleType{ExtAuthz}
|
||||
if fallbacks {
|
||||
authModules = append(authModules, ForwardAuth)
|
||||
}
|
||||
return authModules
|
||||
return []AuthModuleType{ExtAuthz, ForwardAuth}
|
||||
case Nginx:
|
||||
authModules := []AuthModuleType{AuthRequest}
|
||||
if fallbacks {
|
||||
authModules = append(authModules, ForwardAuth)
|
||||
}
|
||||
return authModules
|
||||
return []AuthModuleType{AuthRequest, ForwardAuth}
|
||||
default:
|
||||
return []AuthModuleType{}
|
||||
}
|
||||
@@ -529,39 +514,6 @@ func (controller *ProxyController) getContextFromAuthModule(c *gin.Context, modu
|
||||
return ProxyContext{}, fmt.Errorf("unsupported auth module: %v", module)
|
||||
}
|
||||
|
||||
func (controller *ProxyController) authModuleIdentifiersPresent(c *gin.Context, module AuthModuleType) bool {
|
||||
switch module {
|
||||
case ForwardAuth:
|
||||
_, host := controller.getHeader(c, "x-forwarded-host")
|
||||
_, uri := controller.getHeader(c, "x-forwarded-uri")
|
||||
return host || uri
|
||||
case AuthRequest:
|
||||
_, ok := controller.getHeader(c, "x-original-url")
|
||||
return ok
|
||||
case ExtAuthz:
|
||||
return strings.TrimSpace(c.Query("path")) != ""
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (controller *ProxyController) ensureNoMultipleAuthModules(c *gin.Context, authModules []AuthModuleType) error {
|
||||
present := 0
|
||||
|
||||
for _, module := range authModules {
|
||||
if controller.authModuleIdentifiersPresent(c, module) {
|
||||
present++
|
||||
}
|
||||
}
|
||||
|
||||
if present > 1 {
|
||||
controller.log.App.Warn().Msg("Request carries headers for multiple auth modules, possible spoofing attempt, denying")
|
||||
return fmt.Errorf("conflicting auth module headers")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext, error) {
|
||||
var req Proxy
|
||||
|
||||
@@ -578,34 +530,26 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext
|
||||
|
||||
controller.log.App.Debug().Msgf("Determined proxy type: %v", proxy)
|
||||
|
||||
authModules := controller.determineAuthModules(proxy, !controller.config.Experimental.DisableAuthModuleFallback)
|
||||
authModules := controller.determineAuthModules(proxy)
|
||||
|
||||
if len(authModules) == 0 {
|
||||
return ProxyContext{}, fmt.Errorf("no auth modules supported for proxy: %v", req.Proxy)
|
||||
}
|
||||
|
||||
err = controller.ensureNoMultipleAuthModules(c, controller.determineAuthModules(proxy, true))
|
||||
|
||||
if err != nil {
|
||||
return ProxyContext{}, err
|
||||
}
|
||||
|
||||
var ctx *ProxyContext
|
||||
var ctx ProxyContext
|
||||
|
||||
for _, module := range authModules {
|
||||
controller.log.App.Debug().Msgf("Trying to get context from auth module %v", module)
|
||||
authModuleCtx, err := controller.getContextFromAuthModule(c, module)
|
||||
if err != nil {
|
||||
controller.log.App.Debug().Msgf("Failed to get context from auth module %v: %v", module, err)
|
||||
continue
|
||||
ctx, err = controller.getContextFromAuthModule(c, module)
|
||||
if err == nil {
|
||||
controller.log.App.Debug().Msgf("Successfully got context from auth module %v", module)
|
||||
break
|
||||
}
|
||||
controller.log.App.Debug().Msgf("Successfully got context from auth module %v", module)
|
||||
ctx = &authModuleCtx
|
||||
break
|
||||
controller.log.App.Debug().Msgf("Failed to get context from auth module %v: %v", module, err)
|
||||
}
|
||||
|
||||
if ctx == nil {
|
||||
return ProxyContext{}, fmt.Errorf("failed to get context from any auth module")
|
||||
if err != nil {
|
||||
return ProxyContext{}, err
|
||||
}
|
||||
|
||||
// Parse the raw path to populate the cleaned path used for ACLs
|
||||
@@ -633,5 +577,5 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext
|
||||
|
||||
ctx.IsBrowser = isBrowser
|
||||
ctx.ProxyType = proxy
|
||||
return *ctx, nil
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ func TestProxyController(t *testing.T) {
|
||||
description: "Ensure forward auth fallback for envoy",
|
||||
middlewares: []gin.HandlerFunc{},
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
req := httptest.NewRequest("HEAD", "/api/auth/envoy", nil)
|
||||
req := httptest.NewRequest("HEAD", "/api/auth/envoy?path=/hello", nil)
|
||||
req.Host = ""
|
||||
req.Header.Set("x-forwarded-host", "test.example.com")
|
||||
req.Header.Set("x-forwarded-proto", "https")
|
||||
@@ -261,7 +261,7 @@ func TestProxyController(t *testing.T) {
|
||||
description: "Ensure extauthz with envoy non browser returns json",
|
||||
middlewares: []gin.HandlerFunc{},
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
req := httptest.NewRequest("HEAD", "/api/auth/envoy", nil)
|
||||
req := httptest.NewRequest("HEAD", "/api/auth/envoy?path=/hello", nil)
|
||||
req.Header.Set("x-forwarded-host", "test.example.com")
|
||||
req.Header.Set("x-forwarded-proto", "https")
|
||||
req.Header.Set("x-forwarded-uri", "/hello")
|
||||
@@ -877,32 +877,6 @@ func TestProxyController(t *testing.T) {
|
||||
assert.Equal(t, "bar", recorder.Header().Get("x-foo"))
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Forward auth and auth request headers should fail for nginx",
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
req := httptest.NewRequest("GET", "/api/auth/nginx", nil)
|
||||
req.Header.Set("x-forwarded-host", "foo.example.com")
|
||||
req.Header.Set("x-forwarded-proto", "https")
|
||||
req.Header.Set("x-forwarded-uri", "/foo?bar=foo")
|
||||
req.Header.Set("x-original-url", "https://foo.example.com/foo?bar=foo")
|
||||
router.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Forward auth and ext authz headers should fail for envoy",
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
req := httptest.NewRequest("HEAD", "/api/auth/envoy?path=/hello", nil)
|
||||
req.Host = "foo.example.com"
|
||||
req.Header.Set("x-forwarded-host", "foo.example.com")
|
||||
req.Header.Set("x-forwarded-proto", "https")
|
||||
req.Header.Set("x-forwarded-uri", "/foo?bar=foo")
|
||||
router.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
store := memory.New()
|
||||
@@ -918,7 +892,6 @@ func TestProxyController(t *testing.T) {
|
||||
aclsService := service.NewAccessControlsService(service.AccessControlServiceInput{
|
||||
Log: log,
|
||||
Config: &cfg,
|
||||
Runtime: &runtime,
|
||||
LabelProvider: nil,
|
||||
})
|
||||
|
||||
@@ -979,7 +952,6 @@ func TestProxyController(t *testing.T) {
|
||||
NewProxyController(ProxyControllerInput{
|
||||
Log: log,
|
||||
RuntimeConfig: &runtime,
|
||||
Config: &cfg,
|
||||
RouterGroup: group,
|
||||
ACLsService: aclsService,
|
||||
AuthService: authService,
|
||||
|
||||
@@ -239,8 +239,7 @@ type LogStreamConfig struct {
|
||||
}
|
||||
|
||||
type ExperimentalConfig struct {
|
||||
OAuthBridgeEnabled bool `description:"Enable the OAuth bridge, uses a new way to format OAuth user information." yaml:"oauthBridgeEnabled,omitempty"`
|
||||
DisableAuthModuleFallback bool `description:"Disable the fallback to forward_auth modules when auth_request or ext_authz fail." yaml:"disableAuthModuleFallback,omitempty"`
|
||||
OAuthBridgeEnabled bool `description:"Enable the OAuth bridge, uses a new way to format OAuth user information." yaml:"oauthBridgeEnabled,omitempty"`
|
||||
}
|
||||
|
||||
type TailscaleConfig struct {
|
||||
|
||||
@@ -2,13 +2,11 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
||||
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
||||
"github.com/tinyauthapp/tinyauth/pkg/validators"
|
||||
"go.uber.org/dig"
|
||||
)
|
||||
|
||||
@@ -19,7 +17,6 @@ type LabelProvider interface {
|
||||
type AccessControlsService struct {
|
||||
log *logger.Logger
|
||||
config *model.Config
|
||||
runtime *model.RuntimeConfig
|
||||
labelProvider LabelProvider
|
||||
}
|
||||
|
||||
@@ -28,7 +25,6 @@ type AccessControlServiceInput struct {
|
||||
|
||||
Log *logger.Logger
|
||||
Config *model.Config
|
||||
Runtime *model.RuntimeConfig
|
||||
LabelProvider LabelProvider `optional:"true"`
|
||||
}
|
||||
|
||||
@@ -37,38 +33,12 @@ func NewAccessControlsService(i AccessControlServiceInput) *AccessControlsServic
|
||||
return &AccessControlsService{
|
||||
log: i.Log,
|
||||
config: i.Config,
|
||||
runtime: i.Runtime,
|
||||
labelProvider: i.LabelProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func (service *AccessControlsService) ensureAscii(str string) bool {
|
||||
for i := 0; i < len(str); i++ {
|
||||
if str[i] > unicode.MaxASCII {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (service *AccessControlsService) normalizeDomain(domain string) string {
|
||||
if host, _, err := net.SplitHostPort(domain); err == nil {
|
||||
domain = host
|
||||
}
|
||||
domain = strings.TrimRight(domain, ".")
|
||||
return strings.ToLower(domain)
|
||||
}
|
||||
|
||||
func (service *AccessControlsService) getACLs(domain string, lookup func(locator func(name string, app *model.App) bool) error) (*model.App, error) {
|
||||
if !service.ensureAscii(domain) {
|
||||
return nil, errors.New("domain contains non-ascii characters")
|
||||
}
|
||||
|
||||
normalizedDomain := service.normalizeDomain(domain)
|
||||
|
||||
if !strings.HasSuffix(normalizedDomain, "."+service.runtime.CookieDomain) && normalizedDomain != service.runtime.CookieDomain {
|
||||
return nil, fmt.Errorf("domain does not match cookie domain, expected %s (or a subdomain), got %s", service.runtime.CookieDomain, domain)
|
||||
}
|
||||
v := validators.NewDomainValidator(validators.DomainValidatorOptions{})
|
||||
|
||||
var domainMatch *model.App
|
||||
var nameMatch *model.App
|
||||
@@ -76,18 +46,16 @@ func (service *AccessControlsService) getACLs(domain string, lookup func(locator
|
||||
|
||||
locatorFunc := func(name string, app *model.App) bool {
|
||||
if app.Config.Domain != "" {
|
||||
if !service.ensureAscii(app.Config.Domain) {
|
||||
service.log.App.Warn().Str("name", name).Str("domain", app.Config.Domain).Msg("Domain contains non-ascii characters, skipping")
|
||||
return false
|
||||
}
|
||||
if normalizedDomain == service.normalizeDomain(app.Config.Domain) {
|
||||
err := v.Validate(app.Config.Domain, domain)
|
||||
if err == nil {
|
||||
service.log.App.Debug().Str("name", name).Msg("Found matching container by domain")
|
||||
domainMatch = app
|
||||
return true
|
||||
} else if !errors.Is(err, validators.ErrHostnameMismatch) {
|
||||
service.log.App.Debug().Str("name", name).Err(err).Msg("Domain validation failed")
|
||||
}
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(normalizedDomain, strings.ToLower(name+".")) {
|
||||
if strings.HasPrefix(strings.ToLower(domain), strings.ToLower(name+".")) {
|
||||
service.log.App.Debug().Str("name", name).Msg("Found matching container by app name")
|
||||
nameMatch = app
|
||||
nameMatchedApps = append(nameMatchedApps, name)
|
||||
@@ -111,7 +79,7 @@ func (service *AccessControlsService) getACLs(domain string, lookup func(locator
|
||||
}
|
||||
|
||||
if len(nameMatchedApps) > 1 {
|
||||
return nil, fmt.Errorf("domain matched multiple apps by name prefix, use explicit domain config")
|
||||
service.log.App.Warn().Str("domain", domain).Strs("apps", nameMatchedApps).Msg("Multiple apps matched domain by name, app names must be unique, using last match")
|
||||
}
|
||||
|
||||
service.log.App.Debug().Str("domain", domain).Msg("Found matching app by app name")
|
||||
|
||||
@@ -4,10 +4,8 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
||||
"github.com/tinyauthapp/tinyauth/internal/test"
|
||||
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
||||
)
|
||||
|
||||
@@ -36,25 +34,14 @@ func TestAccessControlsService(t *testing.T) {
|
||||
log := logger.NewLogger().WithTestConfig()
|
||||
log.Init()
|
||||
|
||||
_, runtime := test.CreateTestConfigs(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
domain string
|
||||
acls map[string]model.App
|
||||
want *model.App
|
||||
errorFunc func(t *testing.T, e error)
|
||||
name string
|
||||
domain string
|
||||
acls map[string]model.App
|
||||
want *model.App
|
||||
}{
|
||||
{
|
||||
name: "returns ACLs for domain",
|
||||
domain: "app.example.com",
|
||||
acls: map[string]model.App{
|
||||
"foo": {Config: model.AppConfig{Domain: "app.example.com"}},
|
||||
},
|
||||
want: &model.App{Config: model.AppConfig{Domain: "app.example.com"}},
|
||||
},
|
||||
{
|
||||
name: "returns ACLs for root domain",
|
||||
domain: "example.com",
|
||||
acls: map[string]model.App{
|
||||
"foo": {Config: model.AppConfig{Domain: "example.com"}},
|
||||
@@ -78,11 +65,20 @@ func TestAccessControlsService(t *testing.T) {
|
||||
want: &model.App{Config: model.AppConfig{Domain: "example.com"}},
|
||||
},
|
||||
{
|
||||
name: "returns error for non-ascii domain",
|
||||
name: "returns ACLs for non-ascii domain",
|
||||
domain: "bücher.example.com",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "domain contains non-ascii characters")
|
||||
acls: map[string]model.App{
|
||||
"foo": {Config: model.AppConfig{Domain: "bücher.example.com"}},
|
||||
},
|
||||
want: &model.App{Config: model.AppConfig{Domain: "bücher.example.com"}},
|
||||
},
|
||||
{
|
||||
name: "returns ACLs for punycode domain and non-ascii config",
|
||||
domain: "bücher.example.com",
|
||||
acls: map[string]model.App{
|
||||
"foo": {Config: model.AppConfig{Domain: "xn--bcher-kva.example.com"}},
|
||||
},
|
||||
want: &model.App{Config: model.AppConfig{Domain: "xn--bcher-kva.example.com"}},
|
||||
},
|
||||
{
|
||||
name: "returns ACLs with case-insensitive matching",
|
||||
@@ -114,33 +110,6 @@ func TestAccessControlsService(t *testing.T) {
|
||||
acls: map[string]model.App{},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "App in domain not matching with the cookie domain should return nothing with name matching",
|
||||
domain: "foo.bad_example.com",
|
||||
acls: map[string]model.App{
|
||||
"foo": {
|
||||
Path: model.AppPath{Allow: "/foo"},
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "domain does not match cookie domain")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "App in domain not matching with the cookie domain should return nothing with domain matching",
|
||||
domain: "foo.bad_example.com",
|
||||
acls: map[string]model.App{
|
||||
"foo": {
|
||||
Path: model.AppPath{Allow: "/foo"},
|
||||
Config: model.AppConfig{Domain: "foo.bad_example.com"},
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "domain does not match cookie domain")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// run once for a mock provider
|
||||
@@ -149,15 +118,10 @@ func TestAccessControlsService(t *testing.T) {
|
||||
mock := newMockProvider(test.acls, false)
|
||||
acls := NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Config: &model.Config{},
|
||||
LabelProvider: mock,
|
||||
})
|
||||
app, err := acls.getACLs(test.domain, mock.Lookup)
|
||||
if test.errorFunc != nil {
|
||||
test.errorFunc(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.want, app)
|
||||
})
|
||||
@@ -167,17 +131,12 @@ func TestAccessControlsService(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name+"(staticACLs)", func(t *testing.T) {
|
||||
acls := NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Log: log,
|
||||
Config: &model.Config{
|
||||
Apps: test.acls,
|
||||
},
|
||||
})
|
||||
app, err := acls.lookupStaticACLs(test.domain)
|
||||
if test.errorFunc != nil {
|
||||
test.errorFunc(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.want, app)
|
||||
})
|
||||
@@ -186,32 +145,16 @@ func TestAccessControlsService(t *testing.T) {
|
||||
// get acls should return an error when the provider fails
|
||||
mock := newMockProvider(map[string]model.App{}, true)
|
||||
acls := NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Config: &model.Config{},
|
||||
Log: log,
|
||||
Config: &model.Config{},
|
||||
})
|
||||
_, err := acls.getACLs("example.com", mock.Lookup)
|
||||
assert.Error(t, err)
|
||||
|
||||
// get acls should return an error when multiple apps with the same domain exist
|
||||
acls = NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Config: &model.Config{
|
||||
Apps: map[string]model.App{
|
||||
"foo": {Path: model.AppPath{Allow: "/foo"}},
|
||||
"foo.bar": {Path: model.AppPath{Allow: "/bar"}},
|
||||
},
|
||||
},
|
||||
})
|
||||
_, err = acls.GetAccessControls("foo.bar.example.com")
|
||||
assert.ErrorContains(t, err, "domain matched multiple apps by name prefix, use explicit domain config")
|
||||
require.Error(t, err)
|
||||
|
||||
// get access controls should get acls from
|
||||
// static when static acls are configured
|
||||
acls = NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Log: log,
|
||||
Config: &model.Config{
|
||||
Apps: map[string]model.App{
|
||||
"foo": {Config: model.AppConfig{Domain: "foo.example.com"}},
|
||||
@@ -220,12 +163,12 @@ func TestAccessControlsService(t *testing.T) {
|
||||
})
|
||||
app, err := acls.GetAccessControls("foo.example.com")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &model.App{Config: model.AppConfig{Domain: "foo.example.com"}}, app)
|
||||
require.Equal(t, &model.App{Config: model.AppConfig{Domain: "foo.example.com"}}, app)
|
||||
|
||||
// should return nil for no apps
|
||||
app, err = acls.GetAccessControls("bar.example.com")
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, app)
|
||||
require.Nil(t, app)
|
||||
|
||||
// Should use label provider if available
|
||||
mock = newMockProvider(map[string]model.App{
|
||||
@@ -235,11 +178,10 @@ func TestAccessControlsService(t *testing.T) {
|
||||
}, false)
|
||||
acls = NewAccessControlsService(AccessControlServiceInput{
|
||||
Log: log,
|
||||
Runtime: &runtime,
|
||||
Config: &model.Config{},
|
||||
LabelProvider: mock,
|
||||
})
|
||||
app, err = acls.GetAccessControls("bar.example.com")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &model.App{Config: model.AppConfig{Domain: "bar.example.com"}}, app)
|
||||
require.Equal(t, &model.App{Config: model.AppConfig{Domain: "bar.example.com"}}, app)
|
||||
}
|
||||
|
||||
@@ -38,16 +38,7 @@ func SafeParseAppURL(str string) (string, error) {
|
||||
return "", fmt.Errorf("ip addresses not allowed")
|
||||
}
|
||||
|
||||
i := idna.New(
|
||||
idna.MapForLookup(),
|
||||
idna.Transitional(false),
|
||||
idna.BidiRule(),
|
||||
idna.StrictDomainName(false),
|
||||
idna.CheckHyphens(true),
|
||||
idna.CheckJoiners(false),
|
||||
)
|
||||
|
||||
hostname, err = i.ToASCII(hostname)
|
||||
hostname, err = idna.Lookup.ToASCII(hostname)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert hostname to ascii: %w", err)
|
||||
|
||||
@@ -43,13 +43,6 @@ func TestSafeParseAPPURL(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Underscores
|
||||
appURL = "http://sub_tinyauth.app"
|
||||
expected = "http://sub_tinyauth.app"
|
||||
result, err = utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Lowercase
|
||||
appURL = "HTTP://SUb.tinyAUth.aPP"
|
||||
expected = "http://sub.tinyauth.app"
|
||||
@@ -73,7 +66,7 @@ func TestSafeParseAPPURL(t *testing.T) {
|
||||
assert.ErrorContains(t, err, "invalid url")
|
||||
|
||||
// Invalid punycode
|
||||
appURL = "http://xn--h-kva.example.com"
|
||||
appURL = "http://ab--cd.example.com"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "failed to convert hostname to ascii")
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// Errors
|
||||
@@ -113,10 +115,14 @@ func (v *DomainValidator) getURL(i string) (*url.URL, error) {
|
||||
|
||||
func (v *DomainValidator) getHostname(hostname string) (string, error) {
|
||||
hostname = strings.ToLower(hostname)
|
||||
hostname = strings.TrimRight(hostname, ".")
|
||||
hostname = strings.TrimSuffix(hostname, ".")
|
||||
if net.ParseIP(hostname) != nil {
|
||||
return "", fmt.Errorf("ip addresses are not supported")
|
||||
}
|
||||
hostname, err := idna.Lookup.ToASCII(hostname)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert hostname to ascii: %w", err)
|
||||
}
|
||||
return hostname, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,18 @@ func TestDomainValidator_SafeHostname(t *testing.T) {
|
||||
assert.ErrorContains(t, e, "ip addresses are not supported")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Domains with unicode characters should be allowed",
|
||||
input: "bücher.example.com",
|
||||
expected: "xn--bcher-kva.example.com",
|
||||
},
|
||||
{
|
||||
description: "Invalid IDNA domain should fail",
|
||||
input: "ab--cd.example.com",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "invalid label")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "With port enabled without any port should work",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
@@ -182,6 +194,22 @@ func TestDomainValidator_Validate(t *testing.T) {
|
||||
expected: "https://example.com:443",
|
||||
actual: "https://example.com:443",
|
||||
},
|
||||
{
|
||||
description: "Failure to format expected domain should fail",
|
||||
expected: "ab--cd.example.com",
|
||||
actual: "example.com",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "idna: invalid label")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Failure to format check domain should fail",
|
||||
expected: "example.com",
|
||||
actual: "ab--cd.example.com",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "idna: invalid label")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Valid domains with matching schemes and ports should pass",
|
||||
options: DomainValidatorOptions{WithScheme: true, AllowedSchemes: []string{"https", "http"}, WithPort: true},
|
||||
@@ -208,6 +236,16 @@ func TestDomainValidator_Validate(t *testing.T) {
|
||||
actual: "example.com",
|
||||
expected: "example.com",
|
||||
},
|
||||
{
|
||||
description: "Unicode valid domains should pass",
|
||||
expected: "xn--bcher-kva.example.com",
|
||||
actual: "bücher.example.com",
|
||||
},
|
||||
{
|
||||
description: "Unicode valid domains should pass (reverse)",
|
||||
expected: "bücher.example.com",
|
||||
actual: "xn--bcher-kva.example.com",
|
||||
},
|
||||
{
|
||||
description: "Non matching hostnames should fail",
|
||||
expected: "example.com",
|
||||
|
||||
Reference in New Issue
Block a user