mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-12-31 12:32:29 +00:00
Merge branch 'main' into refactor/sqlc
This commit is contained in:
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -18,7 +18,16 @@ jobs:
|
|||||||
- name: Setup go
|
- name: Setup go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.23.2"
|
go-version: "^1.24.0"
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
58
.github/workflows/nightly.yml
vendored
58
.github/workflows/nightly.yml
vendored
@@ -61,7 +61,16 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.23.2"
|
go-version: "^1.24.0"
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -107,7 +116,16 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.23.2"
|
go-version: "^1.24.0"
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -147,6 +165,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: nightly
|
ref: nightly
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -205,6 +232,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: nightly
|
ref: nightly
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -263,6 +299,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: nightly
|
ref: nightly
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -321,6 +366,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: nightly
|
ref: nightly
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
|
|||||||
58
.github/workflows/release.yml
vendored
58
.github/workflows/release.yml
vendored
@@ -39,7 +39,16 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.23.2"
|
go-version: "^1.24.0"
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -82,7 +91,16 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.23.2"
|
go-version: "^1.24.0"
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -119,6 +137,15 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -174,6 +201,15 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -229,6 +265,15 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -284,6 +329,15 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize submodules
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
- name: Apply patches
|
||||||
|
run: |
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -33,4 +33,7 @@
|
|||||||
|
|
||||||
# binary out
|
# binary out
|
||||||
/tinyauth.db
|
/tinyauth.db
|
||||||
/resources
|
/resources
|
||||||
|
|
||||||
|
# debug files
|
||||||
|
__debug_*
|
||||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[submodule "paerser"]
|
||||||
|
path = paerser
|
||||||
|
url = https://github.com/traefik/paerser
|
||||||
|
ignore = all
|
||||||
@@ -5,7 +5,7 @@ Contributing is relatively easy, you just need to follow the steps below and you
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Bun
|
- Bun
|
||||||
- Golang v1.23.2 and above
|
- Golang 1.24.0+
|
||||||
- Git
|
- Git
|
||||||
- Docker
|
- Docker
|
||||||
|
|
||||||
@@ -18,9 +18,18 @@ git clone https://github.com/steveiliop56/tinyauth
|
|||||||
cd tinyauth
|
cd tinyauth
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Initialize submodules
|
||||||
|
|
||||||
|
The project uses Git submodules for some dependencies, so you need to initialize them with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
```
|
||||||
|
|
||||||
## Install requirements
|
## Install requirements
|
||||||
|
|
||||||
Although you will not need the requirements in your machine since the development will happen in docker, I still recommend to install them because this way you will not have import errors. To install the go requirements run:
|
Although you will not need the requirements in your machine since the development will happen in Docker, I still recommend to install them because this way you will not have import errors. To install the Go requirements run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go mod download
|
go mod download
|
||||||
@@ -33,13 +42,21 @@ cd frontend/
|
|||||||
bun install
|
bun install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Apply patches
|
||||||
|
|
||||||
|
Some of the dependencies need to be patched in order to work correctly with the project, you can apply the patches by running:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git apply --directory paerser/ patches/nested_maps.diff
|
||||||
|
```
|
||||||
|
|
||||||
## Create your `.env` file
|
## Create your `.env` file
|
||||||
|
|
||||||
In order to configure the app you need to create an environment file, this can be done by copying the `.env.example` file to `.env` and modifying the environment variables to suit your needs.
|
In order to configure the app you need to create an environment file, this can be done by copying the `.env.example` file to `.env` and modifying the environment variables to suit your needs.
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
I have designed the development workflow to be entirely in docker, this is because it will directly work with traefik and you will not need to do any building in your host machine. The recommended development setup is to have a subdomain pointing to your machine like this:
|
I have designed the development workflow to be entirely in Docker, this is because it will directly work with Traefik and you will not need to do any building in your host machine. The recommended development setup is to have a subdomain pointing to your machine like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
*.dev.example.com -> 127.0.0.1
|
*.dev.example.com -> 127.0.0.1
|
||||||
@@ -49,7 +66,7 @@ dev.example.com -> 127.0.0.1
|
|||||||
> [!TIP]
|
> [!TIP]
|
||||||
> You can use [sslip.io](https://sslip.io) as a domain if you don't have one to develop with.
|
> You can use [sslip.io](https://sslip.io) as a domain if you don't have one to develop with.
|
||||||
|
|
||||||
Then you can just make sure the domains are correct in the development docker compose file and run:
|
Then you can just make sure the domains are correct in the development Docker compose file and run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker compose -f docker-compose.dev.yml up --build
|
docker compose -f docker-compose.dev.yml up --build
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ ARG BUILD_TIMESTAMP
|
|||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
|
COPY ./paerser ./paerser
|
||||||
|
|
||||||
COPY go.mod ./
|
COPY go.mod ./
|
||||||
COPY go.sum ./
|
COPY go.sum ./
|
||||||
|
|
||||||
@@ -38,7 +40,7 @@ COPY ./internal ./internal
|
|||||||
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
FROM alpine:3.23 AS runner
|
FROM alpine:3.23 AS runner
|
||||||
|
|
||||||
@@ -62,4 +64,4 @@ ENV PATH=$PATH:/tinyauth
|
|||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
||||||
|
|
||||||
ENTRYPOINT ["tinyauth"]
|
ENTRYPOINT ["tinyauth"]
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ FROM golang:1.25-alpine3.21
|
|||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
|
COPY ./paerser ./paerser
|
||||||
|
|
||||||
COPY go.mod ./
|
COPY go.mod ./
|
||||||
COPY go.sum ./
|
COPY go.sum ./
|
||||||
|
|
||||||
@@ -20,4 +22,4 @@ ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db
|
|||||||
|
|
||||||
ENV TINYAUTH_RESOURCESDIR=/data/resources
|
ENV TINYAUTH_RESOURCESDIR=/data/resources
|
||||||
|
|
||||||
ENTRYPOINT ["air", "-c", "air.toml"]
|
ENTRYPOINT ["air", "-c", "air.toml"]
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ ARG BUILD_TIMESTAMP
|
|||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
|
COPY ./paerser ./paerser
|
||||||
|
|
||||||
COPY go.mod ./
|
COPY go.mod ./
|
||||||
COPY go.sum ./
|
COPY go.sum ./
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
|||||||
RUN mkdir -p data
|
RUN mkdir -p data
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
FROM gcr.io/distroless/static-debian12:latest AS runner
|
FROM gcr.io/distroless/static-debian12:latest AS runner
|
||||||
|
|
||||||
@@ -65,4 +67,4 @@ ENV PATH=$PATH:/tinyauth
|
|||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
||||||
|
|
||||||
ENTRYPOINT ["tinyauth"]
|
ENTRYPOINT ["tinyauth"]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
"github.com/mdp/qrterminal/v3"
|
"github.com/mdp/qrterminal/v3"
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/bootstrap"
|
|
||||||
"tinyauth/internal/config"
|
"github.com/steveiliop56/tinyauth/internal/bootstrap"
|
||||||
"tinyauth/internal/utils/loaders"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils/loaders"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -33,6 +34,10 @@ func NewTinyauthCmdConfiguration() *config.Config {
|
|||||||
ForgotPasswordMessage: "You can change your password by changing the configuration.",
|
ForgotPasswordMessage: "You can change your password by changing the configuration.",
|
||||||
BackgroundImage: "/background.jpg",
|
BackgroundImage: "/background.jpg",
|
||||||
},
|
},
|
||||||
|
Ldap: config.LdapConfig{
|
||||||
|
Insecure: false,
|
||||||
|
SearchFilter: "(uid=%s)",
|
||||||
|
},
|
||||||
Experimental: config.ExperimentalConfig{
|
Experimental: config.ExperimentalConfig{
|
||||||
ConfigFile: "",
|
ConfigFile: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"github.com/traefik/paerser/cli"
|
"github.com/traefik/paerser/cli"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.90.15",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.3",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.3",
|
||||||
"react-hook-form": "^7.68.0",
|
"react-hook-form": "^7.69.0",
|
||||||
"react-i18next": "^16.5.0",
|
"react-i18next": "^16.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router": "^7.11.0",
|
"react-router": "^7.11.0",
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"prettier": "3.7.4",
|
"prettier": "3.7.4",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.50.0",
|
"typescript-eslint": "^8.51.0",
|
||||||
"vite": "^7.3.0",
|
"vite": "^7.3.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -339,9 +339,9 @@
|
|||||||
|
|
||||||
"@tanstack/eslint-plugin-query": ["@tanstack/eslint-plugin-query@5.91.2", "", { "dependencies": { "@typescript-eslint/utils": "^8.44.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-UPeWKl/Acu1IuuHJlsN+eITUHqAaa9/04geHHPedY8siVarSaWprY0SVMKrkpKfk5ehRT7+/MZ5QwWuEtkWrFw=="],
|
"@tanstack/eslint-plugin-query": ["@tanstack/eslint-plugin-query@5.91.2", "", { "dependencies": { "@typescript-eslint/utils": "^8.44.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-UPeWKl/Acu1IuuHJlsN+eITUHqAaa9/04geHHPedY8siVarSaWprY0SVMKrkpKfk5ehRT7+/MZ5QwWuEtkWrFw=="],
|
||||||
|
|
||||||
"@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="],
|
"@tanstack/query-core": ["@tanstack/query-core@5.90.15", "", {}, "sha512-mInIZNUZftbERE+/Hbtswfse49uUQwch46p+27gP9DWJL927UjnaWEF2t3RMOqBcXbfMdcNkPe06VyUIAZTV1g=="],
|
||||||
|
|
||||||
"@tanstack/react-query": ["@tanstack/react-query@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg=="],
|
"@tanstack/react-query": ["@tanstack/react-query@5.90.15", "", { "dependencies": { "@tanstack/query-core": "5.90.15" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-uQvnDDcTOgJouNtAyrgRej+Azf0U5WDov3PXmHFUBc+t1INnAYhIlpZtCGNBLwCN41b43yO7dPNZu8xWkUFBwQ=="],
|
||||||
|
|
||||||
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||||
|
|
||||||
@@ -373,25 +373,25 @@
|
|||||||
|
|
||||||
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.50.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/type-utils": "8.50.0", "@typescript-eslint/utils": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.50.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg=="],
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.51.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/type-utils": "8.51.0", "@typescript-eslint/utils": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.51.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og=="],
|
||||||
|
|
||||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.50.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q=="],
|
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.51.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A=="],
|
||||||
|
|
||||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.50.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.50.0", "@typescript-eslint/types": "^8.50.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ=="],
|
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.51.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.51.0", "@typescript-eslint/types": "^8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1" } }, "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A=="],
|
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1" } }, "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A=="],
|
||||||
|
|
||||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.50.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w=="],
|
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.51.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw=="],
|
||||||
|
|
||||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0", "@typescript-eslint/utils": "8.50.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw=="],
|
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0", "debug": "^4.3.4", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q=="],
|
||||||
|
|
||||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="],
|
"@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.50.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.50.0", "@typescript-eslint/tsconfig-utils": "8.50.0", "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ=="],
|
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.51.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.51.0", "@typescript-eslint/tsconfig-utils": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ=="],
|
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q=="],
|
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg=="],
|
||||||
|
|
||||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||||
|
|
||||||
@@ -795,7 +795,7 @@
|
|||||||
|
|
||||||
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
||||||
|
|
||||||
"react-hook-form": ["react-hook-form@7.68.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-oNN3fjrZ/Xo40SWlHf1yCjlMK417JxoSJVUXQjGdvdRCU07NTFei1i1f8ApUAts+IVh14e4EdakeLEA+BEAs/Q=="],
|
"react-hook-form": ["react-hook-form@7.69.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw=="],
|
||||||
|
|
||||||
"react-i18next": ["react-i18next@16.5.0", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 25.6.2", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-IMpPTyCTKxEj8klCrLKUTIUa8uYTd851+jcu2fJuUB9Agkk9Qq8asw4omyeHVnOXHrLgQJGTm5zTvn8HpaPiqw=="],
|
"react-i18next": ["react-i18next@16.5.0", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 25.6.2", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-IMpPTyCTKxEj8klCrLKUTIUa8uYTd851+jcu2fJuUB9Agkk9Qq8asw4omyeHVnOXHrLgQJGTm5zTvn8HpaPiqw=="],
|
||||||
|
|
||||||
@@ -863,7 +863,7 @@
|
|||||||
|
|
||||||
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
|
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
|
||||||
|
|
||||||
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
|
"ts-api-utils": ["ts-api-utils@2.3.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg=="],
|
||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
@@ -873,7 +873,7 @@
|
|||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
"typescript-eslint": ["typescript-eslint@8.50.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.50.0", "@typescript-eslint/parser": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0", "@typescript-eslint/utils": "8.50.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A=="],
|
"typescript-eslint": ["typescript-eslint@8.51.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.51.0", "@typescript-eslint/parser": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
|
||||||
@@ -995,25 +995,25 @@
|
|||||||
|
|
||||||
"@types/estree-jsx/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
"@types/estree-jsx/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0" } }, "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A=="],
|
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.50.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg=="],
|
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.51.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.4", "", {}, "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A=="],
|
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.4", "", {}, "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A=="],
|
||||||
|
|
||||||
"@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0" } }, "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A=="],
|
"@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="],
|
||||||
|
|
||||||
"@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA=="],
|
"@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA=="],
|
||||||
|
|
||||||
"@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.50.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg=="],
|
"@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.51.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
@@ -1021,7 +1021,7 @@
|
|||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.1", "@typescript-eslint/tsconfig-utils": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.1", "@typescript-eslint/tsconfig-utils": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg=="],
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="],
|
"eslint-plugin-react-hooks/@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="],
|
||||||
|
|
||||||
@@ -1039,7 +1039,7 @@
|
|||||||
|
|
||||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||||
|
|
||||||
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.50.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg=="],
|
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.51.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA=="],
|
||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.1", "", { "dependencies": { "@babel/parser": "^7.27.1", "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w=="],
|
"@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.1", "", { "dependencies": { "@babel/parser": "^7.27.1", "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w=="],
|
||||||
|
|
||||||
@@ -1057,11 +1057,11 @@
|
|||||||
|
|
||||||
"@eslint/eslintrc/espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
|
"@eslint/eslintrc/espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0" } }, "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A=="],
|
"@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
||||||
@@ -1075,15 +1075,17 @@
|
|||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||||
|
|
||||||
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core/@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
|
"eslint-plugin-react-hooks/@babel/core/@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core/@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
|
"eslint-plugin-react-hooks/@babel/core/@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
"eslint-plugin-react-hooks/@babel/core/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||||
|
|
||||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0" } }, "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A=="],
|
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="],
|
||||||
|
|
||||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
|
||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.90.15",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.3",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.3",
|
||||||
"react-hook-form": "^7.68.0",
|
"react-hook-form": "^7.69.0",
|
||||||
"react-i18next": "^16.5.0",
|
"react-i18next": "^16.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router": "^7.11.0",
|
"react-router": "^7.11.0",
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"prettier": "3.7.4",
|
"prettier": "3.7.4",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.50.0",
|
"typescript-eslint": "^8.51.0",
|
||||||
"vite": "^7.3.0"
|
"vite": "^7.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
go.mod
52
go.mod
@@ -1,21 +1,30 @@
|
|||||||
module tinyauth
|
module github.com/steveiliop56/tinyauth
|
||||||
|
|
||||||
go 1.24.0
|
go 1.24.0
|
||||||
|
|
||||||
toolchain go1.24.3
|
toolchain go1.24.3
|
||||||
|
|
||||||
|
replace github.com/traefik/paerser v0.2.2 => ./paerser
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3
|
github.com/cenkalti/backoff/v5 v5.0.3
|
||||||
|
github.com/charmbracelet/huh v0.8.0
|
||||||
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
github.com/gin-gonic/gin v1.11.0
|
github.com/gin-gonic/gin v1.11.0
|
||||||
|
github.com/glebarez/sqlite v1.11.0
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.12
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
github.com/golang-migrate/migrate/v4 v4.19.1
|
||||||
github.com/google/go-querystring v1.1.0
|
github.com/google/go-querystring v1.2.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/mdp/qrterminal/v3 v3.2.1
|
github.com/mdp/qrterminal/v3 v3.2.1
|
||||||
|
github.com/pquerna/otp v1.5.0
|
||||||
github.com/rs/zerolog v1.34.0
|
github.com/rs/zerolog v1.34.0
|
||||||
github.com/traefik/paerser v0.2.2
|
github.com/traefik/paerser v0.2.2
|
||||||
github.com/weppos/publicsuffix-go v0.50.1
|
github.com/weppos/publicsuffix-go v0.50.1
|
||||||
golang.org/x/crypto v0.46.0
|
golang.org/x/crypto v0.46.0
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
|
||||||
|
golang.org/x/oauth2 v0.34.0
|
||||||
|
gorm.io/gorm v1.31.1
|
||||||
gotest.tools/v3 v3.5.2
|
gotest.tools/v3 v3.5.2
|
||||||
modernc.org/sqlite v1.38.2
|
modernc.org/sqlite v1.38.2
|
||||||
)
|
)
|
||||||
@@ -68,14 +77,17 @@ require (
|
|||||||
github.com/catppuccin/go v0.3.0 // indirect
|
github.com/catppuccin/go v0.3.0 // indirect
|
||||||
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
|
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
|
||||||
github.com/charmbracelet/bubbletea v1.3.6 // indirect
|
github.com/charmbracelet/bubbletea v1.3.6 // indirect
|
||||||
github.com/charmbracelet/huh v0.8.0
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/docker v28.5.2+incompatible
|
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
@@ -83,12 +95,20 @@ require (
|
|||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12
|
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.4 // indirect
|
github.com/goccy/go-json v0.10.4 // indirect
|
||||||
|
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/huandu/xstrings v1.5.0 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.11 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
@@ -97,31 +117,49 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
||||||
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||||
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pquerna/otp v1.5.0
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
|
github.com/quic-go/quic-go v0.57.0 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||||
golang.org/x/arch v0.20.0 // indirect
|
golang.org/x/arch v0.20.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.47.0 // indirect
|
||||||
golang.org/x/oauth2 v0.34.0
|
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
|
golang.org/x/term v0.38.0 // indirect
|
||||||
golang.org/x/text v0.32.0 // indirect
|
golang.org/x/text v0.32.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/protobuf v1.36.9 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
modernc.org/libc v1.66.3 // indirect
|
||||||
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
|
modernc.org/memory v1.11.0 // indirect
|
||||||
|
modernc.org/sqlite v1.38.2 // indirect
|
||||||
|
rsc.io/qr v0.2.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
9
go.sum
9
go.sum
@@ -125,11 +125,11 @@ github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
@@ -263,8 +263,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ=
|
|
||||||
github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||||
@@ -351,7 +349,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||||
|
|||||||
1
internal/assets/migrations/000003_oauth_sub.down.sql
Normal file
1
internal/assets/migrations/000003_oauth_sub.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "sessions" DROP COLUMN "oauth_sub";
|
||||||
1
internal/assets/migrations/000003_oauth_sub.up.sql
Normal file
1
internal/assets/migrations/000003_oauth_sub.up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "sessions" ADD COLUMN "oauth_sub" TEXT;
|
||||||
@@ -11,10 +11,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/controller"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/repository"
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/repository"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ package bootstrap
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/controller"
|
|
||||||
"tinyauth/internal/middleware"
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/middleware"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package bootstrap
|
package bootstrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"tinyauth/internal/repository"
|
"github.com/steveiliop56/tinyauth/internal/repository"
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
@@ -45,7 +45,7 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er
|
|||||||
|
|
||||||
services.dockerService = dockerService
|
services.dockerService = dockerService
|
||||||
|
|
||||||
accessControlsService := service.NewAccessControlsService(dockerService)
|
accessControlsService := service.NewAccessControlsService(dockerService, app.config.Apps)
|
||||||
|
|
||||||
err = accessControlsService.Init()
|
err = accessControlsService.Init()
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Config struct {
|
|||||||
LogJSON bool `description:"Enable JSON formatted logs." yaml:"logJSON"`
|
LogJSON bool `description:"Enable JSON formatted logs." yaml:"logJSON"`
|
||||||
Server ServerConfig `description:"Server configuration." yaml:"server"`
|
Server ServerConfig `description:"Server configuration." yaml:"server"`
|
||||||
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
|
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
|
||||||
|
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
|
||||||
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
|
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
|
||||||
UI UIConfig `description:"UI customization." yaml:"ui"`
|
UI UIConfig `description:"UI customization." yaml:"ui"`
|
||||||
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
|
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
|
||||||
@@ -79,6 +80,7 @@ const DefaultNamePrefix = "TINYAUTH_"
|
|||||||
// OAuth/OIDC config
|
// OAuth/OIDC config
|
||||||
|
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
|
Sub string `json:"sub"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
@@ -125,6 +127,7 @@ type SessionCookie struct {
|
|||||||
TotpPending bool
|
TotpPending bool
|
||||||
OAuthGroups string
|
OAuthGroups string
|
||||||
OAuthName string
|
OAuthName string
|
||||||
|
OAuthSub string
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserContext struct {
|
type UserContext struct {
|
||||||
@@ -138,6 +141,7 @@ type UserContext struct {
|
|||||||
OAuthGroups string
|
OAuthGroups string
|
||||||
TotpEnabled bool
|
TotpEnabled bool
|
||||||
OAuthName string
|
OAuthName string
|
||||||
|
OAuthSub string
|
||||||
}
|
}
|
||||||
|
|
||||||
// API responses and queries
|
// API responses and queries
|
||||||
@@ -153,61 +157,55 @@ type RedirectQuery struct {
|
|||||||
RedirectURI string `url:"redirect_uri"`
|
RedirectURI string `url:"redirect_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Labels
|
// ACLs
|
||||||
|
|
||||||
type Apps struct {
|
type Apps struct {
|
||||||
Apps map[string]App
|
Apps map[string]App `description:"App ACLs configuration." yaml:"apps"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
Config AppConfig
|
Config AppConfig `description:"App configuration." yaml:"config"`
|
||||||
Users AppUsers
|
Users AppUsers `description:"User access configuration." yaml:"users"`
|
||||||
OAuth AppOAuth
|
OAuth AppOAuth `description:"OAuth access configuration." yaml:"oauth"`
|
||||||
IP AppIP
|
IP AppIP `description:"IP access configuration." yaml:"ip"`
|
||||||
Response AppResponse
|
Response AppResponse `description:"Response customization." yaml:"response"`
|
||||||
Path AppPath
|
Path AppPath `description:"Path access configuration." yaml:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
Domain string
|
Domain string `description:"The domain of the app." yaml:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppUsers struct {
|
type AppUsers struct {
|
||||||
Allow string
|
Allow string `description:"Comma-separated list of allowed users." yaml:"allow"`
|
||||||
Block string
|
Block string `description:"Comma-separated list of blocked users." yaml:"block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppOAuth struct {
|
type AppOAuth struct {
|
||||||
Whitelist string
|
Whitelist string `description:"Comma-separated list of allowed OAuth groups." yaml:"whitelist"`
|
||||||
Groups string
|
Groups string `description:"Comma-separated list of required OAuth groups." yaml:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppIP struct {
|
type AppIP struct {
|
||||||
Allow []string
|
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow"`
|
||||||
Block []string
|
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block"`
|
||||||
Bypass []string
|
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication." yaml:"bypass"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppResponse struct {
|
type AppResponse struct {
|
||||||
Headers []string
|
Headers []string `description:"Custom headers to add to the response." yaml:"headers"`
|
||||||
BasicAuth AppBasicAuth
|
BasicAuth AppBasicAuth `description:"Basic authentication for the app." yaml:"basicAuth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppBasicAuth struct {
|
type AppBasicAuth struct {
|
||||||
Username string
|
Username string `description:"Basic auth username." yaml:"username"`
|
||||||
Password string
|
Password string `description:"Basic auth password." yaml:"password"`
|
||||||
PasswordFile string
|
PasswordFile string `description:"Path to the file containing the basic auth password." yaml:"passwordFile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppPath struct {
|
type AppPath struct {
|
||||||
Allow string
|
Allow string `description:"Comma-separated list of allowed paths." yaml:"allow"`
|
||||||
Block string
|
Block string `description:"Comma-separated list of blocked paths." yaml:"block"`
|
||||||
}
|
|
||||||
|
|
||||||
// Flags
|
|
||||||
|
|
||||||
type Providers struct {
|
|
||||||
Providers map[string]OAuthServiceConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// API server
|
// API server
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -20,6 +21,7 @@ type UserContextResponse struct {
|
|||||||
OAuth bool `json:"oauth"`
|
OAuth bool `json:"oauth"`
|
||||||
TotpPending bool `json:"totpPending"`
|
TotpPending bool `json:"totpPending"`
|
||||||
OAuthName string `json:"oauthName"`
|
OAuthName string `json:"oauthName"`
|
||||||
|
OAuthSub string `json:"oauthSub"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppContextResponse struct {
|
type AppContextResponse struct {
|
||||||
@@ -88,6 +90,7 @@ func (controller *ContextController) userContextHandler(c *gin.Context) {
|
|||||||
OAuth: context.OAuth,
|
OAuth: context.OAuth,
|
||||||
TotpPending: context.TotpPending,
|
TotpPending: context.TotpPending,
|
||||||
OAuthName: context.OAuthName,
|
OAuthName: context.OAuthName,
|
||||||
|
OAuthSub: context.OAuthSub,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/controller"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
@@ -43,6 +44,7 @@ var userContext = config.UserContext{
|
|||||||
TotpPending: false,
|
TotpPending: false,
|
||||||
OAuthGroups: "",
|
OAuthGroups: "",
|
||||||
TotpEnabled: false,
|
TotpEnabled: false,
|
||||||
|
OAuthSub: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupContextController(middlewares *[]gin.HandlerFunc) (*gin.Engine, *httptest.ResponseRecorder) {
|
func setupContextController(middlewares *[]gin.HandlerFunc) (*gin.Engine, *httptest.ResponseRecorder) {
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
@@ -196,6 +197,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
Provider: req.Provider,
|
Provider: req.Provider,
|
||||||
OAuthGroups: utils.CoalesceToString(user.Groups),
|
OAuthGroups: utils.CoalesceToString(user.Groups),
|
||||||
OAuthName: service.GetName(),
|
OAuthName: service.GetName(),
|
||||||
|
OAuthSub: user.Sub,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Interface("session_cookie", sessionCookie).Msg("Creating session cookie")
|
log.Trace().Interface("session_cookie", sessionCookie).Msg("Creating session cookie")
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
@@ -42,7 +43,8 @@ func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, a
|
|||||||
|
|
||||||
func (controller *ProxyController) SetupRoutes() {
|
func (controller *ProxyController) SetupRoutes() {
|
||||||
proxyGroup := controller.router.Group("/auth")
|
proxyGroup := controller.router.Group("/auth")
|
||||||
proxyGroup.Any("/:proxy", controller.proxyHandler)
|
proxyGroup.GET("/:proxy", controller.proxyHandler)
|
||||||
|
proxyGroup.POST("/:proxy", controller.proxyHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||||
@@ -67,15 +69,6 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Proxy != "envoy" && c.Request.Method != http.MethodGet {
|
|
||||||
log.Warn().Str("method", c.Request.Method).Msg("Invalid method for proxy")
|
|
||||||
c.JSON(405, gin.H{
|
|
||||||
"status": 405,
|
|
||||||
"message": "Method Not Allowed",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html")
|
isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html")
|
||||||
|
|
||||||
if isBrowser {
|
if isBrowser {
|
||||||
@@ -246,6 +239,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
c.Header("Remote-Name", utils.SanitizeHeader(userContext.Name))
|
c.Header("Remote-Name", utils.SanitizeHeader(userContext.Name))
|
||||||
c.Header("Remote-Email", utils.SanitizeHeader(userContext.Email))
|
c.Header("Remote-Email", utils.SanitizeHeader(userContext.Email))
|
||||||
c.Header("Remote-Groups", utils.SanitizeHeader(userContext.OAuthGroups))
|
c.Header("Remote-Groups", utils.SanitizeHeader(userContext.OAuthGroups))
|
||||||
|
c.Header("Remote-Sub", utils.SanitizeHeader(userContext.OAuthSub))
|
||||||
|
|
||||||
controller.setHeaders(c, acls)
|
controller.setHeaders(c, acls)
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package controller_test
|
|||||||
import (
|
import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/controller"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
@@ -40,7 +41,7 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
|
|||||||
assert.NilError(t, dockerService.Init())
|
assert.NilError(t, dockerService.Init())
|
||||||
|
|
||||||
// Access controls
|
// Access controls
|
||||||
accessControlsService := service.NewAccessControlsService(dockerService)
|
accessControlsService := service.NewAccessControlsService(dockerService, map[string]config.App{})
|
||||||
|
|
||||||
assert.NilError(t, accessControlsService.Init())
|
assert.NilError(t, accessControlsService.Init())
|
||||||
|
|
||||||
@@ -80,13 +81,6 @@ func TestProxyHandler(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, 400, recorder.Code)
|
assert.Equal(t, 400, recorder.Code)
|
||||||
|
|
||||||
// Test invalid method
|
|
||||||
recorder = httptest.NewRecorder()
|
|
||||||
req = httptest.NewRequest("POST", "/api/auth/traefik", nil)
|
|
||||||
router.ServeHTTP(recorder, req)
|
|
||||||
|
|
||||||
assert.Equal(t, 405, recorder.Code)
|
|
||||||
|
|
||||||
// Test logged out user (traefik/caddy)
|
// Test logged out user (traefik/caddy)
|
||||||
recorder = httptest.NewRecorder()
|
recorder = httptest.NewRecorder()
|
||||||
req = httptest.NewRequest("GET", "/api/auth/traefik", nil)
|
req = httptest.NewRequest("GET", "/api/auth/traefik", nil)
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/controller"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/controller"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/service"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/service"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -65,6 +66,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
|
|||||||
goto basic
|
goto basic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.auth.RefreshSessionCookie(c)
|
||||||
c.Set("context", &config.UserContext{
|
c.Set("context", &config.UserContext{
|
||||||
Username: cookie.Username,
|
Username: cookie.Username,
|
||||||
Name: cookie.Name,
|
Name: cookie.Name,
|
||||||
@@ -89,6 +91,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
|
|||||||
goto basic
|
goto basic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.auth.RefreshSessionCookie(c)
|
||||||
c.Set("context", &config.UserContext{
|
c.Set("context", &config.UserContext{
|
||||||
Username: cookie.Username,
|
Username: cookie.Username,
|
||||||
Name: cookie.Name,
|
Name: cookie.Name,
|
||||||
@@ -96,6 +99,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
|
|||||||
Provider: cookie.Provider,
|
Provider: cookie.Provider,
|
||||||
OAuthGroups: cookie.OAuthGroups,
|
OAuthGroups: cookie.OAuthGroups,
|
||||||
OAuthName: cookie.OAuthName,
|
OAuthName: cookie.OAuthName,
|
||||||
|
OAuthSub: cookie.OAuthSub,
|
||||||
IsLoggedIn: true,
|
IsLoggedIn: true,
|
||||||
OAuth: true,
|
OAuth: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/assets"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/assets"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|||||||
14
internal/model/session_model.go
Normal file
14
internal/model/session_model.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
UUID string `gorm:"column:uuid;primaryKey"`
|
||||||
|
Username string `gorm:"column:username"`
|
||||||
|
Email string `gorm:"column:email"`
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
Provider string `gorm:"column:provider"`
|
||||||
|
TOTPPending bool `gorm:"column:totp_pending"`
|
||||||
|
OAuthGroups string `gorm:"column:oauth_groups"`
|
||||||
|
Expiry int64 `gorm:"column:expiry"`
|
||||||
|
OAuthName string `gorm:"column:oauth_name"`
|
||||||
|
OAuthSub string `gorm:"column:oauth_sub"`
|
||||||
|
}
|
||||||
@@ -1,122 +1,54 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"tinyauth/internal/config"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
Environment variable/flag based ACLs are disabled until v5 due to a technical challenge
|
|
||||||
with the current parsing logic.
|
|
||||||
|
|
||||||
The current parser works for simple OAuth provider configs like:
|
|
||||||
- PROVIDERS_MY_AMAZING_PROVIDER_CLIENT_ID
|
|
||||||
|
|
||||||
However, it breaks down when handling nested structs required for ACLs. The custom parsing
|
|
||||||
solution that worked for v4 OAuth providers is incompatible with the ACL parsing logic,
|
|
||||||
making the codebase unmaintainable and fragile.
|
|
||||||
|
|
||||||
A solution is being considered for v5 that would standardize the format to something like:
|
|
||||||
- TINYAUTH_PROVIDERS_GOOGLE_CLIENTSECRET
|
|
||||||
- TINYAUTH_APPS_MYAPP_CONFIG_DOMAIN
|
|
||||||
|
|
||||||
This would allow the Traefik parser to handle everything consistently, but requires a
|
|
||||||
config migration. Until this is resolved, environment-based ACLs are disabled and only
|
|
||||||
Docker label-based ACLs are supported.
|
|
||||||
|
|
||||||
See: https://discord.com/channels/1337450123600465984/1337459086270271538/1434986689935179838 for more information
|
|
||||||
*/
|
|
||||||
|
|
||||||
type AccessControlsService struct {
|
type AccessControlsService struct {
|
||||||
docker *DockerService
|
docker *DockerService
|
||||||
// envACLs config.Apps
|
static map[string]config.App
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccessControlsService(docker *DockerService) *AccessControlsService {
|
func NewAccessControlsService(docker *DockerService, static map[string]config.App) *AccessControlsService {
|
||||||
return &AccessControlsService{
|
return &AccessControlsService{
|
||||||
docker: docker,
|
docker: docker,
|
||||||
|
static: static,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acls *AccessControlsService) Init() error {
|
func (acls *AccessControlsService) Init() error {
|
||||||
// acls.envACLs = config.Apps{}
|
return nil // No initialization needed
|
||||||
// env := os.Environ()
|
|
||||||
// appEnvVars := []string{}
|
|
||||||
|
|
||||||
// for _, e := range env {
|
|
||||||
// if strings.HasPrefix(e, "TINYAUTH_APPS_") {
|
|
||||||
// appEnvVars = append(appEnvVars, e)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err := acls.loadEnvACLs(appEnvVars)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (acls *AccessControlsService) loadEnvACLs(appEnvVars []string) error {
|
func (acls *AccessControlsService) lookupStaticACLs(domain string) (config.App, error) {
|
||||||
// if len(appEnvVars) == 0 {
|
for app, config := range acls.static {
|
||||||
// return nil
|
if config.Config.Domain == domain {
|
||||||
// }
|
log.Debug().Str("name", app).Msg("Found matching container by domain")
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
// envAcls := map[string]string{}
|
if strings.SplitN(domain, ".", 2)[0] == app {
|
||||||
|
log.Debug().Str("name", app).Msg("Found matching container by app name")
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config.App{}, errors.New("no results")
|
||||||
|
}
|
||||||
|
|
||||||
// for _, e := range appEnvVars {
|
func (acls *AccessControlsService) GetAccessControls(domain string) (config.App, error) {
|
||||||
// parts := strings.SplitN(e, "=", 2)
|
// First check in the static config
|
||||||
// if len(parts) != 2 {
|
app, err := acls.lookupStaticACLs(domain)
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// key := parts[0]
|
if err == nil {
|
||||||
// key = strings.ToLower(key)
|
log.Debug().Msg("Using ACls from static configuration")
|
||||||
// key = strings.ReplaceAll(key, "_", ".")
|
return app, nil
|
||||||
// value := parts[1]
|
}
|
||||||
// envAcls[key] = value
|
|
||||||
// }
|
|
||||||
|
|
||||||
// apps, err := decoders.DecodeLabels(envAcls)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// acls.envACLs = apps
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (acls *AccessControlsService) lookupEnvACLs(appDomain string) *config.App {
|
|
||||||
// if len(acls.envACLs.Apps) == 0 {
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for appName, appACLs := range acls.envACLs.Apps {
|
|
||||||
// if appACLs.Config.Domain == appDomain {
|
|
||||||
// return &appACLs
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if strings.SplitN(appDomain, ".", 2)[0] == appName {
|
|
||||||
// return &appACLs
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (acls *AccessControlsService) GetAccessControls(appDomain string) (config.App, error) {
|
|
||||||
// First check environment variables
|
|
||||||
// envACLs := acls.lookupEnvACLs(appDomain)
|
|
||||||
|
|
||||||
// if envACLs != nil {
|
|
||||||
// log.Debug().Str("domain", appDomain).Msg("Found matching access controls in environment variables")
|
|
||||||
// return *envACLs, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Fallback to Docker labels
|
// Fallback to Docker labels
|
||||||
return acls.docker.GetLabels(appDomain)
|
log.Debug().Msg("Falling back to Docker labels for ACLs")
|
||||||
|
return acls.docker.GetLabels(domain)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/repository"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/model"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -57,7 +58,6 @@ func NewAuthService(config AuthServiceConfig, docker *DockerService, ldap *LdapS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (auth *AuthService) Init() error {
|
func (auth *AuthService) Init() error {
|
||||||
auth.ctx = context.Background()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +215,7 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.Sessio
|
|||||||
OAuthGroups: data.OAuthGroups,
|
OAuthGroups: data.OAuthGroups,
|
||||||
Expiry: time.Now().Add(time.Duration(expiry) * time.Second).Unix(),
|
Expiry: time.Now().Add(time.Duration(expiry) * time.Second).Unix(),
|
||||||
OAuthName: data.OAuthName,
|
OAuthName: data.OAuthName,
|
||||||
|
OAuthSub: data.OAuthSub,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = auth.queries.CreateSession(c, session)
|
_, err = auth.queries.CreateSession(c, session)
|
||||||
@@ -228,6 +229,40 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.Sessio
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (auth *AuthService) RefreshSessionCookie(c *gin.Context) error {
|
||||||
|
cookie, err := c.Cookie(auth.config.SessionCookieName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := gorm.G[model.Session](auth.database).Where("uuid = ?", cookie).First(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTime := time.Now().Unix()
|
||||||
|
|
||||||
|
if session.Expiry-currentTime > int64(time.Hour.Seconds()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newExpiry := currentTime + int64(time.Hour.Seconds())
|
||||||
|
|
||||||
|
_, err = gorm.G[model.Session](auth.database).Where("uuid = ?", cookie).Updates(c, model.Session{
|
||||||
|
Expiry: newExpiry,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetCookie(auth.config.SessionCookieName, cookie, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (auth *AuthService) DeleteSessionCookie(c *gin.Context) error {
|
func (auth *AuthService) DeleteSessionCookie(c *gin.Context) error {
|
||||||
cookie, err := c.Cookie(auth.config.SessionCookieName)
|
cookie, err := c.Cookie(auth.config.SessionCookieName)
|
||||||
|
|
||||||
@@ -282,6 +317,7 @@ func (auth *AuthService) GetSessionCookie(c *gin.Context) (config.SessionCookie,
|
|||||||
TotpPending: session.TotpPending,
|
TotpPending: session.TotpPending,
|
||||||
OAuthGroups: session.OAuthGroups,
|
OAuthGroups: session.OAuthGroups,
|
||||||
OAuthName: session.OAuthName,
|
OAuthName: session.OAuthName,
|
||||||
|
OAuthSub: session.OAuthSub,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
92
internal/service/database_service.go
Normal file
92
internal/service/database_service.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/assets"
|
||||||
|
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
|
"github.com/golang-migrate/migrate/v4"
|
||||||
|
sqliteMigrate "github.com/golang-migrate/migrate/v4/database/sqlite3"
|
||||||
|
"github.com/golang-migrate/migrate/v4/source/iofs"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DatabaseServiceConfig struct {
|
||||||
|
DatabasePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatabaseService struct {
|
||||||
|
config DatabaseServiceConfig
|
||||||
|
database *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatabaseService(config DatabaseServiceConfig) *DatabaseService {
|
||||||
|
return &DatabaseService{
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *DatabaseService) Init() error {
|
||||||
|
dbPath := ds.config.DatabasePath
|
||||||
|
if dbPath == "" {
|
||||||
|
dbPath = "/data/tinyauth.db"
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := filepath.Dir(dbPath)
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create database directory %s: %w", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gormDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB, err := gormDB.DB()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB.SetMaxOpenConns(1)
|
||||||
|
|
||||||
|
err = ds.migrateDatabase(sqlDB)
|
||||||
|
|
||||||
|
if err != nil && err != migrate.ErrNoChange {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ds.database = gormDB
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *DatabaseService) migrateDatabase(sqlDB *sql.DB) error {
|
||||||
|
data, err := iofs.New(assets.Migrations, "migrations")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
target, err := sqliteMigrate.WithInstance(sqlDB, &sqliteMigrate.Config{})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrator, err := migrate.NewWithInstance("iofs", data, "tinyauth", target)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrator.Up()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *DatabaseService) GetDatabase() *gorm.DB {
|
||||||
|
return ds.database
|
||||||
|
}
|
||||||
@@ -3,8 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/utils/decoders"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils/decoders"
|
||||||
|
|
||||||
container "github.com/docker/docker/api/types/container"
|
container "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/endpoints"
|
"golang.org/x/oauth2/endpoints"
|
||||||
@@ -26,6 +28,7 @@ type GithubEmailResponse []struct {
|
|||||||
type GithubUserInfoResponse struct {
|
type GithubUserInfoResponse struct {
|
||||||
Login string `json:"login"`
|
Login string `json:"login"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
ID int `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GithubOAuthService struct {
|
type GithubOAuthService struct {
|
||||||
@@ -171,6 +174,7 @@ func (github *GithubOAuthService) Userinfo() (config.Claims, error) {
|
|||||||
|
|
||||||
user.PreferredUsername = userInfo.Login
|
user.PreferredUsername = userInfo.Login
|
||||||
user.Name = userInfo.Name
|
user.Name = userInfo.Name
|
||||||
|
user.Sub = strconv.Itoa(userInfo.ID)
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,14 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/endpoints"
|
"golang.org/x/oauth2/endpoints"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GoogleOAuthScopes = []string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"}
|
var GoogleOAuthScopes = []string{"openid", "email", "profile"}
|
||||||
|
|
||||||
type GoogleUserInfoResponse struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GoogleOAuthService struct {
|
type GoogleOAuthService struct {
|
||||||
config oauth2.Config
|
config oauth2.Config
|
||||||
@@ -90,7 +86,7 @@ func (google *GoogleOAuthService) Userinfo() (config.Claims, error) {
|
|||||||
|
|
||||||
client := google.config.Client(google.context, google.token)
|
client := google.config.Client(google.context, google.token)
|
||||||
|
|
||||||
res, err := client.Get("https://www.googleapis.com/userinfo/v2/me")
|
res, err := client.Get("https://openidconnect.googleapis.com/v1/userinfo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return config.Claims{}, err
|
return config.Claims{}, err
|
||||||
}
|
}
|
||||||
@@ -105,16 +101,12 @@ func (google *GoogleOAuthService) Userinfo() (config.Claims, error) {
|
|||||||
return config.Claims{}, err
|
return config.Claims{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var userInfo GoogleUserInfoResponse
|
err = json.Unmarshal(body, &user)
|
||||||
|
|
||||||
err = json.Unmarshal(body, &userInfo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return config.Claims{}, err
|
return config.Claims{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.PreferredUsername = strings.Split(userInfo.Email, "@")[0]
|
user.PreferredUsername = strings.SplitN(user.Email, "@", 2)[0]
|
||||||
user.Name = userInfo.Name
|
|
||||||
user.Email = userInfo.Email
|
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/weppos/publicsuffix-go/publicsuffix"
|
"github.com/weppos/publicsuffix-go/publicsuffix"
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package utils_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/utils"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package decoders_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/config"
|
|
||||||
"tinyauth/internal/utils/decoders"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils/decoders"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package utils_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package loaders
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
|
||||||
"github.com/traefik/paerser/cli"
|
"github.com/traefik/paerser/cli"
|
||||||
"github.com/traefik/paerser/env"
|
"github.com/traefik/paerser/env"
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package utils_test
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package utils_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"tinyauth/internal/config"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseUsers(users string) ([]config.User, error) {
|
func ParseUsers(users string) ([]config.User, error) {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package utils_test
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"tinyauth/internal/utils"
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/utils"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
1
paerser
Submodule
1
paerser
Submodule
Submodule paerser added at 7e1b633ba9
95
patches/nested_maps.diff
Normal file
95
patches/nested_maps.diff
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
diff --git a/env/env_test.go b/env/env_test.go
|
||||||
|
index 7045569..365dc00 100644
|
||||||
|
--- a/env/env_test.go
|
||||||
|
+++ b/env/env_test.go
|
||||||
|
@@ -166,6 +166,38 @@ func TestDecode(t *testing.T) {
|
||||||
|
Foo: &struct{ Field string }{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
+ {
|
||||||
|
+ desc: "map under the root key",
|
||||||
|
+ environ: []string{"TRAEFIK_FOO_BAR_FOOBAR_BARFOO=foo"},
|
||||||
|
+ element: &struct {
|
||||||
|
+ Foo map[string]struct {
|
||||||
|
+ Foobar struct {
|
||||||
|
+ Barfoo string
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }{},
|
||||||
|
+ expected: &struct {
|
||||||
|
+ Foo map[string]struct {
|
||||||
|
+ Foobar struct {
|
||||||
|
+ Barfoo string
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }{
|
||||||
|
+ Foo: map[string]struct {
|
||||||
|
+ Foobar struct {
|
||||||
|
+ Barfoo string
|
||||||
|
+ }
|
||||||
|
+ }{
|
||||||
|
+ "bar": {
|
||||||
|
+ Foobar: struct {
|
||||||
|
+ Barfoo string
|
||||||
|
+ }{
|
||||||
|
+ Barfoo: "foo",
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
diff --git a/parser/nodes_metadata.go b/parser/nodes_metadata.go
|
||||||
|
index 36946c1..0279705 100644
|
||||||
|
--- a/parser/nodes_metadata.go
|
||||||
|
+++ b/parser/nodes_metadata.go
|
||||||
|
@@ -75,8 +75,13 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
|
||||||
|
node.Kind = fType.Kind()
|
||||||
|
node.Tag = field.Tag
|
||||||
|
|
||||||
|
- if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct ||
|
||||||
|
- fType.Kind() == reflect.Map {
|
||||||
|
+ if node.Kind == reflect.String && len(node.Children) > 0 {
|
||||||
|
+ fType = reflect.TypeOf(struct{}{})
|
||||||
|
+ node.Kind = reflect.Struct
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if node.Kind == reflect.Struct || node.Kind == reflect.Pointer && fType.Elem().Kind() == reflect.Struct ||
|
||||||
|
+ node.Kind == reflect.Map {
|
||||||
|
if len(node.Children) == 0 && !(field.Tag.Get(m.TagName) == TagLabelAllowEmpty || field.Tag.Get(m.TagName) == "-") {
|
||||||
|
return fmt.Errorf("%s cannot be a standalone element (type %s)", node.Name, fType)
|
||||||
|
}
|
||||||
|
@@ -90,11 +95,11 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
- if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct {
|
||||||
|
+ if node.Kind == reflect.Struct || node.Kind == reflect.Pointer && fType.Elem().Kind() == reflect.Struct {
|
||||||
|
return m.browseChildren(fType, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
- if fType.Kind() == reflect.Map {
|
||||||
|
+ if node.Kind == reflect.Map {
|
||||||
|
if fType.Elem().Kind() == reflect.Interface {
|
||||||
|
addRawValue(node)
|
||||||
|
return nil
|
||||||
|
@@ -115,7 +120,7 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
- if fType.Kind() == reflect.Slice {
|
||||||
|
+ if node.Kind == reflect.Slice {
|
||||||
|
if m.AllowSliceAsStruct && field.Tag.Get(TagLabelSliceAsStruct) != "" {
|
||||||
|
return m.browseChildren(fType.Elem(), node)
|
||||||
|
}
|
||||||
|
@@ -129,7 +134,7 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
- return fmt.Errorf("invalid node %s: %v", node.Name, fType.Kind())
|
||||||
|
+ return fmt.Errorf("invalid node %s: %v", node.Name, node.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m metadata) findTypedField(rType reflect.Type, node *Node) (reflect.StructField, error) {
|
||||||
Reference in New Issue
Block a user