mirror of
https://github.com/tinyauthapp/tinyauth.git
synced 2026-08-12 03:53:32 +08:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c25e4478 | ||
|
|
d6087dc45e | ||
|
|
6efb970673 | ||
|
|
a9221ece92 | ||
|
|
d5b7e60362 | ||
|
|
4d8cd86eec | ||
|
|
504866a432 | ||
|
|
0c1a64d47d | ||
|
|
a79438d6ec | ||
|
|
286aad2e08 | ||
|
|
5091fc2d7a | ||
|
|
0fc87ad58f |
@@ -21,7 +21,7 @@ jobs:
|
||||
package_json_file: ./frontend/package.json
|
||||
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
package_json_file: ./frontend/package.json
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
package_json_file: ./frontend/package.json
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
package_json_file: ./frontend/package.json
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
package_json_file: ./frontend/package.json
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
|
||||
@@ -38,6 +38,6 @@ jobs:
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
|
||||
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.7",
|
||||
"react-hook-form": "^7.81.0",
|
||||
"react-i18next": "^17.0.9",
|
||||
"react-i18next": "^17.0.10",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^8.2.0",
|
||||
"sonner": "^2.0.7",
|
||||
@@ -47,14 +47,14 @@
|
||||
"@types/react": "^19.2.17",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"eslint": "^10.6.0",
|
||||
"eslint": "^10.7.0",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.3",
|
||||
"globals": "^17.7.0",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~6.0.2",
|
||||
"typescript-eslint": "^8.63.0",
|
||||
"vite": "^8.1.4"
|
||||
"typescript-eslint": "^8.64.0",
|
||||
"vite": "^8.1.5"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+122
-122
@@ -28,7 +28,7 @@ importers:
|
||||
version: 1.3.0(@types/react@19.2.17)(react@19.2.7)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.3.2
|
||||
version: 4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))
|
||||
version: 4.3.2(vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0))
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.101.2
|
||||
version: 5.101.2(react@19.2.7)
|
||||
@@ -69,8 +69,8 @@ importers:
|
||||
specifier: ^7.81.0
|
||||
version: 7.81.0(react@19.2.7)
|
||||
react-i18next:
|
||||
specifier: ^17.0.9
|
||||
version: 17.0.9(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
|
||||
specifier: ^17.0.10
|
||||
version: 17.0.10(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
|
||||
react-markdown:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0(@types/react@19.2.17)(react@19.2.7)
|
||||
@@ -92,10 +92,10 @@ importers:
|
||||
devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^10.0.1
|
||||
version: 10.0.1(eslint@10.6.0(jiti@2.7.0))
|
||||
version: 10.0.1(eslint@10.7.0(jiti@2.7.0))
|
||||
'@tanstack/eslint-plugin-query':
|
||||
specifier: ^5.101.2
|
||||
version: 5.101.2(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
version: 5.101.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@types/node':
|
||||
specifier: ^26.1.1
|
||||
version: 26.1.1
|
||||
@@ -107,16 +107,16 @@ importers:
|
||||
version: 19.2.3(@types/react@19.2.17)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))
|
||||
version: 6.0.3(vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0))
|
||||
eslint:
|
||||
specifier: ^10.6.0
|
||||
version: 10.6.0(jiti@2.7.0)
|
||||
specifier: ^10.7.0
|
||||
version: 10.7.0(jiti@2.7.0)
|
||||
eslint-plugin-react-hooks:
|
||||
specifier: ^7.0.1
|
||||
version: 7.1.1(eslint@10.6.0(jiti@2.7.0))
|
||||
version: 7.1.1(eslint@10.7.0(jiti@2.7.0))
|
||||
eslint-plugin-react-refresh:
|
||||
specifier: ^0.5.3
|
||||
version: 0.5.3(eslint@10.6.0(jiti@2.7.0))
|
||||
version: 0.5.3(eslint@10.7.0(jiti@2.7.0))
|
||||
globals:
|
||||
specifier: ^17.7.0
|
||||
version: 17.7.0
|
||||
@@ -130,11 +130,11 @@ importers:
|
||||
specifier: ~6.0.2
|
||||
version: 6.0.3
|
||||
typescript-eslint:
|
||||
specifier: ^8.63.0
|
||||
version: 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
specifier: ^8.64.0
|
||||
version: 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
vite:
|
||||
specifier: ^8.1.4
|
||||
version: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)
|
||||
specifier: ^8.1.5
|
||||
version: 8.1.5(@types/node@26.1.1)(jiti@2.7.0)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1272,16 +1272,16 @@ packages:
|
||||
'@types/unist@3.0.3':
|
||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.63.0':
|
||||
resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==}
|
||||
'@typescript-eslint/eslint-plugin@8.64.0':
|
||||
resolution: {integrity: sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.63.0
|
||||
'@typescript-eslint/parser': ^8.64.0
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/parser@8.63.0':
|
||||
resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==}
|
||||
'@typescript-eslint/parser@8.64.0':
|
||||
resolution: {integrity: sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
@@ -1293,8 +1293,8 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.63.0':
|
||||
resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==}
|
||||
'@typescript-eslint/project-service@8.64.0':
|
||||
resolution: {integrity: sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
@@ -1303,8 +1303,8 @@ packages:
|
||||
resolution: {integrity: sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/scope-manager@8.63.0':
|
||||
resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==}
|
||||
'@typescript-eslint/scope-manager@8.64.0':
|
||||
resolution: {integrity: sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1':
|
||||
@@ -1313,14 +1313,14 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.63.0':
|
||||
resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==}
|
||||
'@typescript-eslint/tsconfig-utils@8.64.0':
|
||||
resolution: {integrity: sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.63.0':
|
||||
resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==}
|
||||
'@typescript-eslint/type-utils@8.64.0':
|
||||
resolution: {integrity: sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
@@ -1330,8 +1330,8 @@ packages:
|
||||
resolution: {integrity: sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/types@8.63.0':
|
||||
resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==}
|
||||
'@typescript-eslint/types@8.64.0':
|
||||
resolution: {integrity: sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1':
|
||||
@@ -1340,8 +1340,8 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.63.0':
|
||||
resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==}
|
||||
'@typescript-eslint/typescript-estree@8.64.0':
|
||||
resolution: {integrity: sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
@@ -1353,8 +1353,8 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/utils@8.63.0':
|
||||
resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==}
|
||||
'@typescript-eslint/utils@8.64.0':
|
||||
resolution: {integrity: sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
@@ -1364,8 +1364,8 @@ packages:
|
||||
resolution: {integrity: sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.63.0':
|
||||
resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==}
|
||||
'@typescript-eslint/visitor-keys@8.64.0':
|
||||
resolution: {integrity: sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@ungap/structured-clone@1.3.1':
|
||||
@@ -1603,8 +1603,8 @@ packages:
|
||||
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
eslint@10.6.0:
|
||||
resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==}
|
||||
eslint@10.7.0:
|
||||
resolution: {integrity: sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1784,8 +1784,8 @@ packages:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
ignore@7.0.5:
|
||||
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
|
||||
ignore@7.0.6:
|
||||
resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
imurmurhash@0.1.4:
|
||||
@@ -2071,8 +2071,8 @@ packages:
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
nanoid@3.3.15:
|
||||
resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
|
||||
nanoid@3.3.16:
|
||||
resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
@@ -2126,8 +2126,8 @@ packages:
|
||||
resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postcss@8.5.16:
|
||||
resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==}
|
||||
postcss@8.5.19:
|
||||
resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
powershell-utils@0.1.0:
|
||||
@@ -2173,8 +2173,8 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17 || ^18 || ^19
|
||||
|
||||
react-i18next@17.0.9:
|
||||
resolution: {integrity: sha512-buLzOSqHtXxjf+qgSrLWNTXVZ1jSwO6kUv3uJqSP1roGBPgNnbhFm7OmdVwWcgf2gIbUyP0J333uPyx+Btsi3w==}
|
||||
react-i18next@17.0.10:
|
||||
resolution: {integrity: sha512-XneHftyYA774MJkkccSkZ5oKrUpCnXIPmxio3wemqrVzCRLWiGXOMbIzObrer03fNDEnm8g8R5yYls4HcE+esg==}
|
||||
peerDependencies:
|
||||
i18next: '>= 26.2.0'
|
||||
react: '>= 16.8.0'
|
||||
@@ -2357,8 +2357,8 @@ packages:
|
||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
typescript-eslint@8.63.0:
|
||||
resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==}
|
||||
typescript-eslint@8.64.0:
|
||||
resolution: {integrity: sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
@@ -2430,8 +2430,8 @@ packages:
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
vite@8.1.4:
|
||||
resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==}
|
||||
vite@8.1.5:
|
||||
resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2647,9 +2647,9 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))':
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@10.7.0(jiti@2.7.0))':
|
||||
dependencies:
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
@@ -2670,9 +2670,9 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.15
|
||||
|
||||
'@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))':
|
||||
'@eslint/js@10.0.1(eslint@10.7.0(jiti@2.7.0))':
|
||||
optionalDependencies:
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
|
||||
'@eslint/object-schema@3.0.5': {}
|
||||
|
||||
@@ -3607,17 +3607,17 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.3.2
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.3.2
|
||||
|
||||
'@tailwindcss/vite@4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))':
|
||||
'@tailwindcss/vite@4.3.2(vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.3.2
|
||||
'@tailwindcss/oxide': 4.3.2
|
||||
tailwindcss: 4.3.2
|
||||
vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)
|
||||
vite: 8.1.5(@types/node@26.1.1)(jiti@2.7.0)
|
||||
|
||||
'@tanstack/eslint-plugin-query@5.101.2(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@tanstack/eslint-plugin-query@5.101.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
optionalDependencies:
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -3675,30 +3675,30 @@ snapshots:
|
||||
|
||||
'@types/unist@3.0.3': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.64.0(@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/scope-manager': 8.63.0
|
||||
'@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.63.0
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
ignore: 7.0.5
|
||||
'@typescript-eslint/parser': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/type-utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
ignore: 7.0.6
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.63.0
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.63.0
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
debug: 4.4.3
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -3712,10 +3712,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.63.0(typescript@6.0.3)':
|
||||
'@typescript-eslint/project-service@8.64.0(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
debug: 4.4.3
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -3726,26 +3726,26 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
|
||||
'@typescript-eslint/scope-manager@8.63.0':
|
||||
'@typescript-eslint/scope-manager@8.64.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/visitor-keys': 8.63.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1(typescript@6.0.3)':
|
||||
dependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.63.0(typescript@6.0.3)':
|
||||
'@typescript-eslint/tsconfig-utils@8.64.0(typescript@6.0.3)':
|
||||
dependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/type-utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
debug: 4.4.3
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -3753,7 +3753,7 @@ snapshots:
|
||||
|
||||
'@typescript-eslint/types@8.62.1': {}
|
||||
|
||||
'@typescript-eslint/types@8.63.0': {}
|
||||
'@typescript-eslint/types@8.64.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1(typescript@6.0.3)':
|
||||
dependencies:
|
||||
@@ -3770,12 +3770,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.63.0(typescript@6.0.3)':
|
||||
'@typescript-eslint/typescript-estree@8.64.0(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/visitor-keys': 8.63.0
|
||||
'@typescript-eslint/project-service': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
debug: 4.4.3
|
||||
minimatch: 10.2.5
|
||||
semver: 7.8.5
|
||||
@@ -3785,24 +3785,24 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/utils@8.62.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0))
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3)
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
|
||||
'@typescript-eslint/scope-manager': 8.63.0
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3)
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0))
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@6.0.3)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -3812,17 +3812,17 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.63.0':
|
||||
'@typescript-eslint/visitor-keys@8.64.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.63.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@ungap/structured-clone@1.3.1': {}
|
||||
|
||||
'@vitejs/plugin-react@6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))':
|
||||
'@vitejs/plugin-react@6.0.3(vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)
|
||||
vite: 8.1.5(@types/node@26.1.1)(jiti@2.7.0)
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.17.0):
|
||||
dependencies:
|
||||
@@ -3997,20 +3997,20 @@ snapshots:
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)):
|
||||
eslint-plugin-react-hooks@7.1.1(eslint@10.7.0(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/parser': 7.29.3
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(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.3(eslint@10.6.0(jiti@2.7.0)):
|
||||
eslint-plugin-react-refresh@0.5.3(eslint@10.7.0(jiti@2.7.0)):
|
||||
dependencies:
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
|
||||
eslint-scope@9.1.2:
|
||||
dependencies:
|
||||
@@ -4023,9 +4023,9 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@5.0.1: {}
|
||||
|
||||
eslint@10.6.0(jiti@2.7.0):
|
||||
eslint@10.7.0(jiti@2.7.0):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.23.5
|
||||
'@eslint/config-helpers': 0.6.0
|
||||
@@ -4226,7 +4226,7 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
ignore@7.0.5: {}
|
||||
ignore@7.0.6: {}
|
||||
|
||||
imurmurhash@0.1.4: {}
|
||||
|
||||
@@ -4591,7 +4591,7 @@ snapshots:
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
nanoid@3.3.15: {}
|
||||
nanoid@3.3.16: {}
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
@@ -4648,9 +4648,9 @@ snapshots:
|
||||
|
||||
picomatch@4.0.5: {}
|
||||
|
||||
postcss@8.5.16:
|
||||
postcss@8.5.19:
|
||||
dependencies:
|
||||
nanoid: 3.3.15
|
||||
nanoid: 3.3.16
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
@@ -4736,7 +4736,7 @@ snapshots:
|
||||
dependencies:
|
||||
react: 19.2.7
|
||||
|
||||
react-i18next@17.0.9(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3):
|
||||
react-i18next@17.0.10(i18next@26.3.6(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
html-parse-stringify: 3.0.1
|
||||
@@ -4923,13 +4923,13 @@ snapshots:
|
||||
dependencies:
|
||||
prelude-ls: 1.2.1
|
||||
|
||||
typescript-eslint@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3):
|
||||
typescript-eslint@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.6.0(jiti@2.7.0)
|
||||
'@typescript-eslint/eslint-plugin': 8.64.0(@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 10.7.0(jiti@2.7.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5010,11 +5010,11 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0):
|
||||
vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0):
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.5
|
||||
postcss: 8.5.16
|
||||
postcss: 8.5.19
|
||||
rolldown: 1.1.5
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
|
||||
@@ -32,8 +32,8 @@ import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "react-router";
|
||||
import { useRef } from "react";
|
||||
import {
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
recompileScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
@@ -70,7 +70,13 @@ export const QuickActions = () => {
|
||||
const redirectTimer = useRef<number | null>(null);
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
type UseLoginForProps = {
|
||||
login_for?: "oidc" | "app";
|
||||
compiledParams: string;
|
||||
params: URLSearchParams;
|
||||
};
|
||||
|
||||
export const useLoginFor = (props: UseLoginForProps): string => {
|
||||
const { login_for, compiledParams } = props;
|
||||
const { login_for, params } = props;
|
||||
const compiledParams = params.toString() ? "?" + params.toString() : "";
|
||||
|
||||
switch (login_for) {
|
||||
case "oidc":
|
||||
@@ -12,6 +13,9 @@ export const useLoginFor = (props: UseLoginForProps): string => {
|
||||
case "app":
|
||||
return "/continue" + compiledParams;
|
||||
default:
|
||||
if (params.get("redirect_uri")) {
|
||||
return "/continue" + compiledParams
|
||||
}
|
||||
return "/logout";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,13 +88,29 @@ const getEffectivePort = (url: URL): string => {
|
||||
return "80";
|
||||
};
|
||||
|
||||
// https://www.geeksforgeeks.org/javascript/how-to-check-if-a-string-is-a-valid-ip-address-format-in-javascript
|
||||
const isIP = (str: string): boolean => {
|
||||
const ipv4 =
|
||||
/^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
const ipv6 =
|
||||
/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
||||
return ipv4.test(str) || ipv6.test(str) || str.startsWith("[");
|
||||
}
|
||||
|
||||
const trimPeriod = (str: string): string => {
|
||||
if(str.lastIndexOf('.') === (str.length - 1)){
|
||||
str = str.substring(0, str.length - 1);
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
export const isTrustedDomain = (
|
||||
url: URL,
|
||||
appUrl: URL,
|
||||
cookieDomain: string,
|
||||
subdomainsEnabled: boolean,
|
||||
): boolean => {
|
||||
if (url.protocol != appUrl.protocol) {
|
||||
if (isIP(url.hostname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,7 +118,7 @@ export const isTrustedDomain = (
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url.hostname == appUrl.hostname) {
|
||||
if (trimPeriod(url.hostname) == trimPeriod(appUrl.hostname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,9 +126,6 @@ export const isTrustedDomain = (
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url.hostname.endsWith("." + cookieDomain.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return trimPeriod(url.hostname).endsWith("." + cookieDomain.toLowerCase())
|
||||
|| trimPeriod(url.hostname) == cookieDomain.toLowerCase();
|
||||
};
|
||||
|
||||
@@ -27,16 +27,10 @@ export function useScreenParams(params: URLSearchParams): ScreenParams {
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
export function recompileScreenParams(params: ScreenParams): string {
|
||||
const p = new URLSearchParams(
|
||||
export function searchParamsFromObject(obj: object): URLSearchParams {
|
||||
return new URLSearchParams(
|
||||
Object.fromEntries(
|
||||
Object.entries(params).filter(([, v]) => v !== undefined),
|
||||
Object.entries(obj).filter(([, v]) => v !== undefined),
|
||||
) as Record<string, string>,
|
||||
).toString();
|
||||
|
||||
if (p.length > 0) {
|
||||
return "?" + p;
|
||||
}
|
||||
|
||||
return "";
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useEffect } from "react";
|
||||
@@ -89,7 +89,13 @@ export const AuthorizePage = () => {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const isOidc = screenParams.login_for === "oidc";
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
// TODO: maybe a better way to do this
|
||||
const shouldAutoAuthorize =
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Navigate, useLocation, useNavigate } from "react-router";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useRedirectUri } from "@/lib/hooks/redirect-uri";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
@@ -32,7 +32,13 @@ export const ContinuePage = () => {
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const redirectUri = screenParams.redirect_uri;
|
||||
const isAppLogin = screenParams.login_for === "app";
|
||||
const recompiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const { url, valid, trusted, allowedProto, httpsDowngrade } = useRedirectUri(
|
||||
redirectUri,
|
||||
@@ -89,7 +95,7 @@ export const ContinuePage = () => {
|
||||
}, [shouldAutoRedirect, redirectToTarget]);
|
||||
|
||||
if (!auth.authenticated) {
|
||||
return <Navigate to={`/login${recompiledParams}`} replace />;
|
||||
return <Navigate to={`/login${compiledParams}`} replace />;
|
||||
}
|
||||
|
||||
if (!hasValidRedirect || !isAppLogin) {
|
||||
|
||||
@@ -12,8 +12,8 @@ import { useTranslation } from "react-i18next";
|
||||
import Markdown from "react-markdown";
|
||||
import { useLocation } from "react-router";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
useScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
export const ForgotPasswordPage = () => {
|
||||
@@ -22,7 +22,13 @@ export const ForgotPasswordPage = () => {
|
||||
const { search } = useLocation();
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
||||
@@ -26,7 +26,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useLoginFor } from "@/lib/hooks/login-for";
|
||||
@@ -63,13 +63,16 @@ export const LoginPage = () => {
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams({
|
||||
...screenParams,
|
||||
oidc_prompt: undefined,
|
||||
});
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
const loginForUrl = useLoginFor({
|
||||
login_for: screenParams.login_for,
|
||||
compiledParams,
|
||||
params: searchParamsFromObject({ ...screenParams, oidc_prompt: undefined}),
|
||||
});
|
||||
|
||||
const [isOauthAutoRedirect, setIsOauthAutoRedirect] = useState(
|
||||
|
||||
@@ -17,8 +17,8 @@ import { type UseMutationResult } from "@tanstack/react-query";
|
||||
import { type AxiosResponse } from "axios";
|
||||
import { useLocation } from "react-router";
|
||||
import {
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
recompileScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
export const LogoutPage = () => {
|
||||
@@ -29,7 +29,13 @@ export const LogoutPage = () => {
|
||||
const redirectTimer = useRef<number | null>(null);
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationFn: () => axios.post("/api/user/logout"),
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useLoginFor } from "@/lib/hooks/login-for";
|
||||
@@ -32,10 +32,16 @@ export const TotpPage = () => {
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
const loginForUrl = useLoginFor({
|
||||
login_for: screenParams.login_for,
|
||||
compiledParams,
|
||||
params: searchParamsFromObject(screenParams),
|
||||
});
|
||||
|
||||
const totpMutation = useMutation({
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/gin-gonic/gin v1.12.0
|
||||
github.com/go-jose/go-jose/v4 v4.1.4
|
||||
github.com/go-ldap/ldap/v3 v3.4.13
|
||||
github.com/go-ldap/ldap/v3 v3.4.14
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
||||
github.com/google/go-querystring v1.2.0
|
||||
@@ -24,12 +24,13 @@ require (
|
||||
github.com/weppos/publicsuffix-go v0.50.3
|
||||
go.uber.org/dig v1.19.0
|
||||
golang.org/x/crypto v0.54.0
|
||||
golang.org/x/net v0.57.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/tools v0.48.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.36.2
|
||||
k8s.io/client-go v0.36.2
|
||||
modernc.org/sqlite v1.53.0
|
||||
modernc.org/sqlite v1.54.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -72,7 +73,7 @@ require (
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||
@@ -135,7 +136,6 @@ require (
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
|
||||
golang.org/x/mod v0.38.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/sync v0.22.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
@@ -147,7 +147,7 @@ require (
|
||||
k8s.io/klog/v2 v2.140.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
|
||||
modernc.org/libc v1.73.4 // indirect
|
||||
modernc.org/libc v1.74.1 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
rsc.io/qr v0.2.0 // indirect
|
||||
|
||||
@@ -113,12 +113,12 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8 h1:H9AZkK22UOmfX8J84ubyaZxKJZ3FMHVwn8swoMML7iQ=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ=
|
||||
github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0=
|
||||
github.com/go-ldap/ldap/v3 v3.4.14 h1:D6PYdEgsaVzsXyr6w/yDC06Ria4uUhWm+Rb+er8lfAs=
|
||||
github.com/go-ldap/ldap/v3 v3.4.14/go.mod h1:S4eJUMUNjDkE0ZJtIZdybwyb03sGGLW6gxXT1Hs8VKA=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -392,20 +392,20 @@ k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hk
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
modernc.org/cc/v4 v4.28.4 h1:Hd/4Es+MBj+/7hSdZaisNyu6bv3V0Dp2MdllyfqaH+c=
|
||||
modernc.org/cc/v4 v4.28.4/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
|
||||
modernc.org/ccgo/v4 v4.34.4 h1:OVnSOWQjVKOYkFxoHYB+qQmSHK5gqMqARM+K9DpR/Ws=
|
||||
modernc.org/ccgo/v4 v4.34.4/go.mod h1:qdKqE8FNIYyysougB1RX9MxCzp5oJOcQXSobANJ4TuE=
|
||||
modernc.org/cc/v4 v4.29.0 h1:CXgwL8cvxmyzBQZzbSl/6xFtMCryb6u8IOqDci39cgc=
|
||||
modernc.org/cc/v4 v4.29.0/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
|
||||
modernc.org/ccgo/v4 v4.34.6 h1:sBgfIwyN0TQ9C5hwIeuqyeAKyMWnbvj2fvpF4L11uzU=
|
||||
modernc.org/ccgo/v4 v4.34.6/go.mod h1:SZ8YcN9NG7XVsQYdm6jYBvi8PQP1qi+kqB6OhjqI3Fk=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc=
|
||||
modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/gc/v3 v3.1.4 h1:2g65LGVSmFQrXeITAw97x7hCRvZFcyE1uDP+7Vng7JI=
|
||||
modernc.org/gc/v3 v3.1.4/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.73.4 h1:+ra4Ui8ngyt8HDcO1FTDPWlkAh6yOdaO2yAoh8MddQA=
|
||||
modernc.org/libc v1.73.4/go.mod h1:DXZ3eO8qMCNn2SnmTNCiC71nJ9Rcq3PsnpU6Vc4rWK8=
|
||||
modernc.org/libc v1.74.1 h1:bdR4VTKFMC4966QSNZ05XLGI/VwzVa2kTUX51Dm0riQ=
|
||||
modernc.org/libc v1.74.1/go.mod h1:uH4t5bOx3G3g9Xcmj10YKlTcVISlRDwv8VoQJG9n8Os=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
@@ -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.53.0 h1:20WG8N9q4ji/dEqGk4uiI0c6OPjSeLTNYGFCc3+7c1M=
|
||||
modernc.org/sqlite v1.53.0/go.mod h1:xoEpOIpGrgT48H5iiyt/YXPCZPEzlfmfFwtk8Lklw8s=
|
||||
modernc.org/sqlite v1.54.0 h1:JCxR4qwkJvOaqAoYcgDoO25Nc+ROg6EJ2LfBVzdrgog=
|
||||
modernc.org/sqlite v1.54.0/go.mod h1:4ntCLuNmnH8+GNqjka1wNg7KJd5/Hi5FYp8K+XQ7GZw=
|
||||
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=
|
||||
|
||||
@@ -88,17 +88,13 @@ func (app *BootstrapApp) Setup() error {
|
||||
app.log.App.Info().Msgf("Starting Tinyauth version: %s", model.Version)
|
||||
|
||||
// get app url
|
||||
if app.config.AppURL == "" {
|
||||
return errors.New("app url cannot be empty, perhaps config loading failed")
|
||||
}
|
||||
|
||||
appUrl, err := url.Parse(app.config.AppURL)
|
||||
appURL, err := utils.SafeParseAppURL(app.config.AppURL)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse app url: %w", err)
|
||||
}
|
||||
|
||||
app.runtime.AppURL = strings.ToLower(appUrl.Scheme + "://" + appUrl.Host)
|
||||
app.runtime.AppURL = appURL
|
||||
|
||||
// validate session config
|
||||
if app.config.Auth.SessionMaxLifetime != 0 && app.config.Auth.SessionMaxLifetime < app.config.Auth.SessionExpiry {
|
||||
@@ -172,7 +168,13 @@ func (app *BootstrapApp) Setup() error {
|
||||
app.runtime.CookieDomain = cookieDomain
|
||||
|
||||
// cookie names
|
||||
app.runtime.UUID = utils.GenerateUUID(appUrl.Hostname())
|
||||
u, err := url.Parse(app.runtime.AppURL)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse app url: %w", err)
|
||||
}
|
||||
|
||||
app.runtime.UUID = utils.GenerateUUID(u.Hostname())
|
||||
|
||||
cookieId := strings.Split(app.runtime.UUID, "-")[0] // first 8 characters of the uuid should be good enough
|
||||
|
||||
|
||||
@@ -313,8 +313,7 @@ func (controller *OAuthController) getCookieDomain() string {
|
||||
|
||||
func (controller *OAuthController) isRedirectSafe(redirectURI string) bool {
|
||||
v := validators.NewDomainValidator(validators.DomainValidatorOptions{
|
||||
WithScheme: true,
|
||||
WithPort: true,
|
||||
WithPort: true,
|
||||
})
|
||||
|
||||
_, err := v.SafeHostname(controller.runtime.AppURL)
|
||||
@@ -333,7 +332,6 @@ func (controller *OAuthController) isRedirectSafe(redirectURI string) bool {
|
||||
controller.log.App.Debug().Err(err).Msg("Failed to validate redirect URI")
|
||||
|
||||
if errors.Is(err, validators.ErrInvalidURL) ||
|
||||
errors.Is(err, validators.ErrSchemeMismatch) ||
|
||||
errors.Is(err, validators.ErrPortMismatch) {
|
||||
return false
|
||||
}
|
||||
@@ -351,7 +349,8 @@ func (controller *OAuthController) isRedirectSafe(redirectURI string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.HasSuffix(hostname, "."+strings.ToLower(controller.runtime.CookieDomain)) {
|
||||
if strings.HasSuffix(hostname, "."+strings.ToLower(controller.runtime.CookieDomain)) ||
|
||||
hostname == controller.runtime.CookieDomain {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -81,14 +81,6 @@ func TestOAuthController_isRedirectSafe(t *testing.T) {
|
||||
redirectURI: "https://sub.example.com",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Cookie domain itself is not a subdomain match",
|
||||
appURL: "https://tinyauth.example.com",
|
||||
cookieDomain: "example.com",
|
||||
subdomainsEnabled: true,
|
||||
redirectURI: "https://example.com",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Different scheme returns false",
|
||||
appURL: "https://tinyauth.example.com",
|
||||
@@ -121,14 +113,6 @@ func TestOAuthController_isRedirectSafe(t *testing.T) {
|
||||
redirectURI: "https:/malicious",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Redirect URI without scheme returns false",
|
||||
appURL: "https://tinyauth.example.com",
|
||||
cookieDomain: "example.com",
|
||||
subdomainsEnabled: true,
|
||||
redirectURI: "tinyauth.example.com",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Relative redirect URI returns false",
|
||||
appURL: "https://tinyauth.example.com",
|
||||
|
||||
@@ -44,13 +44,17 @@ func (service *AccessControlsService) lookupStaticACLs(domain string) *model.App
|
||||
|
||||
// First try to find a matching app by domain, then fallback to matching by app name (subdomain)
|
||||
for app, config := range service.config.Apps {
|
||||
err := v.Validate(config.Config.Domain, domain)
|
||||
if err == nil {
|
||||
service.log.App.Debug().Str("name", app).Msg("Found matching container by domain")
|
||||
return &config
|
||||
}
|
||||
if !errors.Is(err, validators.ErrHostnameMismatch) {
|
||||
service.log.App.Debug().Str("name", app).Err(err).Msg("Domain validation failed")
|
||||
if config.Config.Domain != "" {
|
||||
err := v.Validate(config.Config.Domain, domain)
|
||||
if err == nil {
|
||||
service.log.App.Debug().Str("name", app).Msg("Found matching container by domain")
|
||||
return &config
|
||||
}
|
||||
if !errors.Is(err, validators.ErrHostnameMismatch) &&
|
||||
!errors.Is(err, validators.ErrPortMismatch) &&
|
||||
!errors.Is(err, validators.ErrSchemeMismatch) {
|
||||
service.log.App.Debug().Str("name", app).Err(err).Msg("Domain validation failed")
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(strings.ToLower(domain), strings.ToLower(app+".")) {
|
||||
service.log.App.Debug().Str("name", app).Msg("Found matching container by app name")
|
||||
|
||||
@@ -7,10 +7,55 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/weppos/publicsuffix-go/publicsuffix"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// GetCookieDomain parses the app url and returns the domain value to use for cookies.
|
||||
var (
|
||||
ErrEmptyURL = fmt.Errorf("invalid url")
|
||||
)
|
||||
|
||||
func SafeParseAppURL(str string) (string, error) {
|
||||
if strings.TrimSpace(str) == "" {
|
||||
return "", ErrEmptyURL
|
||||
}
|
||||
|
||||
u, err := url.Parse(str)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid url: %w", err)
|
||||
}
|
||||
|
||||
if u.Host == "" ||
|
||||
(u.Scheme != "http" &&
|
||||
u.Scheme != "https") {
|
||||
return "", fmt.Errorf("invalid url, must be in format https(s)://host")
|
||||
}
|
||||
|
||||
hostname := strings.ToLower(u.Hostname())
|
||||
hostname = strings.TrimSuffix(hostname, ".")
|
||||
|
||||
if netIP := net.ParseIP(hostname); netIP != nil {
|
||||
return "", fmt.Errorf("ip addresses not allowed")
|
||||
}
|
||||
|
||||
hostname, err = idna.Lookup.ToASCII(hostname)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert hostname to ascii: %w", err)
|
||||
}
|
||||
|
||||
appURL := fmt.Sprintf("%s://%s", u.Scheme, hostname)
|
||||
|
||||
if u.Port() != "" {
|
||||
appURL += ":" + u.Port()
|
||||
}
|
||||
|
||||
return appURL, nil
|
||||
}
|
||||
|
||||
// GetCookieDomain parses the app URL and returns the domain value to use for cookies.
|
||||
// When auth for subdomains is enabled, it strips the leftmost label
|
||||
// GetCookieDomain assumes the app URL is first parsed with SafeParseAppURL
|
||||
// (e.g. sub1.sub2.domain.com -> sub2.domain.com), otherwise it returns the full hostname.
|
||||
func GetCookieDomain(appUrl string, subdomainsEnabled bool) (string, error) {
|
||||
u, err := url.Parse(appUrl)
|
||||
@@ -21,10 +66,6 @@ func GetCookieDomain(appUrl string, subdomainsEnabled bool) (string, error) {
|
||||
|
||||
hostname := strings.ToLower(u.Hostname())
|
||||
|
||||
if netIP := net.ParseIP(hostname); netIP != nil {
|
||||
return "", fmt.Errorf("ip addresses not allowed")
|
||||
}
|
||||
|
||||
parts := strings.Split(hostname, ".")
|
||||
|
||||
if len(parts) < 2 {
|
||||
|
||||
@@ -7,7 +7,86 @@ import (
|
||||
"github.com/tinyauthapp/tinyauth/internal/utils"
|
||||
)
|
||||
|
||||
func TestGetRootDomain(t *testing.T) {
|
||||
func TestSafeParseAPPURL(t *testing.T) {
|
||||
// Normal app url
|
||||
appURL := "http://sub.tinyauth.app"
|
||||
expected := "http://sub.tinyauth.app"
|
||||
result, err := utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Strip path
|
||||
appURL = "http://sub.tinyauth.app/path"
|
||||
expected = "http://sub.tinyauth.app"
|
||||
result, err = utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Preserve port
|
||||
appURL = "http://sub.tinyauth.app:8080"
|
||||
expected = "http://sub.tinyauth.app:8080"
|
||||
result, err = utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Remove trailing dot
|
||||
appURL = "http://sub.tinyauth.app."
|
||||
expected = "http://sub.tinyauth.app"
|
||||
result, err = utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Convert to ascii
|
||||
appURL = "http://bücher.example.com"
|
||||
expected = "http://xn--bcher-kva.example.com"
|
||||
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"
|
||||
result, err = utils.SafeParseAppURL(appURL)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
|
||||
// Empty string
|
||||
appURL = ""
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorIs(t, err, utils.ErrEmptyURL)
|
||||
|
||||
// Invalid URL
|
||||
appURL = "invalidurl"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "invalid url")
|
||||
|
||||
// Non http or https URL
|
||||
appURL = "ftp://sub.tinyauth.app"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "invalid url")
|
||||
|
||||
// Invalid punycode
|
||||
appURL = "http://ab--cd.example.com"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "failed to convert hostname to ascii")
|
||||
|
||||
// IP address
|
||||
appURL = "http://10.10.10.10"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "ip addresses not allowed")
|
||||
|
||||
// IPv6 address
|
||||
appURL = "http://[::1]:8080"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "ip addresses not allowed")
|
||||
|
||||
// Invalid URL
|
||||
appURL = "://"
|
||||
_, err = utils.SafeParseAppURL(appURL)
|
||||
assert.ErrorContains(t, err, "invalid url")
|
||||
}
|
||||
|
||||
func TestGetCookieDomain(t *testing.T) {
|
||||
// Normal case
|
||||
domain := "http://sub.tinyauth.app"
|
||||
expected := "tinyauth.app"
|
||||
@@ -27,11 +106,6 @@ func TestGetRootDomain(t *testing.T) {
|
||||
_, err = utils.GetCookieDomain(domain, true)
|
||||
assert.EqualError(t, err, "invalid app url, must be in format subdomain.domain.tld or domain.tld")
|
||||
|
||||
// IP address
|
||||
domain = "http://10.10.10.10"
|
||||
_, err = utils.GetCookieDomain(domain, true)
|
||||
assert.ErrorContains(t, err, "ip addresses not allowed")
|
||||
|
||||
// Invalid URL
|
||||
domain = "http://[::1]:namedport"
|
||||
_, err = utils.GetCookieDomain(domain, true)
|
||||
@@ -56,6 +130,11 @@ func TestGetRootDomain(t *testing.T) {
|
||||
_, err = utils.GetCookieDomain(domain, true)
|
||||
assert.ErrorContains(t, err, "domain in public suffix list, cannot set cookies")
|
||||
|
||||
// Domain managed by ICANN without subdomain
|
||||
domain = "http://co.uk"
|
||||
_, err = utils.GetCookieDomain(domain, true)
|
||||
assert.ErrorContains(t, err, "domain in public suffix list, cannot set cookies")
|
||||
|
||||
// Domain without subdomain
|
||||
domain = "http://tinyauth.app"
|
||||
expected = "tinyauth.app"
|
||||
|
||||
@@ -63,7 +63,7 @@ func (v *DomainValidator) getURL(i string) (*url.URL, error) {
|
||||
return nil, ErrInvalidURL
|
||||
}
|
||||
|
||||
if v.opts.WithPort && !v.opts.WithScheme && u.Port() == "" {
|
||||
if v.opts.WithPort && u.Port() == "" && (u.Scheme != "http" && u.Scheme != "https") {
|
||||
return nil, fmt.Errorf("port validation is enabled but port is missing in input url and schemes are not enabled")
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,24 @@ func TestDomainValidator_SafeHostname(t *testing.T) {
|
||||
assert.ErrorContains(t, e, "input url is missing scheme")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "With port enabled but without scheme and url with https should work",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
input: "https://example.com",
|
||||
expected: "example.com",
|
||||
},
|
||||
{
|
||||
description: "With port enabled but without scheme and url with http should work",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
input: "http://example.com",
|
||||
expected: "example.com",
|
||||
},
|
||||
{
|
||||
description: "With port enabled but without scheme and url with port should work",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
input: "example.com:8080",
|
||||
expected: "example.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -194,7 +212,7 @@ func TestDomainValidator_Validate(t *testing.T) {
|
||||
expected: "ssh://example.com:22",
|
||||
actual: "ssh://example.com",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "failed to get effective port for url")
|
||||
assert.ErrorContains(t, e, "port validation is enabled but port is missing in input url and schemes are not enabled")
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -203,9 +221,21 @@ func TestDomainValidator_Validate(t *testing.T) {
|
||||
expected: "ssh://example.com",
|
||||
actual: "ssh://example.com:22",
|
||||
errorFunc: func(t *testing.T, e error) {
|
||||
assert.ErrorContains(t, e, "failed to get effective port for url")
|
||||
assert.ErrorContains(t, e, "port validation is enabled but port is missing in input url and schemes are not enabled")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Port enabled but no scheme and https scheme should pass",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
expected: "https://example.com",
|
||||
actual: "https://example.com",
|
||||
},
|
||||
{
|
||||
description: "Port enabled but no scheme and http scheme should pass",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
expected: "http://example.com",
|
||||
actual: "http://example.com",
|
||||
},
|
||||
{
|
||||
description: "Port validation with port and no scheme should fail with different port",
|
||||
options: DomainValidatorOptions{WithPort: true},
|
||||
|
||||
Reference in New Issue
Block a user