mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-12-30 20:12:29 +00:00
Compare commits
2 Commits
feat/non-d
...
feat/analy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
902574e501 | ||
|
|
aac19d4d5a |
@@ -1,3 +0,0 @@
|
|||||||
issue_enrichment:
|
|
||||||
auto_enrich:
|
|
||||||
enabled: false
|
|
||||||
119
.env.example
119
.env.example
@@ -1,86 +1,33 @@
|
|||||||
# Base Configuration
|
PORT=3000
|
||||||
|
ADDRESS=0.0.0.0
|
||||||
# The base URL where Tinyauth is accessible
|
APP_URL=http://localhost:3000
|
||||||
TINYAUTH_APPURL="https://auth.example.com"
|
USERS=your_user_password_hash
|
||||||
# Log level: trace, debug, info, warn, error
|
USERS_FILE=users_file
|
||||||
TINYAUTH_LOGLEVEL="info"
|
SECURE_COOKIE=false
|
||||||
# Directory for static resources
|
GITHUB_CLIENT_ID=github_client_id
|
||||||
TINYAUTH_RESOURCESDIR="/data/resources"
|
GITHUB_CLIENT_SECRET=github_client_secret
|
||||||
# Path to SQLite database file
|
GITHUB_CLIENT_SECRET_FILE=github_client_secret_file
|
||||||
TINYAUTH_DATABASEPATH="/data/tinyauth.db"
|
GOOGLE_CLIENT_ID=google_client_id
|
||||||
# Disable version heartbeat
|
GOOGLE_CLIENT_SECRET=google_client_secret
|
||||||
TINYAUTH_DISABLEANALYTICS="false"
|
GOOGLE_CLIENT_SECRET_FILE=google_client_secret_file
|
||||||
# Disable static resource serving
|
GENERIC_CLIENT_ID=generic_client_id
|
||||||
TINYAUTH_DISABLERESOURCES="false"
|
GENERIC_CLIENT_SECRET=generic_client_secret
|
||||||
# Disable UI warning messages
|
GENERIC_CLIENT_SECRET_FILE=generic_client_secret_file
|
||||||
TINYAUTH_DISABLEUIWARNINGS="false"
|
GENERIC_SCOPES=generic_scopes
|
||||||
# Enable JSON formatted logs
|
GENERIC_AUTH_URL=generic_auth_url
|
||||||
TINYAUTH_LOGJSON="false"
|
GENERIC_TOKEN_URL=generic_token_url
|
||||||
|
GENERIC_USER_URL=generic_user_url
|
||||||
# Server Configuration
|
DISABLE_CONTINUE=false
|
||||||
|
OAUTH_WHITELIST=
|
||||||
# Port to listen on
|
GENERIC_NAME=My OAuth
|
||||||
TINYAUTH_SERVER_PORT="3000"
|
SESSION_EXPIRY=7200
|
||||||
# Interface to bind to (0.0.0.0 for all interfaces)
|
LOGIN_TIMEOUT=300
|
||||||
TINYAUTH_SERVER_ADDRESS="0.0.0.0"
|
LOGIN_MAX_RETRIES=5
|
||||||
# Unix socket path (optional, overrides port/address if set)
|
LOG_LEVEL=debug
|
||||||
TINYAUTH_SERVER_SOCKETPATH=""
|
APP_TITLE=Tinyauth SSO
|
||||||
# Comma-separated list of trusted proxy IPs/CIDRs
|
FORGOT_PASSWORD_MESSAGE=Some message about resetting the password
|
||||||
TINYAUTH_SERVER_TRUSTEDPROXIES=""
|
OAUTH_AUTO_REDIRECT=none
|
||||||
|
BACKGROUND_IMAGE=some_image_url
|
||||||
# Authentication Configuration
|
GENERIC_SKIP_SSL=false
|
||||||
|
RESOURCES_DIR=/data/resources
|
||||||
# Format: username:bcrypt_hash (use bcrypt to generate hash)
|
DATABASE_PATH=/data/tinyauth.db
|
||||||
TINYAUTH_AUTH_USERS="admin:$2a$10$example_bcrypt_hash_here"
|
|
||||||
# Path to external users file (optional)
|
|
||||||
TINYAUTH_USERSFILE=""
|
|
||||||
# Enable secure cookies (requires HTTPS)
|
|
||||||
TINYAUTH_SECURECOOKIE="true"
|
|
||||||
# Session expiry in seconds (7200 = 2 hours)
|
|
||||||
TINYAUTH_SESSIONEXPIRY="7200"
|
|
||||||
# Login timeout in seconds (300 = 5 minutes)
|
|
||||||
TINYAUTH_LOGINTIMEOUT="300"
|
|
||||||
# Maximum login retries before lockout
|
|
||||||
TINYAUTH_LOGINMAXRETRIES="5"
|
|
||||||
|
|
||||||
# OAuth Configuration
|
|
||||||
|
|
||||||
# Regex pattern for allowed email addresses (e.g., /@example\.com$/)
|
|
||||||
TINYAUTH_OAUTH_WHITELIST=""
|
|
||||||
# Provider ID to auto-redirect to (skips login page)
|
|
||||||
TINYAUTH_OAUTH_AUTOREDIRECT=""
|
|
||||||
# OAuth Provider Configuration (replace MYPROVIDER with your provider name)
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_CLIENTID="your_client_id_here"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_CLIENTSECRET="your_client_secret_here"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_AUTHURL="https://provider.example.com/oauth/authorize"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_TOKENURL="https://provider.example.com/oauth/token"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_USERINFOURL="https://provider.example.com/oauth/userinfo"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_REDIRECTURL="https://auth.example.com/oauth/callback/myprovider"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_SCOPES="openid email profile"
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_NAME="My OAuth Provider"
|
|
||||||
# Allow self-signed certificates
|
|
||||||
TINYAUTH_OAUTH_PROVIDERS_MYPROVIDER_INSECURE="false"
|
|
||||||
|
|
||||||
# UI Customization
|
|
||||||
|
|
||||||
# Custom title for login page
|
|
||||||
TINYAUTH_UI_TITLE="Tinyauth"
|
|
||||||
# Message shown on forgot password page
|
|
||||||
TINYAUTH_UI_FORGOTPASSWORDMESSAGE="Contact your administrator to reset your password"
|
|
||||||
# Background image URL for login page
|
|
||||||
TINYAUTH_UI_BACKGROUNDIMAGE=""
|
|
||||||
|
|
||||||
# LDAP Configuration
|
|
||||||
|
|
||||||
# LDAP server address
|
|
||||||
TINYAUTH_LDAP_ADDRESS="ldap://ldap.example.com:389"
|
|
||||||
# DN for binding to LDAP server
|
|
||||||
TINYAUTH_LDAP_BINDDN="cn=readonly,dc=example,dc=com"
|
|
||||||
# Password for bind DN
|
|
||||||
TINYAUTH_LDAP_BINDPASSWORD="your_bind_password"
|
|
||||||
# Base DN for user searches
|
|
||||||
TINYAUTH_LDAP_BASEDN="dc=example,dc=com"
|
|
||||||
# Search filter (%s will be replaced with username)
|
|
||||||
TINYAUTH_LDAP_SEARCHFILTER="(&(uid=%s)(memberOf=cn=users,ou=groups,dc=example,dc=com))"
|
|
||||||
# Allow insecure LDAP connections
|
|
||||||
TINYAUTH_LDAP_INSECURE="false"
|
|
||||||
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -18,31 +18,17 @@ jobs:
|
|||||||
- name: Setup go
|
- name: Setup go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.24.0"
|
go-version: "^1.23.2"
|
||||||
|
|
||||||
- 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: |
|
||||||
cd frontend
|
cd frontend
|
||||||
bun install --frozen-lockfile
|
bun install
|
||||||
|
|
||||||
- name: Set version
|
- name: Set version
|
||||||
run: |
|
run: |
|
||||||
echo testing > internal/assets/version
|
echo testing > internal/assets/version
|
||||||
|
|
||||||
- name: Lint frontend
|
|
||||||
run: |
|
|
||||||
cd frontend
|
|
||||||
bun run lint
|
|
||||||
|
|
||||||
- name: Build frontend
|
- name: Build frontend
|
||||||
run: |
|
run: |
|
||||||
cd frontend
|
cd frontend
|
||||||
|
|||||||
235
.github/workflows/nightly.yml
vendored
235
.github/workflows/nightly.yml
vendored
@@ -61,21 +61,12 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.24.0"
|
go-version: "^1.23.2"
|
||||||
|
|
||||||
- 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: |
|
||||||
cd frontend
|
cd frontend
|
||||||
bun install --frozen-lockfile
|
bun install
|
||||||
|
|
||||||
- name: Install backend dependencies
|
- name: Install backend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -89,7 +80,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
|
go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -116,21 +107,12 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.24.0"
|
go-version: "^1.23.2"
|
||||||
|
|
||||||
- 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: |
|
||||||
cd frontend
|
cd frontend
|
||||||
bun install --frozen-lockfile
|
bun install
|
||||||
|
|
||||||
- name: Install backend dependencies
|
- name: Install backend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -144,7 +126,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
|
go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -165,15 +147,6 @@ 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
|
||||||
@@ -198,9 +171,6 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
@@ -220,74 +190,6 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
image-build-distroless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- create-release
|
|
||||||
- generate-metadata
|
|
||||||
- image-build
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
platforms: linux/amd64
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
|
||||||
file: Dockerfile.distroless
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-distroless-linux-amd64
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
image-build-arm:
|
image-build-arm:
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
needs:
|
needs:
|
||||||
@@ -299,15 +201,6 @@ 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
|
||||||
@@ -324,6 +217,10 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set version
|
||||||
|
run: |
|
||||||
|
echo nightly > internal/assets/version
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
id: build
|
id: build
|
||||||
@@ -332,9 +229,6 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
@@ -354,74 +248,6 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
image-build-arm-distroless:
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
needs:
|
|
||||||
- create-release
|
|
||||||
- generate-metadata
|
|
||||||
- image-build-arm
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
platforms: linux/arm64
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
|
||||||
file: Dockerfile.distroless
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-distroless-linux-arm64
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
image-merge:
|
image-merge:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
@@ -450,8 +276,6 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,nightly
|
type=raw,nightly
|
||||||
|
|
||||||
@@ -461,45 +285,6 @@ jobs:
|
|||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||||
$(printf 'ghcr.io/${{ github.repository_owner }}/tinyauth@sha256:%s ' *)
|
$(printf 'ghcr.io/${{ github.repository_owner }}/tinyauth@sha256:%s ' *)
|
||||||
|
|
||||||
image-merge-distroless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- image-build-distroless
|
|
||||||
- image-build-arm-distroless
|
|
||||||
steps:
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/digests
|
|
||||||
pattern: digests-distroless-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
tags: |
|
|
||||||
type=raw,nightly-distroless
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: ${{ runner.temp }}/digests
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
$(printf 'ghcr.io/${{ github.repository_owner }}/tinyauth@sha256:%s ' *)
|
|
||||||
|
|
||||||
update-release:
|
update-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
|
|||||||
235
.github/workflows/release.yml
vendored
235
.github/workflows/release.yml
vendored
@@ -39,21 +39,12 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.24.0"
|
go-version: "^1.23.2"
|
||||||
|
|
||||||
- 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: |
|
||||||
cd frontend
|
cd frontend
|
||||||
bun install --frozen-lockfile
|
bun install
|
||||||
|
|
||||||
- name: Install backend dependencies
|
- name: Install backend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -67,7 +58,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
|
go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -91,21 +82,12 @@ jobs:
|
|||||||
- name: Install go
|
- name: Install go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "^1.24.0"
|
go-version: "^1.23.2"
|
||||||
|
|
||||||
- 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: |
|
||||||
cd frontend
|
cd frontend
|
||||||
bun install --frozen-lockfile
|
bun install
|
||||||
|
|
||||||
- name: Install backend dependencies
|
- name: Install backend dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -119,7 +101,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
|
go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -137,15 +119,6 @@ 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
|
||||||
@@ -170,9 +143,6 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
@@ -192,71 +162,6 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
image-build-distroless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- generate-metadata
|
|
||||||
- image-build
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
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
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
platforms: linux/amd64
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
|
||||||
file: Dockerfile.distroless
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-distroless-linux-amd64
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
image-build-arm:
|
image-build-arm:
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
needs:
|
needs:
|
||||||
@@ -265,15 +170,6 @@ 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
|
||||||
@@ -298,9 +194,6 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
@@ -320,71 +213,6 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
image-build-arm-distroless:
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
needs:
|
|
||||||
- generate-metadata
|
|
||||||
- image-build-arm
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
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
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
platforms: linux/arm64
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
|
||||||
file: Dockerfile.distroless
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
build-args: |
|
|
||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digests-distroless-linux-arm64
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
image-merge:
|
image-merge:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
@@ -413,55 +241,10 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
flavor: |
|
|
||||||
prefix=v,onlatest=false
|
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}},prefix=v
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}},prefix=v
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}},prefix=v
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: ${{ runner.temp }}/digests
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
$(printf 'ghcr.io/${{ github.repository_owner }}/tinyauth@sha256:%s ' *)
|
|
||||||
|
|
||||||
image-merge-distroless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- image-build-distroless
|
|
||||||
- image-build-arm-distroless
|
|
||||||
steps:
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/digests
|
|
||||||
pattern: digests-distroless-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
prefix=v
|
|
||||||
suffix=-distroless
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
- name: Create manifest list and push
|
||||||
working-directory: ${{ runner.temp }}/digests
|
working-directory: ${{ runner.temp }}/digests
|
||||||
|
|||||||
28
.gitignore
vendored
28
.gitignore
vendored
@@ -1,39 +1,29 @@
|
|||||||
# dist
|
# dist
|
||||||
/internal/assets/dist
|
internal/assets/dist
|
||||||
|
|
||||||
# binaries
|
# binaries
|
||||||
/tinyauth
|
tinyauth
|
||||||
|
|
||||||
# test docker compose
|
# test docker compose
|
||||||
/docker-compose.test*
|
docker-compose.test*
|
||||||
|
|
||||||
# users file
|
# users file
|
||||||
/users.txt
|
users.txt
|
||||||
|
|
||||||
# secret test file
|
# secret test file
|
||||||
/secret*
|
secret*
|
||||||
|
|
||||||
# apple stuff
|
# apple stuff
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# env
|
# env
|
||||||
/.env
|
.env
|
||||||
|
|
||||||
# tmp directory
|
# tmp directory
|
||||||
/tmp
|
tmp
|
||||||
|
|
||||||
# version files
|
# version files
|
||||||
/internal/assets/version
|
internal/assets/version
|
||||||
|
|
||||||
# data directory
|
# data directory
|
||||||
/data
|
data
|
||||||
|
|
||||||
# config file
|
|
||||||
/config.yml
|
|
||||||
|
|
||||||
# binary out
|
|
||||||
/tinyauth.db
|
|
||||||
/resources
|
|
||||||
|
|
||||||
# debug files
|
|
||||||
__debug_*
|
|
||||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
|||||||
[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 1.24.0+
|
- Golang v1.23.2 and above
|
||||||
- Git
|
- Git
|
||||||
- Docker
|
- Docker
|
||||||
|
|
||||||
@@ -18,21 +18,12 @@ 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 tidy
|
||||||
```
|
```
|
||||||
|
|
||||||
You also need to download the frontend dependencies, this can be done like so:
|
You also need to download the frontend dependencies, this can be done like so:
|
||||||
@@ -42,21 +33,13 @@ 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
|
||||||
@@ -66,7 +49,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
|
||||||
|
|||||||
29
Dockerfile
29
Dockerfile
@@ -1,12 +1,12 @@
|
|||||||
# Site builder
|
# Site builder
|
||||||
FROM oven/bun:1.3.5-alpine AS frontend-builder
|
FROM oven/bun:1.2.22-alpine AS frontend-builder
|
||||||
|
|
||||||
WORKDIR /frontend
|
WORKDIR /frontend
|
||||||
|
|
||||||
COPY ./frontend/package.json ./
|
COPY ./frontend/package.json ./
|
||||||
COPY ./frontend/bun.lock ./
|
COPY ./frontend/bun.lock ./
|
||||||
|
|
||||||
RUN bun install --frozen-lockfile
|
RUN bun install
|
||||||
|
|
||||||
COPY ./frontend/public ./public
|
COPY ./frontend/public ./public
|
||||||
COPY ./frontend/src ./src
|
COPY ./frontend/src ./src
|
||||||
@@ -28,40 +28,29 @@ ARG BUILD_TIMESTAMP
|
|||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
COPY ./paerser ./paerser
|
|
||||||
|
|
||||||
COPY go.mod ./
|
COPY go.mod ./
|
||||||
COPY go.sum ./
|
COPY go.sum ./
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY ./main.go ./
|
||||||
COPY ./cmd ./cmd
|
COPY ./cmd ./cmd
|
||||||
COPY ./internal ./internal
|
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/constants.Version=${VERSION} -X tinyauth/internal/constants.CommitHash=${COMMIT_HASH} -X tinyauth/internal/constants.BuildTimestamp=${BUILD_TIMESTAMP}"
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
FROM alpine:3.23 AS runner
|
FROM alpine:3.22 AS runner
|
||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
COPY --from=builder /tinyauth/tinyauth ./
|
RUN apk add --no-cache curl
|
||||||
|
|
||||||
RUN mkdir -p /data
|
COPY --from=builder /tinyauth/tinyauth ./
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|
||||||
ENV DATABASEPATH=/data/tinyauth.db
|
ENTRYPOINT ["./tinyauth"]
|
||||||
|
|
||||||
ENV RESOURCESDIR=/data/resources
|
|
||||||
|
|
||||||
ENV GIN_MODE=release
|
|
||||||
|
|
||||||
ENV PATH=$PATH:/tinyauth
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
|
||||||
|
|
||||||
ENTRYPOINT ["tinyauth"]
|
|
||||||
@@ -2,24 +2,18 @@ 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 ./
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
RUN go install github.com/air-verse/air@v1.61.7
|
|
||||||
RUN go install github.com/go-delve/delve/cmd/dlv@latest
|
|
||||||
|
|
||||||
COPY ./cmd ./cmd
|
COPY ./cmd ./cmd
|
||||||
COPY ./internal ./internal
|
COPY ./internal ./internal
|
||||||
|
COPY ./main.go ./
|
||||||
COPY ./air.toml ./
|
COPY ./air.toml ./
|
||||||
|
|
||||||
|
RUN go install github.com/air-verse/air@v1.61.7
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db
|
ENTRYPOINT ["air", "-c", "air.toml"]
|
||||||
|
|
||||||
ENV TINYAUTH_RESOURCESDIR=/data/resources
|
|
||||||
|
|
||||||
ENTRYPOINT ["air", "-c", "air.toml"]
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# Site builder
|
|
||||||
FROM oven/bun:1.3.5-alpine AS frontend-builder
|
|
||||||
|
|
||||||
WORKDIR /frontend
|
|
||||||
|
|
||||||
COPY ./frontend/package.json ./
|
|
||||||
COPY ./frontend/bun.lock ./
|
|
||||||
|
|
||||||
RUN bun install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY ./frontend/public ./public
|
|
||||||
COPY ./frontend/src ./src
|
|
||||||
COPY ./frontend/eslint.config.js ./
|
|
||||||
COPY ./frontend/index.html ./
|
|
||||||
COPY ./frontend/tsconfig.json ./
|
|
||||||
COPY ./frontend/tsconfig.app.json ./
|
|
||||||
COPY ./frontend/tsconfig.node.json ./
|
|
||||||
COPY ./frontend/vite.config.ts ./
|
|
||||||
|
|
||||||
RUN bun run build
|
|
||||||
|
|
||||||
# Builder
|
|
||||||
FROM golang:1.25-alpine3.21 AS builder
|
|
||||||
|
|
||||||
ARG VERSION
|
|
||||||
ARG COMMIT_HASH
|
|
||||||
ARG BUILD_TIMESTAMP
|
|
||||||
|
|
||||||
WORKDIR /tinyauth
|
|
||||||
|
|
||||||
COPY ./paerser ./paerser
|
|
||||||
|
|
||||||
COPY go.mod ./
|
|
||||||
COPY go.sum ./
|
|
||||||
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
COPY ./cmd ./cmd
|
|
||||||
COPY ./internal ./internal
|
|
||||||
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# Runner
|
|
||||||
FROM gcr.io/distroless/static-debian12:latest AS runner
|
|
||||||
|
|
||||||
WORKDIR /tinyauth
|
|
||||||
|
|
||||||
COPY --from=builder /tinyauth/tinyauth ./
|
|
||||||
|
|
||||||
# Since it's distroless, we need to copy the data directory from the builder stage
|
|
||||||
COPY --from=builder /tinyauth/data /data
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
VOLUME ["/data"]
|
|
||||||
|
|
||||||
ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db
|
|
||||||
|
|
||||||
ENV TINYAUTH_RESOURCESDIR=/data/resources
|
|
||||||
|
|
||||||
ENV GIN_MODE=release
|
|
||||||
|
|
||||||
ENV PATH=$PATH:/tinyauth
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["tinyauth", "healthcheck"]
|
|
||||||
|
|
||||||
ENTRYPOINT ["tinyauth"]
|
|
||||||
10
README.md
10
README.md
@@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img alt="Tinyauth" title="Tinyauth" width="96" src="assets/logo-rounded.png">
|
<img alt="Tinyauth" title="Tinyauth" width="96" src="assets/logo-rounded.png">
|
||||||
<h1>Tinyauth</h1>
|
<h1>Tinyauth</h1>
|
||||||
<p>The simplest way to protect your apps with a login screen.</p>
|
<p>The easiest way to secure your apps with a login screen.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
Tinyauth is a simple authentication middleware that adds a simple login screen or OAuth with Google, Github or any other provider to all of your apps. It supports all the popular proxies like Traefik, Nginx and Caddy.
|
Tinyauth is a simple authentication middleware that adds a simple login screen or OAuth with Google, Github and any provider to all of your docker apps. It supports all the popular proxies like Traefik, Nginx and Caddy.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ Tinyauth is a simple authentication middleware that adds a simple login screen o
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
You can easily get started with Tinyauth by following the guide in the [documentation](https://tinyauth.app/docs/getting-started). There is also an available [docker compose](./docker-compose.example.yml) file that has Traefik, Whoami and Tinyauth to demonstrate its capabilities.
|
You can easily get started with Tinyauth by following the guide in the [documentation](https://tinyauth.app/docs/getting-started.html). There is also an available [docker compose](./docker-compose.example.yml) file that has Traefik, Whoami and Tinyauth to demonstrate its capabilities.
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@ If you are still not sure if Tinyauth suits your needs you can try out the [demo
|
|||||||
|
|
||||||
You can find documentation and guides on all of the available configuration of Tinyauth in the [website](https://tinyauth.app).
|
You can find documentation and guides on all of the available configuration of Tinyauth in the [website](https://tinyauth.app).
|
||||||
|
|
||||||
If you wish to contribute to the documentation head over to the [repository](https://github.com/steveiliop56/tinyauth-docs).
|
|
||||||
|
|
||||||
## Discord
|
## Discord
|
||||||
|
|
||||||
Tinyauth has a [discord](https://discord.gg/eHzVaCzRRd) server. Feel free to hop in to chat about self-hosting, homelabs and of course Tinyauth. See you there!
|
Tinyauth has a [discord](https://discord.gg/eHzVaCzRRd) server. Feel free to hop in to chat about self-hosting, homelabs and of course Tinyauth. See you there!
|
||||||
@@ -55,7 +53,7 @@ Tinyauth is licensed under the GNU General Public License v3.0. TL;DR — You ma
|
|||||||
|
|
||||||
A big thank you to the following people for providing me with more coffee:
|
A big thank you to the following people for providing me with more coffee:
|
||||||
|
|
||||||
<!-- sponsors --><a href="https://github.com/erwinkramer"><img src="https://github.com/erwinkramer.png" width="64px" alt="User avatar: erwinkramer" /></a> <a href="https://github.com/nicotsx"><img src="https://github.com/nicotsx.png" width="64px" alt="User avatar: nicotsx" /></a> <a href="https://github.com/SimpleHomelab"><img src="https://github.com/SimpleHomelab.png" width="64px" alt="User avatar: SimpleHomelab" /></a> <a href="https://github.com/jmadden91"><img src="https://github.com/jmadden91.png" width="64px" alt="User avatar: jmadden91" /></a> <a href="https://github.com/tribor"><img src="https://github.com/tribor.png" width="64px" alt="User avatar: tribor" /></a> <a href="https://github.com/eliasbenb"><img src="https://github.com/eliasbenb.png" width="64px" alt="User avatar: eliasbenb" /></a> <a href="https://github.com/afunworm"><img src="https://github.com/afunworm.png" width="64px" alt="User avatar: afunworm" /></a> <a href="https://github.com/chip-well"><img src="https://github.com/chip-well.png" width="64px" alt="User avatar: chip-well" /></a> <a href="https://github.com/Lancelot-Enguerrand"><img src="https://github.com/Lancelot-Enguerrand.png" width="64px" alt="User avatar: Lancelot-Enguerrand" /></a> <a href="https://github.com/allgoewer"><img src="https://github.com/allgoewer.png" width="64px" alt="User avatar: allgoewer" /></a> <!-- sponsors -->
|
<!-- sponsors --><a href="https://github.com/erwinkramer"><img src="https://github.com/erwinkramer.png" width="64px" alt="User avatar: erwinkramer" /></a> <a href="https://github.com/nicotsx"><img src="https://github.com/nicotsx.png" width="64px" alt="User avatar: nicotsx" /></a> <a href="https://github.com/SimpleHomelab"><img src="https://github.com/SimpleHomelab.png" width="64px" alt="User avatar: SimpleHomelab" /></a> <a href="https://github.com/jmadden91"><img src="https://github.com/jmadden91.png" width="64px" alt="User avatar: jmadden91" /></a> <a href="https://github.com/tribor"><img src="https://github.com/tribor.png" width="64px" alt="User avatar: tribor" /></a> <a href="https://github.com/eliasbenb"><img src="https://github.com/eliasbenb.png" width="64px" alt="User avatar: eliasbenb" /></a> <a href="https://github.com/afunworm"><img src="https://github.com/afunworm.png" width="64px" alt="User avatar: afunworm" /></a> <!-- sponsors -->
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
|
|||||||
7
air.toml
7
air.toml
@@ -2,10 +2,9 @@ root = "/tinyauth"
|
|||||||
tmp_dir = "tmp"
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
pre_cmd = ["mkdir -p internal/assets/dist", "mkdir -p /data", "echo 'backend running' > internal/assets/dist/index.html"]
|
pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"]
|
||||||
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ./cmd/tinyauth"
|
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ."
|
||||||
bin = "tmp/tinyauth"
|
bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue --check-go-version=false"
|
||||||
full_bin = "dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue --check-go-version=false"
|
|
||||||
include_ext = ["go"]
|
include_ext = ["go"]
|
||||||
exclude_dir = ["internal/assets/dist"]
|
exclude_dir = ["internal/assets/dist"]
|
||||||
exclude_regex = [".*_test\\.go"]
|
exclude_regex = [".*_test\\.go"]
|
||||||
|
|||||||
116
cmd/root.go
Normal file
116
cmd/root.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
totpCmd "tinyauth/cmd/totp"
|
||||||
|
userCmd "tinyauth/cmd/user"
|
||||||
|
"tinyauth/internal/bootstrap"
|
||||||
|
"tinyauth/internal/config"
|
||||||
|
"tinyauth/internal/utils"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "tinyauth",
|
||||||
|
Short: "The simplest way to protect your apps with a login screen.",
|
||||||
|
Long: `Tinyauth is a simple authentication middleware that adds simple username/password login or OAuth with Google, Github and any generic OAuth provider to all of your docker apps.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
var conf config.Config
|
||||||
|
|
||||||
|
err := viper.Unmarshal(&conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to parse config")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate config
|
||||||
|
v := validator.New()
|
||||||
|
|
||||||
|
err = v.Struct(conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Invalid config")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logger = log.Level(zerolog.Level(utils.GetLogLevel(conf.LogLevel)))
|
||||||
|
log.Info().Str("version", strings.TrimSpace(config.Version)).Msg("Starting tinyauth")
|
||||||
|
|
||||||
|
// Create bootstrap app
|
||||||
|
app := bootstrap.NewBootstrapApp(conf)
|
||||||
|
|
||||||
|
// Run
|
||||||
|
err = app.Setup()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to setup app")
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
rootCmd.FParseErrWhitelist.UnknownFlags = true
|
||||||
|
err := rootCmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to execute command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(userCmd.UserCmd())
|
||||||
|
rootCmd.AddCommand(totpCmd.TotpCmd())
|
||||||
|
|
||||||
|
viper.AutomaticEnv()
|
||||||
|
|
||||||
|
configOptions := []struct {
|
||||||
|
name string
|
||||||
|
defaultVal any
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{"port", 3000, "Port to run the server on."},
|
||||||
|
{"address", "0.0.0.0", "Address to bind the server to."},
|
||||||
|
{"app-url", "", "The Tinyauth URL."},
|
||||||
|
{"users", "", "Comma separated list of users in the format username:hash."},
|
||||||
|
{"users-file", "", "Path to a file containing users in the format username:hash."},
|
||||||
|
{"secure-cookie", false, "Send cookie over secure connection only."},
|
||||||
|
{"oauth-whitelist", "", "Comma separated list of email addresses to whitelist when using OAuth."},
|
||||||
|
{"oauth-auto-redirect", "none", "Auto redirect to the specified OAuth provider if configured. (available providers: github, google, generic)"},
|
||||||
|
{"session-expiry", 86400, "Session (cookie) expiration time in seconds."},
|
||||||
|
{"login-timeout", 300, "Login timeout in seconds after max retries reached (0 to disable)."},
|
||||||
|
{"login-max-retries", 5, "Maximum login attempts before timeout (0 to disable)."},
|
||||||
|
{"log-level", "info", "Log level."},
|
||||||
|
{"app-title", "Tinyauth", "Title of the app."},
|
||||||
|
{"forgot-password-message", "", "Message to show on the forgot password page."},
|
||||||
|
{"background-image", "/background.jpg", "Background image URL for the login page."},
|
||||||
|
{"ldap-address", "", "LDAP server address (e.g. ldap://localhost:389)."},
|
||||||
|
{"ldap-bind-dn", "", "LDAP bind DN (e.g. uid=user,dc=example,dc=com)."},
|
||||||
|
{"ldap-bind-password", "", "LDAP bind password."},
|
||||||
|
{"ldap-base-dn", "", "LDAP base DN (e.g. dc=example,dc=com)."},
|
||||||
|
{"ldap-insecure", false, "Skip certificate verification for the LDAP server."},
|
||||||
|
{"ldap-search-filter", "(uid=%s)", "LDAP search filter for user lookup."},
|
||||||
|
{"resources-dir", "/data/resources", "Path to a directory containing custom resources (e.g. background image)."},
|
||||||
|
{"database-path", "/data/tinyauth.db", "Path to the Sqlite database file."},
|
||||||
|
{"trusted-proxies", "", "Comma separated list of trusted proxies (IP addresses or CIDRs) for correct client IP detection."},
|
||||||
|
{"disable-analytics", false, "Disable anonymous version collection."},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range configOptions {
|
||||||
|
switch v := opt.defaultVal.(type) {
|
||||||
|
case bool:
|
||||||
|
rootCmd.Flags().Bool(opt.name, v, opt.description)
|
||||||
|
case int:
|
||||||
|
rootCmd.Flags().Int(opt.name, v, opt.description)
|
||||||
|
case string:
|
||||||
|
rootCmd.Flags().String(opt.name, v, opt.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create uppercase env var name
|
||||||
|
envVar := strings.ReplaceAll(strings.ToUpper(opt.name), "-", "_")
|
||||||
|
viper.BindEnv(opt.name, envVar)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.BindPFlags(rootCmd.Flags())
|
||||||
|
}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreateUserConfig struct {
|
|
||||||
Interactive bool `description:"Create a user interactively."`
|
|
||||||
Docker bool `description:"Format output for docker."`
|
|
||||||
Username string `description:"Username."`
|
|
||||||
Password string `description:"Password."`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCreateUserConfig() *CreateUserConfig {
|
|
||||||
return &CreateUserConfig{
|
|
||||||
Interactive: false,
|
|
||||||
Docker: false,
|
|
||||||
Username: "",
|
|
||||||
Password: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createUserCmd() *cli.Command {
|
|
||||||
tCfg := NewCreateUserConfig()
|
|
||||||
|
|
||||||
loaders := []cli.ResourceLoader{
|
|
||||||
&cli.FlagLoader{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "create",
|
|
||||||
Description: "Create a user",
|
|
||||||
Configuration: tCfg,
|
|
||||||
Resources: loaders,
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
|
|
||||||
|
|
||||||
if tCfg.Interactive {
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("username cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("password cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
huh.NewSelect[bool]().Title("Format the output for Docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&tCfg.Docker),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
var baseTheme *huh.Theme = huh.ThemeBase()
|
|
||||||
|
|
||||||
err := form.WithTheme(baseTheme).Run()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to run interactive prompt: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tCfg.Username == "" || tCfg.Password == "" {
|
|
||||||
return errors.New("username and password cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("username", tCfg.Username).Msg("Creating user")
|
|
||||||
|
|
||||||
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to hash password: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If docker format is enabled, escape the dollar sign
|
|
||||||
passwdStr := string(passwd)
|
|
||||||
if tCfg.Docker {
|
|
||||||
passwdStr = strings.ReplaceAll(passwdStr, "$", "$$")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("user", fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)).Msg("User created")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/utils"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
"github.com/mdp/qrterminal/v3"
|
|
||||||
"github.com/pquerna/otp/totp"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GenerateTotpConfig struct {
|
|
||||||
Interactive bool `description:"Generate a TOTP secret interactively."`
|
|
||||||
User string `description:"Your current user (username:hash)."`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGenerateTotpConfig() *GenerateTotpConfig {
|
|
||||||
return &GenerateTotpConfig{
|
|
||||||
Interactive: false,
|
|
||||||
User: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateTotpCmd() *cli.Command {
|
|
||||||
tCfg := NewGenerateTotpConfig()
|
|
||||||
|
|
||||||
loaders := []cli.ResourceLoader{
|
|
||||||
&cli.FlagLoader{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "generate",
|
|
||||||
Description: "Generate a TOTP secret",
|
|
||||||
Configuration: tCfg,
|
|
||||||
Resources: loaders,
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
|
|
||||||
|
|
||||||
if tCfg.Interactive {
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().Title("Current user (username:hash)").Value(&tCfg.User).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("user cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
var baseTheme *huh.Theme = huh.ThemeBase()
|
|
||||||
|
|
||||||
err := form.WithTheme(baseTheme).Run()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to run interactive prompt: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := utils.ParseUser(tCfg.User)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse user: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
docker := false
|
|
||||||
if strings.Contains(tCfg.User, "$$") {
|
|
||||||
docker = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.TotpSecret != "" {
|
|
||||||
return fmt.Errorf("user already has a TOTP secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := totp.Generate(totp.GenerateOpts{
|
|
||||||
Issuer: "Tinyauth",
|
|
||||||
AccountName: user.Username,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to generate TOTP secret: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := key.Secret()
|
|
||||||
|
|
||||||
log.Info().Str("secret", secret).Msg("Generated TOTP secret")
|
|
||||||
|
|
||||||
log.Info().Msg("Generated QR code")
|
|
||||||
|
|
||||||
config := qrterminal.Config{
|
|
||||||
Level: qrterminal.L,
|
|
||||||
Writer: os.Stdout,
|
|
||||||
BlackChar: qrterminal.BLACK,
|
|
||||||
WhiteChar: qrterminal.WHITE,
|
|
||||||
QuietZone: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
qrterminal.GenerateWithConfig(key.URL(), config)
|
|
||||||
|
|
||||||
user.TotpSecret = secret
|
|
||||||
|
|
||||||
// If using docker escape re-escape it
|
|
||||||
if docker {
|
|
||||||
user.Password = strings.ReplaceAll(user.Password, "$", "$$")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("user", fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TotpSecret)).Msg("Add the totp secret to your authenticator app then use the verify command to ensure everything is working correctly.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
type healthzResponse struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func healthcheckCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "healthcheck",
|
|
||||||
Description: "Perform a health check",
|
|
||||||
Configuration: nil,
|
|
||||||
Resources: nil,
|
|
||||||
AllowArg: true,
|
|
||||||
Run: func(args []string) error {
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
|
|
||||||
|
|
||||||
appUrl := os.Getenv("TINYAUTH_APPURL")
|
|
||||||
|
|
||||||
if len(args) > 0 {
|
|
||||||
appUrl = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if appUrl == "" {
|
|
||||||
return errors.New("TINYAUTH_APPURL is not set and no argument was provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("app_url", appUrl).Msg("Performing health check")
|
|
||||||
|
|
||||||
client := http.Client{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", appUrl+"/api/healthz", nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to perform request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("service is not healthy, got: %s", resp.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var healthResp healthzResponse
|
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(body, &healthResp)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Interface("response", healthResp).Msg("Tinyauth is healthy")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/bootstrap"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/utils/loaders"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTinyauthCmdConfiguration() *config.Config {
|
|
||||||
return &config.Config{
|
|
||||||
LogLevel: "info",
|
|
||||||
ResourcesDir: "./resources",
|
|
||||||
DatabasePath: "./tinyauth.db",
|
|
||||||
Server: config.ServerConfig{
|
|
||||||
Port: 3000,
|
|
||||||
Address: "0.0.0.0",
|
|
||||||
},
|
|
||||||
Auth: config.AuthConfig{
|
|
||||||
SessionExpiry: 3600,
|
|
||||||
LoginTimeout: 300,
|
|
||||||
LoginMaxRetries: 3,
|
|
||||||
},
|
|
||||||
UI: config.UIConfig{
|
|
||||||
Title: "Tinyauth",
|
|
||||||
ForgotPasswordMessage: "You can change your password by changing the configuration.",
|
|
||||||
BackgroundImage: "/background.jpg",
|
|
||||||
},
|
|
||||||
Ldap: config.LdapConfig{
|
|
||||||
Insecure: false,
|
|
||||||
SearchFilter: "(uid=%s)",
|
|
||||||
},
|
|
||||||
Experimental: config.ExperimentalConfig{
|
|
||||||
ConfigFile: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tConfig := NewTinyauthCmdConfiguration()
|
|
||||||
|
|
||||||
loaders := []cli.ResourceLoader{
|
|
||||||
&loaders.FileLoader{},
|
|
||||||
&loaders.FlagLoader{},
|
|
||||||
&loaders.EnvLoader{},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdTinyauth := &cli.Command{
|
|
||||||
Name: "tinyauth",
|
|
||||||
Description: "The simplest way to protect your apps with a login screen.",
|
|
||||||
Configuration: tConfig,
|
|
||||||
Resources: loaders,
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
return runCmd(*tConfig)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := cmdTinyauth.AddCommand(versionCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to add version command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(verifyUserCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to add verify command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(healthcheckCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to add healthcheck command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(generateTotpCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to add generate command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(createUserCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to add create command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cli.Execute(cmdTinyauth)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to execute command")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCmd(cfg config.Config) error {
|
|
||||||
logLevel, err := zerolog.ParseLevel(strings.ToLower(cfg.LogLevel))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Invalid or missing log level, defaulting to info")
|
|
||||||
} else {
|
|
||||||
zerolog.SetGlobalLevel(logLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Logger = log.With().Caller().Logger()
|
|
||||||
|
|
||||||
if !cfg.LogJSON {
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("version", config.Version).Msg("Starting tinyauth")
|
|
||||||
|
|
||||||
app := bootstrap.NewBootstrapApp(cfg)
|
|
||||||
|
|
||||||
err = app.Setup()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to bootstrap app: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/utils"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
"github.com/pquerna/otp/totp"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type VerifyUserConfig struct {
|
|
||||||
Interactive bool `description:"Validate a user interactively."`
|
|
||||||
Username string `description:"Username."`
|
|
||||||
Password string `description:"Password."`
|
|
||||||
Totp string `description:"TOTP code."`
|
|
||||||
User string `description:"Hash (username:hash:totp)."`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewVerifyUserConfig() *VerifyUserConfig {
|
|
||||||
return &VerifyUserConfig{
|
|
||||||
Interactive: false,
|
|
||||||
Username: "",
|
|
||||||
Password: "",
|
|
||||||
Totp: "",
|
|
||||||
User: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyUserCmd() *cli.Command {
|
|
||||||
tCfg := NewVerifyUserConfig()
|
|
||||||
|
|
||||||
loaders := []cli.ResourceLoader{
|
|
||||||
&cli.FlagLoader{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "verify",
|
|
||||||
Description: "Verify a user is set up correctly.",
|
|
||||||
Configuration: tCfg,
|
|
||||||
Resources: loaders,
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
|
|
||||||
|
|
||||||
if tCfg.Interactive {
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().Title("User (username:hash:totp)").Value(&tCfg.User).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("user cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("username cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate((func(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return errors.New("password cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})),
|
|
||||||
huh.NewInput().Title("TOTP Code (optional)").Value(&tCfg.Totp),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
var baseTheme *huh.Theme = huh.ThemeBase()
|
|
||||||
|
|
||||||
err := form.WithTheme(baseTheme).Run()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to run interactive prompt: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := utils.ParseUser(tCfg.User)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse user: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.Username != tCfg.Username {
|
|
||||||
return fmt.Errorf("username is incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(tCfg.Password))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("password is incorrect: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.TotpSecret == "" {
|
|
||||||
if tCfg.Totp != "" {
|
|
||||||
log.Warn().Msg("User does not have TOTP secret")
|
|
||||||
}
|
|
||||||
log.Info().Msg("User verified")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := totp.Validate(tCfg.Totp, user.TotpSecret)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("TOTP code incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Msg("User verified")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
|
||||||
|
|
||||||
"github.com/traefik/paerser/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func versionCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "version",
|
|
||||||
Description: "Print the version number of Tinyauth.",
|
|
||||||
Configuration: nil,
|
|
||||||
Resources: nil,
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
fmt.Printf("Version: %s\n", config.Version)
|
|
||||||
fmt.Printf("Commit Hash: %s\n", config.CommitHash)
|
|
||||||
fmt.Printf("Build Timestamp: %s\n", config.BuildTimestamp)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
99
cmd/totp/generate/generate.go
Normal file
99
cmd/totp/generate/generate.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package generate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"tinyauth/internal/utils"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/mdp/qrterminal/v3"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var interactive bool
|
||||||
|
|
||||||
|
// Input user
|
||||||
|
var iUser string
|
||||||
|
|
||||||
|
var GenerateCmd = &cobra.Command{
|
||||||
|
Use: "generate",
|
||||||
|
Short: "Generate a totp secret",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
log.Logger = log.Level(zerolog.InfoLevel)
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewInput().Title("Current username:hash").Value(&iUser).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("user cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var baseTheme *huh.Theme = huh.ThemeBase()
|
||||||
|
err := form.WithTheme(baseTheme).Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Form failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := utils.ParseUser(iUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to parse user")
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerEscape := false
|
||||||
|
if strings.Contains(iUser, "$$") {
|
||||||
|
dockerEscape = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.TotpSecret != "" {
|
||||||
|
log.Fatal().Msg("User already has a totp secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
|
Issuer: "Tinyauth",
|
||||||
|
AccountName: user.Username,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to generate totp secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := key.Secret()
|
||||||
|
|
||||||
|
log.Info().Str("secret", secret).Msg("Generated totp secret")
|
||||||
|
|
||||||
|
log.Info().Msg("Generated QR code")
|
||||||
|
|
||||||
|
config := qrterminal.Config{
|
||||||
|
Level: qrterminal.L,
|
||||||
|
Writer: os.Stdout,
|
||||||
|
BlackChar: qrterminal.BLACK,
|
||||||
|
WhiteChar: qrterminal.WHITE,
|
||||||
|
QuietZone: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
qrterminal.GenerateWithConfig(key.URL(), config)
|
||||||
|
|
||||||
|
user.TotpSecret = secret
|
||||||
|
|
||||||
|
// If using docker escape re-escape it
|
||||||
|
if dockerEscape {
|
||||||
|
user.Password = strings.ReplaceAll(user.Password, "$", "$$")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Str("user", fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TotpSecret)).Msg("Add the totp secret to your authenticator app then use the verify command to ensure everything is working correctly.")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
GenerateCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Run in interactive mode")
|
||||||
|
GenerateCmd.Flags().StringVar(&iUser, "user", "", "Your current username:hash")
|
||||||
|
}
|
||||||
17
cmd/totp/totp.go
Normal file
17
cmd/totp/totp.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tinyauth/cmd/totp/generate"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TotpCmd() *cobra.Command {
|
||||||
|
totpCmd := &cobra.Command{
|
||||||
|
Use: "totp",
|
||||||
|
Short: "Totp utilities",
|
||||||
|
Long: `Utilities for creating and verifying totp codes.`,
|
||||||
|
}
|
||||||
|
totpCmd.AddCommand(generate.GenerateCmd)
|
||||||
|
return totpCmd
|
||||||
|
}
|
||||||
80
cmd/user/create/create.go
Normal file
80
cmd/user/create/create.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package create
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var interactive bool
|
||||||
|
var docker bool
|
||||||
|
|
||||||
|
// i stands for input
|
||||||
|
var iUsername string
|
||||||
|
var iPassword string
|
||||||
|
|
||||||
|
var CreateCmd = &cobra.Command{
|
||||||
|
Use: "create",
|
||||||
|
Short: "Create a user",
|
||||||
|
Long: `Create a user either interactively or by passing flags.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
log.Logger = log.Level(zerolog.InfoLevel)
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewInput().Title("Username").Value(&iUsername).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("username cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
huh.NewInput().Title("Password").Value(&iPassword).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("password cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
huh.NewSelect[bool]().Title("Format the output for docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&docker),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var baseTheme *huh.Theme = huh.ThemeBase()
|
||||||
|
err := form.WithTheme(baseTheme).Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Form failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iUsername == "" || iPassword == "" {
|
||||||
|
log.Fatal().Err(errors.New("error invalid input")).Msg("Username and password cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Str("username", iUsername).Str("password", iPassword).Bool("docker", docker).Msg("Creating user")
|
||||||
|
|
||||||
|
password, err := bcrypt.GenerateFromPassword([]byte(iPassword), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to hash password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If docker format is enabled, escape the dollar sign
|
||||||
|
passwordString := string(password)
|
||||||
|
if docker {
|
||||||
|
passwordString = strings.ReplaceAll(passwordString, "$", "$$")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Str("user", fmt.Sprintf("%s:%s", iUsername, passwordString)).Msg("User created")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
CreateCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Create a user interactively")
|
||||||
|
CreateCmd.Flags().BoolVar(&docker, "docker", false, "Format output for docker")
|
||||||
|
CreateCmd.Flags().StringVar(&iUsername, "username", "", "Username")
|
||||||
|
CreateCmd.Flags().StringVar(&iPassword, "password", "", "Password")
|
||||||
|
}
|
||||||
19
cmd/user/user.go
Normal file
19
cmd/user/user.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tinyauth/cmd/user/create"
|
||||||
|
"tinyauth/cmd/user/verify"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UserCmd() *cobra.Command {
|
||||||
|
userCmd := &cobra.Command{
|
||||||
|
Use: "user",
|
||||||
|
Short: "User utilities",
|
||||||
|
Long: `Utilities for creating and verifying tinyauth compatible users.`,
|
||||||
|
}
|
||||||
|
userCmd.AddCommand(create.CreateCmd)
|
||||||
|
userCmd.AddCommand(verify.VerifyCmd)
|
||||||
|
return userCmd
|
||||||
|
}
|
||||||
101
cmd/user/verify/verify.go
Normal file
101
cmd/user/verify/verify.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package verify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"tinyauth/internal/utils"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var interactive bool
|
||||||
|
var docker bool
|
||||||
|
|
||||||
|
// i stands for input
|
||||||
|
var iUsername string
|
||||||
|
var iPassword string
|
||||||
|
var iTotp string
|
||||||
|
var iUser string
|
||||||
|
|
||||||
|
var VerifyCmd = &cobra.Command{
|
||||||
|
Use: "verify",
|
||||||
|
Short: "Verify a user is set up correctly",
|
||||||
|
Long: `Verify a user is set up correctly meaning that it has a correct username, password and totp code.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
log.Logger = log.Level(zerolog.InfoLevel)
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewInput().Title("User (username:hash:totp)").Value(&iUser).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("user cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
huh.NewInput().Title("Username").Value(&iUsername).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("username cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
huh.NewInput().Title("Password").Value(&iPassword).Validate((func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("password cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})),
|
||||||
|
huh.NewInput().Title("Totp Code (if setup)").Value(&iTotp),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var baseTheme *huh.Theme = huh.ThemeBase()
|
||||||
|
err := form.WithTheme(baseTheme).Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Form failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := utils.ParseUser(iUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to parse user")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Username != iUsername {
|
||||||
|
log.Fatal().Msg("Username is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(iPassword))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Msg("Ppassword is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.TotpSecret == "" {
|
||||||
|
if iTotp != "" {
|
||||||
|
log.Warn().Msg("User does not have 2fa secret")
|
||||||
|
}
|
||||||
|
log.Info().Msg("User verified")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := totp.Validate(iTotp, user.TotpSecret)
|
||||||
|
if !ok {
|
||||||
|
log.Fatal().Msg("Totp code incorrect")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Msg("User verified")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
VerifyCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Create a user interactively")
|
||||||
|
VerifyCmd.Flags().BoolVar(&docker, "docker", false, "Is the user formatted for docker?")
|
||||||
|
VerifyCmd.Flags().StringVar(&iUsername, "username", "", "Username")
|
||||||
|
VerifyCmd.Flags().StringVar(&iPassword, "password", "", "Password")
|
||||||
|
VerifyCmd.Flags().StringVar(&iTotp, "totp", "", "Totp code")
|
||||||
|
VerifyCmd.Flags().StringVar(&iUser, "user", "", "Hash (username:hash:totp combination)")
|
||||||
|
}
|
||||||
23
cmd/version.go
Normal file
23
cmd/version.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"tinyauth/internal/config"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var versionCmd = &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print the version number of Tinyauth",
|
||||||
|
Long: `All software has versions. This is Tinyauth's`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Version: %s\n", config.Version)
|
||||||
|
fmt.Printf("Commit Hash: %s\n", config.CommitHash)
|
||||||
|
fmt.Printf("Build Timestamp: %s\n", config.BuildTimestamp)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(versionCmd)
|
||||||
|
}
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
# Tinyauth Example Configuration
|
|
||||||
|
|
||||||
# The base URL where Tinyauth is accessible
|
|
||||||
appUrl: "https://auth.example.com"
|
|
||||||
# Log level: trace, debug, info, warn, error
|
|
||||||
logLevel: "info"
|
|
||||||
# Directory for static resources
|
|
||||||
resourcesDir: "./resources"
|
|
||||||
# Path to SQLite database file
|
|
||||||
databasePath: "./tinyauth.db"
|
|
||||||
# Disable usage analytics
|
|
||||||
disableAnalytics: false
|
|
||||||
# Disable static resource serving
|
|
||||||
disableResources: false
|
|
||||||
# Disable UI warning messages
|
|
||||||
disableUIWarnings: false
|
|
||||||
# Enable JSON formatted logs
|
|
||||||
logJSON: false
|
|
||||||
|
|
||||||
# Server Configuration
|
|
||||||
server:
|
|
||||||
# Port to listen on
|
|
||||||
port: 3000
|
|
||||||
# Interface to bind to (0.0.0.0 for all interfaces)
|
|
||||||
address: "0.0.0.0"
|
|
||||||
# Unix socket path (optional, overrides port/address if set)
|
|
||||||
socketPath: ""
|
|
||||||
# Comma-separated list of trusted proxy IPs/CIDRs
|
|
||||||
trustedProxies: ""
|
|
||||||
|
|
||||||
# Authentication Configuration
|
|
||||||
auth:
|
|
||||||
# Format: username:bcrypt_hash (use bcrypt to generate hash)
|
|
||||||
users: "admin:$2a$10$example_bcrypt_hash_here"
|
|
||||||
# Path to external users file (optional)
|
|
||||||
usersFile: ""
|
|
||||||
# Enable secure cookies (requires HTTPS)
|
|
||||||
secureCookie: false
|
|
||||||
# Session expiry in seconds (3600 = 1 hour)
|
|
||||||
sessionExpiry: 3600
|
|
||||||
# Login timeout in seconds (300 = 5 minutes)
|
|
||||||
loginTimeout: 300
|
|
||||||
# Maximum login retries before lockout
|
|
||||||
loginMaxRetries: 3
|
|
||||||
|
|
||||||
# OAuth Configuration
|
|
||||||
oauth:
|
|
||||||
# Regex pattern for allowed email addresses (e.g., /@example\.com$/)
|
|
||||||
whitelist: ""
|
|
||||||
# Provider ID to auto-redirect to (skips login page)
|
|
||||||
autoRedirect: ""
|
|
||||||
# OAuth Provider Configuration (replace myprovider with your provider name)
|
|
||||||
providers:
|
|
||||||
myprovider:
|
|
||||||
clientId: "your_client_id_here"
|
|
||||||
clientSecret: "your_client_secret_here"
|
|
||||||
authUrl: "https://provider.example.com/oauth/authorize"
|
|
||||||
tokenUrl: "https://provider.example.com/oauth/token"
|
|
||||||
userInfoUrl: "https://provider.example.com/oauth/userinfo"
|
|
||||||
redirectUrl: "https://auth.example.com/api/oauth/callback/myprovider"
|
|
||||||
scopes: "openid email profile"
|
|
||||||
name: "My OAuth Provider"
|
|
||||||
# Allow insecure connections (self-signed certificates)
|
|
||||||
insecure: false
|
|
||||||
|
|
||||||
# UI Customization
|
|
||||||
ui:
|
|
||||||
# Custom title for login page
|
|
||||||
title: "Tinyauth"
|
|
||||||
# Message shown on forgot password page
|
|
||||||
forgotPasswordMessage: "Contact your administrator to reset your password"
|
|
||||||
# Background image URL for login page
|
|
||||||
backgroundImage: ""
|
|
||||||
|
|
||||||
# LDAP Configuration (optional)
|
|
||||||
ldap:
|
|
||||||
# LDAP server address
|
|
||||||
address: "ldap://ldap.example.com:389"
|
|
||||||
# DN for binding to LDAP server
|
|
||||||
bindDn: "cn=readonly,dc=example,dc=com"
|
|
||||||
# Password for bind DN
|
|
||||||
bindPassword: "your_bind_password"
|
|
||||||
# Base DN for user searches
|
|
||||||
baseDn: "dc=example,dc=com"
|
|
||||||
# Search filter (%s will be replaced with username)
|
|
||||||
searchFilter: "(&(uid=%s)(memberOf=cn=users,ou=groups,dc=example,dc=com))"
|
|
||||||
# Allow insecure LDAP connections
|
|
||||||
insecure: false
|
|
||||||
@@ -34,14 +34,11 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.dev
|
dockerfile: Dockerfile.dev
|
||||||
args:
|
|
||||||
- VERSION=development
|
|
||||||
- COMMIT_HASH=development
|
|
||||||
- BUILD_TIMESTAMP=000-00-00T00:00:00Z
|
|
||||||
env_file: .env
|
env_file: .env
|
||||||
volumes:
|
volumes:
|
||||||
- ./internal:/tinyauth/internal
|
- ./internal:/tinyauth/internal
|
||||||
- ./cmd:/tinyauth/cmd
|
- ./cmd:/tinyauth/cmd
|
||||||
|
- ./main.go:/tinyauth/main.go
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ./data:/data
|
- ./data:/data
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ services:
|
|||||||
container_name: tinyauth
|
container_name: tinyauth
|
||||||
image: ghcr.io/steveiliop56/tinyauth:v3
|
image: ghcr.io/steveiliop56/tinyauth:v3
|
||||||
environment:
|
environment:
|
||||||
- TINYAUTH_APPURL=https://tinyauth.example.com
|
- APP_URL=https://tinyauth.example.com
|
||||||
- TINYAUTH_AUTH_USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
|
- USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/data
|
- ./data:/data
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,54 +1,52 @@
|
|||||||
{
|
{
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"configVersion": 0,
|
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "tinyauth-shadcn",
|
"name": "tinyauth-shadcn",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.13",
|
||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.89.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.12.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^25.7.3",
|
"i18next": "^25.5.2",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"i18next-resources-to-backend": "^1.2.1",
|
"i18next-resources-to-backend": "^1.2.1",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.562.0",
|
"lucide-react": "^0.544.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.3",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.1.1",
|
||||||
"react-hook-form": "^7.68.0",
|
"react-hook-form": "^7.62.0",
|
||||||
"react-i18next": "^16.5.0",
|
"react-i18next": "^15.7.3",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router": "^7.11.0",
|
"react-router": "^7.9.1",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.1.13",
|
||||||
"zod": "^4.2.1",
|
"zod": "^4.1.9",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.35.0",
|
||||||
"@tanstack/eslint-plugin-query": "^5.91.2",
|
"@tanstack/eslint-plugin-query": "^5.89.0",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^24.5.2",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.1.13",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.1.9",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.0.3",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.35.0",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.26",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.5.0",
|
"globals": "^16.4.0",
|
||||||
"prettier": "3.7.4",
|
"prettier": "3.6.2",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.3.8",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.2",
|
||||||
"typescript-eslint": "^8.50.0",
|
"typescript-eslint": "^8.44.0",
|
||||||
"vite": "^7.3.0",
|
"vite": "^7.1.6",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -57,9 +55,9 @@
|
|||||||
|
|
||||||
"@babel/compat-data": ["@babel/compat-data@7.27.2", "", {}, "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ=="],
|
"@babel/compat-data": ["@babel/compat-data@7.27.2", "", {}, "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ=="],
|
||||||
|
|
||||||
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@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-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
|
"@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=="],
|
||||||
|
|
||||||
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
|
"@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=="],
|
||||||
|
|
||||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||||
|
|
||||||
@@ -85,83 +83,81 @@
|
|||||||
|
|
||||||
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
||||||
|
|
||||||
"@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
|
"@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="],
|
||||||
|
|
||||||
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||||
|
|
||||||
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
|
"@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=="],
|
||||||
|
|
||||||
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
|
"@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=="],
|
||||||
|
|
||||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||||
|
|
||||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
|
||||||
|
|
||||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="],
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="],
|
||||||
|
|
||||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="],
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="],
|
||||||
|
|
||||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="],
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="],
|
||||||
|
|
||||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="],
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="],
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="],
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="],
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="],
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="],
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="],
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="],
|
||||||
|
|
||||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="],
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="],
|
||||||
|
|
||||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="],
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="],
|
||||||
|
|
||||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="],
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="],
|
||||||
|
|
||||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="],
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="],
|
||||||
|
|
||||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="],
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="],
|
||||||
|
|
||||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="],
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="],
|
||||||
|
|
||||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="],
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="],
|
||||||
|
|
||||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="],
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="],
|
||||||
|
|
||||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="],
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="],
|
||||||
|
|
||||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="],
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="],
|
||||||
|
|
||||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="],
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="],
|
||||||
|
|
||||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="],
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="],
|
||||||
|
|
||||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="],
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
|
||||||
|
|
||||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
|
|
||||||
|
|
||||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
|
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
|
||||||
|
|
||||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
||||||
|
|
||||||
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="],
|
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
|
||||||
|
|
||||||
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
|
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
|
||||||
|
|
||||||
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
|
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
|
||||||
|
|
||||||
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
|
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
|
||||||
|
|
||||||
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="],
|
"@eslint/js": ["@eslint/js@9.35.0", "", {}, "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw=="],
|
||||||
|
|
||||||
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
|
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
|
||||||
|
|
||||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
|
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
|
||||||
|
|
||||||
"@floating-ui/core": ["@floating-ui/core@1.7.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA=="],
|
"@floating-ui/core": ["@floating-ui/core@1.7.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA=="],
|
||||||
|
|
||||||
@@ -181,6 +177,8 @@
|
|||||||
|
|
||||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||||
|
|
||||||
|
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||||
|
|
||||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
|
||||||
|
|
||||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||||
@@ -215,33 +213,25 @@
|
|||||||
|
|
||||||
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||||
|
|
||||||
"@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||||
|
|
||||||
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
|
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
|
||||||
|
|
||||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||||
|
|
||||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
|
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||||
|
|
||||||
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
|
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
|
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
|
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||||
|
|
||||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
|
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||||
|
|
||||||
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
|
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
|
||||||
|
|
||||||
@@ -263,7 +253,7 @@
|
|||||||
|
|
||||||
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
|
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
|
||||||
|
|
||||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="],
|
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.35", "", {}, "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg=="],
|
||||||
|
|
||||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="],
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="],
|
||||||
|
|
||||||
@@ -307,41 +297,41 @@
|
|||||||
|
|
||||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
||||||
|
|
||||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="],
|
"@tailwindcss/node": ["@tailwindcss/node@4.1.13", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.5.1", "lightningcss": "1.30.1", "magic-string": "^0.30.18", "source-map-js": "^1.2.1", "tailwindcss": "4.1.13" } }, "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="],
|
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.13", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.13", "@tailwindcss/oxide-darwin-arm64": "4.1.13", "@tailwindcss/oxide-darwin-x64": "4.1.13", "@tailwindcss/oxide-freebsd-x64": "4.1.13", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13", "@tailwindcss/oxide-linux-arm64-musl": "4.1.13", "@tailwindcss/oxide-linux-x64-gnu": "4.1.13", "@tailwindcss/oxide-linux-x64-musl": "4.1.13", "@tailwindcss/oxide-wasm32-wasi": "4.1.13", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13", "@tailwindcss/oxide-win32-x64-msvc": "4.1.13" } }, "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="],
|
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.13", "", { "os": "android", "cpu": "arm64" }, "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="],
|
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="],
|
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="],
|
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.13", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="],
|
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13", "", { "os": "linux", "cpu": "arm" }, "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="],
|
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="],
|
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="],
|
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.13", "", { "os": "linux", "cpu": "x64" }, "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="],
|
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.13", "", { "os": "linux", "cpu": "x64" }, "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="],
|
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.13", "", { "dependencies": { "@emnapi/core": "^1.4.5", "@emnapi/runtime": "^1.4.5", "@emnapi/wasi-threads": "^1.0.4", "@napi-rs/wasm-runtime": "^0.2.12", "@tybys/wasm-util": "^0.10.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="],
|
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="],
|
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.13", "", { "os": "win32", "cpu": "x64" }, "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw=="],
|
||||||
|
|
||||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
|
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.13", "", { "dependencies": { "@tailwindcss/node": "4.1.13", "@tailwindcss/oxide": "4.1.13", "tailwindcss": "4.1.13" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ=="],
|
||||||
|
|
||||||
"@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.89.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.37.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-vz8TEuw9GO0xXIdreMpcofvOY17T3cjgob9bSFln8yQsKsbsUvtpvV3F8pVC3tZEDq0IwO++3/e0/+7YKEarNA=="],
|
||||||
|
|
||||||
"@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.89.0", "", {}, "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q=="],
|
||||||
|
|
||||||
"@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.89.0", "", { "dependencies": { "@tanstack/query-core": "5.89.0" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
@@ -365,37 +355,37 @@
|
|||||||
|
|
||||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
|
"@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
|
"@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
"@types/react-dom": ["@types/react-dom@19.1.9", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/type-utils": "8.44.0", "@typescript-eslint/utils": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.44.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/types": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.44.0", "@typescript-eslint/types": "^8.44.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA=="],
|
||||||
|
|
||||||
"@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.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0" } }, "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0", "@typescript-eslint/utils": "8.44.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-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg=="],
|
||||||
|
|
||||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="],
|
"@typescript-eslint/types": ["@typescript-eslint/types@8.43.0", "", {}, "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.44.0", "@typescript-eslint/tsconfig-utils": "8.44.0", "@typescript-eslint/types": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0", "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-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw=="],
|
||||||
|
|
||||||
"@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.43.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw=="],
|
||||||
|
|
||||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="],
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.0.3", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.35", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
@@ -411,7 +401,7 @@
|
|||||||
|
|
||||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||||
|
|
||||||
"axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="],
|
"axios": ["axios@1.12.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw=="],
|
||||||
|
|
||||||
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
||||||
|
|
||||||
@@ -441,6 +431,8 @@
|
|||||||
|
|
||||||
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
|
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
|
||||||
|
|
||||||
|
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
||||||
|
|
||||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||||
@@ -461,7 +453,7 @@
|
|||||||
|
|
||||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||||
|
|
||||||
@@ -493,17 +485,17 @@
|
|||||||
|
|
||||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||||
|
|
||||||
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
"esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
|
||||||
|
|
||||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||||
|
|
||||||
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
|
"eslint": ["eslint@9.35.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.35.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="],
|
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
|
||||||
|
|
||||||
"eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.26", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ=="],
|
"eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.20", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA=="],
|
||||||
|
|
||||||
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
|
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
|
||||||
|
|
||||||
@@ -563,12 +555,14 @@
|
|||||||
|
|
||||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||||
|
|
||||||
"globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="],
|
"globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="],
|
||||||
|
|
||||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||||
|
|
||||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
|
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
||||||
|
|
||||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||||
|
|
||||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||||
@@ -581,15 +575,11 @@
|
|||||||
|
|
||||||
"hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
|
"hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
|
||||||
|
|
||||||
"hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
|
|
||||||
|
|
||||||
"hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
|
|
||||||
|
|
||||||
"html-parse-stringify": ["html-parse-stringify@3.0.1", "", { "dependencies": { "void-elements": "3.1.0" } }, "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg=="],
|
"html-parse-stringify": ["html-parse-stringify@3.0.1", "", { "dependencies": { "void-elements": "3.1.0" } }, "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg=="],
|
||||||
|
|
||||||
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
|
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
|
||||||
|
|
||||||
"i18next": ["i18next@25.7.3", "", { "dependencies": { "@babel/runtime": "^7.28.4" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-2XaT+HpYGuc2uTExq9TVRhLsso+Dxym6PWaKpn36wfBmTI779OQ7iP/XaZHzrnGyzU4SHpFrTYLKfVyBfAhVNA=="],
|
"i18next": ["i18next@25.5.2", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw=="],
|
||||||
|
|
||||||
"i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="],
|
"i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="],
|
||||||
|
|
||||||
@@ -643,29 +633,27 @@
|
|||||||
|
|
||||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||||
|
|
||||||
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
|
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
||||||
|
|
||||||
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
|
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
||||||
|
|
||||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
|
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
|
||||||
|
|
||||||
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
|
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
|
||||||
|
|
||||||
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
|
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
|
||||||
|
|
||||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
|
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
|
||||||
|
|
||||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
|
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
|
||||||
|
|
||||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
|
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
|
||||||
|
|
||||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
|
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
|
||||||
|
|
||||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
|
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
|
||||||
|
|
||||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
|
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
||||||
|
|
||||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
|
|
||||||
|
|
||||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||||
|
|
||||||
@@ -675,9 +663,9 @@
|
|||||||
|
|
||||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||||
|
|
||||||
"lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="],
|
"lucide-react": ["lucide-react@0.544.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw=="],
|
||||||
|
|
||||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
"magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
|
||||||
|
|
||||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
@@ -749,6 +737,12 @@
|
|||||||
|
|
||||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||||
|
|
||||||
|
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
|
|
||||||
|
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
||||||
|
|
||||||
|
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
@@ -781,7 +775,7 @@
|
|||||||
|
|
||||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||||
|
|
||||||
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
|
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||||
|
|
||||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||||
|
|
||||||
@@ -791,23 +785,23 @@
|
|||||||
|
|
||||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
|
|
||||||
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
||||||
|
|
||||||
"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.1.1", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw=="],
|
||||||
|
|
||||||
"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.62.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA=="],
|
||||||
|
|
||||||
"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@15.7.3", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 25.4.1", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw=="],
|
||||||
|
|
||||||
"react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
|
"react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
|
||||||
|
|
||||||
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
|
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||||
|
|
||||||
"react-remove-scroll": ["react-remove-scroll@2.6.3", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ=="],
|
"react-remove-scroll": ["react-remove-scroll@2.6.3", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ=="],
|
||||||
|
|
||||||
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
|
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
|
||||||
|
|
||||||
"react-router": ["react-router@7.11.0", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ=="],
|
"react-router": ["react-router@7.9.1", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-pfAByjcTpX55mqSDGwGnY9vDCpxqBLASg0BMNAuMmpSGESo/TaOUG6BllhAtAkCGx8Rnohik/XtaqiYUJtgW2g=="],
|
||||||
|
|
||||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||||
|
|
||||||
@@ -823,7 +817,7 @@
|
|||||||
|
|
||||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
|
||||||
|
|
||||||
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
@@ -849,12 +843,14 @@
|
|||||||
|
|
||||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
|
|
||||||
"tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="],
|
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
|
"tailwindcss": ["tailwindcss@4.1.13", "", {}, "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w=="],
|
||||||
|
|
||||||
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
||||||
|
|
||||||
|
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||||
|
|
||||||
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||||
|
|
||||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
@@ -867,15 +863,15 @@
|
|||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
|
"tw-animate-css": ["tw-animate-css@1.3.8", "", {}, "sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw=="],
|
||||||
|
|
||||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||||
|
|
||||||
"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.44.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.44.0", "@typescript-eslint/parser": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0", "@typescript-eslint/utils": "8.44.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
"undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
|
||||||
|
|
||||||
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
||||||
|
|
||||||
@@ -897,13 +893,11 @@
|
|||||||
|
|
||||||
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
|
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
|
||||||
|
|
||||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
|
||||||
|
|
||||||
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||||
|
|
||||||
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
|
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
|
||||||
|
|
||||||
"vite": ["vite@7.3.0", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg=="],
|
"vite": ["vite@7.1.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ=="],
|
||||||
|
|
||||||
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
|
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
|
||||||
|
|
||||||
@@ -911,19 +905,17 @@
|
|||||||
|
|
||||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||||
|
|
||||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||||
|
|
||||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||||
|
|
||||||
"zod": ["zod@4.2.1", "", {}, "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw=="],
|
"zod": ["zod@4.1.9", "", {}, "sha512-HI32jTq0AUAC125z30E8bQNz0RQ+9Uc+4J7V97gLYjZVKRjeydPgGt6dvQzFrav7MYOUGFqqOGiHpA/fdbd0cQ=="],
|
||||||
|
|
||||||
"zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
|
|
||||||
|
|
||||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||||
|
|
||||||
"@babel/core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
"@babel/generator/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
||||||
|
|
||||||
"@babel/generator/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
"@babel/generator/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse": ["@babel/traverse@7.27.1", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg=="],
|
"@babel/helper-module-imports/@babel/traverse": ["@babel/traverse@7.27.1", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg=="],
|
||||||
|
|
||||||
@@ -931,18 +923,10 @@
|
|||||||
|
|
||||||
"@babel/helper-module-transforms/@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="],
|
"@babel/helper-module-transforms/@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="],
|
||||||
|
|
||||||
"@babel/helpers/@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=="],
|
|
||||||
|
|
||||||
"@babel/parser/@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=="],
|
|
||||||
|
|
||||||
"@babel/template/@babel/parser": ["@babel/parser@7.27.2", "", { "dependencies": { "@babel/types": "^7.27.1" }, "bin": "./bin/babel-parser.js" }, "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw=="],
|
"@babel/template/@babel/parser": ["@babel/parser@7.27.2", "", { "dependencies": { "@babel/types": "^7.27.1" }, "bin": "./bin/babel-parser.js" }, "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw=="],
|
||||||
|
|
||||||
"@babel/template/@babel/types": ["@babel/types@7.27.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q=="],
|
"@babel/template/@babel/types": ["@babel/types@7.27.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q=="],
|
||||||
|
|
||||||
"@babel/traverse/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
|
||||||
|
|
||||||
"@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
|
||||||
|
|
||||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||||
|
|
||||||
"@eslint/eslintrc/espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="],
|
"@eslint/eslintrc/espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="],
|
||||||
@@ -955,29 +939,17 @@
|
|||||||
|
|
||||||
"@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
"@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
"@tailwindcss/node/jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="],
|
||||||
|
|
||||||
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" }, "bundled": true }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="],
|
||||||
|
|
||||||
"@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="],
|
||||||
|
|
||||||
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="],
|
||||||
|
|
||||||
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
|
||||||
|
|
||||||
"@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="],
|
||||||
|
|
||||||
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.0", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
@@ -995,37 +967,33 @@
|
|||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0" } }, "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/types": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0" } }, "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/types": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
"@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": ["@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.43.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.43.0", "@typescript-eslint/tsconfig-utils": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "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-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"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/zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],
|
|
||||||
|
|
||||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
@@ -1035,11 +1003,13 @@
|
|||||||
|
|
||||||
"i18next-resources-to-backend/@babel/runtime": ["@babel/runtime@7.27.1", "", {}, "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog=="],
|
"i18next-resources-to-backend/@babel/runtime": ["@babel/runtime@7.27.1", "", {}, "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog=="],
|
||||||
|
|
||||||
|
"lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||||
|
|
||||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
"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.44.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/types": "8.44.0", "@typescript-eslint/typescript-estree": "8.44.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
@@ -1047,8 +1017,6 @@
|
|||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
"@babel/helper-module-imports/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||||
|
|
||||||
"@babel/helper-module-transforms/@babel/traverse/@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=="],
|
|
||||||
|
|
||||||
"@babel/helper-module-transforms/@babel/traverse/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
"@babel/helper-module-transforms/@babel/traverse/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
||||||
|
|
||||||
"@babel/helper-module-transforms/@babel/traverse/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
"@babel/helper-module-transforms/@babel/traverse/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||||
@@ -1057,33 +1025,27 @@
|
|||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"@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.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0" } }, "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.1", "@typescript-eslint/types": "^8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.43.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.43.0", "@typescript-eslint/types": "^8.43.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.43.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@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/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
"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=="],
|
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.44.0", "", { "dependencies": { "@typescript-eslint/types": "8.44.0", "@typescript-eslint/visitor-keys": "8.44.0" } }, "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA=="],
|
||||||
|
|
||||||
"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=="],
|
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.44.0", "", {}, "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA=="],
|
||||||
|
|
||||||
"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/types": ["@typescript-eslint/types@8.50.0", "", {}, "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w=="],
|
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
@@ -1091,10 +1053,6 @@
|
|||||||
|
|
||||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core/@babel/generator/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
|
||||||
|
|
||||||
"eslint-plugin-react-hooks/@babel/core/@babel/generator/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
|
||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||||
|
|
||||||
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
"@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||||
|
|||||||
@@ -8,11 +8,10 @@
|
|||||||
<link rel="shortcut icon" href="/favicon.ico" />
|
<link rel="shortcut icon" href="/favicon.ico" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Tinyauth" />
|
<meta name="apple-mobile-web-app-title" content="Tinyauth" />
|
||||||
<meta name="robots" content="nofollow, noindex" />
|
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<title>Tinyauth</title>
|
<title>Tinyauth</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="dark">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "tinyauth",
|
"name": "tinyauth-shadcn",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -7,53 +7,51 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview"
|
||||||
"tsc": "tsc -b"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.13",
|
||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.89.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.12.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^25.7.3",
|
"i18next": "^25.5.2",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"i18next-resources-to-backend": "^1.2.1",
|
"i18next-resources-to-backend": "^1.2.1",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.562.0",
|
"lucide-react": "^0.544.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.3",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.1.1",
|
||||||
"react-hook-form": "^7.68.0",
|
"react-hook-form": "^7.62.0",
|
||||||
"react-i18next": "^16.5.0",
|
"react-i18next": "^15.7.3",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router": "^7.11.0",
|
"react-router": "^7.9.1",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.1.13",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.1.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.35.0",
|
||||||
"@tanstack/eslint-plugin-query": "^5.91.2",
|
"@tanstack/eslint-plugin-query": "^5.89.0",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^24.5.2",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.1.13",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.1.9",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.0.3",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.35.0",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.26",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.5.0",
|
"globals": "^16.4.0",
|
||||||
"prettier": "3.7.4",
|
"prettier": "3.6.2",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.3.8",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.2",
|
||||||
"typescript-eslint": "^8.50.0",
|
"typescript-eslint": "^8.44.0",
|
||||||
"vite": "^7.3.0"
|
"vite": "^7.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,6 @@ export const TotpForm = (props: Props) => {
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
{...field}
|
{...field}
|
||||||
autoComplete="one-time-code"
|
autoComplete="one-time-code"
|
||||||
autoFocus
|
|
||||||
>
|
>
|
||||||
<InputOTPGroup>
|
<InputOTPGroup>
|
||||||
<InputOTPSlot index={0} />
|
<InputOTPSlot index={0} />
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ export const LanguageSelector = () => {
|
|||||||
setLanguage(option as SupportedLanguage);
|
setLanguage(option as SupportedLanguage);
|
||||||
i18n.changeLanguage(option as SupportedLanguage);
|
i18n.changeLanguage(option as SupportedLanguage);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select onValueChange={handleSelect} value={language}>
|
<Select onValueChange={handleSelect} value={language}>
|
||||||
<SelectTrigger>
|
<SelectTrigger className="absolute top-5 right-5">
|
||||||
<SelectValue placeholder="Select language" />
|
<SelectValue placeholder="Select language" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { useAppContext } from "@/context/app-context";
|
import { useAppContext } from "@/context/app-context";
|
||||||
import { LanguageSelector } from "../language/language";
|
import { LanguageSelector } from "../language/language";
|
||||||
import { Outlet } from "react-router";
|
import { Outlet } from "react-router";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { DomainWarning } from "../domain-warning/domain-warning";
|
import { DomainWarning } from "../domain-warning/domain-warning";
|
||||||
import { ThemeToggle } from "../theme-toggle/theme-toggle";
|
|
||||||
|
|
||||||
const BaseLayout = ({ children }: { children: React.ReactNode }) => {
|
const BaseLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
const { backgroundImage, title } = useAppContext();
|
const { backgroundImage } = useAppContext();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = title;
|
|
||||||
}, [title]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -21,17 +16,14 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
backgroundPosition: "center",
|
backgroundPosition: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="absolute top-5 right-5 flex flex-row gap-2">
|
<LanguageSelector />
|
||||||
<ThemeToggle />
|
|
||||||
<LanguageSelector />
|
|
||||||
</div>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Layout = () => {
|
export const Layout = () => {
|
||||||
const { appUrl, disableUiWarnings } = useAppContext();
|
const { appUrl } = useAppContext();
|
||||||
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
|
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
|
||||||
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
|
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
|
||||||
});
|
});
|
||||||
@@ -42,7 +34,7 @@ export const Layout = () => {
|
|||||||
setIgnoreDomainWarning(true);
|
setIgnoreDomainWarning(true);
|
||||||
}, [setIgnoreDomainWarning]);
|
}, [setIgnoreDomainWarning]);
|
||||||
|
|
||||||
if (!ignoreDomainWarning && !disableUiWarnings && appUrl !== currentUrl) {
|
if (!ignoreDomainWarning && appUrl !== currentUrl) {
|
||||||
return (
|
return (
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
<DomainWarning
|
<DomainWarning
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import { createContext, useContext, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
type Theme = "dark" | "light" | "system";
|
|
||||||
|
|
||||||
type ThemeProviderProps = {
|
|
||||||
children: React.ReactNode;
|
|
||||||
defaultTheme?: Theme;
|
|
||||||
storageKey?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ThemeProviderState = {
|
|
||||||
theme: Theme;
|
|
||||||
setTheme: (theme: Theme) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialState: ThemeProviderState = {
|
|
||||||
theme: "system",
|
|
||||||
setTheme: () => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
|
|
||||||
|
|
||||||
export function ThemeProvider({
|
|
||||||
children,
|
|
||||||
defaultTheme = "system",
|
|
||||||
storageKey = "vite-ui-theme",
|
|
||||||
...props
|
|
||||||
}: ThemeProviderProps) {
|
|
||||||
const [theme, setTheme] = useState<Theme>(
|
|
||||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const root = window.document.documentElement;
|
|
||||||
|
|
||||||
root.classList.remove("light", "dark");
|
|
||||||
|
|
||||||
if (theme === "system") {
|
|
||||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
|
||||||
.matches
|
|
||||||
? "dark"
|
|
||||||
: "light";
|
|
||||||
|
|
||||||
root.classList.add(systemTheme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
root.classList.add(theme);
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
const value = {
|
|
||||||
theme,
|
|
||||||
setTheme: (theme: Theme) => {
|
|
||||||
localStorage.setItem(storageKey, theme);
|
|
||||||
setTheme(theme);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ThemeProviderContext.Provider {...props} value={value}>
|
|
||||||
{children}
|
|
||||||
</ThemeProviderContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useTheme = () => {
|
|
||||||
const context = useContext(ThemeProviderContext);
|
|
||||||
|
|
||||||
if (context === undefined)
|
|
||||||
throw new Error("useTheme must be used within a ThemeProvider");
|
|
||||||
|
|
||||||
return context;
|
|
||||||
};
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import { Moon, Sun } from "lucide-react";
|
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
} from "@/components/ui/dropdown-menu";
|
|
||||||
import { useTheme } from "@/components/providers/theme-provider";
|
|
||||||
|
|
||||||
export function ThemeToggle() {
|
|
||||||
const { setTheme } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button
|
|
||||||
className="bg-card text-card-foreground hover:bg-card/90"
|
|
||||||
size="icon"
|
|
||||||
>
|
|
||||||
<Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
|
|
||||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
|
|
||||||
<span className="sr-only">Toggle theme</span>
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
<DropdownMenuItem onClick={() => setTheme("light")}>
|
|
||||||
Light
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => setTheme("dark")}>
|
|
||||||
Dark
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => setTheme("system")}>
|
|
||||||
System
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive hover:cursor-pointer",
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
|
|||||||
@@ -1,255 +0,0 @@
|
|||||||
import * as React from "react"
|
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
|
||||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
|
|
||||||
function DropdownMenu({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
||||||
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuPortal({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuTrigger({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Trigger
|
|
||||||
data-slot="dropdown-menu-trigger"
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuContent({
|
|
||||||
className,
|
|
||||||
sideOffset = 4,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Portal>
|
|
||||||
<DropdownMenuPrimitive.Content
|
|
||||||
data-slot="dropdown-menu-content"
|
|
||||||
sideOffset={sideOffset}
|
|
||||||
className={cn(
|
|
||||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</DropdownMenuPrimitive.Portal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuGroup({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuItem({
|
|
||||||
className,
|
|
||||||
inset,
|
|
||||||
variant = "default",
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
||||||
inset?: boolean
|
|
||||||
variant?: "default" | "destructive"
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Item
|
|
||||||
data-slot="dropdown-menu-item"
|
|
||||||
data-inset={inset}
|
|
||||||
data-variant={variant}
|
|
||||||
className={cn(
|
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuCheckboxItem({
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
checked,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.CheckboxItem
|
|
||||||
data-slot="dropdown-menu-checkbox-item"
|
|
||||||
className={cn(
|
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
checked={checked}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
|
||||||
<CheckIcon className="size-4" />
|
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
|
||||||
</span>
|
|
||||||
{children}
|
|
||||||
</DropdownMenuPrimitive.CheckboxItem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuRadioGroup({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.RadioGroup
|
|
||||||
data-slot="dropdown-menu-radio-group"
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuRadioItem({
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.RadioItem
|
|
||||||
data-slot="dropdown-menu-radio-item"
|
|
||||||
className={cn(
|
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
|
||||||
<CircleIcon className="size-2 fill-current" />
|
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
|
||||||
</span>
|
|
||||||
{children}
|
|
||||||
</DropdownMenuPrimitive.RadioItem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuLabel({
|
|
||||||
className,
|
|
||||||
inset,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
||||||
inset?: boolean
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Label
|
|
||||||
data-slot="dropdown-menu-label"
|
|
||||||
data-inset={inset}
|
|
||||||
className={cn(
|
|
||||||
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuSeparator({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.Separator
|
|
||||||
data-slot="dropdown-menu-separator"
|
|
||||||
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuShortcut({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<"span">) {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
data-slot="dropdown-menu-shortcut"
|
|
||||||
className={cn(
|
|
||||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuSub({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
||||||
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuSubTrigger({
|
|
||||||
className,
|
|
||||||
inset,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
||||||
inset?: boolean
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
|
||||||
data-slot="dropdown-menu-sub-trigger"
|
|
||||||
data-inset={inset}
|
|
||||||
className={cn(
|
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
<ChevronRightIcon className="ml-auto size-4" />
|
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropdownMenuSubContent({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
||||||
return (
|
|
||||||
<DropdownMenuPrimitive.SubContent
|
|
||||||
data-slot="dropdown-menu-sub-content"
|
|
||||||
className={cn(
|
|
||||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuPortal,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuGroup,
|
|
||||||
DropdownMenuLabel,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuCheckboxItem,
|
|
||||||
DropdownMenuRadioGroup,
|
|
||||||
DropdownMenuRadioItem,
|
|
||||||
DropdownMenuSeparator,
|
|
||||||
DropdownMenuShortcut,
|
|
||||||
DropdownMenuSub,
|
|
||||||
DropdownMenuSubTrigger,
|
|
||||||
DropdownMenuSubContent,
|
|
||||||
}
|
|
||||||
@@ -35,7 +35,7 @@ function SelectTrigger({
|
|||||||
data-slot="select-trigger"
|
data-slot="select-trigger"
|
||||||
data-size={size}
|
data-size={size}
|
||||||
className={cn(
|
className={cn(
|
||||||
"hover:cursor-pointer border-input data-[placeholder]:text-card-foreground [&_svg:not([class*='text-'])]:text-card-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border bg-card hover:bg-card/90 px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-card dark:hover:bg-card/90 flex w-fit items-center justify-between gap-2 rounded-md border bg-card hover:bg-card/90 px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useTheme } from "../providers/theme-provider";
|
import { useTheme } from "next-themes";
|
||||||
import { Toaster as Sonner, ToasterProps } from "sonner";
|
import { Toaster as Sonner, ToasterProps } from "sonner";
|
||||||
|
|
||||||
const Toaster = ({ ...props }: ToasterProps) => {
|
const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme = "system" } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sonner
|
<Sonner
|
||||||
|
|||||||
15
frontend/src/lib/hooks/use-is-mounted.ts
Normal file
15
frontend/src/lib/hooks/use-is-mounted.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
export function useIsMounted(): () => boolean {
|
||||||
|
const isMounted = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
isMounted.current = true;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMounted.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return useCallback(() => isMounted.current, []);
|
||||||
|
}
|
||||||
@@ -14,11 +14,12 @@ i18n
|
|||||||
.init({
|
.init({
|
||||||
fallbackLng: "en",
|
fallbackLng: "en",
|
||||||
debug: import.meta.env.MODE === "development",
|
debug: import.meta.env.MODE === "development",
|
||||||
nonExplicitSupportedLngs: true,
|
|
||||||
load: "currentOnly",
|
interpolation: {
|
||||||
detection: {
|
escapeValue: false,
|
||||||
lookupLocalStorage: "tinyauth-lang",
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
load: "currentOnly",
|
||||||
});
|
});
|
||||||
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export const languages = {
|
|||||||
"nl-NL": "Nederlands",
|
"nl-NL": "Nederlands",
|
||||||
"no-NO": "Norsk",
|
"no-NO": "Norsk",
|
||||||
"pl-PL": "Polski",
|
"pl-PL": "Polski",
|
||||||
"pt-BR": "Português (Brasil)",
|
"pt-BR": "Português",
|
||||||
"pt-PT": "Português (Portugal)",
|
"pt-PT": "Português",
|
||||||
"ro-RO": "Română",
|
"ro-RO": "Română",
|
||||||
"ru-RU": "Русский",
|
"ru-RU": "Русский",
|
||||||
"sr-SP": "Српски",
|
"sr-SP": "Српски",
|
||||||
@@ -28,7 +28,7 @@ export const languages = {
|
|||||||
"uk-UA": "Українська",
|
"uk-UA": "Українська",
|
||||||
"vi-VN": "Tiếng Việt",
|
"vi-VN": "Tiếng Việt",
|
||||||
"zh-CN": "简体中文",
|
"zh-CN": "简体中文",
|
||||||
"zh-TW": "繁體中文",
|
"zh-TW": "繁體中文(台灣)",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SupportedLanguage = keyof typeof languages;
|
export type SupportedLanguage = keyof typeof languages;
|
||||||
|
|||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "أخفق الحصول على رابط OAuth",
|
"loginOauthFailSubtitle": "أخفق الحصول على رابط OAuth",
|
||||||
"loginOauthSuccessTitle": "إعادة توجيه",
|
"loginOauthSuccessTitle": "إعادة توجيه",
|
||||||
"loginOauthSuccessSubtitle": "إعادة توجيه إلى مزود OAuth الخاص بك",
|
"loginOauthSuccessSubtitle": "إعادة توجيه إلى مزود OAuth الخاص بك",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "متابعة",
|
|
||||||
"continueRedirectingTitle": "إعادة توجيه...",
|
"continueRedirectingTitle": "إعادة توجيه...",
|
||||||
"continueRedirectingSubtitle": "يجب إعادة توجيهك إلى التطبيق قريبا",
|
"continueRedirectingSubtitle": "يجب إعادة توجيهك إلى التطبيق قريبا",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "إعادة توجيه غير صالحة",
|
||||||
|
"continueInvalidRedirectSubtitle": "رابط إعادة التوجيه غير صالح",
|
||||||
"continueInsecureRedirectTitle": "إعادة توجيه غير آمنة",
|
"continueInsecureRedirectTitle": "إعادة توجيه غير آمنة",
|
||||||
"continueInsecureRedirectSubtitle": "أنت تحاول إعادة التوجيه من <code>https</code> إلى <code>http</code>، هل أنت متأكد أنك تريد المتابعة؟",
|
"continueInsecureRedirectSubtitle": "أنت تحاول إعادة التوجيه من <code>https</code> إلى <code>http</code>، هل أنت متأكد أنك تريد المتابعة؟",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "متابعة",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "انقر الزر للمتابعة إلى التطبيق الخاص بك.",
|
||||||
"logoutFailTitle": "فشل تسجيل الخروج",
|
"logoutFailTitle": "فشل تسجيل الخروج",
|
||||||
"logoutFailSubtitle": "يرجى إعادة المحاولة",
|
"logoutFailSubtitle": "يرجى إعادة المحاولة",
|
||||||
"logoutSuccessTitle": "تم تسجيل الخروج",
|
"logoutSuccessTitle": "تم تسجيل الخروج",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "حاول مجددا",
|
"unauthorizedButton": "حاول مجددا",
|
||||||
|
"untrustedRedirectTitle": "إعادة توجيه غير موثوقة",
|
||||||
|
"untrustedRedirectSubtitle": "أنت تحاول إعادة التوجيه إلى نطاق لا يتطابق مع النطاق المكون الخاص بك (<code>{{domain}}</code>). هل أنت متأكد من أنك تريد المتابعة؟",
|
||||||
"cancelTitle": "إلغاء",
|
"cancelTitle": "إلغاء",
|
||||||
"forgotPasswordTitle": "نسيت كلمة المرور؟",
|
"forgotPasswordTitle": "نسيت كلمة المرور؟",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "تجاهل",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -1,62 +1,57 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "Vítejte zpět, přihlaste se pomocí",
|
"loginTitle": "Welcome back, login with",
|
||||||
"loginTitleSimple": "Vítejte zpět, přihlaste se prosím",
|
"loginTitleSimple": "Welcome back, please login",
|
||||||
"loginDivider": "Nebo",
|
"loginDivider": "Or",
|
||||||
"loginUsername": "Uživatelské jméno",
|
"loginUsername": "Username",
|
||||||
"loginPassword": "Heslo",
|
"loginPassword": "Password",
|
||||||
"loginSubmit": "Přihlásit",
|
"loginSubmit": "Login",
|
||||||
"loginFailTitle": "Přihlášení se nezdařilo",
|
"loginFailTitle": "Failed to log in",
|
||||||
"loginFailSubtitle": "Zkontrolujte prosím své uživatelské jméno a heslo",
|
"loginFailSubtitle": "Please check your username and password",
|
||||||
"loginFailRateLimit": "Přiliš mnoho neúspěšných pokusů přihlášení. Zkuste to prosím později",
|
"loginFailRateLimit": "You failed to login too many times. Please try again later",
|
||||||
"loginSuccessTitle": "Přihlášen",
|
"loginSuccessTitle": "Logged in",
|
||||||
"loginSuccessSubtitle": "Vítejte zpět!",
|
"loginSuccessSubtitle": "Welcome back!",
|
||||||
"loginOauthFailTitle": "Došlo k chybě",
|
"loginOauthFailTitle": "An error occurred",
|
||||||
"loginOauthFailSubtitle": "Nepodařilo se získat OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Přesměrování",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Přesměrování k poskytovateli OAuth",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
"continueTitle": "Pokračovat",
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueRedirectingTitle": "Přesměrování...",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueRedirectingSubtitle": "Brzy budete přesměrováni do aplikace",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueTitle": "Continue",
|
||||||
"continueInsecureRedirectTitle": "Nezabezpečené přesměrování",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"continueInsecureRedirectSubtitle": "Pokoušíte se přesměrovat z <code>https</code> na <code>http</code>, které není bezpečné. Opravdu chcete pokračovat?",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"logoutSuccessTitle": "Logged out",
|
||||||
"logoutFailTitle": "Odhlášení se nezdařilo",
|
"logoutSuccessSubtitle": "You have been logged out",
|
||||||
"logoutFailSubtitle": "Zkuste to prosím znovu",
|
"logoutTitle": "Logout",
|
||||||
"logoutSuccessTitle": "Odhlášen",
|
"logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.",
|
||||||
"logoutSuccessSubtitle": "Byl jste odhlášen",
|
"logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.",
|
||||||
"logoutTitle": "Odhlásit",
|
"notFoundTitle": "Page not found",
|
||||||
"logoutUsernameSubtitle": "Jste přihlášen jako <code>{{username}}</code>. Pro odhlášení klikněte na tlačítko níže.",
|
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||||
"logoutOauthSubtitle": "Jste přihlášen jako <code>{{username}}</code> pomocí {{provider}} poskytovatele OAuth. Pro odhlášení klikněte na tlačítko níže.",
|
"notFoundButton": "Go home",
|
||||||
"notFoundTitle": "Stránka nenalezena",
|
"totpFailTitle": "Failed to verify code",
|
||||||
"notFoundSubtitle": "Stránka, kterou hledáte, neexistuje.",
|
"totpFailSubtitle": "Please check your code and try again",
|
||||||
"notFoundButton": "Jít domů",
|
"totpSuccessTitle": "Verified",
|
||||||
"totpFailTitle": "Nepodařilo se ověřit kód",
|
"totpSuccessSubtitle": "Redirecting to your app",
|
||||||
"totpFailSubtitle": "Zkontrolujte prosím kód a zkuste to znovu",
|
"totpTitle": "Enter your TOTP code",
|
||||||
"totpSuccessTitle": "Ověřeno",
|
"totpSubtitle": "Please enter the code from your authenticator app.",
|
||||||
"totpSuccessSubtitle": "Přesměrování do aplikace",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"totpTitle": "Zadejte TOTP kód",
|
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"totpSubtitle": "Zadejte prosím kód z ověřovací aplikace.",
|
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
|
||||||
"unauthorizedTitle": "Nepovoleno",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedResourceSubtitle": "Uživatel s uživatelským jménem <code>{{username}}</code> není oprávněn k přístupu ke zdroji <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "Uživatel s uživatelským jménem <code>{{username}}</code> není oprávněn k přihlášení.",
|
"unauthorizedButton": "Try again",
|
||||||
"unauthorizedGroupsSubtitle": "Uživatel s uživatelským jménem <code>{{username}}</code> není ve skupině potřebné k přístupu ke zdroji <code>{{resource}}</code>.",
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
"unauthorizedIpSubtitle": "Vaše IP adresa <code>{{ip}}</code> není oprávněna k přístupu ke zdroji <code>{{resource}}</code>.",
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"unauthorizedButton": "Zkusit znovu",
|
"cancelTitle": "Cancel",
|
||||||
"cancelTitle": "Zrušit",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"forgotPasswordTitle": "Zapomněli jste heslo?",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
"failedToFetchProvidersTitle": "Nepodařilo se načíst poskytovatele ověřování. Zkontrolujte prosím konfiguraci.",
|
"errorTitle": "An error occurred",
|
||||||
"errorTitle": "Došlo k chybě",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"errorSubtitle": "Nastala chyba při pokusu o provedení této akce. Pro více informací prosím zkontrolujte konzolu.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"forgotPasswordMessage": "Heslo můžete obnovit změnou proměnné `USERS`.",
|
"fieldRequired": "This field is required",
|
||||||
"fieldRequired": "Toto pole je povinné",
|
"invalidInput": "Invalid input"
|
||||||
"invalidInput": "Neplatný údaj",
|
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Kunne ikke hente OAuth-URL",
|
"loginOauthFailSubtitle": "Kunne ikke hente OAuth-URL",
|
||||||
"loginOauthSuccessTitle": "Omdirigerer",
|
"loginOauthSuccessTitle": "Omdirigerer",
|
||||||
"loginOauthSuccessSubtitle": "Omdirigerer til din OAuth-udbyder",
|
"loginOauthSuccessSubtitle": "Omdirigerer til din OAuth-udbyder",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Fortsæt",
|
|
||||||
"continueRedirectingTitle": "Omdirigerer...",
|
"continueRedirectingTitle": "Omdirigerer...",
|
||||||
"continueRedirectingSubtitle": "Du bør blive omdirigeret til appen snart",
|
"continueRedirectingSubtitle": "Du bør blive omdirigeret til appen snart",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Ugyldig omdirigering",
|
||||||
|
"continueInvalidRedirectSubtitle": "Omdirigerings-URL'en er ugyldig",
|
||||||
"continueInsecureRedirectTitle": "Usikker omdirigering",
|
"continueInsecureRedirectTitle": "Usikker omdirigering",
|
||||||
"continueInsecureRedirectSubtitle": "Du forsøger at omdirigere fra <code>https</code> til <code>http</code>, som ikke er sikker. Er du sikker på, at du vil fortsætte?",
|
"continueInsecureRedirectSubtitle": "Du forsøger at omdirigere fra <code>https</code> til <code>http</code>, som ikke er sikker. Er du sikker på, at du vil fortsætte?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Fortsæt",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Klik på knappen for at fortsætte til din app.",
|
||||||
"logoutFailTitle": "Log ud mislykkedes",
|
"logoutFailTitle": "Log ud mislykkedes",
|
||||||
"logoutFailSubtitle": "Prøv venligst igen",
|
"logoutFailSubtitle": "Prøv venligst igen",
|
||||||
"logoutSuccessTitle": "Logget ud",
|
"logoutSuccessTitle": "Logget ud",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "Brugeren med brugernavnet <code>{{username}}</code> er ikke i de grupper, som ressourcen <code>{{resource}}</code> kræver.",
|
"unauthorizedGroupsSubtitle": "Brugeren med brugernavnet <code>{{username}}</code> er ikke i de grupper, som ressourcen <code>{{resource}}</code> kræver.",
|
||||||
"unauthorizedIpSubtitle": "Din IP adresse <code>{{ip}}</code> er ikke autoriseret til at tilgå ressourcen <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Din IP adresse <code>{{ip}}</code> er ikke autoriseret til at tilgå ressourcen <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Prøv igen",
|
"unauthorizedButton": "Prøv igen",
|
||||||
|
"untrustedRedirectTitle": "Usikker omdirigering",
|
||||||
|
"untrustedRedirectSubtitle": "Du forsøger at omdirigere til et domæne, der ikke matcher dit konfigurerede domæne (<code>{{domain}}</code>). Er du sikker på, at du vil fortsætte?",
|
||||||
"cancelTitle": "Annuller",
|
"cancelTitle": "Annuller",
|
||||||
"forgotPasswordTitle": "Glemt din adgangskode?",
|
"forgotPasswordTitle": "Glemt din adgangskode?",
|
||||||
"failedToFetchProvidersTitle": "Kunne ikke indlæse godkendelsesudbydere. Tjek venligst din konfiguration.",
|
"failedToFetchProvidersTitle": "Kunne ikke indlæse godkendelsesudbydere. Tjek venligst din konfiguration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "Der opstod en fejl under forsøget på at udføre denne handling. Tjek venligst konsollen for mere information.",
|
"errorSubtitle": "Der opstod en fejl under forsøget på at udføre denne handling. Tjek venligst konsollen for mere information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Fehler beim Abrufen der OAuth-URL",
|
"loginOauthFailSubtitle": "Fehler beim Abrufen der OAuth-URL",
|
||||||
"loginOauthSuccessTitle": "Leite weiter",
|
"loginOauthSuccessTitle": "Leite weiter",
|
||||||
"loginOauthSuccessSubtitle": "Weiterleitung zu Ihrem OAuth-Provider",
|
"loginOauthSuccessSubtitle": "Weiterleitung zu Ihrem OAuth-Provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Weiter",
|
|
||||||
"continueRedirectingTitle": "Leite weiter...",
|
"continueRedirectingTitle": "Leite weiter...",
|
||||||
"continueRedirectingSubtitle": "Sie sollten in Kürze zur App weitergeleitet werden",
|
"continueRedirectingSubtitle": "Sie sollten in Kürze zur App weitergeleitet werden",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Ungültige Weiterleitung",
|
||||||
|
"continueInvalidRedirectSubtitle": "Die Weiterleitungs-URL ist ungültig",
|
||||||
"continueInsecureRedirectTitle": "Unsichere Weiterleitung",
|
"continueInsecureRedirectTitle": "Unsichere Weiterleitung",
|
||||||
"continueInsecureRedirectSubtitle": "Sie versuchen von <code>https</code> auf <code>http</code> weiterzuleiten, was unsicher ist. Sind Sie sicher, dass Sie fortfahren möchten?",
|
"continueInsecureRedirectSubtitle": "Sie versuchen von <code>https</code> auf <code>http</code> weiterzuleiten, was unsicher ist. Sind Sie sicher, dass Sie fortfahren möchten?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Weiter",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Klicken Sie auf den Button, um zur App zu gelangen.",
|
||||||
"logoutFailTitle": "Abmelden fehlgeschlagen",
|
"logoutFailTitle": "Abmelden fehlgeschlagen",
|
||||||
"logoutFailSubtitle": "Bitte versuchen Sie es erneut",
|
"logoutFailSubtitle": "Bitte versuchen Sie es erneut",
|
||||||
"logoutSuccessTitle": "Abgemeldet",
|
"logoutSuccessTitle": "Abgemeldet",
|
||||||
@@ -34,7 +31,7 @@
|
|||||||
"logoutOauthSubtitle": "Sie sind derzeit als <code>{{username}}</code> über den OAuth-Anbieter {{provider}} angemeldet. Klicken Sie auf den Button unten, um sich abzumelden.",
|
"logoutOauthSubtitle": "Sie sind derzeit als <code>{{username}}</code> über den OAuth-Anbieter {{provider}} angemeldet. Klicken Sie auf den Button unten, um sich abzumelden.",
|
||||||
"notFoundTitle": "Seite nicht gefunden",
|
"notFoundTitle": "Seite nicht gefunden",
|
||||||
"notFoundSubtitle": "Die gesuchte Seite existiert nicht.",
|
"notFoundSubtitle": "Die gesuchte Seite existiert nicht.",
|
||||||
"notFoundButton": "Zurück",
|
"notFoundButton": "Nach Hause",
|
||||||
"totpFailTitle": "Fehler beim Verifizieren des Codes",
|
"totpFailTitle": "Fehler beim Verifizieren des Codes",
|
||||||
"totpFailSubtitle": "Bitte überprüfen Sie Ihren Code und versuchen Sie es erneut",
|
"totpFailSubtitle": "Bitte überprüfen Sie Ihren Code und versuchen Sie es erneut",
|
||||||
"totpSuccessTitle": "Verifiziert",
|
"totpSuccessTitle": "Verifiziert",
|
||||||
@@ -47,16 +44,14 @@
|
|||||||
"unauthorizedGroupsSubtitle": "Der Benutzer mit Benutzername <code>{{username}}</code> ist nicht in den Gruppen, die von der Ressource <code>{{resource}}</code> benötigt werden.",
|
"unauthorizedGroupsSubtitle": "Der Benutzer mit Benutzername <code>{{username}}</code> ist nicht in den Gruppen, die von der Ressource <code>{{resource}}</code> benötigt werden.",
|
||||||
"unauthorizedIpSubtitle": "Ihre IP-Adresse <code>{{ip}}</code> ist nicht berechtigt, auf die Ressource <code>{{resource}}</code> zuzugreifen.",
|
"unauthorizedIpSubtitle": "Ihre IP-Adresse <code>{{ip}}</code> ist nicht berechtigt, auf die Ressource <code>{{resource}}</code> zuzugreifen.",
|
||||||
"unauthorizedButton": "Erneut versuchen",
|
"unauthorizedButton": "Erneut versuchen",
|
||||||
|
"untrustedRedirectTitle": "Nicht vertrauenswürdige Weiterleitung",
|
||||||
|
"untrustedRedirectSubtitle": "Sie versuchen auf eine Domain umzuleiten, die nicht mit Ihrer konfigurierten Domain übereinstimmt (<code>{{domain}}</code>). Sind Sie sicher, dass Sie fortfahren möchten?",
|
||||||
"cancelTitle": "Abbrechen",
|
"cancelTitle": "Abbrechen",
|
||||||
"forgotPasswordTitle": "Passwort vergessen?",
|
"forgotPasswordTitle": "Passwort vergessen?",
|
||||||
"failedToFetchProvidersTitle": "Fehler beim Laden der Authentifizierungsanbieter. Bitte überprüfen Sie Ihre Konfiguration.",
|
"failedToFetchProvidersTitle": "Fehler beim Laden der Authentifizierungsanbieter. Bitte überprüfen Sie Ihre Konfiguration.",
|
||||||
"errorTitle": "Ein Fehler ist aufgetreten",
|
"errorTitle": "Ein Fehler ist aufgetreten",
|
||||||
"errorSubtitle": "Beim Versuch, diese Aktion auszuführen, ist ein Fehler aufgetreten. Bitte überprüfen Sie die Konsole für weitere Informationen.",
|
"errorSubtitle": "Beim Versuch, diese Aktion auszuführen, ist ein Fehler aufgetreten. Bitte überprüfen Sie die Konsole für weitere Informationen.",
|
||||||
"forgotPasswordMessage": "Das Passwort kann durch Änderung der 'USERS' Variable zurückgesetzt werden.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "Dieses Feld ist notwendig",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Ungültige Eingabe",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Αποτυχία λήψης OAuth URL",
|
"loginOauthFailSubtitle": "Αποτυχία λήψης OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Ανακατεύθυνση",
|
"loginOauthSuccessTitle": "Ανακατεύθυνση",
|
||||||
"loginOauthSuccessSubtitle": "Ανακατεύθυνση στον πάροχο OAuth σας",
|
"loginOauthSuccessSubtitle": "Ανακατεύθυνση στον πάροχο OAuth σας",
|
||||||
"loginOauthAutoRedirectTitle": "Αυτόματη Ανακατεύθυνση OAuth",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "Θα ανακατευθυνθείτε αυτόματα στον πάροχο OAuth σας για να επαληθευτείτε.",
|
|
||||||
"loginOauthAutoRedirectButton": "Ανακατεύθυνση τώρα",
|
|
||||||
"continueTitle": "Συνέχεια",
|
|
||||||
"continueRedirectingTitle": "Ανακατεύθυνση...",
|
"continueRedirectingTitle": "Ανακατεύθυνση...",
|
||||||
"continueRedirectingSubtitle": "Θα πρέπει να μεταφερθείτε σύντομα στην εφαρμογή σας",
|
"continueRedirectingSubtitle": "Θα πρέπει να μεταφερθείτε σύντομα στην εφαρμογή σας",
|
||||||
"continueRedirectManually": "Χειροκίνητη ανακατεύθυνση",
|
"continueInvalidRedirectTitle": "Μη έγκυρη ανακατεύθυνση",
|
||||||
|
"continueInvalidRedirectSubtitle": "Το URL ανακατεύθυνσης δεν είναι έγκυρο",
|
||||||
"continueInsecureRedirectTitle": "Μη ασφαλής ανακατεύθυνση",
|
"continueInsecureRedirectTitle": "Μη ασφαλής ανακατεύθυνση",
|
||||||
"continueInsecureRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε από <code>https</code> σε <code>http</code> το οποίο δεν είναι ασφαλές. Είστε σίγουροι ότι θέλετε να συνεχίσετε;",
|
"continueInsecureRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε από <code>https</code> σε <code>http</code> το οποίο δεν είναι ασφαλές. Είστε σίγουροι ότι θέλετε να συνεχίσετε;",
|
||||||
"continueUntrustedRedirectTitle": "Μη έμπιστη ανακατεύθυνση",
|
"continueTitle": "Συνέχεια",
|
||||||
"continueUntrustedRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε σε ένα domain που δεν ταιριάζει με το ρυθμισμένο domain σας (<code>{{cookieDomain}}</code>). Είστε βέβαιοι ότι θέλετε να συνεχίσετε;",
|
"continueSubtitle": "Κάντε κλικ στο κουμπί για να συνεχίσετε στην εφαρμογή σας.",
|
||||||
"logoutFailTitle": "Αποτυχία αποσύνδεσης",
|
"logoutFailTitle": "Αποτυχία αποσύνδεσης",
|
||||||
"logoutFailSubtitle": "Παρακαλώ δοκιμάστε ξανά",
|
"logoutFailSubtitle": "Παρακαλώ δοκιμάστε ξανά",
|
||||||
"logoutSuccessTitle": "Αποσυνδεδεμένος",
|
"logoutSuccessTitle": "Αποσυνδεδεμένος",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "Ο χρήστης με όνομα χρήστη <code>{{username}}</code> δεν είναι στις ομάδες που απαιτούνται από τον πόρο <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "Ο χρήστης με όνομα χρήστη <code>{{username}}</code> δεν είναι στις ομάδες που απαιτούνται από τον πόρο <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Η διεύθυνση IP σας <code>{{ip}}</code> δεν είναι εξουσιοδοτημένη να έχει πρόσβαση στον πόρο <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Η διεύθυνση IP σας <code>{{ip}}</code> δεν είναι εξουσιοδοτημένη να έχει πρόσβαση στον πόρο <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Προσπαθήστε ξανά",
|
"unauthorizedButton": "Προσπαθήστε ξανά",
|
||||||
|
"untrustedRedirectTitle": "Μη έμπιστη ανακατεύθυνση",
|
||||||
|
"untrustedRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε σε ένα domain που δεν ταιριάζει με τον ρυθμισμένο domain σας (<code>{{domain}}</code>). Είστε βέβαιοι ότι θέλετε να συνεχίσετε;",
|
||||||
"cancelTitle": "Ακύρωση",
|
"cancelTitle": "Ακύρωση",
|
||||||
"forgotPasswordTitle": "Ξεχάσατε το συνθηματικό σας;",
|
"forgotPasswordTitle": "Ξεχάσατε το συνθηματικό σας;",
|
||||||
"failedToFetchProvidersTitle": "Αποτυχία φόρτωσης παρόχων πιστοποίησης. Παρακαλώ ελέγξτε τις ρυθμίσεις σας.",
|
"failedToFetchProvidersTitle": "Αποτυχία φόρτωσης παρόχων πιστοποίησης. Παρακαλώ ελέγξτε τις ρυθμίσεις σας.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια εκτέλεσης αυτής της ενέργειας. Ελέγξτε την κονσόλα για περισσότερες πληροφορίες.",
|
"errorSubtitle": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια εκτέλεσης αυτής της ενέργειας. Ελέγξτε την κονσόλα για περισσότερες πληροφορίες.",
|
||||||
"forgotPasswordMessage": "Μπορείτε να επαναφέρετε τον κωδικό πρόσβασής σας αλλάζοντας τη μεταβλητή περιβάλλοντος `USERS`.",
|
"forgotPasswordMessage": "Μπορείτε να επαναφέρετε τον κωδικό πρόσβασής σας αλλάζοντας τη μεταβλητή περιβάλλοντος `USERS`.",
|
||||||
"fieldRequired": "Αυτό το πεδίο είναι υποχρεωτικό",
|
"fieldRequired": "Αυτό το πεδίο είναι υποχρεωτικό",
|
||||||
"invalidInput": "Μη έγκυρη καταχώρηση",
|
"invalidInput": "Μη έγκυρη καταχώρηση"
|
||||||
"domainWarningTitle": "Μη έγκυρο domain",
|
|
||||||
"domainWarningSubtitle": "Αυτή η εφαρμογή έχει ρυθμιστεί για πρόσβαση από <code>{{appUrl}}</code>, αλλά <code>{{currentUrl}}</code> χρησιμοποιείται. Αν συνεχίσετε, μπορεί να αντιμετωπίσετε προβλήματα με την ταυτοποίηση.",
|
|
||||||
"ignoreTitle": "Παράβλεψη",
|
|
||||||
"goToCorrectDomainTitle": "Μεταβείτε στο σωστό domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Error al obtener la URL de OAuth",
|
"loginOauthFailSubtitle": "Error al obtener la URL de OAuth",
|
||||||
"loginOauthSuccessTitle": "Redireccionando",
|
"loginOauthSuccessTitle": "Redireccionando",
|
||||||
"loginOauthSuccessSubtitle": "Redireccionando a tu proveedor de OAuth",
|
"loginOauthSuccessSubtitle": "Redireccionando a tu proveedor de OAuth",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continuar",
|
|
||||||
"continueRedirectingTitle": "Redireccionando...",
|
"continueRedirectingTitle": "Redireccionando...",
|
||||||
"continueRedirectingSubtitle": "Pronto será redirigido a la aplicación",
|
"continueRedirectingSubtitle": "Pronto será redirigido a la aplicación",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Redirección inválida",
|
||||||
|
"continueInvalidRedirectSubtitle": "La URL de redirección es inválida",
|
||||||
"continueInsecureRedirectTitle": "Redirección insegura",
|
"continueInsecureRedirectTitle": "Redirección insegura",
|
||||||
"continueInsecureRedirectSubtitle": "Está intentando redirigir desde <code>https</code> a <code>http</code> lo cual no es seguro. ¿Está seguro que desea continuar?",
|
"continueInsecureRedirectSubtitle": "Está intentando redirigir desde <code>https</code> a <code>http</code> lo cual no es seguro. ¿Está seguro que desea continuar?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continuar",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Haga clic en el botón para continuar hacia su aplicación.",
|
||||||
"logoutFailTitle": "Fallo al cerrar sesión",
|
"logoutFailTitle": "Fallo al cerrar sesión",
|
||||||
"logoutFailSubtitle": "Por favor intente nuevamente",
|
"logoutFailSubtitle": "Por favor intente nuevamente",
|
||||||
"logoutSuccessTitle": "Sesión cerrada",
|
"logoutSuccessTitle": "Sesión cerrada",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "El usuario con nombre de usuario <code>{{username}}</code> no está en los grupos requeridos por el recurso <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "El usuario con nombre de usuario <code>{{username}}</code> no está en los grupos requeridos por el recurso <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Inténtelo de nuevo",
|
"unauthorizedButton": "Inténtelo de nuevo",
|
||||||
|
"untrustedRedirectTitle": "Redirección no confiable",
|
||||||
|
"untrustedRedirectSubtitle": "Está intentando redirigir a un dominio que no coincide con su dominio configurado (<code>{{domain}}</code>). ¿Está seguro que desea continuar?",
|
||||||
"cancelTitle": "Cancelar",
|
"cancelTitle": "Cancelar",
|
||||||
"forgotPasswordTitle": "¿Olvidó su contraseña?",
|
"forgotPasswordTitle": "¿Olvidó su contraseña?",
|
||||||
"failedToFetchProvidersTitle": "Error al cargar los proveedores de autenticación. Por favor revise su configuración.",
|
"failedToFetchProvidersTitle": "Error al cargar los proveedores de autenticación. Por favor revise su configuración.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "Ocurrió un error mientras se trataba de realizar esta acción. Por favor, revise la consola para más información.",
|
"errorSubtitle": "Ocurrió un error mientras se trataba de realizar esta acción. Por favor, revise la consola para más información.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -1,62 +1,57 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "Tervetuloa takaisin, kirjaudu sisään käyttäen",
|
"loginTitle": "Welcome back, login with",
|
||||||
"loginTitleSimple": "Tervetuloa takaisin, ole hyvä ja kirjaudu",
|
"loginTitleSimple": "Welcome back, please login",
|
||||||
"loginDivider": "Tai",
|
"loginDivider": "Or",
|
||||||
"loginUsername": "Käyttäjätunnus",
|
"loginUsername": "Username",
|
||||||
"loginPassword": "Salasana",
|
"loginPassword": "Password",
|
||||||
"loginSubmit": "Kirjaudu",
|
"loginSubmit": "Login",
|
||||||
"loginFailTitle": "Kirjautuminen epäonnistui",
|
"loginFailTitle": "Failed to log in",
|
||||||
"loginFailSubtitle": "Tarkista käyttäjätunnuksesi ja salasanasi",
|
"loginFailSubtitle": "Please check your username and password",
|
||||||
"loginFailRateLimit": "Kirjautuminen epäonnistui liian monta kertaa. Yritä myöhemmin uudelleen",
|
"loginFailRateLimit": "You failed to login too many times. Please try again later",
|
||||||
"loginSuccessTitle": "Olet kirjautunut sisään",
|
"loginSuccessTitle": "Logged in",
|
||||||
"loginSuccessSubtitle": "Tervetuloa takaisin!",
|
"loginSuccessSubtitle": "Welcome back!",
|
||||||
"loginOauthFailTitle": "Tapahtui virhe",
|
"loginOauthFailTitle": "An error occurred",
|
||||||
"loginOauthFailSubtitle": "OAuthin URL-osoitteen haku epäonnistui",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Uudelleenohjataan",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Uudelleenohjaus OAuth -palveluntarjoajallesi",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "Automaattinen OAuth -uudelleenohjaus",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"loginOauthAutoRedirectSubtitle": "Sinut ohjataan automaattisesti OAuth -palveluntarjoajallesi todentamista varten.",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"loginOauthAutoRedirectButton": "Siirry nyt",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
"continueTitle": "Jatka",
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueRedirectingTitle": "Uudelleenohjataan...",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueRedirectingSubtitle": "Sinun pitäisi ohjautua sovellukseen pian",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueRedirectManually": "Siirrä minut manuaalisesti",
|
"continueTitle": "Continue",
|
||||||
"continueInsecureRedirectTitle": "Turvaton uudelleenohjaus",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"continueInsecureRedirectSubtitle": "Yrität siirtyä suojatusta <code>https</code> -sivusta suojaamattomalle <code>http</code> -sivulle. Oletko varma, että haluat jatkaa?",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"continueUntrustedRedirectTitle": "Ei-luotettu uudelleenohjaus",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"continueUntrustedRedirectSubtitle": "Yrität uudelleenohjata domainiin, joka ei vastaa määritettyä verkkotunnusta (<code>{{cookieDomain}}</code>). Oletko varma, että haluat jatkaa?",
|
"logoutSuccessTitle": "Logged out",
|
||||||
"logoutFailTitle": "Uloskirjautuminen epäonnistui",
|
"logoutSuccessSubtitle": "You have been logged out",
|
||||||
"logoutFailSubtitle": "Ole hyvä ja yritä uudelleen",
|
"logoutTitle": "Logout",
|
||||||
"logoutSuccessTitle": "Kirjauduttu ulos",
|
"logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.",
|
||||||
"logoutSuccessSubtitle": "Sinut on kirjattu ulos",
|
"logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.",
|
||||||
"logoutTitle": "Kirjaudu ulos",
|
"notFoundTitle": "Page not found",
|
||||||
"logoutUsernameSubtitle": "Olet kirjautuneena sisään tunnuksella <code>{{username}}</code>. Kirjaudu ulos alla olevasta painikkeesta.",
|
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||||
"logoutOauthSubtitle": "Olet kirjautuneena sisään tunnuksella <code>{{username}}</code> OAuth palvelun {{provider}} kautta. Kirjaudu ulos alla olevasta painikkeesta.",
|
"notFoundButton": "Go home",
|
||||||
"notFoundTitle": "Sivua ei löydy",
|
"totpFailTitle": "Failed to verify code",
|
||||||
"notFoundSubtitle": "Sivua, jota etsit ei ole olemassa.",
|
"totpFailSubtitle": "Please check your code and try again",
|
||||||
"notFoundButton": "Palaa kotinäkymään",
|
"totpSuccessTitle": "Verified",
|
||||||
"totpFailTitle": "Koodin vahvistus epäonnistui",
|
"totpSuccessSubtitle": "Redirecting to your app",
|
||||||
"totpFailSubtitle": "Tarkista koodisi ja yritä uudelleen",
|
"totpTitle": "Enter your TOTP code",
|
||||||
"totpSuccessTitle": "Vahvistettu",
|
"totpSubtitle": "Please enter the code from your authenticator app.",
|
||||||
"totpSuccessSubtitle": "Uudelleenohjataan sovelluksellesi",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"totpTitle": "Syötä TOTP -koodisi",
|
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"totpSubtitle": "Ole hyvä ja syötä koodi todennussovelluksestasi.",
|
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
|
||||||
"unauthorizedTitle": "Ei sallittu",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedResourceSubtitle": "Käyttäjällä <code>{{username}}</code> ei ole pääsyä kohteeseen <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "Käyttäjällä <code>{{username}}</code> ei ole lupaa kirjautua.",
|
"unauthorizedButton": "Try again",
|
||||||
"unauthorizedGroupsSubtitle": "Käyttäjä <code>{{username}}</code> ei ole ryhmässä, joka vaaditaan pääsyyn kohteeseen <code>{{resource}}</code>.",
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
"unauthorizedIpSubtitle": "IP osoitteestasi <code>{{ip}}</code> ei ole pääsyä kohteeseen <code>{{resource}}</code>.",
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"unauthorizedButton": "Yritä uudelleen",
|
"cancelTitle": "Cancel",
|
||||||
"cancelTitle": "Peruuta",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"forgotPasswordTitle": "Unohditko salasanasi?",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
"failedToFetchProvidersTitle": "Todennuspalvelujen tarjoajien lataaminen epäonnistui. Tarkista määrityksesi.",
|
"errorTitle": "An error occurred",
|
||||||
"errorTitle": "Tapahtui virhe",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"errorSubtitle": "Tapahtui virhe yritettäessä suorittaa tämä toiminto. Ole hyvä ja tarkista konsoli saadaksesi lisätietoja.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"forgotPasswordMessage": "Voit nollata salasanasi vaihtamalla ympäristömuuttujan `USERS`.",
|
"fieldRequired": "This field is required",
|
||||||
"fieldRequired": "Tämä kenttä on pakollinen",
|
"invalidInput": "Invalid input"
|
||||||
"invalidInput": "Virheellinen syöte",
|
|
||||||
"domainWarningTitle": "Virheellinen verkkotunnus",
|
|
||||||
"domainWarningSubtitle": "Tämä instanssi on määritelty käyttämään osoitetta <code>{{appUrl}}</code>, mutta nykyinen osoite on <code>{{currentUrl}}</code>. Jos jatkat, saatat törmätä ongelmiin autentikoinnissa.",
|
|
||||||
"ignoreTitle": "Jätä huomiotta",
|
|
||||||
"goToCorrectDomainTitle": "Siirry oikeaan verkkotunnukseen"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Impossible d'obtenir l'URL OAuth",
|
"loginOauthFailSubtitle": "Impossible d'obtenir l'URL OAuth",
|
||||||
"loginOauthSuccessTitle": "Redirection",
|
"loginOauthSuccessTitle": "Redirection",
|
||||||
"loginOauthSuccessSubtitle": "Redirection vers votre fournisseur OAuth",
|
"loginOauthSuccessSubtitle": "Redirection vers votre fournisseur OAuth",
|
||||||
"loginOauthAutoRedirectTitle": "Redirection automatique OAuth",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "Vous allez être automatiquement redirigé vers votre fournisseur OAuth pour vous authentifier.",
|
|
||||||
"loginOauthAutoRedirectButton": "Rediriger",
|
|
||||||
"continueTitle": "Continuer",
|
|
||||||
"continueRedirectingTitle": "Redirection...",
|
"continueRedirectingTitle": "Redirection...",
|
||||||
"continueRedirectingSubtitle": "Vous devriez être redirigé vers l'application bientôt",
|
"continueRedirectingSubtitle": "Vous devriez être redirigé vers l'application bientôt",
|
||||||
"continueRedirectManually": "Redirection manuelle",
|
"continueInvalidRedirectTitle": "Redirection invalide",
|
||||||
|
"continueInvalidRedirectSubtitle": "L'URL de redirection est invalide",
|
||||||
"continueInsecureRedirectTitle": "Redirection non sécurisée",
|
"continueInsecureRedirectTitle": "Redirection non sécurisée",
|
||||||
"continueInsecureRedirectSubtitle": "Vous tentez de rediriger de <code>https</code> vers <code>http</code>, ce qui n'est pas sécurisé. Êtes-vous sûr de vouloir continuer ?",
|
"continueInsecureRedirectSubtitle": "Vous tentez de rediriger de <code>https</code> vers <code>http</code>, ce qui n'est pas sécurisé. Êtes-vous sûr de vouloir continuer ?",
|
||||||
"continueUntrustedRedirectTitle": "Redirection non sécurisée",
|
"continueTitle": "Continuer",
|
||||||
"continueUntrustedRedirectSubtitle": "Vous essayez de rediriger vers un domaine qui ne correspond pas à votre domaine configuré (<code>{{cookieDomain}}</code>). Êtes-vous sûr de vouloir continuer ?",
|
"continueSubtitle": "Cliquez sur le bouton pour continuer vers votre application.",
|
||||||
"logoutFailTitle": "Échec de la déconnexion",
|
"logoutFailTitle": "Échec de la déconnexion",
|
||||||
"logoutFailSubtitle": "Veuillez réessayer",
|
"logoutFailSubtitle": "Veuillez réessayer",
|
||||||
"logoutSuccessTitle": "Déconnecté",
|
"logoutSuccessTitle": "Déconnecté",
|
||||||
@@ -41,22 +38,20 @@
|
|||||||
"totpSuccessSubtitle": "Redirection vers votre application",
|
"totpSuccessSubtitle": "Redirection vers votre application",
|
||||||
"totpTitle": "Saisissez votre code TOTP",
|
"totpTitle": "Saisissez votre code TOTP",
|
||||||
"totpSubtitle": "Veuillez saisir le code de votre application d'authentification.",
|
"totpSubtitle": "Veuillez saisir le code de votre application d'authentification.",
|
||||||
"unauthorizedTitle": "Non autorisé",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"unauthorizedResourceSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'est pas autorisé à accéder à la ressource <code>{{resource}}</code>.",
|
"unauthorizedResourceSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'est pas autorisé à accéder à la ressource <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'est pas autorisé à se connecter.",
|
"unauthorizedLoginSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'est pas autorisé à se connecter.",
|
||||||
"unauthorizedGroupsSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'appartient pas aux groupes requis par la ressource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "L'utilisateur avec le nom d'utilisateur <code>{{username}}</code> n'appartient pas aux groupes requis par la ressource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Votre adresse IP <code>{{ip}}</code> n'est pas autorisée à accéder à la ressource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Votre adresse IP <code>{{ip}}</code> n'est pas autorisée à accéder à la ressource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Réessayer",
|
"unauthorizedButton": "Réessayer",
|
||||||
|
"untrustedRedirectTitle": "Redirection non fiable",
|
||||||
|
"untrustedRedirectSubtitle": "Vous tentez de rediriger vers un domaine qui ne correspond pas à votre domaine configuré (<code>{{domain}}</code>). Êtes-vous sûr de vouloir continuer ?",
|
||||||
"cancelTitle": "Annuler",
|
"cancelTitle": "Annuler",
|
||||||
"forgotPasswordTitle": "Mot de passe oublié ?",
|
"forgotPasswordTitle": "Mot de passe oublié ?",
|
||||||
"failedToFetchProvidersTitle": "Échec du chargement des fournisseurs d'authentification. Veuillez vérifier votre configuration.",
|
"failedToFetchProvidersTitle": "Échec du chargement des fournisseurs d'authentification. Veuillez vérifier votre configuration.",
|
||||||
"errorTitle": "Une erreur est survenue",
|
"errorTitle": "Une erreur est survenue",
|
||||||
"errorSubtitle": "Une erreur est survenue lors de l'exécution de cette action. Veuillez consulter la console pour plus d'informations.",
|
"errorSubtitle": "Une erreur est survenue lors de l'exécution de cette action. Veuillez consulter la console pour plus d'informations.",
|
||||||
"forgotPasswordMessage": "Vous pouvez réinitialiser votre mot de passe en modifiant la variable d'environnement `USERS`.",
|
"forgotPasswordMessage": "Vous pouvez réinitialiser votre mot de passe en modifiant la variable d'environnement `USERS`.",
|
||||||
"fieldRequired": "Ce champ est obligatoire",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Saisie non valide",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Domaine invalide",
|
|
||||||
"domainWarningSubtitle": "Cette instance est configurée pour être accédée depuis <code>{{appUrl}}</code>, mais <code>{{currentUrl}}</code> est utilisé. Si vous continuez, vous pourriez rencontrer des problèmes d'authentification.",
|
|
||||||
"ignoreTitle": "Ignorer",
|
|
||||||
"goToCorrectDomainTitle": "Aller au bon domaine"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Fout bij het ophalen van OAuth URL",
|
"loginOauthFailSubtitle": "Fout bij het ophalen van OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Omleiden",
|
"loginOauthSuccessTitle": "Omleiden",
|
||||||
"loginOauthSuccessSubtitle": "Omleiden naar je OAuth provider",
|
"loginOauthSuccessSubtitle": "Omleiden naar je OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Ga verder",
|
|
||||||
"continueRedirectingTitle": "Omleiden...",
|
"continueRedirectingTitle": "Omleiden...",
|
||||||
"continueRedirectingSubtitle": "Je wordt naar de app doorgestuurd",
|
"continueRedirectingSubtitle": "Je wordt naar de app doorgestuurd",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Ongeldige omleiding",
|
||||||
|
"continueInvalidRedirectSubtitle": "De omleidings-URL is ongeldig",
|
||||||
"continueInsecureRedirectTitle": "Onveilige doorverwijzing",
|
"continueInsecureRedirectTitle": "Onveilige doorverwijzing",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Ga verder",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Klik op de knop om door te gaan naar de app.",
|
||||||
"logoutFailTitle": "Afmelden mislukt",
|
"logoutFailTitle": "Afmelden mislukt",
|
||||||
"logoutFailSubtitle": "Probeer het opnieuw",
|
"logoutFailSubtitle": "Probeer het opnieuw",
|
||||||
"logoutSuccessTitle": "Afgemeld",
|
"logoutSuccessTitle": "Afgemeld",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Opnieuw proberen",
|
"unauthorizedButton": "Opnieuw proberen",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Nie udało się uzyskać adresu URL OAuth",
|
"loginOauthFailSubtitle": "Nie udało się uzyskać adresu URL OAuth",
|
||||||
"loginOauthSuccessTitle": "Przekierowywanie",
|
"loginOauthSuccessTitle": "Przekierowywanie",
|
||||||
"loginOauthSuccessSubtitle": "Przekierowywanie do Twojego dostawcy OAuth",
|
"loginOauthSuccessSubtitle": "Przekierowywanie do Twojego dostawcy OAuth",
|
||||||
"loginOauthAutoRedirectTitle": "Automatyczne przekierowanie OAuth",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "Nastąpi automatyczne przekierowanie do dostawcy OAuth w celu uwierzytelnienia.",
|
|
||||||
"loginOauthAutoRedirectButton": "Przekieruj teraz",
|
|
||||||
"continueTitle": "Kontynuuj",
|
|
||||||
"continueRedirectingTitle": "Przekierowywanie...",
|
"continueRedirectingTitle": "Przekierowywanie...",
|
||||||
"continueRedirectingSubtitle": "Wkrótce powinieneś zostać przekierowany do aplikacji",
|
"continueRedirectingSubtitle": "Wkrótce powinieneś zostać przekierowany do aplikacji",
|
||||||
"continueRedirectManually": "Przekieruj mnie ręcznie",
|
"continueInvalidRedirectTitle": "Nieprawidłowe przekierowanie",
|
||||||
|
"continueInvalidRedirectSubtitle": "Adres przekierowania jest nieprawidłowy",
|
||||||
"continueInsecureRedirectTitle": "Niezabezpieczone przekierowanie",
|
"continueInsecureRedirectTitle": "Niezabezpieczone przekierowanie",
|
||||||
"continueInsecureRedirectSubtitle": "Próbujesz przekierować z <code>https</code> do <code>http</code>, co nie jest bezpieczne. Czy na pewno chcesz kontynuować?",
|
"continueInsecureRedirectSubtitle": "Próbujesz przekierować z <code>https</code> do <code>http</code>, co nie jest bezpieczne. Czy na pewno chcesz kontynuować?",
|
||||||
"continueUntrustedRedirectTitle": "Niezaufane przekierowanie",
|
"continueTitle": "Kontynuuj",
|
||||||
"continueUntrustedRedirectSubtitle": "Próbujesz przekierować do domeny, która nie pasuje do skonfigurowanej domeny (<code>{{cookieDomain}}</code>). Czy na pewno chcesz kontynuować?",
|
"continueSubtitle": "Kliknij przycisk, aby przejść do aplikacji.",
|
||||||
"logoutFailTitle": "Nie udało się wylogować",
|
"logoutFailTitle": "Nie udało się wylogować",
|
||||||
"logoutFailSubtitle": "Spróbuj ponownie",
|
"logoutFailSubtitle": "Spróbuj ponownie",
|
||||||
"logoutSuccessTitle": "Wylogowano",
|
"logoutSuccessTitle": "Wylogowano",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "Użytkownik o nazwie <code>{{username}}</code> nie należy do grup wymaganych przez zasób <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "Użytkownik o nazwie <code>{{username}}</code> nie należy do grup wymaganych przez zasób <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Twój adres IP <code>{{ip}}</code> nie ma autoryzacji do dostępu do zasobu <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Twój adres IP <code>{{ip}}</code> nie ma autoryzacji do dostępu do zasobu <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Spróbuj ponownie",
|
"unauthorizedButton": "Spróbuj ponownie",
|
||||||
|
"untrustedRedirectTitle": "Niezaufane przekierowanie",
|
||||||
|
"untrustedRedirectSubtitle": "Próbujesz przekierować do domeny, która nie pasuje do Twojej skonfigurowanej domeny (<code>{{domain}}</code>). Czy na pewno chcesz kontynuować?",
|
||||||
"cancelTitle": "Anuluj",
|
"cancelTitle": "Anuluj",
|
||||||
"forgotPasswordTitle": "Nie pamiętasz hasła?",
|
"forgotPasswordTitle": "Nie pamiętasz hasła?",
|
||||||
"failedToFetchProvidersTitle": "Nie udało się załadować dostawców uwierzytelniania. Sprawdź swoją konfigurację.",
|
"failedToFetchProvidersTitle": "Nie udało się załadować dostawców uwierzytelniania. Sprawdź swoją konfigurację.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "Wystąpił błąd podczas próby wykonania tej czynności. Sprawdź konsolę, aby uzyskać więcej informacji.",
|
"errorSubtitle": "Wystąpił błąd podczas próby wykonania tej czynności. Sprawdź konsolę, aby uzyskać więcej informacji.",
|
||||||
"forgotPasswordMessage": "Możesz zresetować hasło, zmieniając zmienną środowiskową `USERS`.",
|
"forgotPasswordMessage": "Możesz zresetować hasło, zmieniając zmienną środowiskową `USERS`.",
|
||||||
"fieldRequired": "To pole jest wymagane",
|
"fieldRequired": "To pole jest wymagane",
|
||||||
"invalidInput": "Nieprawidłowe dane wejściowe",
|
"invalidInput": "Nieprawidłowe dane wejściowe"
|
||||||
"domainWarningTitle": "Nieprawidłowa domena",
|
|
||||||
"domainWarningSubtitle": "Ta instancja jest skonfigurowana do uzyskania dostępu z <code>{{appUrl}}</code>, ale <code>{{currentUrl}}</code> jest w użyciu. Jeśli będziesz kontynuować, mogą wystąpić problemy z uwierzytelnianiem.",
|
|
||||||
"ignoreTitle": "Zignoruj",
|
|
||||||
"goToCorrectDomainTitle": "Przejdź do prawidłowej domeny"
|
|
||||||
}
|
}
|
||||||
@@ -1,37 +1,34 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "Bem-vindo de volta, acesse com",
|
"loginTitle": "Bem-vindo de volta, acesse com",
|
||||||
"loginTitleSimple": "Bem-vindo de volta, faça o login",
|
"loginTitleSimple": "Welcome back, please login",
|
||||||
"loginDivider": "Ou",
|
"loginDivider": "Or",
|
||||||
"loginUsername": "Nome de usuário",
|
"loginUsername": "Nome de usuário",
|
||||||
"loginPassword": "Senha",
|
"loginPassword": "Senha",
|
||||||
"loginSubmit": "Entrar",
|
"loginSubmit": "Entrar",
|
||||||
"loginFailTitle": "Falha ao iniciar sessão",
|
"loginFailTitle": "Falha ao iniciar sessão",
|
||||||
"loginFailSubtitle": "Por favor, verifique seu usuário e senha",
|
"loginFailSubtitle": "Por favor, verifique seu usuário e senha",
|
||||||
"loginFailRateLimit": "Você falhou em iniciar sessão muitas vezes, por favor tente novamente mais tarde",
|
"loginFailRateLimit": "You failed to login too many times. Please try again later",
|
||||||
"loginSuccessTitle": "Sessão Iniciada",
|
"loginSuccessTitle": "Sessão Iniciada",
|
||||||
"loginSuccessSubtitle": "Bem-vindo de volta!",
|
"loginSuccessSubtitle": "Bem-vindo de volta!",
|
||||||
"loginOauthFailTitle": "Ocorreu um erro",
|
"loginOauthFailTitle": "An error occurred",
|
||||||
"loginOauthFailSubtitle": "Falha ao obter URL de OAuth",
|
"loginOauthFailSubtitle": "Falha ao obter URL de OAuth",
|
||||||
"loginOauthSuccessTitle": "Redirecionando",
|
"loginOauthSuccessTitle": "Redirecionando",
|
||||||
"loginOauthSuccessSubtitle": "Redirecionando para seu provedor OAuth",
|
"loginOauthSuccessSubtitle": "Redirecionando para seu provedor OAuth",
|
||||||
"loginOauthAutoRedirectTitle": "Redirecionamento automático do OAuth",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "Você será automaticamente redirecionado para seu provedor OAuth para autenticar.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirecionar agora",
|
|
||||||
"continueTitle": "Continuar",
|
|
||||||
"continueRedirectingTitle": "Redirecionando...",
|
"continueRedirectingTitle": "Redirecionando...",
|
||||||
"continueRedirectingSubtitle": "Você deve ser redirecionado para o aplicativo em breve",
|
"continueRedirectingSubtitle": "Você deve ser redirecionado para o aplicativo em breve",
|
||||||
"continueRedirectManually": "Redirecionar-me manualmente",
|
"continueInvalidRedirectTitle": "Redirecionamento inválido",
|
||||||
|
"continueInvalidRedirectSubtitle": "O endereço de redirecionamento é inválido",
|
||||||
"continueInsecureRedirectTitle": "Redirecionamento inseguro",
|
"continueInsecureRedirectTitle": "Redirecionamento inseguro",
|
||||||
"continueInsecureRedirectSubtitle": "Você está tentando redirecionar de <code>https</code> para <code>http</code>, você tem certeza que deseja continuar?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Redirecionamento não confiável",
|
"continueTitle": "Continuar",
|
||||||
"continueUntrustedRedirectSubtitle": "Você está tentando redirecionar para um domínio que não corresponde ao seu domínio configurado (<code>{{cookieDomain}}</code>). Tem certeza que deseja continuar?",
|
"continueSubtitle": "Clique no botão para continuar para o seu aplicativo.",
|
||||||
"logoutFailTitle": "Falha ao encerrar sessão",
|
"logoutFailTitle": "Falha ao encerrar sessão",
|
||||||
"logoutFailSubtitle": "Por favor, tente novamente",
|
"logoutFailSubtitle": "Por favor, tente novamente",
|
||||||
"logoutSuccessTitle": "Sessão encerrada",
|
"logoutSuccessTitle": "Sessão encerrada",
|
||||||
"logoutSuccessSubtitle": "Você foi desconectado",
|
"logoutSuccessSubtitle": "Você foi desconectado",
|
||||||
"logoutTitle": "Sair",
|
"logoutTitle": "Sair",
|
||||||
"logoutUsernameSubtitle": "Você está atualmente logado como <code>{{username}}</code>, clique no botão abaixo para sair.",
|
"logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.",
|
||||||
"logoutOauthSubtitle": "Você está atualmente logado como <code>{{username}}</code> usando o provedor {{provider}} OAuth, clique no botão abaixo para sair.",
|
"logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.",
|
||||||
"notFoundTitle": "Página não encontrada",
|
"notFoundTitle": "Página não encontrada",
|
||||||
"notFoundSubtitle": "A página que você está procurando não existe.",
|
"notFoundSubtitle": "A página que você está procurando não existe.",
|
||||||
"notFoundButton": "Voltar para a tela inicial",
|
"notFoundButton": "Voltar para a tela inicial",
|
||||||
@@ -40,23 +37,21 @@
|
|||||||
"totpSuccessTitle": "Verificado",
|
"totpSuccessTitle": "Verificado",
|
||||||
"totpSuccessSubtitle": "Redirecionando para o seu aplicativo",
|
"totpSuccessSubtitle": "Redirecionando para o seu aplicativo",
|
||||||
"totpTitle": "Insira o seu código TOTP",
|
"totpTitle": "Insira o seu código TOTP",
|
||||||
"totpSubtitle": "Por favor, insira o código do seu aplicativo de autenticação.",
|
"totpSubtitle": "Please enter the code from your authenticator app.",
|
||||||
"unauthorizedTitle": "Não autorizado",
|
"unauthorizedTitle": "Não autorizado",
|
||||||
"unauthorizedResourceSubtitle": "O usuário com nome de usuário <code>{{username}}</code> não está autorizado a acessar o recurso <code>{{resource}}</code>.",
|
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "O usuário com o nome <code>{{username}}</code> não está autorizado a acessar.",
|
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
|
||||||
"unauthorizedGroupsSubtitle": "O usuário <code>{{username}}</code> não está autorizado a acessar o recurso <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Seu endereço IP <code>{{ip}}</code> não está autorizado a acessar o recurso <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Tentar novamente",
|
"unauthorizedButton": "Tentar novamente",
|
||||||
|
"untrustedRedirectTitle": "Redirecionamento não confiável",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancelar",
|
"cancelTitle": "Cancelar",
|
||||||
"forgotPasswordTitle": "Esqueceu sua senha?",
|
"forgotPasswordTitle": "Esqueceu sua senha?",
|
||||||
"failedToFetchProvidersTitle": "Falha ao carregar provedores de autenticação. Verifique sua configuração.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
"errorTitle": "Ocorreu um erro",
|
"errorTitle": "An error occurred",
|
||||||
"errorSubtitle": "Ocorreu um erro ao tentar executar esta ação. Por favor, verifique o console para mais informações.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "Você pode redefinir sua senha alterando a variável de ambiente `USERS`.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "Este campo é obrigatório",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Entrada Inválida",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Domínio inválido",
|
|
||||||
"domainWarningSubtitle": "Esta instância está configurada para ser acessada de <code>{{appUrl}}</code>, mas <code>{{currentUrl}}</code> está sendo usado. Se você continuar, você pode encontrar problemas com a autenticação.",
|
|
||||||
"ignoreTitle": "Ignorar",
|
|
||||||
"goToCorrectDomainTitle": "Ir para o domínio correto"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "С возвращением, войти с",
|
"loginTitle": "С возвращением, войти с",
|
||||||
"loginTitleSimple": "С возвращением, пожалуйста войдите",
|
"loginTitleSimple": "Вход",
|
||||||
"loginDivider": "Или",
|
"loginDivider": "Или",
|
||||||
"loginUsername": "Имя пользователя",
|
"loginUsername": "Имя пользователя",
|
||||||
"loginPassword": "Пароль",
|
"loginPassword": "Пароль",
|
||||||
@@ -8,27 +8,24 @@
|
|||||||
"loginFailTitle": "Вход не удался",
|
"loginFailTitle": "Вход не удался",
|
||||||
"loginFailSubtitle": "Проверьте имя пользователя и пароль",
|
"loginFailSubtitle": "Проверьте имя пользователя и пароль",
|
||||||
"loginFailRateLimit": "Слишком много ошибок входа. Попробуйте позже",
|
"loginFailRateLimit": "Слишком много ошибок входа. Попробуйте позже",
|
||||||
"loginSuccessTitle": "Вход выполнен",
|
"loginSuccessTitle": "Вы вошли",
|
||||||
"loginSuccessSubtitle": "С возвращением!",
|
"loginSuccessSubtitle": "С возвращением!",
|
||||||
"loginOauthFailTitle": "Произошла ошибка",
|
"loginOauthFailTitle": "Произошла ошибка",
|
||||||
"loginOauthFailSubtitle": "Не удалось получить ссылку OAuth",
|
"loginOauthFailSubtitle": "Не удалось получить OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Перенаправление",
|
"loginOauthSuccessTitle": "Перенаправление",
|
||||||
"loginOauthSuccessSubtitle": "Перенаправление к поставщику OAuth",
|
"loginOauthSuccessSubtitle": "Перенаправление к поставщику OAuth",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth автоматическое перенаправление",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "Вы будете автоматически перенаправлены для авторизации у вашего поставщика OAuth.",
|
|
||||||
"loginOauthAutoRedirectButton": "Перенаправить сейчас",
|
|
||||||
"continueTitle": "Продолжить",
|
|
||||||
"continueRedirectingTitle": "Перенаправление...",
|
"continueRedirectingTitle": "Перенаправление...",
|
||||||
"continueRedirectingSubtitle": "Скоро вы будете перенаправлены в приложение",
|
"continueRedirectingSubtitle": "Скоро вы будете перенаправлены в приложение",
|
||||||
"continueRedirectManually": "Перенаправить вручную",
|
"continueInvalidRedirectTitle": "Неверное перенаправление",
|
||||||
|
"continueInvalidRedirectSubtitle": "URL перенаправления недействителен",
|
||||||
"continueInsecureRedirectTitle": "Небезопасное перенаправление",
|
"continueInsecureRedirectTitle": "Небезопасное перенаправление",
|
||||||
"continueInsecureRedirectSubtitle": "Попытка перенаправления с <code>https</code> на <code>http</code>, уверены, что хотите продолжить?",
|
"continueInsecureRedirectSubtitle": "Попытка перенаправления с <code>https</code> на <code>http</code>, уверены, что хотите продолжить?",
|
||||||
"continueUntrustedRedirectTitle": "Недоверенное перенаправление",
|
"continueTitle": "Продолжить",
|
||||||
"continueUntrustedRedirectSubtitle": "Вы пытаетесь перенаправить на домен, который не соответствует вашему настроенному домену (<code>{{cookieDomain}}</code>). Вы уверены, что хотите продолжить?",
|
"continueSubtitle": "Нажмите на кнопку, чтобы перейти к приложению.",
|
||||||
"logoutFailTitle": "Не удалось выйти",
|
"logoutFailTitle": "Не удалось выйти",
|
||||||
"logoutFailSubtitle": "Попробуйте ещё раз",
|
"logoutFailSubtitle": "Попробуйте ещё раз",
|
||||||
"logoutSuccessTitle": "Выход",
|
"logoutSuccessTitle": "Выход",
|
||||||
"logoutSuccessSubtitle": "Вы вышли",
|
"logoutSuccessSubtitle": "Вы вышли из системы",
|
||||||
"logoutTitle": "Выйти",
|
"logoutTitle": "Выйти",
|
||||||
"logoutUsernameSubtitle": "Вход выполнен как <code>{{username}}</code>, нажмите на кнопку ниже, чтобы выйти.",
|
"logoutUsernameSubtitle": "Вход выполнен как <code>{{username}}</code>, нажмите на кнопку ниже, чтобы выйти.",
|
||||||
"logoutOauthSubtitle": "Вход выполнен как <code>{{username}}</code> с использованием {{provider}} OAuth, нажмите кнопку ниже, чтобы выйти.",
|
"logoutOauthSubtitle": "Вход выполнен как <code>{{username}}</code> с использованием {{provider}} OAuth, нажмите кнопку ниже, чтобы выйти.",
|
||||||
@@ -40,23 +37,21 @@
|
|||||||
"totpSuccessTitle": "Подтверждён",
|
"totpSuccessTitle": "Подтверждён",
|
||||||
"totpSuccessSubtitle": "Перенаправление в приложение",
|
"totpSuccessSubtitle": "Перенаправление в приложение",
|
||||||
"totpTitle": "Введите код TOTP",
|
"totpTitle": "Введите код TOTP",
|
||||||
"totpSubtitle": "Пожалуйста, введите код из вашего приложения авторизации.",
|
"totpSubtitle": "Пожалуйста, введите код из вашего приложения — аутентификатора.",
|
||||||
"unauthorizedTitle": "Доступ запрещён",
|
"unauthorizedTitle": "Доступ запрещен",
|
||||||
"unauthorizedResourceSubtitle": "Пользователю <code>{{username}}</code> не разрешён доступ к <code>{{resource}}</code>.",
|
"unauthorizedResourceSubtitle": "Пользователю <code>{{username}}</code> не разрешен доступ к <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "Пользователю <code>{{username}}</code> не разрешён вход.",
|
"unauthorizedLoginSubtitle": "Пользователю <code>{{username}}</code> не разрешен вход.",
|
||||||
"unauthorizedGroupsSubtitle": "Пользователь <code>{{username}}</code> не состоит в группах, которым разрешён доступ к <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "Пользователь <code>{{username}}</code> не состоит в группах, которым разрешен доступ к <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Вашему IP-адресу <code>{{ip}}</code> не разрешён доступ к ресурсу <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Ваш IP адрес <code>{{ip}}</code> не авторизован для доступа к ресурсу <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Повторить",
|
"unauthorizedButton": "Повторить",
|
||||||
|
"untrustedRedirectTitle": "Ненадежное перенаправление",
|
||||||
|
"untrustedRedirectSubtitle": "Попытка перенаправить на домен, который не соответствует вашему заданному домену (<code>{{domain}}</code>). Уверены, что хотите продолжить?",
|
||||||
"cancelTitle": "Отмена",
|
"cancelTitle": "Отмена",
|
||||||
"forgotPasswordTitle": "Забыли пароль?",
|
"forgotPasswordTitle": "Забыли пароль?",
|
||||||
"failedToFetchProvidersTitle": "Не удалось загрузить поставщика авторизации. Пожалуйста, проверьте конфигурацию.",
|
"failedToFetchProvidersTitle": "Не удалось загрузить провайдеров аутентификации. Пожалуйста, проверьте конфигурацию.",
|
||||||
"errorTitle": "Произошла ошибка",
|
"errorTitle": "Произошла ошибка",
|
||||||
"errorSubtitle": "Произошла ошибка при попытке выполнить это действие. Проверьте консоль для дополнительной информации.",
|
"errorSubtitle": "Произошла ошибка при попытке выполнить это действие. Проверьте консоль для дополнительной информации.",
|
||||||
"forgotPasswordMessage": "Вы можете сбросить свой пароль, изменив переменную окружения `USERS`.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "Это поле является обязательным",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Недопустимый ввод",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Неверный домен",
|
|
||||||
"domainWarningSubtitle": "Этот экземпляр настроен на доступ к нему из <code>{{appUrl}}</code>, но <code>{{currentUrl}}</code> в настоящее время используется. Если вы продолжите, то могут возникнуть проблемы с авторизацией.",
|
|
||||||
"ignoreTitle": "Игнорировать",
|
|
||||||
"goToCorrectDomainTitle": "Перейти к правильному домену"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Неуспело преузимање OAuth адресе",
|
"loginOauthFailSubtitle": "Неуспело преузимање OAuth адресе",
|
||||||
"loginOauthSuccessTitle": "Преусмеравање",
|
"loginOauthSuccessTitle": "Преусмеравање",
|
||||||
"loginOauthSuccessSubtitle": "Преусмеравање на вашег OAuth провајдера",
|
"loginOauthSuccessSubtitle": "Преусмеравање на вашег OAuth провајдера",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Настави",
|
|
||||||
"continueRedirectingTitle": "Преусмеравање...",
|
"continueRedirectingTitle": "Преусмеравање...",
|
||||||
"continueRedirectingSubtitle": "Требали би сте ускоро да будете преусмерени на апликацију",
|
"continueRedirectingSubtitle": "Требали би сте ускоро да будете преусмерени на апликацију",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Неисправно преусмеравање",
|
||||||
|
"continueInvalidRedirectSubtitle": "Адреса за преусмеравање није исправна",
|
||||||
"continueInsecureRedirectTitle": "Небезбедно преусмеравање",
|
"continueInsecureRedirectTitle": "Небезбедно преусмеравање",
|
||||||
"continueInsecureRedirectSubtitle": "Покушавате да преусмерите са <code>https</code> на <code>http</code> што није безбедно. Да ли желите да наставите?",
|
"continueInsecureRedirectSubtitle": "Покушавате да преусмерите са <code>https</code> на <code>http</code> што није безбедно. Да ли желите да наставите?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Настави",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Кликните на дугме да би сте наставили на нашу апликацију.",
|
||||||
"logoutFailTitle": "Неуспешно одјављивање",
|
"logoutFailTitle": "Неуспешно одјављивање",
|
||||||
"logoutFailSubtitle": "Молим вас покушајте поново",
|
"logoutFailSubtitle": "Молим вас покушајте поново",
|
||||||
"logoutSuccessTitle": "Одјављени",
|
"logoutSuccessTitle": "Одјављени",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "Корисник са корисничким именом <code>{{username}}</code> није у групама које захтева ресурс <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "Корисник са корисничким именом <code>{{username}}</code> није у групама које захтева ресурс <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Ваша IP адреса <code>{{ip}}</code> није ауторизована да приступи ресурсу <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Ваша IP адреса <code>{{ip}}</code> није ауторизована да приступи ресурсу <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Покушајте поново",
|
"unauthorizedButton": "Покушајте поново",
|
||||||
|
"untrustedRedirectTitle": "Преусмерење без поверења",
|
||||||
|
"untrustedRedirectSubtitle": "Покушавате да преусмерите на домен који се не поклапа са подешеним доменом (<code>{{domain}}</code>). Да ли желите да наставите?",
|
||||||
"cancelTitle": "Поништи",
|
"cancelTitle": "Поништи",
|
||||||
"forgotPasswordTitle": "Заборавили сте лозинку?",
|
"forgotPasswordTitle": "Заборавили сте лозинку?",
|
||||||
"failedToFetchProvidersTitle": "Није успело учитавање провајдера аутентификације. Молим вас проверите ваша подешавања.",
|
"failedToFetchProvidersTitle": "Није успело учитавање провајдера аутентификације. Молим вас проверите ваша подешавања.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "Појавила се грешка при покушају извршавања ове радње. Молим вас проверите конзолу за додатне информације.",
|
"errorSubtitle": "Појавила се грешка при покушају извршавања ове радње. Молим вас проверите конзолу за додатне информације.",
|
||||||
"forgotPasswordMessage": "Можете поништити вашу лозинку променом `USERS` променљиве окружења.",
|
"forgotPasswordMessage": "Можете поништити вашу лозинку променом `USERS` променљиве окружења.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,32 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "Välkommen tillbaka, logga in med",
|
"loginTitle": "Welcome back, login with",
|
||||||
"loginTitleSimple": "Välkommen tillbaka, logga in",
|
"loginTitleSimple": "Welcome back, please login",
|
||||||
"loginDivider": "Eller",
|
"loginDivider": "Or",
|
||||||
"loginUsername": "Användarnamn",
|
"loginUsername": "Username",
|
||||||
"loginPassword": "Lösenord",
|
"loginPassword": "Password",
|
||||||
"loginSubmit": "Logga in",
|
"loginSubmit": "Login",
|
||||||
"loginFailTitle": "Kunde inte logga in",
|
"loginFailTitle": "Failed to log in",
|
||||||
"loginFailSubtitle": "Kontrollera ditt användarnamn och lösenord",
|
"loginFailSubtitle": "Please check your username and password",
|
||||||
"loginFailRateLimit": "Du misslyckades med att logga in för många gånger. Försök igen senare",
|
"loginFailRateLimit": "You failed to login too many times. Please try again later",
|
||||||
"loginSuccessTitle": "Inloggad",
|
"loginSuccessTitle": "Logged in",
|
||||||
"loginSuccessSubtitle": "Välkommen tillbaka!",
|
"loginSuccessSubtitle": "Welcome back!",
|
||||||
"loginOauthFailTitle": "Ett fel har uppstått",
|
"loginOauthFailTitle": "An error occurred",
|
||||||
"loginOauthFailSubtitle": "Kunde inte hämta OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Omdirigerar",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Omdirigera till din OAuth leverantör",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
"continueTitle": "Fortsätt",
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueRedirectingTitle": "Omdirigerar...",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueRedirectingSubtitle": "Du bör omdirigeras till appen snart",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueTitle": "Continue",
|
||||||
"continueInsecureRedirectTitle": "Osäker omdirigering",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"continueInsecureRedirectSubtitle": "Du försöker omdirigera från <code>https</code> till <code>http</code> som inte är säker. Är du säker på att du vill fortsätta?",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"logoutSuccessTitle": "Logged out",
|
||||||
"logoutFailTitle": "Kunde inte logga ut.",
|
"logoutSuccessSubtitle": "You have been logged out",
|
||||||
"logoutFailSubtitle": "Vänligen försök igen",
|
"logoutTitle": "Logout",
|
||||||
"logoutSuccessTitle": "Utloggad",
|
|
||||||
"logoutSuccessSubtitle": "Du har blivit utloggad",
|
|
||||||
"logoutTitle": "Logga ut",
|
|
||||||
"logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.",
|
"logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.",
|
||||||
"logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.",
|
"logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.",
|
||||||
"notFoundTitle": "Page not found",
|
"notFoundTitle": "Page not found",
|
||||||
@@ -41,12 +38,14 @@
|
|||||||
"totpSuccessSubtitle": "Redirecting to your app",
|
"totpSuccessSubtitle": "Redirecting to your app",
|
||||||
"totpTitle": "Enter your TOTP code",
|
"totpTitle": "Enter your TOTP code",
|
||||||
"totpSubtitle": "Please enter the code from your authenticator app.",
|
"totpSubtitle": "Please enter the code from your authenticator app.",
|
||||||
"unauthorizedTitle": "Obehörig",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
|
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
|
||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Yönlendiriliyor",
|
"loginOauthSuccessTitle": "Yönlendiriliyor",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Devam et",
|
|
||||||
"continueRedirectingTitle": "Yönlendiriliyor...",
|
"continueRedirectingTitle": "Yönlendiriliyor...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Devam et",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Lütfen tekrar deneyin",
|
"logoutFailSubtitle": "Lütfen tekrar deneyin",
|
||||||
"logoutSuccessTitle": "Çıkış yapıldı",
|
"logoutSuccessTitle": "Çıkış yapıldı",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "İptal",
|
"cancelTitle": "İptal",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "З поверненням, увійдіть через",
|
"loginTitle": "Welcome back, login with",
|
||||||
"loginTitleSimple": "Welcome back, please login",
|
"loginTitleSimple": "Welcome back, please login",
|
||||||
"loginDivider": "Or",
|
"loginDivider": "Or",
|
||||||
"loginUsername": "Username",
|
"loginUsername": "Username",
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,6 +44,8 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Forgot your password?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
@@ -54,9 +53,5 @@
|
|||||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||||
"loginOauthSuccessTitle": "Redirecting",
|
"loginOauthSuccessTitle": "Redirecting",
|
||||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
|
||||||
"loginOauthAutoRedirectButton": "Redirect now",
|
|
||||||
"continueTitle": "Continue",
|
|
||||||
"continueRedirectingTitle": "Redirecting...",
|
"continueRedirectingTitle": "Redirecting...",
|
||||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||||
"continueRedirectManually": "Redirect me manually",
|
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||||
|
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
|
||||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
"continueTitle": "Continue",
|
||||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
"continueSubtitle": "Click the button to continue to your app.",
|
||||||
"logoutFailTitle": "Failed to log out",
|
"logoutFailTitle": "Failed to log out",
|
||||||
"logoutFailSubtitle": "Please try again",
|
"logoutFailSubtitle": "Please try again",
|
||||||
"logoutSuccessTitle": "Logged out",
|
"logoutSuccessTitle": "Logged out",
|
||||||
@@ -47,16 +44,14 @@
|
|||||||
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{domain}}</code>). Are you sure you want to continue?",
|
||||||
"cancelTitle": "Cancel",
|
"cancelTitle": "Cancel",
|
||||||
"forgotPasswordTitle": "Bạn quên mật khẩu?",
|
"forgotPasswordTitle": "Forgot your password?",
|
||||||
"failedToFetchProvidersTitle": "Không tải được nhà cung cấp xác thực. Vui lòng kiểm tra cấu hình của bạn.",
|
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
|
||||||
"errorTitle": "An error occurred",
|
"errorTitle": "An error occurred",
|
||||||
"errorSubtitle": "Đã xảy ra lỗi khi thực hiện thao tác này. Vui lòng kiểm tra bảng điều khiển để biết thêm thông tin.",
|
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||||
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "This field is required",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "Invalid input",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "Invalid Domain",
|
|
||||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
|
||||||
"ignoreTitle": "Ignore",
|
|
||||||
"goToCorrectDomainTitle": "Go to correct domain"
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "获取 OAuth URL 失败",
|
"loginOauthFailSubtitle": "获取 OAuth URL 失败",
|
||||||
"loginOauthSuccessTitle": "重定向中",
|
"loginOauthSuccessTitle": "重定向中",
|
||||||
"loginOauthSuccessSubtitle": "重定向到您的 OAuth 提供商",
|
"loginOauthSuccessSubtitle": "重定向到您的 OAuth 提供商",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth自动重定向",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "您将被自动重定向到您的 OAuth 提供商进行身份验证。",
|
|
||||||
"loginOauthAutoRedirectButton": "立即跳转",
|
|
||||||
"continueTitle": "继续",
|
|
||||||
"continueRedirectingTitle": "正在重定向……",
|
"continueRedirectingTitle": "正在重定向……",
|
||||||
"continueRedirectingSubtitle": "您应该很快被重定向到应用",
|
"continueRedirectingSubtitle": "您应该很快被重定向到应用",
|
||||||
"continueRedirectManually": "请手动跳转",
|
"continueInvalidRedirectTitle": "无效的重定向",
|
||||||
|
"continueInvalidRedirectSubtitle": "重定向URL无效",
|
||||||
"continueInsecureRedirectTitle": "不安全的重定向",
|
"continueInsecureRedirectTitle": "不安全的重定向",
|
||||||
"continueInsecureRedirectSubtitle": "您正在尝试从<code>https</code>重定向到<code>http</code>可能存在风险。您确定要继续吗?",
|
"continueInsecureRedirectSubtitle": "您正在尝试从<code>https</code>重定向到<code>http</code>可能存在风险。您确定要继续吗?",
|
||||||
"continueUntrustedRedirectTitle": "不可信的重定向",
|
"continueTitle": "继续",
|
||||||
"continueUntrustedRedirectSubtitle": "您尝试跳转的域名与配置的域名(<code>{{cookieDomain}}</code>)不匹配。是否继续?",
|
"continueSubtitle": "点击按钮以继续您的应用。",
|
||||||
"logoutFailTitle": "注销失败",
|
"logoutFailTitle": "注销失败",
|
||||||
"logoutFailSubtitle": "请重试",
|
"logoutFailSubtitle": "请重试",
|
||||||
"logoutSuccessTitle": "已登出",
|
"logoutSuccessTitle": "已登出",
|
||||||
@@ -33,7 +30,7 @@
|
|||||||
"logoutUsernameSubtitle": "您当前登录用户为<code>{{username}}</code>。点击下方按钮注销。",
|
"logoutUsernameSubtitle": "您当前登录用户为<code>{{username}}</code>。点击下方按钮注销。",
|
||||||
"logoutOauthSubtitle": "您当前以<code>{{username}}</code>登录,使用的是{{provider}} OAuth 提供商。点击下方按钮注销。",
|
"logoutOauthSubtitle": "您当前以<code>{{username}}</code>登录,使用的是{{provider}} OAuth 提供商。点击下方按钮注销。",
|
||||||
"notFoundTitle": "无法找到页面",
|
"notFoundTitle": "无法找到页面",
|
||||||
"notFoundSubtitle": "您访问的页面不存在。",
|
"notFoundSubtitle": "您正在查找的页面不存在。",
|
||||||
"notFoundButton": "回到主页",
|
"notFoundButton": "回到主页",
|
||||||
"totpFailTitle": "无法验证代码",
|
"totpFailTitle": "无法验证代码",
|
||||||
"totpFailSubtitle": "请检查您的代码并重试",
|
"totpFailSubtitle": "请检查您的代码并重试",
|
||||||
@@ -45,18 +42,16 @@
|
|||||||
"unauthorizedResourceSubtitle": "用户名为<code>{{username}}</code>的用户无权访问资源<code>{{resource}}</code>。",
|
"unauthorizedResourceSubtitle": "用户名为<code>{{username}}</code>的用户无权访问资源<code>{{resource}}</code>。",
|
||||||
"unauthorizedLoginSubtitle": "用户名为<code>{{username}}</code>的用户无权登录。",
|
"unauthorizedLoginSubtitle": "用户名为<code>{{username}}</code>的用户无权登录。",
|
||||||
"unauthorizedGroupsSubtitle": "用户名为<code>{{username}}</code>的用户不在资源<code>{{resource}}</code>所需的组中。",
|
"unauthorizedGroupsSubtitle": "用户名为<code>{{username}}</code>的用户不在资源<code>{{resource}}</code>所需的组中。",
|
||||||
"unauthorizedIpSubtitle": "用户 <code>{{ip}}</code> 无权访问资源 <code>{{resource}}</code>。",
|
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
|
||||||
"unauthorizedButton": "重试",
|
"unauthorizedButton": "重试",
|
||||||
|
"untrustedRedirectTitle": "不可信的重定向",
|
||||||
|
"untrustedRedirectSubtitle": "您正在尝试重定向到一个与您已配置的域名 (<code>{{domain}}</code>) 不匹配的域名。您确定要继续吗?",
|
||||||
"cancelTitle": "取消",
|
"cancelTitle": "取消",
|
||||||
"forgotPasswordTitle": "忘记密码?",
|
"forgotPasswordTitle": "忘记密码?",
|
||||||
"failedToFetchProvidersTitle": "加载身份验证提供程序失败,请检查您的配置。",
|
"failedToFetchProvidersTitle": "加载身份验证提供程序失败,请检查您的配置。",
|
||||||
"errorTitle": "发生了错误",
|
"errorTitle": "发生了错误",
|
||||||
"errorSubtitle": "执行此操作时发生错误,请检查控制台以获取更多信息。",
|
"errorSubtitle": "执行此操作时发生错误,请检查控制台以获取更多信息。",
|
||||||
"forgotPasswordMessage": "您可以通过更改 `USERS ` 环境变量重置您的密码。",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "必添字段",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "无效的输入",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "无效域名",
|
|
||||||
"domainWarningSubtitle": "当前实例配置的访问地址为 <code>{{appUrl}}</code>,但您正在使用 <code>{{currentUrl}}</code>。若继续操作,可能会遇到身份验证问题。",
|
|
||||||
"ignoreTitle": "忽略",
|
|
||||||
"goToCorrectDomainTitle": "转到正确的域名"
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"loginTitle": "歡迎回來,請使用以下方式登入",
|
"loginTitle": "歡迎回來,請用以下方式登入",
|
||||||
"loginTitleSimple": "歡迎回來,請登入",
|
"loginTitleSimple": "歡迎回來,請登入",
|
||||||
"loginDivider": "或",
|
"loginDivider": "或",
|
||||||
"loginUsername": "帳號",
|
"loginUsername": "帳號",
|
||||||
@@ -14,17 +14,14 @@
|
|||||||
"loginOauthFailSubtitle": "無法取得 OAuth 網址",
|
"loginOauthFailSubtitle": "無法取得 OAuth 網址",
|
||||||
"loginOauthSuccessTitle": "重新導向中",
|
"loginOauthSuccessTitle": "重新導向中",
|
||||||
"loginOauthSuccessSubtitle": "正在將您重新導向至 OAuth 供應商",
|
"loginOauthSuccessSubtitle": "正在將您重新導向至 OAuth 供應商",
|
||||||
"loginOauthAutoRedirectTitle": "OAuth 自動跳轉",
|
|
||||||
"loginOauthAutoRedirectSubtitle": "自動跳轉到 OAuth 供應商進行身份驗證。",
|
|
||||||
"loginOauthAutoRedirectButton": "立即重新導向",
|
|
||||||
"continueTitle": "繼續",
|
|
||||||
"continueRedirectingTitle": "重新導向中……",
|
"continueRedirectingTitle": "重新導向中……",
|
||||||
"continueRedirectingSubtitle": "您即將被重新導向至應用程式",
|
"continueRedirectingSubtitle": "您即將被重新導向至應用程式",
|
||||||
"continueRedirectManually": "手動重新導向",
|
"continueInvalidRedirectTitle": "無效的重新導向",
|
||||||
|
"continueInvalidRedirectSubtitle": "重新導向的網址無效",
|
||||||
"continueInsecureRedirectTitle": "不安全的重新導向",
|
"continueInsecureRedirectTitle": "不安全的重新導向",
|
||||||
"continueInsecureRedirectSubtitle": "您正嘗試從安全的 <code>https</code> 重新導向至不安全的 <code>http</code>。您確定要繼續嗎?",
|
"continueInsecureRedirectSubtitle": "您正嘗試從安全的 <code>https</code> 重新導向至不安全的 <code>http</code>。您確定要繼續嗎?",
|
||||||
"continueUntrustedRedirectTitle": "不受信任的重新導向",
|
"continueTitle": "繼續",
|
||||||
"continueUntrustedRedirectSubtitle": "你嘗試重新導向的域名與設定不符(<code>{{cookieDomain}}</code>)。你確定要繼續嗎?",
|
"continueSubtitle": "點擊按鈕以繼續前往您的應用程式。",
|
||||||
"logoutFailTitle": "登出失敗",
|
"logoutFailTitle": "登出失敗",
|
||||||
"logoutFailSubtitle": "請再試一次",
|
"logoutFailSubtitle": "請再試一次",
|
||||||
"logoutSuccessTitle": "登出成功",
|
"logoutSuccessTitle": "登出成功",
|
||||||
@@ -47,16 +44,14 @@
|
|||||||
"unauthorizedGroupsSubtitle": "使用者 <code>{{username}}</code> 不在存取資源 <code>{{resource}}</code> 所需的群組中。",
|
"unauthorizedGroupsSubtitle": "使用者 <code>{{username}}</code> 不在存取資源 <code>{{resource}}</code> 所需的群組中。",
|
||||||
"unauthorizedIpSubtitle": "您的 IP 位址 <code>{{ip}}</code> 未被授權存取資源 <code>{{resource}}</code>。",
|
"unauthorizedIpSubtitle": "您的 IP 位址 <code>{{ip}}</code> 未被授權存取資源 <code>{{resource}}</code>。",
|
||||||
"unauthorizedButton": "再試一次",
|
"unauthorizedButton": "再試一次",
|
||||||
|
"untrustedRedirectTitle": "不受信任的重新導向",
|
||||||
|
"untrustedRedirectSubtitle": "您正嘗試重新導向至的網域與您設定的網域 (<code>{{domain}}</code>) 不符。您確定要繼續嗎?",
|
||||||
"cancelTitle": "取消",
|
"cancelTitle": "取消",
|
||||||
"forgotPasswordTitle": "忘記密碼?",
|
"forgotPasswordTitle": "忘記密碼?",
|
||||||
"failedToFetchProvidersTitle": "載入驗證供應商失敗。請檢查您的設定。",
|
"failedToFetchProvidersTitle": "載入驗證供應商失敗。請檢查您的設定。",
|
||||||
"errorTitle": "發生錯誤",
|
"errorTitle": "發生錯誤",
|
||||||
"errorSubtitle": "執行此操作時發生錯誤。請檢查主控台以獲取更多資訊。",
|
"errorSubtitle": "執行此操作時發生錯誤。請檢查主控台以獲取更多資訊。",
|
||||||
"forgotPasswordMessage": "透過修改 `USERS` 環境變數,你可以重設你的密碼。",
|
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
|
||||||
"fieldRequired": "此為必填欄位",
|
"fieldRequired": "This field is required",
|
||||||
"invalidInput": "無效的輸入",
|
"invalidInput": "Invalid input"
|
||||||
"domainWarningTitle": "無效的網域",
|
|
||||||
"domainWarningSubtitle": "此服務設定為透過 <code>{{appUrl}}</code> 存取,但目前使用的是 <code>{{currentUrl}}</code>。若繼續操作,可能會遇到驗證問題。",
|
|
||||||
"ignoreTitle": "忽略",
|
|
||||||
"goToCorrectDomainTitle": "前往正確域名"
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ export const isValidUrl = (url: string) => {
|
|||||||
try {
|
try {
|
||||||
new URL(url);
|
new URL(url);
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|||||||
import { AppContextProvider } from "./context/app-context.tsx";
|
import { AppContextProvider } from "./context/app-context.tsx";
|
||||||
import { UserContextProvider } from "./context/user-context.tsx";
|
import { UserContextProvider } from "./context/user-context.tsx";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import { ThemeProvider } from "./components/providers/theme-provider.tsx";
|
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
@@ -25,27 +24,25 @@ createRoot(document.getElementById("root")!).render(
|
|||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<UserContextProvider>
|
<UserContextProvider>
|
||||||
<ThemeProvider defaultTheme="system" storageKey="tinyauth-theme">
|
<BrowserRouter>
|
||||||
<BrowserRouter>
|
<Routes>
|
||||||
<Routes>
|
<Route element={<Layout />} errorElement={<ErrorPage />}>
|
||||||
<Route element={<Layout />} errorElement={<ErrorPage />}>
|
<Route path="/" element={<App />} />
|
||||||
<Route path="/" element={<App />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/logout" element={<LogoutPage />} />
|
||||||
<Route path="/logout" element={<LogoutPage />} />
|
<Route path="/continue" element={<ContinuePage />} />
|
||||||
<Route path="/continue" element={<ContinuePage />} />
|
<Route path="/totp" element={<TotpPage />} />
|
||||||
<Route path="/totp" element={<TotpPage />} />
|
<Route
|
||||||
<Route
|
path="/forgot-password"
|
||||||
path="/forgot-password"
|
element={<ForgotPasswordPage />}
|
||||||
element={<ForgotPasswordPage />}
|
/>
|
||||||
/>
|
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
||||||
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
<Route path="/error" element={<ErrorPage />} />
|
||||||
<Route path="/error" element={<ErrorPage />} />
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
<Route path="*" element={<NotFoundPage />} />
|
</Route>
|
||||||
</Route>
|
</Routes>
|
||||||
</Routes>
|
</BrowserRouter>
|
||||||
</BrowserRouter>
|
<Toaster />
|
||||||
<Toaster />
|
|
||||||
</ThemeProvider>
|
|
||||||
</UserContextProvider>
|
</UserContextProvider>
|
||||||
</AppContextProvider>
|
</AppContextProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Navigate, useLocation, useNavigate } from "react-router";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export const ContinuePage = () => {
|
export const ContinuePage = () => {
|
||||||
const { cookieDomain, disableUiWarnings } = useAppContext();
|
const { cookieDomain } = useAppContext();
|
||||||
const { isLoggedIn } = useUserContext();
|
const { isLoggedIn } = useUserContext();
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -53,16 +53,12 @@ export const ContinuePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoggedIn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!isValidRedirectUri ||
|
!isLoggedIn ||
|
||||||
!isAllowedRedirectProto ||
|
!isValidRedirectUri ||
|
||||||
!isTrustedRedirectUri ||
|
!isTrustedRedirectUri ||
|
||||||
isHttpsDowngrade) &&
|
!isAllowedRedirectProto ||
|
||||||
!disableUiWarnings
|
isHttpsDowngrade
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -95,7 +91,7 @@ export const ContinuePage = () => {
|
|||||||
return <Navigate to="/logout" replace />;
|
return <Navigate to="/logout" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTrustedRedirectUri && !disableUiWarnings) {
|
if (!isTrustedRedirectUri) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -133,7 +129,7 @@ export const ContinuePage = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHttpsDowngrade && !disableUiWarnings) {
|
if (isHttpsDowngrade) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { OAuthButton } from "@/components/ui/oauth-button";
|
|||||||
import { SeperatorWithChildren } from "@/components/ui/separator";
|
import { SeperatorWithChildren } from "@/components/ui/separator";
|
||||||
import { useAppContext } from "@/context/app-context";
|
import { useAppContext } from "@/context/app-context";
|
||||||
import { useUserContext } from "@/context/user-context";
|
import { useUserContext } from "@/context/user-context";
|
||||||
|
import { useIsMounted } from "@/lib/hooks/use-is-mounted";
|
||||||
import { LoginSchema } from "@/schemas/login-schema";
|
import { LoginSchema } from "@/schemas/login-schema";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import axios, { AxiosError } from "axios";
|
import axios, { AxiosError } from "axios";
|
||||||
@@ -39,6 +40,7 @@ export const LoginPage = () => {
|
|||||||
const { providers, title, oauthAutoRedirect } = useAppContext();
|
const { providers, title, oauthAutoRedirect } = useAppContext();
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const isMounted = useIsMounted();
|
||||||
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
|
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
||||||
@@ -110,18 +112,19 @@ export const LoginPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (isMounted()) {
|
||||||
providers.find((provider) => provider.id === oauthAutoRedirect) &&
|
if (
|
||||||
!isLoggedIn &&
|
oauthProviders.length !== 0 &&
|
||||||
redirectUri
|
providers.find((provider) => provider.id === oauthAutoRedirect) &&
|
||||||
) {
|
!isLoggedIn &&
|
||||||
// Not sure of a better way to do this
|
redirectUri
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
) {
|
||||||
setOauthAutoRedirectHandover(true);
|
setOauthAutoRedirectHandover(true);
|
||||||
oauthMutation.mutate(oauthAutoRedirect);
|
oauthMutation.mutate(oauthAutoRedirect);
|
||||||
redirectButtonTimer.current = window.setTimeout(() => {
|
redirectButtonTimer.current = window.setTimeout(() => {
|
||||||
setShowRedirectButton(true);
|
setShowRedirectButton(true);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export const appContextSchema = z.object({
|
|||||||
forgotPasswordMessage: z.string(),
|
forgotPasswordMessage: z.string(),
|
||||||
backgroundImage: z.string(),
|
backgroundImage: z.string(),
|
||||||
oauthAutoRedirect: z.string(),
|
oauthAutoRedirect: z.string(),
|
||||||
disableUiWarnings: z.boolean(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AppContextSchema = z.infer<typeof appContextSchema>;
|
export type AppContextSchema = z.infer<typeof appContextSchema>;
|
||||||
|
|||||||
179
go.mod
179
go.mod
@@ -1,131 +1,134 @@
|
|||||||
module github.com/steveiliop56/tinyauth
|
module 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/gin-gonic/gin v1.10.1
|
||||||
github.com/docker/docker v28.5.2+incompatible
|
|
||||||
github.com/gin-gonic/gin v1.11.0
|
|
||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12
|
github.com/go-playground/validator/v10 v10.27.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
github.com/golang-migrate/migrate/v4 v4.19.0
|
||||||
github.com/google/go-querystring v1.1.0
|
github.com/google/go-querystring v1.1.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/spf13/cobra v1.10.1
|
||||||
|
github.com/spf13/viper v1.21.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.0
|
||||||
golang.org/x/crypto v0.46.0
|
golang.org/x/crypto v0.42.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.0
|
||||||
gorm.io/gorm v1.31.1
|
|
||||||
gotest.tools/v3 v3.5.2
|
gotest.tools/v3 v3.5.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
|
||||||
github.com/boombuler/barcode v1.0.2 // indirect
|
|
||||||
github.com/bytedance/sonic v1.14.0 // indirect
|
|
||||||
github.com/bytedance/sonic/loader 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/bubbletea v1.3.6 // indirect
|
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
|
||||||
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13 // 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/term v0.2.1 // indirect
|
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
|
||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
|
||||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
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-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
|
||||||
github.com/go-playground/locales v0.14.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-yaml v1.18.0 // indirect
|
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/huandu/xstrings v1.5.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.11 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.32 // 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/reflectwalk v1.0.2 // indirect
|
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
|
||||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.2 // indirect
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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/twitchyliquid64/golang-asm v0.15.1 // indirect
|
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // 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/otel v1.37.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.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/sdk v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/arch v0.20.0 // indirect
|
golang.org/x/term v0.35.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
|
||||||
golang.org/x/sync v0.19.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
|
|
||||||
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/libc v1.66.3 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.11.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.38.2 // indirect
|
modernc.org/sqlite v1.38.2 // indirect
|
||||||
rsc.io/qr v0.2.0 // indirect
|
rsc.io/qr v0.2.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
|
github.com/boombuler/barcode v1.0.2 // indirect
|
||||||
|
github.com/bytedance/sonic v1.12.7 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.3 // indirect
|
||||||
|
github.com/catppuccin/go v0.3.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.4 // indirect
|
||||||
|
github.com/charmbracelet/huh v0.7.0
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||||
|
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/docker v28.4.0+incompatible
|
||||||
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
|
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.11
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.4 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pquerna/otp v1.5.0
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||||
|
golang.org/x/arch v0.13.0 // indirect
|
||||||
|
golang.org/x/net v0.44.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.31.0
|
||||||
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
|
golang.org/x/text v0.29.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.3 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|||||||
265
go.sum
265
go.sum
@@ -2,52 +2,44 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
|
|||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
|
||||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
|
||||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
|
||||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
|
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||||
github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
|
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
|
||||||
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
|
||||||
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
|
||||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||||
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
||||||
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws=
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw=
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU=
|
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
|
||||||
github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc=
|
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||||
github.com/charmbracelet/huh v0.8.0 h1:Xz/Pm2h64cXQZn/Jvele4J3r7DDiqFCNIVteYukxDvY=
|
github.com/charmbracelet/huh v0.7.0 h1:W8S1uyGETgj9Tuda3/JdVkc3x7DBLZYPZc4c+/rnRdc=
|
||||||
github.com/charmbracelet/huh v0.8.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4=
|
github.com/charmbracelet/huh v0.7.0/go.mod h1:UGC3DZHlgOKHvHC07a5vHag41zzhpPFj34U92sOmyuk=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
|
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||||
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
|
github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
|
||||||
@@ -64,8 +56,9 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8
|
|||||||
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
||||||
github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI=
|
github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI=
|
||||||
github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4=
|
github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
@@ -73,16 +66,16 @@ github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmC
|
|||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk=
|
||||||
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
@@ -95,20 +88,22 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
|||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||||
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
|
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||||
|
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||||
|
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
|
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
|
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
@@ -120,15 +115,15 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
||||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
|
||||||
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.0 h1:RcjOnCGz3Or6HQYEJ/EEVLfWnmw9KnoigPSjzhCuaSE=
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
github.com/golang-migrate/migrate/v4 v4.19.0/go.mod h1:9dyEcu+hO+G9hPSw8AIg50yg622pXJsoHItQnDGZkI0=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
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=
|
||||||
@@ -137,18 +132,19 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
|
|||||||
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=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||||
@@ -167,8 +163,10 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
@@ -194,14 +192,8 @@ github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuE
|
|||||||
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFet4=
|
github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFet4=
|
||||||
github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=
|
github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
@@ -233,15 +225,10 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
|
|||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||||
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
|
||||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
|
||||||
github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE=
|
|
||||||
github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
@@ -252,38 +239,53 @@ github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWN
|
|||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
|
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
||||||
|
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
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.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/weppos/publicsuffix-go v0.50.1 h1:elrBHeSkS/eIb169+DnLrknqmdP4AjT0Q0tEdytz1Og=
|
github.com/weppos/publicsuffix-go v0.50.0 h1:M178k6l8cnh9T1c1cStkhytVxdk5zPd6gGZf8ySIuVo=
|
||||||
github.com/weppos/publicsuffix-go v0.50.1/go.mod h1:znn0JVXjcR5hpUl9pbEogwH6I710rA1AX0QQPT0bf+k=
|
github.com/weppos/publicsuffix-go v0.50.0/go.mod h1:VXhClBYMlDrUsome4pOTpe68Ui0p6iQRAbyHQD1yKoU=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||||
@@ -292,92 +294,60 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3S
|
|||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
|
||||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
|
||||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
|
||||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
|
||||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
|
||||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
|
||||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
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/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-20191204190536-9bdfabe68543/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-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
|
||||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
||||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
|
||||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
||||||
@@ -406,5 +376,6 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
|||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
||||||
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
|
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "sessions" DROP COLUMN "oauth_sub";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "sessions" ADD COLUMN "oauth_sub" TEXT;
|
|
||||||
@@ -2,38 +2,39 @@ package bootstrap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"tinyauth/internal/config"
|
||||||
|
"tinyauth/internal/controller"
|
||||||
|
"tinyauth/internal/middleware"
|
||||||
|
"tinyauth/internal/service"
|
||||||
|
"tinyauth/internal/utils"
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/steveiliop56/tinyauth/internal/controller"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/model"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/utils"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Controller interface {
|
||||||
|
SetupRoutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Middleware interface {
|
||||||
|
Middleware() gin.HandlerFunc
|
||||||
|
Init() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Init() error
|
||||||
|
}
|
||||||
|
|
||||||
type BootstrapApp struct {
|
type BootstrapApp struct {
|
||||||
config config.Config
|
config config.Config
|
||||||
context struct {
|
uuid string
|
||||||
uuid string
|
|
||||||
cookieDomain string
|
|
||||||
sessionCookieName string
|
|
||||||
csrfCookieName string
|
|
||||||
redirectCookieName string
|
|
||||||
users []config.User
|
|
||||||
oauthProviders map[string]config.OAuthServiceConfig
|
|
||||||
configuredProviders []controller.Provider
|
|
||||||
}
|
|
||||||
services Services
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBootstrapApp(config config.Config) *BootstrapApp {
|
func NewBootstrapApp(config config.Config) *BootstrapApp {
|
||||||
@@ -44,42 +45,17 @@ func NewBootstrapApp(config config.Config) *BootstrapApp {
|
|||||||
|
|
||||||
func (app *BootstrapApp) Setup() error {
|
func (app *BootstrapApp) Setup() error {
|
||||||
// Parse users
|
// Parse users
|
||||||
users, err := utils.GetUsers(app.config.Auth.Users, app.config.Auth.UsersFile)
|
users, err := utils.GetUsers(app.config.Users, app.config.UsersFile)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
app.context.users = users
|
// Get OAuth configs
|
||||||
|
oauthProviders, err := utils.GetOAuthProvidersConfig(os.Environ(), os.Args, app.config.AppURL)
|
||||||
|
|
||||||
// Setup OAuth providers
|
if err != nil {
|
||||||
app.context.oauthProviders = app.config.OAuth.Providers
|
return err
|
||||||
|
|
||||||
for name, provider := range app.context.oauthProviders {
|
|
||||||
secret := utils.GetSecret(provider.ClientSecret, provider.ClientSecretFile)
|
|
||||||
provider.ClientSecret = secret
|
|
||||||
provider.ClientSecretFile = ""
|
|
||||||
app.context.oauthProviders[name] = provider
|
|
||||||
}
|
|
||||||
|
|
||||||
for id := range config.OverrideProviders {
|
|
||||||
if provider, exists := app.context.oauthProviders[id]; exists {
|
|
||||||
if provider.RedirectURL == "" {
|
|
||||||
provider.RedirectURL = app.config.AppURL + "/api/oauth/callback/" + id
|
|
||||||
app.context.oauthProviders[id] = provider
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, provider := range app.context.oauthProviders {
|
|
||||||
if provider.Name == "" {
|
|
||||||
if name, ok := config.OverrideProviders[id]; ok {
|
|
||||||
provider.Name = name
|
|
||||||
} else {
|
|
||||||
provider.Name = utils.Capitalize(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.context.oauthProviders[id] = provider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cookie domain
|
// Get cookie domain
|
||||||
@@ -89,38 +65,107 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
app.context.cookieDomain = cookieDomain
|
|
||||||
|
|
||||||
// Cookie names
|
// Cookie names
|
||||||
appUrl, _ := url.Parse(app.config.AppURL) // Already validated
|
appUrl, _ := url.Parse(app.config.AppURL) // Already validated
|
||||||
app.context.uuid = utils.GenerateUUID(appUrl.Hostname())
|
uuid := utils.GenerateUUID(appUrl.Hostname())
|
||||||
cookieId := strings.Split(app.context.uuid, "-")[0]
|
app.uuid = uuid
|
||||||
app.context.sessionCookieName = fmt.Sprintf("%s-%s", config.SessionCookieName, cookieId)
|
cookieId := strings.Split(uuid, "-")[0]
|
||||||
app.context.csrfCookieName = fmt.Sprintf("%s-%s", config.CSRFCookieName, cookieId)
|
sessionCookieName := fmt.Sprintf("%s-%s", config.SessionCookieName, cookieId)
|
||||||
app.context.redirectCookieName = fmt.Sprintf("%s-%s", config.RedirectCookieName, cookieId)
|
csrfCookieName := fmt.Sprintf("%s-%s", config.CSRFCookieName, cookieId)
|
||||||
|
redirectCookieName := fmt.Sprintf("%s-%s", config.RedirectCookieName, cookieId)
|
||||||
|
|
||||||
// Dumps
|
// Create configs
|
||||||
log.Trace().Interface("config", app.config).Msg("Config dump")
|
authConfig := service.AuthServiceConfig{
|
||||||
log.Trace().Interface("users", app.context.users).Msg("Users dump")
|
Users: users,
|
||||||
log.Trace().Interface("oauthProviders", app.context.oauthProviders).Msg("OAuth providers dump")
|
OauthWhitelist: app.config.OAuthWhitelist,
|
||||||
log.Trace().Str("cookieDomain", app.context.cookieDomain).Msg("Cookie domain")
|
SessionExpiry: app.config.SessionExpiry,
|
||||||
log.Trace().Str("sessionCookieName", app.context.sessionCookieName).Msg("Session cookie name")
|
SecureCookie: app.config.SecureCookie,
|
||||||
log.Trace().Str("csrfCookieName", app.context.csrfCookieName).Msg("CSRF cookie name")
|
CookieDomain: cookieDomain,
|
||||||
log.Trace().Str("redirectCookieName", app.context.redirectCookieName).Msg("Redirect cookie name")
|
LoginTimeout: app.config.LoginTimeout,
|
||||||
|
LoginMaxRetries: app.config.LoginMaxRetries,
|
||||||
// Services
|
SessionCookieName: sessionCookieName,
|
||||||
services, err := app.initServices()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to initialize services: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.services = services
|
// Setup services
|
||||||
|
var ldapService *service.LdapService
|
||||||
|
|
||||||
|
if app.config.LdapAddress != "" {
|
||||||
|
ldapConfig := service.LdapServiceConfig{
|
||||||
|
Address: app.config.LdapAddress,
|
||||||
|
BindDN: app.config.LdapBindDN,
|
||||||
|
BindPassword: app.config.LdapBindPassword,
|
||||||
|
BaseDN: app.config.LdapBaseDN,
|
||||||
|
Insecure: app.config.LdapInsecure,
|
||||||
|
SearchFilter: app.config.LdapSearchFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
ldapService = service.NewLdapService(ldapConfig)
|
||||||
|
|
||||||
|
err := ldapService.Init()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("Failed to initialize LDAP service, continuing without LDAP")
|
||||||
|
ldapService = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap database
|
||||||
|
databaseService := service.NewDatabaseService(service.DatabaseServiceConfig{
|
||||||
|
DatabasePath: app.config.DatabasePath,
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Debug().Str("service", fmt.Sprintf("%T", databaseService)).Msg("Initializing service")
|
||||||
|
|
||||||
|
err = databaseService.Init()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize database service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database := databaseService.GetDatabase()
|
||||||
|
|
||||||
|
// Create services
|
||||||
|
dockerService := service.NewDockerService()
|
||||||
|
authService := service.NewAuthService(authConfig, dockerService, ldapService, database)
|
||||||
|
oauthBrokerService := service.NewOAuthBrokerService(oauthProviders)
|
||||||
|
|
||||||
|
// Initialize services
|
||||||
|
services := []Service{
|
||||||
|
dockerService,
|
||||||
|
authService,
|
||||||
|
oauthBrokerService,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, svc := range services {
|
||||||
|
if svc != nil {
|
||||||
|
log.Debug().Str("service", fmt.Sprintf("%T", svc)).Msg("Initializing service")
|
||||||
|
err := svc.Init()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Configured providers
|
// Configured providers
|
||||||
|
babysit := map[string]string{
|
||||||
|
"google": "Google",
|
||||||
|
"github": "GitHub",
|
||||||
|
}
|
||||||
configuredProviders := make([]controller.Provider, 0)
|
configuredProviders := make([]controller.Provider, 0)
|
||||||
|
|
||||||
for id, provider := range app.context.oauthProviders {
|
for id, provider := range oauthProviders {
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.Name == "" {
|
||||||
|
if name, ok := babysit[id]; ok {
|
||||||
|
provider.Name = name
|
||||||
|
} else {
|
||||||
|
provider.Name = utils.Capitalize(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
configuredProviders = append(configuredProviders, controller.Provider{
|
configuredProviders = append(configuredProviders, controller.Provider{
|
||||||
Name: provider.Name,
|
Name: provider.Name,
|
||||||
ID: id,
|
ID: id,
|
||||||
@@ -128,11 +173,7 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(configuredProviders, func(i, j int) bool {
|
if authService.UserAuthConfigured() || ldapService != nil {
|
||||||
return configuredProviders[i].Name < configuredProviders[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
if services.authService.UserAuthConfigured() {
|
|
||||||
configuredProviders = append(configuredProviders, controller.Provider{
|
configuredProviders = append(configuredProviders, controller.Provider{
|
||||||
Name: "Username",
|
Name: "Username",
|
||||||
ID: "username",
|
ID: "username",
|
||||||
@@ -146,18 +187,89 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
return fmt.Errorf("no authentication providers configured")
|
return fmt.Errorf("no authentication providers configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
app.context.configuredProviders = configuredProviders
|
// Create engine
|
||||||
|
engine := gin.New()
|
||||||
|
|
||||||
// Setup router
|
if len(app.config.TrustedProxies) > 0 {
|
||||||
router, err := app.setupRouter()
|
engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ","))
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to setup routes: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start DB cleanup routine
|
if config.Version != "development" {
|
||||||
log.Debug().Msg("Starting database cleanup routine")
|
gin.SetMode(gin.ReleaseMode)
|
||||||
go app.dbCleanup(services.databaseService.GetDatabase())
|
}
|
||||||
|
|
||||||
|
// Create middlewares
|
||||||
|
var middlewares []Middleware
|
||||||
|
|
||||||
|
contextMiddleware := middleware.NewContextMiddleware(middleware.ContextMiddlewareConfig{
|
||||||
|
CookieDomain: cookieDomain,
|
||||||
|
}, authService, oauthBrokerService)
|
||||||
|
|
||||||
|
uiMiddleware := middleware.NewUIMiddleware()
|
||||||
|
zerologMiddleware := middleware.NewZerologMiddleware()
|
||||||
|
|
||||||
|
middlewares = append(middlewares, contextMiddleware, uiMiddleware, zerologMiddleware)
|
||||||
|
|
||||||
|
for _, middleware := range middlewares {
|
||||||
|
log.Debug().Str("middleware", fmt.Sprintf("%T", middleware)).Msg("Initializing middleware")
|
||||||
|
err := middleware.Init()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize middleware %T: %w", middleware, err)
|
||||||
|
}
|
||||||
|
engine.Use(middleware.Middleware())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create routers
|
||||||
|
mainRouter := engine.Group("")
|
||||||
|
apiRouter := engine.Group("/api")
|
||||||
|
|
||||||
|
// Create controllers
|
||||||
|
contextController := controller.NewContextController(controller.ContextControllerConfig{
|
||||||
|
Providers: configuredProviders,
|
||||||
|
Title: app.config.Title,
|
||||||
|
AppURL: app.config.AppURL,
|
||||||
|
CookieDomain: cookieDomain,
|
||||||
|
ForgotPasswordMessage: app.config.ForgotPasswordMessage,
|
||||||
|
BackgroundImage: app.config.BackgroundImage,
|
||||||
|
OAuthAutoRedirect: app.config.OAuthAutoRedirect,
|
||||||
|
}, apiRouter)
|
||||||
|
|
||||||
|
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
|
||||||
|
AppURL: app.config.AppURL,
|
||||||
|
SecureCookie: app.config.SecureCookie,
|
||||||
|
CSRFCookieName: csrfCookieName,
|
||||||
|
RedirectCookieName: redirectCookieName,
|
||||||
|
CookieDomain: cookieDomain,
|
||||||
|
}, apiRouter, authService, oauthBrokerService)
|
||||||
|
|
||||||
|
proxyController := controller.NewProxyController(controller.ProxyControllerConfig{
|
||||||
|
AppURL: app.config.AppURL,
|
||||||
|
}, apiRouter, dockerService, authService)
|
||||||
|
|
||||||
|
userController := controller.NewUserController(controller.UserControllerConfig{
|
||||||
|
CookieDomain: cookieDomain,
|
||||||
|
}, apiRouter, authService)
|
||||||
|
|
||||||
|
resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
|
||||||
|
ResourcesDir: app.config.ResourcesDir,
|
||||||
|
}, mainRouter)
|
||||||
|
|
||||||
|
healthController := controller.NewHealthController(apiRouter)
|
||||||
|
|
||||||
|
// Setup routes
|
||||||
|
controller := []Controller{
|
||||||
|
contextController,
|
||||||
|
oauthController,
|
||||||
|
proxyController,
|
||||||
|
userController,
|
||||||
|
healthController,
|
||||||
|
resourcesController,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ctrl := range controller {
|
||||||
|
log.Debug().Msgf("Setting up %T controller", ctrl)
|
||||||
|
ctrl.SetupRoutes()
|
||||||
|
}
|
||||||
|
|
||||||
// If analytics are not disabled, start heartbeat
|
// If analytics are not disabled, start heartbeat
|
||||||
if !app.config.DisableAnalytics {
|
if !app.config.DisableAnalytics {
|
||||||
@@ -165,28 +277,10 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
go app.heartbeat()
|
go app.heartbeat()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have an socket path, bind to it
|
|
||||||
if app.config.Server.SocketPath != "" {
|
|
||||||
if _, err := os.Stat(app.config.Server.SocketPath); err == nil {
|
|
||||||
log.Info().Msgf("Removing existing socket file %s", app.config.Server.SocketPath)
|
|
||||||
err := os.Remove(app.config.Server.SocketPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to remove existing socket file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Msgf("Starting server on unix socket %s", app.config.Server.SocketPath)
|
|
||||||
if err := router.RunUnix(app.config.Server.SocketPath); err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to start server")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
address := fmt.Sprintf("%s:%d", app.config.Server.Address, app.config.Server.Port)
|
address := fmt.Sprintf("%s:%d", app.config.Address, app.config.Port)
|
||||||
log.Info().Msgf("Starting server on %s", address)
|
log.Info().Msgf("Starting server on %s", address)
|
||||||
if err := router.Run(address); err != nil {
|
if err := engine.Run(address); err != nil {
|
||||||
log.Fatal().Err(err).Msg("Failed to start server")
|
log.Fatal().Err(err).Msg("Failed to start server")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +298,7 @@ func (app *BootstrapApp) heartbeat() {
|
|||||||
|
|
||||||
var body heartbeat
|
var body heartbeat
|
||||||
|
|
||||||
body.UUID = app.context.uuid
|
body.UUID = app.uuid
|
||||||
body.Version = config.Version
|
body.Version = config.Version
|
||||||
|
|
||||||
bodyJson, err := json.Marshal(body)
|
bodyJson, err := json.Marshal(body)
|
||||||
@@ -214,9 +308,7 @@ func (app *BootstrapApp) heartbeat() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{}
|
||||||
Timeout: 30 * time.Second, // The server should never take more than 30 seconds to respond
|
|
||||||
}
|
|
||||||
|
|
||||||
heartbeatURL := config.ApiServer + "/v1/instances/heartbeat"
|
heartbeatURL := config.ApiServer + "/v1/instances/heartbeat"
|
||||||
|
|
||||||
@@ -241,22 +333,8 @@ func (app *BootstrapApp) heartbeat() {
|
|||||||
|
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
|
|
||||||
if res.StatusCode != 200 && res.StatusCode != 201 {
|
if res.StatusCode != 200 {
|
||||||
log.Debug().Str("status", res.Status).Msg("Heartbeat returned non-200/201 status")
|
log.Debug().Str("status", res.Status).Msg("Heartbeat returned non-200 status")
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *BootstrapApp) dbCleanup(db *gorm.DB) {
|
|
||||||
ticker := time.NewTicker(time.Duration(30) * time.Minute)
|
|
||||||
defer ticker.Stop()
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
for ; true; <-ticker.C {
|
|
||||||
log.Debug().Msg("Cleaning up old database sessions")
|
|
||||||
_, err := gorm.G[model.Session](db).Where("expiry < ?", time.Now().Unix()).Delete(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to cleanup old sessions")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
package bootstrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/controller"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/middleware"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
|
|
||||||
engine := gin.New()
|
|
||||||
engine.Use(gin.Recovery())
|
|
||||||
|
|
||||||
if len(app.config.Server.TrustedProxies) > 0 {
|
|
||||||
err := engine.SetTrustedProxies(strings.Split(app.config.Server.TrustedProxies, ","))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set trusted proxies: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contextMiddleware := middleware.NewContextMiddleware(middleware.ContextMiddlewareConfig{
|
|
||||||
CookieDomain: app.context.cookieDomain,
|
|
||||||
}, app.services.authService, app.services.oauthBrokerService)
|
|
||||||
|
|
||||||
err := contextMiddleware.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to initialize context middleware: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.Use(contextMiddleware.Middleware())
|
|
||||||
|
|
||||||
uiMiddleware := middleware.NewUIMiddleware()
|
|
||||||
|
|
||||||
err = uiMiddleware.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to initialize UI middleware: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.Use(uiMiddleware.Middleware())
|
|
||||||
|
|
||||||
zerologMiddleware := middleware.NewZerologMiddleware()
|
|
||||||
|
|
||||||
err = zerologMiddleware.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to initialize zerolog middleware: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.Use(zerologMiddleware.Middleware())
|
|
||||||
|
|
||||||
apiRouter := engine.Group("/api")
|
|
||||||
|
|
||||||
contextController := controller.NewContextController(controller.ContextControllerConfig{
|
|
||||||
Providers: app.context.configuredProviders,
|
|
||||||
Title: app.config.UI.Title,
|
|
||||||
AppURL: app.config.AppURL,
|
|
||||||
CookieDomain: app.context.cookieDomain,
|
|
||||||
ForgotPasswordMessage: app.config.UI.ForgotPasswordMessage,
|
|
||||||
BackgroundImage: app.config.UI.BackgroundImage,
|
|
||||||
OAuthAutoRedirect: app.config.OAuth.AutoRedirect,
|
|
||||||
DisableUIWarnings: app.config.DisableUIWarnings,
|
|
||||||
}, apiRouter)
|
|
||||||
|
|
||||||
contextController.SetupRoutes()
|
|
||||||
|
|
||||||
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
|
|
||||||
AppURL: app.config.AppURL,
|
|
||||||
SecureCookie: app.config.Auth.SecureCookie,
|
|
||||||
CSRFCookieName: app.context.csrfCookieName,
|
|
||||||
RedirectCookieName: app.context.redirectCookieName,
|
|
||||||
CookieDomain: app.context.cookieDomain,
|
|
||||||
}, apiRouter, app.services.authService, app.services.oauthBrokerService)
|
|
||||||
|
|
||||||
oauthController.SetupRoutes()
|
|
||||||
|
|
||||||
proxyController := controller.NewProxyController(controller.ProxyControllerConfig{
|
|
||||||
AppURL: app.config.AppURL,
|
|
||||||
}, apiRouter, app.services.accessControlService, app.services.authService)
|
|
||||||
|
|
||||||
proxyController.SetupRoutes()
|
|
||||||
|
|
||||||
userController := controller.NewUserController(controller.UserControllerConfig{
|
|
||||||
CookieDomain: app.context.cookieDomain,
|
|
||||||
}, apiRouter, app.services.authService)
|
|
||||||
|
|
||||||
userController.SetupRoutes()
|
|
||||||
|
|
||||||
resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
|
|
||||||
ResourcesDir: app.config.ResourcesDir,
|
|
||||||
ResourcesDisabled: app.config.DisableResources,
|
|
||||||
}, &engine.RouterGroup)
|
|
||||||
|
|
||||||
resourcesController.SetupRoutes()
|
|
||||||
|
|
||||||
healthController := controller.NewHealthController(apiRouter)
|
|
||||||
|
|
||||||
healthController.SetupRoutes()
|
|
||||||
|
|
||||||
return engine, nil
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
package bootstrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Services struct {
|
|
||||||
accessControlService *service.AccessControlsService
|
|
||||||
authService *service.AuthService
|
|
||||||
databaseService *service.DatabaseService
|
|
||||||
dockerService *service.DockerService
|
|
||||||
ldapService *service.LdapService
|
|
||||||
oauthBrokerService *service.OAuthBrokerService
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *BootstrapApp) initServices() (Services, error) {
|
|
||||||
services := Services{}
|
|
||||||
|
|
||||||
databaseService := service.NewDatabaseService(service.DatabaseServiceConfig{
|
|
||||||
DatabasePath: app.config.DatabasePath,
|
|
||||||
})
|
|
||||||
|
|
||||||
err := databaseService.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Services{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
services.databaseService = databaseService
|
|
||||||
|
|
||||||
ldapService := service.NewLdapService(service.LdapServiceConfig{
|
|
||||||
Address: app.config.Ldap.Address,
|
|
||||||
BindDN: app.config.Ldap.BindDN,
|
|
||||||
BindPassword: app.config.Ldap.BindPassword,
|
|
||||||
BaseDN: app.config.Ldap.BaseDN,
|
|
||||||
Insecure: app.config.Ldap.Insecure,
|
|
||||||
SearchFilter: app.config.Ldap.SearchFilter,
|
|
||||||
})
|
|
||||||
|
|
||||||
err = ldapService.Init()
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
services.ldapService = ldapService
|
|
||||||
} else {
|
|
||||||
log.Warn().Err(err).Msg("Failed to initialize LDAP service, continuing without it")
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerService := service.NewDockerService()
|
|
||||||
|
|
||||||
err = dockerService.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Services{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
services.dockerService = dockerService
|
|
||||||
|
|
||||||
accessControlsService := service.NewAccessControlsService(dockerService, app.config.Apps)
|
|
||||||
|
|
||||||
err = accessControlsService.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Services{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
services.accessControlService = accessControlsService
|
|
||||||
|
|
||||||
authService := service.NewAuthService(service.AuthServiceConfig{
|
|
||||||
Users: app.context.users,
|
|
||||||
OauthWhitelist: app.config.OAuth.Whitelist,
|
|
||||||
SessionExpiry: app.config.Auth.SessionExpiry,
|
|
||||||
SecureCookie: app.config.Auth.SecureCookie,
|
|
||||||
CookieDomain: app.context.cookieDomain,
|
|
||||||
LoginTimeout: app.config.Auth.LoginTimeout,
|
|
||||||
LoginMaxRetries: app.config.Auth.LoginMaxRetries,
|
|
||||||
SessionCookieName: app.context.sessionCookieName,
|
|
||||||
}, dockerService, ldapService, databaseService.GetDatabase())
|
|
||||||
|
|
||||||
err = authService.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Services{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
services.authService = authService
|
|
||||||
|
|
||||||
oauthBrokerService := service.NewOAuthBrokerService(app.context.oauthProviders)
|
|
||||||
|
|
||||||
err = oauthBrokerService.Init()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Services{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
services.oauthBrokerService = oauthBrokerService
|
|
||||||
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,8 @@ package config
|
|||||||
// Version information, set at build time
|
// Version information, set at build time
|
||||||
|
|
||||||
var Version = "development"
|
var Version = "development"
|
||||||
var CommitHash = "development"
|
var CommitHash = "n/a"
|
||||||
var BuildTimestamp = "0000-00-00T00:00:00Z"
|
var BuildTimestamp = "n/a"
|
||||||
|
|
||||||
// Cookie name templates
|
// Cookie name templates
|
||||||
|
|
||||||
@@ -15,72 +15,36 @@ var RedirectCookieName = "tinyauth-redirect"
|
|||||||
// Main app config
|
// Main app config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"`
|
Port int `mapstructure:"port" validate:"required"`
|
||||||
LogLevel string `description:"Log level (trace, debug, info, warn, error)." yaml:"logLevel"`
|
Address string `validate:"required,ip4_addr" mapstructure:"address"`
|
||||||
ResourcesDir string `description:"The directory where resources are stored." yaml:"resourcesDir"`
|
AppURL string `validate:"required,url" mapstructure:"app-url"`
|
||||||
DatabasePath string `description:"The path to the database file." yaml:"databasePath"`
|
Users string `mapstructure:"users"`
|
||||||
DisableAnalytics bool `description:"Disable analytics." yaml:"disableAnalytics"`
|
UsersFile string `mapstructure:"users-file"`
|
||||||
DisableResources bool `description:"Disable resources server." yaml:"disableResources"`
|
SecureCookie bool `mapstructure:"secure-cookie"`
|
||||||
DisableUIWarnings bool `description:"Disable UI warnings." yaml:"disableUIWarnings"`
|
OAuthWhitelist string `mapstructure:"oauth-whitelist"`
|
||||||
LogJSON bool `description:"Enable JSON formatted logs." yaml:"logJSON"`
|
OAuthAutoRedirect string `mapstructure:"oauth-auto-redirect"`
|
||||||
Server ServerConfig `description:"Server configuration." yaml:"server"`
|
SessionExpiry int `mapstructure:"session-expiry"`
|
||||||
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
|
LogLevel string `mapstructure:"log-level" validate:"oneof=trace debug info warn error fatal panic"`
|
||||||
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
|
Title string `mapstructure:"app-title"`
|
||||||
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
|
LoginTimeout int `mapstructure:"login-timeout"`
|
||||||
UI UIConfig `description:"UI customization." yaml:"ui"`
|
LoginMaxRetries int `mapstructure:"login-max-retries"`
|
||||||
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
|
ForgotPasswordMessage string `mapstructure:"forgot-password-message"`
|
||||||
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
|
BackgroundImage string `mapstructure:"background-image" validate:"required"`
|
||||||
|
LdapAddress string `mapstructure:"ldap-address"`
|
||||||
|
LdapBindDN string `mapstructure:"ldap-bind-dn"`
|
||||||
|
LdapBindPassword string `mapstructure:"ldap-bind-password"`
|
||||||
|
LdapBaseDN string `mapstructure:"ldap-base-dn"`
|
||||||
|
LdapInsecure bool `mapstructure:"ldap-insecure"`
|
||||||
|
LdapSearchFilter string `mapstructure:"ldap-search-filter"`
|
||||||
|
ResourcesDir string `mapstructure:"resources-dir"`
|
||||||
|
DatabasePath string `mapstructure:"database-path" validate:"required"`
|
||||||
|
TrustedProxies string `mapstructure:"trusted-proxies"`
|
||||||
|
DisableAnalytics bool `mapstructure:"disable-analytics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerConfig struct {
|
|
||||||
Port int `description:"The port on which the server listens." yaml:"port"`
|
|
||||||
Address string `description:"The address on which the server listens." yaml:"address"`
|
|
||||||
SocketPath string `description:"The path to the Unix socket." yaml:"socketPath"`
|
|
||||||
TrustedProxies string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthConfig struct {
|
|
||||||
Users string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
|
|
||||||
UsersFile string `description:"Path to the users file." yaml:"usersFile"`
|
|
||||||
SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"`
|
|
||||||
SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"`
|
|
||||||
LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"`
|
|
||||||
LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OAuthConfig struct {
|
|
||||||
Whitelist string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
|
|
||||||
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect"`
|
|
||||||
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UIConfig struct {
|
|
||||||
Title string `description:"The title of the UI." yaml:"title"`
|
|
||||||
ForgotPasswordMessage string `description:"Message displayed on the forgot password page." yaml:"forgotPasswordMessage"`
|
|
||||||
BackgroundImage string `description:"Path to the background image." yaml:"backgroundImage"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LdapConfig struct {
|
|
||||||
Address string `description:"LDAP server address." yaml:"address"`
|
|
||||||
BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn"`
|
|
||||||
BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword"`
|
|
||||||
BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn"`
|
|
||||||
Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure"`
|
|
||||||
SearchFilter string `description:"LDAP search filter." yaml:"searchFilter"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExperimentalConfig struct {
|
|
||||||
ConfigFile string `description:"Path to config file." yaml:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config loader options
|
|
||||||
|
|
||||||
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"`
|
||||||
@@ -88,21 +52,16 @@ type Claims struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OAuthServiceConfig struct {
|
type OAuthServiceConfig struct {
|
||||||
ClientID string `description:"OAuth client ID."`
|
ClientID string `key:"client-id"`
|
||||||
ClientSecret string `description:"OAuth client secret."`
|
ClientSecret string `key:"client-secret"`
|
||||||
ClientSecretFile string `description:"Path to the file containing the OAuth client secret."`
|
ClientSecretFile string `key:"client-secret-file"`
|
||||||
Scopes []string `description:"OAuth scopes."`
|
Scopes []string `key:"scopes"`
|
||||||
RedirectURL string `description:"OAuth redirect URL."`
|
RedirectURL string `key:"redirect-url"`
|
||||||
AuthURL string `description:"OAuth authorization URL."`
|
AuthURL string `key:"auth-url"`
|
||||||
TokenURL string `description:"OAuth token URL."`
|
TokenURL string `key:"token-url"`
|
||||||
UserinfoURL string `description:"OAuth userinfo URL."`
|
UserinfoURL string `key:"user-info-url"`
|
||||||
Insecure bool `description:"Allow insecure OAuth connections."`
|
InsecureSkipVerify bool `key:"insecure-skip-verify"`
|
||||||
Name string `description:"Provider name in UI."`
|
Name string `key:"name"`
|
||||||
}
|
|
||||||
|
|
||||||
var OverrideProviders = map[string]string{
|
|
||||||
"google": "Google",
|
|
||||||
"github": "GitHub",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User/session related stuff
|
// User/session related stuff
|
||||||
@@ -127,7 +86,6 @@ type SessionCookie struct {
|
|||||||
TotpPending bool
|
TotpPending bool
|
||||||
OAuthGroups string
|
OAuthGroups string
|
||||||
OAuthName string
|
OAuthName string
|
||||||
OAuthSub string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserContext struct {
|
type UserContext struct {
|
||||||
@@ -141,7 +99,6 @@ 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
|
||||||
@@ -157,55 +114,61 @@ type RedirectQuery struct {
|
|||||||
RedirectURI string `url:"redirect_uri"`
|
RedirectURI string `url:"redirect_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACLs
|
// Labels
|
||||||
|
|
||||||
type Apps struct {
|
type Apps struct {
|
||||||
Apps map[string]App `description:"App ACLs configuration." yaml:"apps"`
|
Apps map[string]App
|
||||||
}
|
}
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
Config AppConfig `description:"App configuration." yaml:"config"`
|
Config AppConfig
|
||||||
Users AppUsers `description:"User access configuration." yaml:"users"`
|
Users AppUsers
|
||||||
OAuth AppOAuth `description:"OAuth access configuration." yaml:"oauth"`
|
OAuth AppOAuth
|
||||||
IP AppIP `description:"IP access configuration." yaml:"ip"`
|
IP AppIP
|
||||||
Response AppResponse `description:"Response customization." yaml:"response"`
|
Response AppResponse
|
||||||
Path AppPath `description:"Path access configuration." yaml:"path"`
|
Path AppPath
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
Domain string `description:"The domain of the app." yaml:"domain"`
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppUsers struct {
|
type AppUsers struct {
|
||||||
Allow string `description:"Comma-separated list of allowed users." yaml:"allow"`
|
Allow string
|
||||||
Block string `description:"Comma-separated list of blocked users." yaml:"block"`
|
Block string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppOAuth struct {
|
type AppOAuth struct {
|
||||||
Whitelist string `description:"Comma-separated list of allowed OAuth groups." yaml:"whitelist"`
|
Whitelist string
|
||||||
Groups string `description:"Comma-separated list of required OAuth groups." yaml:"groups"`
|
Groups string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppIP struct {
|
type AppIP struct {
|
||||||
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow"`
|
Allow []string
|
||||||
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block"`
|
Block []string
|
||||||
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication." yaml:"bypass"`
|
Bypass []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppResponse struct {
|
type AppResponse struct {
|
||||||
Headers []string `description:"Custom headers to add to the response." yaml:"headers"`
|
Headers []string
|
||||||
BasicAuth AppBasicAuth `description:"Basic authentication for the app." yaml:"basicAuth"`
|
BasicAuth AppBasicAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppBasicAuth struct {
|
type AppBasicAuth struct {
|
||||||
Username string `description:"Basic auth username." yaml:"username"`
|
Username string
|
||||||
Password string `description:"Basic auth password." yaml:"password"`
|
Password string
|
||||||
PasswordFile string `description:"Path to the file containing the basic auth password." yaml:"passwordFile"`
|
PasswordFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppPath struct {
|
type AppPath struct {
|
||||||
Allow string `description:"Comma-separated list of allowed paths." yaml:"allow"`
|
Allow string
|
||||||
Block string `description:"Comma-separated list of blocked paths." yaml:"block"`
|
Block string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
|
||||||
|
type Providers struct {
|
||||||
|
Providers map[string]OAuthServiceConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// API server
|
// API server
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ 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"
|
||||||
@@ -21,7 +20,6 @@ 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 {
|
||||||
@@ -34,7 +32,6 @@ type AppContextResponse struct {
|
|||||||
ForgotPasswordMessage string `json:"forgotPasswordMessage"`
|
ForgotPasswordMessage string `json:"forgotPasswordMessage"`
|
||||||
BackgroundImage string `json:"backgroundImage"`
|
BackgroundImage string `json:"backgroundImage"`
|
||||||
OAuthAutoRedirect string `json:"oauthAutoRedirect"`
|
OAuthAutoRedirect string `json:"oauthAutoRedirect"`
|
||||||
DisableUIWarnings bool `json:"disableUiWarnings"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
@@ -51,7 +48,6 @@ type ContextControllerConfig struct {
|
|||||||
ForgotPasswordMessage string
|
ForgotPasswordMessage string
|
||||||
BackgroundImage string
|
BackgroundImage string
|
||||||
OAuthAutoRedirect string
|
OAuthAutoRedirect string
|
||||||
DisableUIWarnings bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextController struct {
|
type ContextController struct {
|
||||||
@@ -60,10 +56,6 @@ type ContextController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController {
|
func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController {
|
||||||
if config.DisableUIWarnings {
|
|
||||||
log.Warn().Msg("UI warnings are disabled. This may expose users to security risks. Proceed with caution.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ContextController{
|
return &ContextController{
|
||||||
config: config,
|
config: config,
|
||||||
router: router,
|
router: router,
|
||||||
@@ -90,7 +82,6 @@ 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 {
|
||||||
@@ -106,15 +97,7 @@ func (controller *ContextController) userContextHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (controller *ContextController) appContextHandler(c *gin.Context) {
|
func (controller *ContextController) appContextHandler(c *gin.Context) {
|
||||||
appUrl, err := url.Parse(controller.config.AppURL)
|
appUrl, _ := url.Parse(controller.config.AppURL) // no need to check error, validated on startup
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to parse app URL")
|
|
||||||
c.JSON(500, gin.H{
|
|
||||||
"status": 500,
|
|
||||||
"message": "Internal Server Error",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(200, AppContextResponse{
|
c.JSON(200, AppContextResponse{
|
||||||
Status: 200,
|
Status: 200,
|
||||||
@@ -126,6 +109,5 @@ func (controller *ContextController) appContextHandler(c *gin.Context) {
|
|||||||
ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
|
ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
|
||||||
BackgroundImage: controller.config.BackgroundImage,
|
BackgroundImage: controller.config.BackgroundImage,
|
||||||
OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
|
OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
|
||||||
DisableUIWarnings: controller.config.DisableUIWarnings,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"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"
|
||||||
@@ -31,7 +30,6 @@ var controllerCfg = controller.ContextControllerConfig{
|
|||||||
ForgotPasswordMessage: "Contact admin to reset your password.",
|
ForgotPasswordMessage: "Contact admin to reset your password.",
|
||||||
BackgroundImage: "/assets/bg.jpg",
|
BackgroundImage: "/assets/bg.jpg",
|
||||||
OAuthAutoRedirect: "google",
|
OAuthAutoRedirect: "google",
|
||||||
DisableUIWarnings: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var userContext = config.UserContext{
|
var userContext = config.UserContext{
|
||||||
@@ -44,7 +42,6 @@ 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) {
|
||||||
@@ -78,7 +75,6 @@ func TestAppContextHandler(t *testing.T) {
|
|||||||
ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage,
|
ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage,
|
||||||
BackgroundImage: controllerCfg.BackgroundImage,
|
BackgroundImage: controllerCfg.BackgroundImage,
|
||||||
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
||||||
DisableUIWarnings: controllerCfg.DisableUIWarnings,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router, recorder := setupContextController(nil)
|
router, recorder := setupContextController(nil)
|
||||||
@@ -106,7 +102,6 @@ func TestUserContextHandler(t *testing.T) {
|
|||||||
Provider: userContext.Provider,
|
Provider: userContext.Provider,
|
||||||
OAuth: userContext.OAuth,
|
OAuth: userContext.OAuth,
|
||||||
TotpPending: userContext.TotpPending,
|
TotpPending: userContext.TotpPending,
|
||||||
OAuthName: userContext.OAuthName,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with context
|
// Test with context
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ func NewHealthController(router *gin.RouterGroup) *HealthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (controller *HealthController) SetupRoutes() {
|
func (controller *HealthController) SetupRoutes() {
|
||||||
controller.router.GET("/healthz", controller.healthHandler)
|
controller.router.GET("/health", controller.healthHandler)
|
||||||
controller.router.HEAD("/healthz", controller.healthHandler)
|
controller.router.HEAD("/health", controller.healthHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controller *HealthController) healthHandler(c *gin.Context) {
|
func (controller *HealthController) healthHandler(c *gin.Context) {
|
||||||
|
|||||||
@@ -5,10 +5,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/service"
|
||||||
"github.com/steveiliop56/tinyauth/internal/service"
|
"tinyauth/internal/utils"
|
||||||
"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"
|
||||||
@@ -73,20 +72,13 @@ func (controller *OAuthController) oauthURLHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
service.GenerateVerifier()
|
|
||||||
state := service.GenerateState()
|
state := service.GenerateState()
|
||||||
authURL := service.GetAuthURL(state)
|
authURL := service.GetAuthURL(state)
|
||||||
c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true)
|
c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true)
|
||||||
|
|
||||||
redirectURI := c.Query("redirect_uri")
|
redirectURI := c.Query("redirect_uri")
|
||||||
isRedirectSafe := utils.IsRedirectSafe(redirectURI, controller.config.CookieDomain)
|
|
||||||
|
|
||||||
if !isRedirectSafe {
|
if redirectURI != "" && utils.IsRedirectSafe(redirectURI, controller.config.CookieDomain) {
|
||||||
log.Warn().Str("redirect_uri", redirectURI).Msg("Unsafe redirect URI detected, ignoring")
|
|
||||||
redirectURI = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if redirectURI != "" && isRedirectSafe {
|
|
||||||
log.Debug().Msg("Setting redirect URI cookie")
|
log.Debug().Msg("Setting redirect URI cookie")
|
||||||
c.SetCookie(controller.config.RedirectCookieName, redirectURI, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true)
|
c.SetCookie(controller.config.RedirectCookieName, redirectURI, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true)
|
||||||
}
|
}
|
||||||
@@ -154,8 +146,6 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !controller.auth.IsEmailWhitelisted(user.Email) {
|
if !controller.auth.IsEmailWhitelisted(user.Email) {
|
||||||
log.Warn().Str("email", user.Email).Msg("Email not whitelisted")
|
|
||||||
|
|
||||||
queries, err := query.Values(config.UnauthorizedQuery{
|
queries, err := query.Values(config.UnauthorizedQuery{
|
||||||
Username: user.Email,
|
Username: user.Email,
|
||||||
})
|
})
|
||||||
@@ -172,7 +162,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
|
|
||||||
var name string
|
var name string
|
||||||
|
|
||||||
if strings.TrimSpace(user.Name) != "" {
|
if user.Name != "" {
|
||||||
log.Debug().Msg("Using name from OAuth provider")
|
log.Debug().Msg("Using name from OAuth provider")
|
||||||
name = user.Name
|
name = user.Name
|
||||||
} else {
|
} else {
|
||||||
@@ -182,7 +172,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
|
|
||||||
var username string
|
var username string
|
||||||
|
|
||||||
if strings.TrimSpace(user.PreferredUsername) != "" {
|
if user.PreferredUsername != "" {
|
||||||
log.Debug().Msg("Using preferred username from OAuth provider")
|
log.Debug().Msg("Using preferred username from OAuth provider")
|
||||||
username = user.PreferredUsername
|
username = user.PreferredUsername
|
||||||
} else {
|
} else {
|
||||||
@@ -190,19 +180,14 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
username = strings.Replace(user.Email, "@", "_", -1)
|
username = strings.Replace(user.Email, "@", "_", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionCookie := config.SessionCookie{
|
err = controller.auth.CreateSessionCookie(c, &config.SessionCookie{
|
||||||
Username: username,
|
Username: username,
|
||||||
Name: name,
|
Name: name,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
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")
|
|
||||||
|
|
||||||
err = controller.auth.CreateSessionCookie(c, &sessionCookie)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to create session cookie")
|
log.Error().Err(err).Msg("Failed to create session cookie")
|
||||||
|
|||||||
@@ -3,20 +3,16 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/service"
|
||||||
"github.com/steveiliop56/tinyauth/internal/service"
|
"tinyauth/internal/utils"
|
||||||
"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"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var SupportedProxies = []string{"nginx", "traefik", "caddy", "envoy"}
|
|
||||||
|
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
Proxy string `uri:"proxy" binding:"required"`
|
Proxy string `uri:"proxy" binding:"required"`
|
||||||
}
|
}
|
||||||
@@ -28,15 +24,15 @@ type ProxyControllerConfig struct {
|
|||||||
type ProxyController struct {
|
type ProxyController struct {
|
||||||
config ProxyControllerConfig
|
config ProxyControllerConfig
|
||||||
router *gin.RouterGroup
|
router *gin.RouterGroup
|
||||||
acls *service.AccessControlsService
|
docker *service.DockerService
|
||||||
auth *service.AuthService
|
auth *service.AuthService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, acls *service.AccessControlsService, auth *service.AuthService) *ProxyController {
|
func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, docker *service.DockerService, auth *service.AuthService) *ProxyController {
|
||||||
return &ProxyController{
|
return &ProxyController{
|
||||||
config: config,
|
config: config,
|
||||||
router: router,
|
router: router,
|
||||||
acls: acls,
|
docker: docker,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +40,6 @@ 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.GET("/: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) {
|
||||||
@@ -60,7 +55,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(SupportedProxies, req.Proxy) {
|
if req.Proxy != "nginx" && req.Proxy != "traefik" && req.Proxy != "caddy" {
|
||||||
log.Warn().Str("proxy", req.Proxy).Msg("Invalid proxy")
|
log.Warn().Str("proxy", req.Proxy).Msg("Invalid proxy")
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": 400,
|
"status": 400,
|
||||||
@@ -81,21 +76,18 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
proto := c.Request.Header.Get("X-Forwarded-Proto")
|
proto := c.Request.Header.Get("X-Forwarded-Proto")
|
||||||
host := c.Request.Header.Get("X-Forwarded-Host")
|
host := c.Request.Header.Get("X-Forwarded-Host")
|
||||||
|
|
||||||
// Get acls
|
labels, err := controller.docker.GetLabels(host)
|
||||||
acls, err := controller.acls.GetAccessControls(host)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to get access controls for resource")
|
log.Error().Err(err).Msg("Failed to get labels from Docker")
|
||||||
controller.handleError(c, req, isBrowser)
|
controller.handleError(c, req, isBrowser)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Interface("acls", acls).Msg("ACLs for resource")
|
|
||||||
|
|
||||||
clientIP := c.ClientIP()
|
clientIP := c.ClientIP()
|
||||||
|
|
||||||
if controller.auth.IsBypassedIP(acls.IP, clientIP) {
|
if controller.auth.IsBypassedIP(labels.IP, clientIP) {
|
||||||
controller.setHeaders(c, acls)
|
controller.setHeaders(c, labels)
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"message": "Authenticated",
|
"message": "Authenticated",
|
||||||
@@ -103,7 +95,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authEnabled, err := controller.auth.IsAuthEnabled(uri, acls.Path)
|
authEnabled, err := controller.auth.IsAuthEnabled(uri, labels.Path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to check if auth is enabled for resource")
|
log.Error().Err(err).Msg("Failed to check if auth is enabled for resource")
|
||||||
@@ -113,7 +105,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
|
|
||||||
if !authEnabled {
|
if !authEnabled {
|
||||||
log.Debug().Msg("Authentication disabled for resource, allowing access")
|
log.Debug().Msg("Authentication disabled for resource, allowing access")
|
||||||
controller.setHeaders(c, acls)
|
controller.setHeaders(c, labels)
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"message": "Authenticated",
|
"message": "Authenticated",
|
||||||
@@ -121,7 +113,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !controller.auth.CheckIP(acls.IP, clientIP) {
|
if !controller.auth.CheckIP(labels.IP, clientIP) {
|
||||||
if req.Proxy == "nginx" || !isBrowser {
|
if req.Proxy == "nginx" || !isBrowser {
|
||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
"status": 401,
|
"status": 401,
|
||||||
@@ -158,15 +150,13 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
userContext = context
|
userContext = context
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Interface("context", userContext).Msg("User context from request")
|
|
||||||
|
|
||||||
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
||||||
log.Debug().Msg("User has TOTP enabled, denying basic auth access")
|
log.Debug().Msg("User has TOTP enabled, denying basic auth access")
|
||||||
userContext.IsLoggedIn = false
|
userContext.IsLoggedIn = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if userContext.IsLoggedIn {
|
if userContext.IsLoggedIn {
|
||||||
appAllowed := controller.auth.IsResourceAllowed(c, userContext, acls)
|
appAllowed := controller.auth.IsResourceAllowed(c, userContext, labels)
|
||||||
|
|
||||||
if !appAllowed {
|
if !appAllowed {
|
||||||
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User not allowed to access resource")
|
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User not allowed to access resource")
|
||||||
@@ -200,7 +190,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if userContext.OAuth {
|
if userContext.OAuth {
|
||||||
groupOK := controller.auth.IsInOAuthGroup(c, userContext, acls.OAuth.Groups)
|
groupOK := controller.auth.IsInOAuthGroup(c, userContext, labels.OAuth.Groups)
|
||||||
|
|
||||||
if !groupOK {
|
if !groupOK {
|
||||||
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User OAuth groups do not match resource requirements")
|
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User OAuth groups do not match resource requirements")
|
||||||
@@ -239,9 +229,8 @@ 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, labels)
|
||||||
|
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
"status": 200,
|
"status": 200,
|
||||||
@@ -271,21 +260,21 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode()))
|
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controller *ProxyController) setHeaders(c *gin.Context, acls config.App) {
|
func (controller *ProxyController) setHeaders(c *gin.Context, labels config.App) {
|
||||||
c.Header("Authorization", c.Request.Header.Get("Authorization"))
|
c.Header("Authorization", c.Request.Header.Get("Authorization"))
|
||||||
|
|
||||||
headers := utils.ParseHeaders(acls.Response.Headers)
|
headers := utils.ParseHeaders(labels.Response.Headers)
|
||||||
|
|
||||||
for key, value := range headers {
|
for key, value := range headers {
|
||||||
log.Debug().Str("header", key).Msg("Setting header")
|
log.Debug().Str("header", key).Msg("Setting header")
|
||||||
c.Header(key, value)
|
c.Header(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
basicPassword := utils.GetSecret(acls.Response.BasicAuth.Password, acls.Response.BasicAuth.PasswordFile)
|
basicPassword := utils.GetSecret(labels.Response.BasicAuth.Password, labels.Response.BasicAuth.PasswordFile)
|
||||||
|
|
||||||
if acls.Response.BasicAuth.Username != "" && basicPassword != "" {
|
if labels.Response.BasicAuth.Username != "" && basicPassword != "" {
|
||||||
log.Debug().Str("username", acls.Response.BasicAuth.Username).Msg("Setting basic auth header")
|
log.Debug().Str("username", labels.Response.BasicAuth.Username).Msg("Setting basic auth header")
|
||||||
c.Header("Authorization", fmt.Sprintf("Basic %s", utils.GetBasicAuth(acls.Response.BasicAuth.Username, basicPassword)))
|
c.Header("Authorization", fmt.Sprintf("Basic %s", utils.GetBasicAuth(labels.Response.BasicAuth.Username, basicPassword)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ package controller_test
|
|||||||
import (
|
import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/controller"
|
||||||
"github.com/steveiliop56/tinyauth/internal/controller"
|
"tinyauth/internal/service"
|
||||||
"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,11 +39,6 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
|
|||||||
|
|
||||||
assert.NilError(t, dockerService.Init())
|
assert.NilError(t, dockerService.Init())
|
||||||
|
|
||||||
// Access controls
|
|
||||||
accessControlsService := service.NewAccessControlsService(dockerService, map[string]config.App{})
|
|
||||||
|
|
||||||
assert.NilError(t, accessControlsService.Init())
|
|
||||||
|
|
||||||
// Auth service
|
// Auth service
|
||||||
authService := service.NewAuthService(service.AuthServiceConfig{
|
authService := service.NewAuthService(service.AuthServiceConfig{
|
||||||
Users: []config.User{
|
Users: []config.User{
|
||||||
@@ -65,7 +59,7 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
|
|||||||
// Controller
|
// Controller
|
||||||
ctrl := controller.NewProxyController(controller.ProxyControllerConfig{
|
ctrl := controller.NewProxyController(controller.ProxyControllerConfig{
|
||||||
AppURL: "http://localhost:8080",
|
AppURL: "http://localhost:8080",
|
||||||
}, group, accessControlsService, authService)
|
}, group, dockerService, authService)
|
||||||
ctrl.SetupRoutes()
|
ctrl.SetupRoutes()
|
||||||
|
|
||||||
return router, recorder, authService
|
return router, recorder, authService
|
||||||
@@ -93,18 +87,6 @@ func TestProxyHandler(t *testing.T) {
|
|||||||
assert.Equal(t, 307, recorder.Code)
|
assert.Equal(t, 307, recorder.Code)
|
||||||
assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location"))
|
assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location"))
|
||||||
|
|
||||||
// Test logged out user (envoy)
|
|
||||||
recorder = httptest.NewRecorder()
|
|
||||||
req = httptest.NewRequest("POST", "/api/auth/envoy", nil)
|
|
||||||
req.Header.Set("X-Forwarded-Proto", "https")
|
|
||||||
req.Header.Set("X-Forwarded-Host", "example.com")
|
|
||||||
req.Header.Set("X-Forwarded-Uri", "/somepath")
|
|
||||||
req.Header.Set("Accept", "text/html")
|
|
||||||
router.ServeHTTP(recorder, req)
|
|
||||||
|
|
||||||
assert.Equal(t, 307, recorder.Code)
|
|
||||||
assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location"))
|
|
||||||
|
|
||||||
// Test logged out user (nginx)
|
// Test logged out user (nginx)
|
||||||
recorder = httptest.NewRecorder()
|
recorder = httptest.NewRecorder()
|
||||||
req = httptest.NewRequest("GET", "/api/auth/nginx", nil)
|
req = httptest.NewRequest("GET", "/api/auth/nginx", nil)
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ResourcesControllerConfig struct {
|
type ResourcesControllerConfig struct {
|
||||||
ResourcesDir string
|
ResourcesDir string
|
||||||
ResourcesDisabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourcesController struct {
|
type ResourcesController struct {
|
||||||
@@ -39,12 +38,5 @@ func (controller *ResourcesController) resourcesHandler(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if controller.config.ResourcesDisabled {
|
|
||||||
c.JSON(403, gin.H{
|
|
||||||
"status": 403,
|
|
||||||
"message": "Resources are disabled",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
controller.fileServer.ServeHTTP(c.Writer, c.Request)
|
controller.fileServer.ServeHTTP(c.Writer, c.Request)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ 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,10 +3,9 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/service"
|
||||||
"github.com/steveiliop56/tinyauth/internal/service"
|
"tinyauth/internal/utils"
|
||||||
"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"
|
||||||
@@ -139,16 +138,12 @@ func (controller *UserController) loginHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionCookie := config.SessionCookie{
|
err = controller.auth.CreateSessionCookie(c, &config.SessionCookie{
|
||||||
Username: req.Username,
|
Username: req.Username,
|
||||||
Name: utils.Capitalize(req.Username),
|
Name: utils.Capitalize(req.Username),
|
||||||
Email: fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.CookieDomain),
|
Email: fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.CookieDomain),
|
||||||
Provider: "username",
|
Provider: "username",
|
||||||
}
|
})
|
||||||
|
|
||||||
log.Trace().Interface("session_cookie", sessionCookie).Msg("Creating session cookie")
|
|
||||||
|
|
||||||
err = controller.auth.CreateSessionCookie(c, &sessionCookie)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to create session cookie")
|
log.Error().Err(err).Msg("Failed to create session cookie")
|
||||||
@@ -248,16 +243,12 @@ func (controller *UserController) totpHandler(c *gin.Context) {
|
|||||||
|
|
||||||
controller.auth.RecordLoginAttempt(rateIdentifier, true)
|
controller.auth.RecordLoginAttempt(rateIdentifier, true)
|
||||||
|
|
||||||
sessionCookie := config.SessionCookie{
|
err = controller.auth.CreateSessionCookie(c, &config.SessionCookie{
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
Name: utils.Capitalize(user.Username),
|
Name: utils.Capitalize(user.Username),
|
||||||
Email: fmt.Sprintf("%s@%s", strings.ToLower(user.Username), controller.config.CookieDomain),
|
Email: fmt.Sprintf("%s@%s", strings.ToLower(user.Username), controller.config.CookieDomain),
|
||||||
Provider: "username",
|
Provider: "username",
|
||||||
}
|
})
|
||||||
|
|
||||||
log.Trace().Interface("session_cookie", sessionCookie).Msg("Creating session cookie")
|
|
||||||
|
|
||||||
err = controller.auth.CreateSessionCookie(c, &sessionCookie)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to create session cookie")
|
log.Error().Err(err).Msg("Failed to create session cookie")
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/controller"
|
||||||
"github.com/steveiliop56/tinyauth/internal/controller"
|
"tinyauth/internal/service"
|
||||||
"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,10 +3,9 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"tinyauth/internal/config"
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"tinyauth/internal/service"
|
||||||
"github.com/steveiliop56/tinyauth/internal/service"
|
"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"
|
||||||
@@ -66,7 +65,6 @@ 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,
|
||||||
@@ -91,7 +89,6 @@ 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,
|
||||||
@@ -99,7 +96,6 @@ 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,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"tinyauth/internal/assets"
|
||||||
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/assets"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -30,16 +27,14 @@ func (m *UIMiddleware) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.uiFs = ui
|
m.uiFs = ui
|
||||||
m.uiFileServer = http.FileServerFS(ui)
|
m.uiFileServer = http.FileServer(http.FS(ui))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
switch strings.Split(c.Request.URL.Path, "/")[1] {
|
||||||
|
|
||||||
switch strings.SplitN(path, "/", 2)[0] {
|
|
||||||
case "api":
|
case "api":
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
@@ -47,19 +42,12 @@ func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
|||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
_, err := fs.Stat(m.uiFs, path)
|
_, err := fs.Stat(m.uiFs, strings.TrimPrefix(c.Request.URL.Path, "/"))
|
||||||
|
|
||||||
// Enough for one authentication flow
|
|
||||||
maxAge := 15 * time.Minute
|
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
c.Request.URL.Path = "/"
|
c.Request.URL.Path = "/"
|
||||||
} else if strings.HasPrefix(path, "assets/") {
|
|
||||||
// assets are named with a hash and can be cached for a long time
|
|
||||||
maxAge = 30 * 24 * time.Hour
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Writer.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", int(maxAge.Seconds())))
|
|
||||||
m.uiFileServer.ServeHTTP(c.Writer, c.Request)
|
m.uiFileServer.ServeHTTP(c.Writer, c.Request)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,5 +10,4 @@ type Session struct {
|
|||||||
OAuthGroups string `gorm:"column:oauth_groups"`
|
OAuthGroups string `gorm:"column:oauth_groups"`
|
||||||
Expiry int64 `gorm:"column:expiry"`
|
Expiry int64 `gorm:"column:expiry"`
|
||||||
OAuthName string `gorm:"column:oauth_name"`
|
OAuthName string `gorm:"column:oauth_name"`
|
||||||
OAuthSub string `gorm:"column:oauth_sub"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccessControlsService struct {
|
|
||||||
docker *DockerService
|
|
||||||
static map[string]config.App
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAccessControlsService(docker *DockerService, static map[string]config.App) *AccessControlsService {
|
|
||||||
return &AccessControlsService{
|
|
||||||
docker: docker,
|
|
||||||
static: static,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (acls *AccessControlsService) Init() error {
|
|
||||||
return nil // No initialization needed
|
|
||||||
}
|
|
||||||
|
|
||||||
func (acls *AccessControlsService) lookupStaticACLs(domain string) (config.App, error) {
|
|
||||||
for app, config := range acls.static {
|
|
||||||
if config.Config.Domain == domain {
|
|
||||||
log.Debug().Str("name", app).Msg("Found matching container by domain")
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (acls *AccessControlsService) GetAccessControls(domain string) (config.App, error) {
|
|
||||||
// First check in the static config
|
|
||||||
app, err := acls.lookupStaticACLs(domain)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
log.Debug().Msg("Using ACls from static configuration")
|
|
||||||
return app, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to Docker labels
|
|
||||||
log.Debug().Msg("Falling back to Docker labels for ACLs")
|
|
||||||
return acls.docker.GetLabels(domain)
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user