Compare commits

...

30 Commits

Author SHA1 Message Date
Elias Schneider
4ba3a7e13c validate callback url pattern 2026-02-23 18:20:25 +01:00
Elias Schneider
280d603617 fix: improve wildcard matching by using go-urlpattern 2026-02-23 18:00:58 +01:00
Elias Schneider
0678699d0c chore: upgrade dependencies 2026-02-22 17:14:57 +01:00
dependabot[bot]
4f82957e13 chore(deps-dev): bump @sveltejs/kit from 2.49.5 to 2.52.2 in the npm_and_yarn group across 1 directory (#1327)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 14:54:01 +01:00
dependabot[bot]
5e2534bd6b chore(deps-dev): bump svelte from 5.46.4 to 5.51.5 in the npm_and_yarn group across 1 directory (#1324) 2026-02-20 14:23:55 -06:00
Alessandro (Ale) Segala
eb0456a395 fix: token endpoint must not accept params as query string args (#1321) 2026-02-17 22:31:09 -06:00
Elias Schneider
f0249377ac chore(translations): update translations via Crowdin (#1312) 2026-02-17 15:55:22 -06:00
github-actions[bot]
97f2e4eec2 chore: update AAGUIDs (#1316)
Co-authored-by: stonith404 <58886915+stonith404@users.noreply.github.com>
2026-02-16 09:54:02 -06:00
Elias Schneider
adbdfcf9ff chore(translations): update translations via Crowdin (#1307) 2026-02-10 15:29:08 -06:00
Kyle Mendell
94a48977ba chore(deps): update dependenicies 2026-02-10 15:26:25 -06:00
dependabot[bot]
5ab0996475 chore(deps): bump axios from 1.13.2 to 1.13.5 in the npm_and_yarn group across 1 directory (#1309)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 15:25:21 -06:00
Kyle Mendell
60825c5743 chore: run formatter 2026-02-10 15:21:09 -06:00
Cheng Gu
310b81c277 feat: manageability of uncompressed geolite db file (#1234) 2026-02-10 21:17:06 +00:00
Elias Schneider
549b487663 chore(translations): update translations via Crowdin (#1271) 2026-02-04 02:21:13 -06:00
Yegor Pomortsev
6eebecd85a fix: decode URL-encoded client ID and secret in Basic auth (#1263) 2026-01-24 20:52:17 +00:00
Elias Schneider
1de231f1ff chore(translations): update translations via Crowdin (#1270) 2026-01-24 21:46:48 +01:00
Elias Schneider
aab7e364e8 fix: increase rate limit for frontend and api requests 2026-01-24 20:29:50 +01:00
Elias Schneider
56afebc242 feat: add support for HTTP/2 2026-01-24 18:24:34 +01:00
Elias Schneider
bb7b0d5608 fix: add type="url" to url inputs 2026-01-24 17:37:54 +01:00
Elias Schneider
80558c5625 chore(translations): add Norwegian language files 2026-01-24 17:33:58 +01:00
Moritz
a5629e63d2 fix: prevent deletion of OIDC provider logo for non admin/anonymous users (#1267) 2026-01-24 17:23:21 +01:00
github-actions[bot]
317879bb37 chore: update AAGUIDs (#1257)
Co-authored-by: stonith404 <58886915+stonith404@users.noreply.github.com>
2026-01-20 19:26:25 -06:00
Kyle Mendell
c62533d388 fix: ENCRYPTION_KEY needed for version and help commands (#1256) 2026-01-18 18:04:53 -06:00
Jasper Bernhardt
0978a89fcc feat: add VERSION_CHECK_DISABLED environment variable (#1254) 2026-01-18 17:28:24 -06:00
Kyle Mendell
53ef61a3e5 chore(translations): add Estonian files 2026-01-17 19:42:28 -06:00
Kyle Mendell
4811625cdd chore: upgrade deps 2026-01-15 18:15:41 -06:00
Kyle Mendell
9dbc02e568 chore(deps): bump devalue to 5.6.2 2026-01-15 18:14:00 -06:00
dependabot[bot]
43a1e4a25b chore(deps-dev): bump svelte from 5.46.1 to 5.46.4 in the npm_and_yarn group across 1 directory (#1242)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 20:32:39 +00:00
dependabot[bot]
e78b16d0c6 chore(deps-dev): bump @sveltejs/kit from 2.49.2 to 2.49.5 in the npm_and_yarn group across 1 directory (#1240)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 14:23:39 -06:00
Elias Schneider
1967de6828 chore(translations): update translations via Crowdin (#1233) 2026-01-14 01:17:08 -06:00
38 changed files with 3199 additions and 1533 deletions

View File

@@ -4,6 +4,6 @@ package frontend
import "github.com/gin-gonic/gin"
func RegisterFrontend(router *gin.Engine) error {
func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) error {
return ErrFrontendNotIncluded
}

View File

@@ -52,7 +52,7 @@ func init() {
}
}
func RegisterFrontend(router *gin.Engine) error {
func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) error {
distFS, err := fs.Sub(frontendFS, "dist")
if err != nil {
return fmt.Errorf("failed to create sub FS: %w", err)
@@ -61,7 +61,7 @@ func RegisterFrontend(router *gin.Engine) error {
cacheMaxAge := time.Hour * 24
fileServer := NewFileServerWithCaching(http.FS(distFS), int(cacheMaxAge.Seconds()))
router.NoRoute(func(c *gin.Context) {
handler := func(c *gin.Context) {
path := strings.TrimPrefix(c.Request.URL.Path, "/")
if strings.HasSuffix(path, "/") {
@@ -97,7 +97,9 @@ func RegisterFrontend(router *gin.Engine) error {
// Serve other static assets with caching
c.Request.URL.Path = "/" + path
fileServer.ServeHTTP(c.Writer, c.Request)
})
}
router.NoRoute(rateLimitMiddleware, handler)
return nil
}

View File

@@ -1,24 +1,25 @@
module github.com/pocket-id/pocket-id/backend
go 1.25
go 1.25.0
require (
github.com/aws/aws-sdk-go-v2 v1.41.0
github.com/aws/aws-sdk-go-v2/config v1.32.6
github.com/aws/aws-sdk-go-v2/credentials v1.19.6
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0
github.com/aws/smithy-go v1.24.0
github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.9
github.com/aws/aws-sdk-go-v2/credentials v1.19.9
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
github.com/aws/smithy-go v1.24.1
github.com/caarlos0/env/v11 v11.3.1
github.com/cenkalti/backoff/v5 v5.0.3
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
github.com/disintegration/imaging v1.6.2
github.com/dunglas/go-urlpattern v0.0.0-20241020164140-716dfa1c80b1
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6
github.com/emersion/go-smtp v0.24.0
github.com/gin-contrib/slog v1.2.0
github.com/gin-gonic/gin v1.11.0
github.com/glebarez/go-sqlite v1.22.0
github.com/glebarez/sqlite v1.11.0
github.com/go-co-op/gocron/v2 v2.19.0
github.com/go-co-op/gocron/v2 v2.19.1
github.com/go-ldap/ldap/v3 v3.4.12
github.com/go-playground/validator/v10 v10.30.1
github.com/go-webauthn/webauthn v0.15.0
@@ -27,30 +28,31 @@ require (
github.com/hashicorp/go-uuid v1.0.3
github.com/jinzhu/copier v0.4.0
github.com/joho/godotenv v1.5.1
github.com/lestrrat-go/httprc/v3 v3.0.3
github.com/lestrrat-go/jwx/v3 v3.0.12
github.com/lmittmann/tint v1.1.2
github.com/lestrrat-go/httprc/v3 v3.0.4
github.com/lestrrat-go/jwx/v3 v3.0.13
github.com/lmittmann/tint v1.1.3
github.com/mattn/go-isatty v0.0.20
github.com/mileusna/useragent v1.3.5
github.com/orandin/slog-gorm v1.4.0
github.com/oschwald/maxminddb-golang/v2 v2.1.1
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
go.opentelemetry.io/otel v1.39.0
go.opentelemetry.io/otel/log v0.15.0
go.opentelemetry.io/otel/metric v1.39.0
go.opentelemetry.io/otel/sdk v1.39.0
go.opentelemetry.io/otel/sdk/log v0.15.0
go.opentelemetry.io/otel/sdk/metric v1.39.0
go.opentelemetry.io/otel/trace v1.39.0
golang.org/x/crypto v0.46.0
golang.org/x/image v0.34.0
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0
go.opentelemetry.io/otel v1.40.0
go.opentelemetry.io/otel/log v0.16.0
go.opentelemetry.io/otel/metric v1.40.0
go.opentelemetry.io/otel/sdk v1.40.0
go.opentelemetry.io/otel/sdk/log v0.16.0
go.opentelemetry.io/otel/sdk/metric v1.40.0
go.opentelemetry.io/otel/trace v1.40.0
golang.org/x/crypto v0.48.0
golang.org/x/image v0.36.0
golang.org/x/net v0.50.0
golang.org/x/sync v0.19.0
golang.org/x/text v0.32.0
golang.org/x/text v0.34.0
golang.org/x/time v0.14.0
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.31.1
@@ -59,23 +61,24 @@ require (
require (
github.com/Azure/go-ntlmssp v0.1.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.14.3 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.14.2 // indirect
github.com/bytedance/sonic/loader v0.4.0 // indirect
github.com/bytedance/sonic v1.15.0 // indirect
github.com/bytedance/sonic/loader v0.5.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@@ -84,22 +87,22 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-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/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-webauthn/x v0.1.27 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/go-webauthn/x v0.2.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.1 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/google/go-github/v39 v39.2.0 // indirect
github.com/google/go-querystring v1.2.0 // indirect
github.com/google/go-tpm v0.9.8 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
@@ -116,56 +119,56 @@ require (
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-sqlite3 v1.14.33 // indirect
github.com/lib/pq v1.11.2 // indirect
github.com/mattn/go-sqlite3 v1.14.34 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/nlnwa/whatwg-url v0.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/otlptranslator v1.0.0 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.58.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
github.com/valyala/fastjson v1.6.7 // indirect
github.com/valyala/fastjson v1.6.10 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.61.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.62.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/arch v0.23.0 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sys v0.39.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/grpc v1.78.0 // indirect
golang.org/x/arch v0.24.0 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
golang.org/x/oauth2 v0.35.0 // indirect
golang.org/x/sys v0.41.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect
google.golang.org/grpc v1.79.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.67.4 // indirect
modernc.org/libc v1.68.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.42.2 // indirect
modernc.org/sqlite v1.46.1 // indirect
)

View File

@@ -6,52 +6,55 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
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-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8=
github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI=
github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
github.com/aws/aws-sdk-go-v2/config v1.32.9 h1:ktda/mtAydeObvJXlHzyGpK1xcsLaP16zfUPDGoW90A=
github.com/aws/aws-sdk-go-v2/config v1.32.9/go.mod h1:U+fCQ+9QKsLW786BCfEjYRj34VVTbPdsLP3CHSYXMOI=
github.com/aws/aws-sdk-go-v2/credentials v1.19.9 h1:sWvTKsyrMlJGEuj/WgrwilpoJ6Xa1+KhIpGdzw7mMU8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.9/go.mod h1:+J44MBhmfVY/lETFiKI+klz0Vym2aCmIjqgClMmW82w=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 h1:+VTRawC4iVY58pS/lzpo0lnoa/SYNGF4/B/3/U5ro8Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0=
github.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
@@ -88,6 +91,8 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
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/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dunglas/go-urlpattern v0.0.0-20241020164140-716dfa1c80b1 h1:RW22Y3QjGrb97NUA8yupdFcaqg//+hMI2fZrETBvQ4s=
github.com/dunglas/go-urlpattern v0.0.0-20241020164140-716dfa1c80b1/go.mod h1:mnVcdqOeYg0HvT6veRo7wINa1mJ+lC/R4ig2lWcapSI=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3DfFi4EXdT+B+gTtzx8GC9xsc26Znk=
@@ -98,8 +103,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/slog v1.2.0 h1:vAxZfr7knD1ZYK5+pMJLP52sZXIkJXkcRPa/0dx9hSk=
github.com/gin-contrib/slog v1.2.0/go.mod h1:vYK6YltmpsEFkO0zfRMLTKHrWS3DwUSn0TMpT+kMagI=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
@@ -112,8 +117,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
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/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-co-op/gocron/v2 v2.19.0 h1:OKf2y6LXPs/BgBI2fl8PxUpNAI1DA9Mg+hSeGOS38OU=
github.com/go-co-op/gocron/v2 v2.19.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
github.com/go-co-op/gocron/v2 v2.19.1 h1:B4iLeA0NB/2iO3EKQ7NfKn5KsQgZfjb2fkvoZJU3yBI=
github.com/go-co-op/gocron/v2 v2.19.1/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -129,20 +134,20 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
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/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-webauthn/webauthn v0.15.0 h1:LR1vPv62E0/6+sTenX35QrCmpMCzLeVAcnXeH4MrbJY=
github.com/go-webauthn/webauthn v0.15.0/go.mod h1:hcAOhVChPRG7oqG7Xj6XKN1mb+8eXTGP/B7zBLzkX5A=
github.com/go-webauthn/x v0.1.27 h1:CLyuB8JGn9xvw0etBl4fnclcbPTwhKpN4Xg32zaSYnI=
github.com/go-webauthn/x v0.1.27/go.mod h1:KGYJQAPPgbpDKi4N7zKMGL+Iz6WgxKg3OlhVbPtuJXI=
github.com/go-webauthn/x v0.2.1 h1:/oB8i0FhSANuoN+YJF5XHMtppa7zGEYaQrrf6ytotjc=
github.com/go-webauthn/x v0.2.1/go.mod h1:Wm0X0zXkzznit4gHj4m82GiBZRMEm+TDUIoJWIQLsE4=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -166,8 +171,8 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
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/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
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/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -226,20 +231,20 @@ github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc/v3 v3.0.3 h1:WjLHWkDkgWXeIUrKi/7lS/sGq2DjkSAwdTbH5RHXAKs=
github.com/lestrrat-go/httprc/v3 v3.0.3/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg=
github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8=
github.com/lestrrat-go/httprc/v3 v3.0.4 h1:pXyH2ppK8GYYggygxJ3TvxpCZnbEUWc9qSwRTTApaLA=
github.com/lestrrat-go/httprc/v3 v3.0.4/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk=
github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU=
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs=
github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/lmittmann/tint v1.1.3 h1:Hv4EaHWXQr+GTFnOU4VKf8UvAtZgn0VuKT+G0wFlO3I=
github.com/lmittmann/tint v1.1.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
@@ -257,6 +262,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nlnwa/whatwg-url v0.5.0 h1:l71cqfqG44+VCQZQX3wD4bwheFWicPxuwaCimLEfpDo=
github.com/nlnwa/whatwg-url v0.5.0/go.mod h1:X/ejnFFVbaOWdSul+cnlsSHviCzGZJdvPkgc9zD8IY8=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@@ -276,16 +283,16 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
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.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug=
github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
@@ -316,62 +323,63 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM=
github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4=
github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0 h1:eypSOd+0txRKCXPNyqLPsbSfA0jULgJcGmSAdFAnrCM=
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0/go.mod h1:CRGvIBL/aAxpQU34ZxyQVFlovVcp67s4cAmQu8Jh9mc=
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0 h1:7TYhBCu6Xz6vDJGNtEslWZLuuX2IJ/aH50hBY4MVeUg=
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0/go.mod h1:tHQctZfAe7e4PBPGyt3kae6mQFXNpj+iiDJa3ithM50=
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0 h1:9pzPj3RFyKOxBAMkM2w84LpT+rdHam1XoFA+QhARiRw=
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0/go.mod h1:hlVZx1btWH0XTfXpuGX9dsquB50s+tc3fYFOO5elo2M=
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0 h1:7IKZbAYwlwLXAdu7SVPhzTjDjogWZxP4MIa7rovY+PU=
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0/go.mod h1:+TF5nf3NIv2X8PGxqfYOaRnAoMM43rUA2C3XsN2DoWA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
go.opentelemetry.io/contrib/propagators/b3 v1.39.0 h1:PI7pt9pkSnimWcp5sQhUA9OzLbc3Ba4sL+VEUTNsxrk=
go.opentelemetry.io/contrib/propagators/b3 v1.39.0/go.mod h1:5gV/EzPnfYIwjzj+6y8tbGW2PKWhcsz5e/7twptRVQY=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 h1:EKpiGphOYq3CYnIe2eX9ftUkyU+Y8Dtte8OaWyHJ4+I=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0/go.mod h1:nWFP7C+T8TygkTjJ7mAyEaFaE7wNfms3nV/vexZ6qt0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf8jF6WbuGQWUVcqgyWtTR0kOOAWY1DYZ+UhvdmQPw=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 h1:nKP4Z2ejtHn3yShBb+2KawiXgpn8In5cT7aO2wXuOTE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0/go.mod h1:NwjeBbNigsO4Aj9WgM0C+cKIrxsZUaRmZUO7A8I7u8o=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU=
go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0=
go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0 h1:0BSddrtQqLEylcErkeFrJBmwFzcqfQq9+/uxfTZq+HE=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0/go.mod h1:87sjYuAPzaRCtdd09GU5gM1U9wQLrrcYrm77mh5EBoc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0/go.mod h1:0fBG6ZJxhqByfFZDwSwpZGzJU671HkwpWaNe2t4VUPI=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g=
go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY=
go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE=
go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ=
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM=
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0/go.mod h1:CvaNVqIfcybc+7xqZNubbE+26K6P7AKZF/l0lE2kdCk=
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0 h1:I/7S/yWobR3QHFLqHsJ8QOndoiFsj1VgHpQiq43KlUI=
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0/go.mod h1:jPF6gn3y1E+nozCAEQj3c6NZ8KY+tvAgSVfvoOJUFac=
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0 h1:2gApdml7SznX9szEKFjKjM4qGcGSvAybYLBY319XG3g=
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0/go.mod h1:0QqAGlbHXhmPYACG3n5hNzO5DnEqqtg4VcK5pr22RI0=
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0 h1:LSJsvNqhj2sBNFb5NWHbyDK4QJ/skQ2ydjeOZ9OYNZ4=
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0/go.mod h1:0Q5ocj6h/+C6KYq8cnl4tDFVd4I1HBdsJ440aeagHos=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
go.opentelemetry.io/contrib/propagators/b3 v1.40.0 h1:xariChe8OOVF3rNlfzGFgQc61npQmXhzZj/i82mxMfg=
go.opentelemetry.io/contrib/propagators/b3 v1.40.0/go.mod h1:72WvbdxbOfXaELEQfonFfOL6osvcVjI7uJEE8C2nkrs=
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0/go.mod h1:eQqT90eR3X5Dbs1g9YSM30RavwLF725Ris5/XSXWvqE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
go.opentelemetry.io/otel/exporters/prometheus v0.62.0 h1:krvC4JMfIOVdEuNPTtQ0ZjCiXrybhv+uOHMfHRmnvVo=
go.opentelemetry.io/otel/exporters/prometheus v0.62.0/go.mod h1:fgOE6FM/swEnsVQCqCnbOfRV4tOnWPg7bVeo4izBuhQ=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 h1:ivlbaajBWJqhcCPniDqDJmRwj4lc6sRT+dCAVKNmxlQ=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0/go.mod h1:u/G56dEKDDwXNCVLsbSrllB2o8pbtFLUC4HpR66r2dc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 h1:MzfofMZN8ulNqobCmCAVbqVL5syHw+eB2qPRkCMA/fQ=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0/go.mod h1:E73G9UFtKRXrxhBsHtG00TB5WxX57lpsQzogDkqBTz8=
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -381,55 +389,89 @@ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y=
golang.org/x/arch v0.24.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.35.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.1.0/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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
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=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E=
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -444,18 +486,18 @@ gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so=
modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw=
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.67.4 h1:zZGmCMUVPORtKv95c2ReQN5VDjvkoRm9GWPTEPuvlWg=
modernc.org/libc v1.67.4/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -464,8 +506,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.42.2 h1:7hkZUNJvJFN2PgfUdjni9Kbvd4ef4mNLOu0B9FGxM74=
modernc.org/sqlite v1.42.2/go.mod h1:+VkC6v3pLOAE0A0uVucQEcbVW0I5nHCeDaBf+DpsQT8=
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View File

@@ -15,6 +15,8 @@ import (
sloggin "github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"golang.org/x/time/rate"
"gorm.io/gorm"
@@ -51,8 +53,6 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
r.Use(otelgin.Middleware(common.Name))
}
rateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(time.Second), 60)
// Setup global middleware
r.Use(middleware.HeadMiddleware())
r.Use(middleware.NewCacheControlMiddleware().Add())
@@ -60,7 +60,8 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
r.Use(middleware.NewCspMiddleware().Add())
r.Use(middleware.NewErrorHandlerMiddleware().Add())
err := frontend.RegisterFrontend(r)
frontendRateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(100*time.Millisecond), 300)
err := frontend.RegisterFrontend(r, frontendRateLimitMiddleware)
if errors.Is(err, frontend.ErrFrontendNotIncluded) {
slog.Warn("Frontend is not included in the build. Skipping frontend registration.")
} else if err != nil {
@@ -71,8 +72,10 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
authMiddleware := middleware.NewAuthMiddleware(svc.apiKeyService, svc.userService, svc.jwtService)
fileSizeLimitMiddleware := middleware.NewFileSizeLimitMiddleware()
apiRateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(time.Second), 100)
// Set up API routes
apiGroup := r.Group("/api", rateLimitMiddleware)
apiGroup := r.Group("/api", apiRateLimitMiddleware)
controller.NewApiKeyController(apiGroup, authMiddleware, svc.apiKeyService)
controller.NewWebauthnController(apiGroup, authMiddleware, middleware.NewRateLimitMiddleware(), svc.webauthnService, svc.appConfigService)
controller.NewOidcController(apiGroup, authMiddleware, fileSizeLimitMiddleware, svc.oidcService, svc.jwtService)
@@ -94,18 +97,23 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
}
// Set up base routes
baseGroup := r.Group("/", rateLimitMiddleware)
baseGroup := r.Group("/", apiRateLimitMiddleware)
controller.NewWellKnownController(baseGroup, svc.jwtService)
// Set up healthcheck routes
// These are not rate-limited
controller.NewHealthzController(r)
var protocols http.Protocols
protocols.SetHTTP1(true)
protocols.SetUnencryptedHTTP2(true)
// Set up the server
srv := &http.Server{
MaxHeaderBytes: 1 << 20,
ReadHeaderTimeout: 10 * time.Second,
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Protocols: &protocols,
Handler: h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// HEAD requests don't get matched by Gin routes, so we convert them to GET
// middleware.HeadMiddleware will convert them back to HEAD later
if req.Method == http.MethodHead {
@@ -115,7 +123,7 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
}
r.ServeHTTP(w, req)
}),
}), &http2.Server{}),
}
// Set up the listener

View File

@@ -50,6 +50,7 @@ type EnvConfigSchema struct {
InternalAppURL string `env:"INTERNAL_APP_URL"`
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
DisableRateLimiting bool `env:"DISABLE_RATE_LIMITING"`
VersionCheckDisabled bool `env:"VERSION_CHECK_DISABLED"`
StaticApiKey string `env:"STATIC_API_KEY" options:"file"`
FileBackend string `env:"FILE_BACKEND" options:"toLower"`
@@ -128,6 +129,10 @@ func parseEnvConfig() error {
// ValidateEnvConfig checks the EnvConfig for required fields and valid values
func ValidateEnvConfig(config *EnvConfigSchema) error {
if shouldSkipEnvValidation(os.Args) {
return nil
}
if _, err := sloggin.ParseLevel(config.LogLevel); err != nil {
return errors.New("invalid LOG_LEVEL value. Must be 'debug', 'info', 'warn' or 'error'")
}
@@ -209,6 +214,17 @@ func ValidateEnvConfig(config *EnvConfigSchema) error {
}
func shouldSkipEnvValidation(args []string) bool {
for _, arg := range args[1:] {
switch arg {
case "-h", "--help", "help", "version":
return true
}
}
return false
}
// prepareEnvConfig processes special options for EnvConfig fields
func prepareEnvConfig(config *EnvConfigSchema) error {
val := reflect.ValueOf(config).Elem()

View File

@@ -1,6 +1,7 @@
package controller
import (
"context"
"errors"
"log/slog"
"net/http"
@@ -24,7 +25,11 @@ import (
// @Description Initializes all OIDC-related API endpoints for authentication and client management
// @Tags OIDC
func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, oidcService *service.OidcService, jwtService *service.JwtService) {
oc := &OidcController{oidcService: oidcService, jwtService: jwtService}
oc := &OidcController{
oidcService: oidcService,
jwtService: jwtService,
createTokens: oidcService.CreateTokens,
}
group.POST("/oidc/authorize", authMiddleware.WithAdminNotRequired().Add(), oc.authorizeHandler)
group.POST("/oidc/authorization-required", authMiddleware.WithAdminNotRequired().Add(), oc.authorizationConfirmationRequiredHandler)
@@ -47,7 +52,7 @@ func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMi
group.POST("/oidc/clients/:id/secret", authMiddleware.Add(), oc.createClientSecretHandler)
group.GET("/oidc/clients/:id/logo", oc.getClientLogoHandler)
group.DELETE("/oidc/clients/:id/logo", oc.deleteClientLogoHandler)
group.DELETE("/oidc/clients/:id/logo", authMiddleware.Add(), oc.deleteClientLogoHandler)
group.POST("/oidc/clients/:id/logo", authMiddleware.Add(), fileSizeLimitMiddleware.Add(2<<20), oc.updateClientLogoHandler)
group.GET("/oidc/clients/:id/preview/:userId", authMiddleware.Add(), oc.getClientPreviewHandler)
@@ -68,8 +73,9 @@ func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMi
}
type OidcController struct {
oidcService *service.OidcService
jwtService *service.JwtService
oidcService *service.OidcService
jwtService *service.JwtService
createTokens func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error)
}
// authorizeHandler godoc
@@ -144,8 +150,13 @@ func (oc *OidcController) authorizationConfirmationRequiredHandler(c *gin.Contex
// @Success 200 {object} dto.OidcTokenResponseDto "Token response with access_token and optional id_token and refresh_token"
// @Router /api/oidc/token [post]
func (oc *OidcController) createTokensHandler(c *gin.Context) {
// Per RFC-6749, parameters passed to the /token endpoint MUST be passed in the body of the request
// Gin's "ShouldBind" by default reads from the query string too, so we need to reset all query string args before invoking ShouldBind
c.Request.URL.RawQuery = ""
var input dto.OidcCreateTokensDto
if err := c.ShouldBind(&input); err != nil {
err := c.ShouldBind(&input)
if err != nil {
_ = c.Error(err)
return
}
@@ -164,10 +175,10 @@ func (oc *OidcController) createTokensHandler(c *gin.Context) {
// Client id and secret can also be passed over the Authorization header
if input.ClientID == "" && input.ClientSecret == "" {
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
}
tokens, err := oc.oidcService.CreateTokens(c.Request.Context(), input)
tokens, err := oc.createTokens(c.Request.Context(), input)
switch {
case errors.Is(err, &common.OidcAuthorizationPendingError{}):
@@ -322,7 +333,7 @@ func (oc *OidcController) introspectTokenHandler(c *gin.Context) {
creds service.ClientAuthCredentials
ok bool
)
creds.ClientID, creds.ClientSecret, ok = c.Request.BasicAuth()
creds.ClientID, creds.ClientSecret, ok = utils.OAuthClientBasicAuth(c.Request)
if !ok {
// If there's no basic auth, check if we have a bearer token
bearer, ok := utils.BearerAuth(c.Request)
@@ -659,7 +670,7 @@ func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) {
// Client id and secret can also be passed over the Authorization header
if input.ClientID == "" && input.ClientSecret == "" {
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
}
response, err := oc.oidcService.CreateDeviceAuthorization(c.Request.Context(), input)

View File

@@ -0,0 +1,227 @@
package controller
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/service"
)
func TestCreateTokensHandler(t *testing.T) {
createTestContext := func(t *testing.T, rawURL string, form url.Values, authHeader string, noCT bool) (*gin.Context, *httptest.ResponseRecorder) {
t.Helper()
mode := gin.Mode()
gin.SetMode(gin.TestMode)
t.Cleanup(func() { gin.SetMode(mode) })
recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)
req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, rawURL, strings.NewReader(form.Encode()))
require.NoError(t, err)
if !noCT {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
if authHeader != "" {
req.Header.Set("Authorization", authHeader)
}
c.Request = req
return c, recorder
}
t.Run("Ignores Query String Parameters For Binding", func(t *testing.T) {
oc := &OidcController{}
c, _ := createTestContext(
t,
"http://example.com/oidc/token?grant_type=refresh_token&refresh_token=query-value",
url.Values{},
"",
false,
)
oc.createTokensHandler(c)
require.Len(t, c.Errors, 1)
assert.Contains(t, c.Errors[0].Err.Error(), "GrantType")
})
t.Run("Missing Authorization Code", func(t *testing.T) {
oc := &OidcController{}
c, _ := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeAuthorizationCode},
},
"",
false,
)
oc.createTokensHandler(c)
require.Len(t, c.Errors, 1)
var missingCodeErr *common.OidcMissingAuthorizationCodeError
require.ErrorAs(t, c.Errors[0].Err, &missingCodeErr)
})
t.Run("Missing Refresh Token", func(t *testing.T) {
oc := &OidcController{}
c, _ := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeRefreshToken},
},
"",
false,
)
oc.createTokensHandler(c)
require.Len(t, c.Errors, 1)
var missingRefreshErr *common.OidcMissingRefreshTokenError
require.ErrorAs(t, c.Errors[0].Err, &missingRefreshErr)
})
t.Run("Uses Basic Auth Credentials When Body Credentials Missing", func(t *testing.T) {
var capturedInput dto.OidcCreateTokensDto
oc := &OidcController{
createTokens: func(_ context.Context, input dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
capturedInput = input
return service.CreatedTokens{
AccessToken: "access-token",
IdToken: "id-token",
RefreshToken: "refresh-token",
ExpiresIn: 2 * time.Minute,
}, nil
},
}
basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte("client-id:client-secret"))
c, recorder := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeRefreshToken},
"refresh_token": {"input-refresh-token"},
},
basicAuth,
false,
)
oc.createTokensHandler(c)
require.Empty(t, c.Errors)
assert.Equal(t, "client-id", capturedInput.ClientID)
assert.Equal(t, "client-secret", capturedInput.ClientSecret)
assert.Equal(t, "input-refresh-token", capturedInput.RefreshToken)
require.Equal(t, http.StatusOK, recorder.Code)
var response dto.OidcTokenResponseDto
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
assert.Equal(t, "access-token", response.AccessToken)
assert.Equal(t, "Bearer", response.TokenType)
assert.Equal(t, "id-token", response.IdToken)
assert.Equal(t, "refresh-token", response.RefreshToken)
assert.Equal(t, 120, response.ExpiresIn)
})
t.Run("Maps Authorization Pending Error", func(t *testing.T) {
oc := &OidcController{
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
return service.CreatedTokens{}, &common.OidcAuthorizationPendingError{}
},
}
c, recorder := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeRefreshToken},
"refresh_token": {"input-refresh-token"},
},
"",
false,
)
oc.createTokensHandler(c)
require.Empty(t, c.Errors)
require.Equal(t, http.StatusBadRequest, recorder.Code)
var response map[string]string
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
assert.Equal(t, "authorization_pending", response["error"])
})
t.Run("Maps Slow Down Error", func(t *testing.T) {
oc := &OidcController{
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
return service.CreatedTokens{}, &common.OidcSlowDownError{}
},
}
c, recorder := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeRefreshToken},
"refresh_token": {"input-refresh-token"},
},
"",
false,
)
oc.createTokensHandler(c)
require.Empty(t, c.Errors)
require.Equal(t, http.StatusBadRequest, recorder.Code)
var response map[string]string
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
assert.Equal(t, "slow_down", response["error"])
})
t.Run("Returns Generic Service Error In Context", func(t *testing.T) {
expectedErr := errors.New("boom")
oc := &OidcController{
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
return service.CreatedTokens{}, expectedErr
},
}
c, _ := createTestContext(
t,
"http://example.com/oidc/token",
url.Values{
"grant_type": {service.GrantTypeRefreshToken},
"refresh_token": {"input-refresh-token"},
},
"",
false,
)
oc.createTokensHandler(c)
require.Len(t, c.Errors, 1)
assert.ErrorIs(t, c.Errors[0].Err, expectedErr)
})
}

View File

@@ -1,9 +1,7 @@
package dto
import (
"net/url"
"regexp"
"strings"
"time"
"github.com/pocket-id/pocket-id/backend/internal/utils"
@@ -67,19 +65,6 @@ func ValidateClientID(clientID string) bool {
// ValidateCallbackURL validates callback URLs with support for wildcards
func ValidateCallbackURL(raw string) bool {
// Don't validate if it contains a wildcard
if strings.Contains(raw, "*") {
return true
}
u, err := url.Parse(raw)
if err != nil {
return false
}
if !u.IsAbs() {
return false
}
return true
err := utils.ValidateCallbackURLPattern(raw)
return err == nil
}

View File

@@ -2,6 +2,7 @@ package service
import (
"archive/tar"
"bytes"
"compress/gzip"
"context"
"errors"
@@ -22,6 +23,8 @@ import (
"github.com/pocket-id/pocket-id/backend/internal/common"
)
const maxTotalSize = 300 * 1024 * 1024 // 300 MB limit for total decompressed size
type GeoLiteService struct {
httpClient *http.Client
disableUpdater bool
@@ -151,7 +154,24 @@ func (s *GeoLiteService) isDatabaseUpToDate() bool {
// extractDatabase extracts the database file from the tar.gz archive directly to the target location.
func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
gzr, err := gzip.NewReader(reader)
// Check for gzip magic number
buf := make([]byte, 2)
_, err := io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("failed to read magic number: %w", err)
}
// Check if the file starts with the gzip magic number
// Gosec returns false positive for "G602: slice index out of range"
//nolint:gosec
isGzip := buf[0] == 0x1f && buf[1] == 0x8b
if !isGzip {
// If not gzip, assume it's a regular database file
return s.writeDatabaseFile(io.MultiReader(bytes.NewReader(buf), reader))
}
gzr, err := gzip.NewReader(io.MultiReader(bytes.NewReader(buf), reader))
if err != nil {
return fmt.Errorf("failed to create gzip reader: %w", err)
}
@@ -160,7 +180,6 @@ func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
tarReader := tar.NewReader(gzr)
var totalSize int64
const maxTotalSize = 300 * 1024 * 1024 // 300 MB limit for total decompressed size
// Iterate over the files in the tar archive
for {
@@ -222,3 +241,47 @@ func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
return errors.New("GeoLite2-City.mmdb not found in archive")
}
func (s *GeoLiteService) writeDatabaseFile(reader io.Reader) error {
baseDir := filepath.Dir(common.EnvConfig.GeoLiteDBPath)
tmpFile, err := os.CreateTemp(baseDir, "geolite.*.mmdb.tmp")
if err != nil {
return fmt.Errorf("failed to create temporary database file: %w", err)
}
defer tmpFile.Close()
// Limit the amount we read to maxTotalSize.
// We read one extra byte to detect if the source is larger than the limit.
limitReader := io.LimitReader(reader, maxTotalSize+1)
// Write the file contents directly to the temporary file
written, err := io.Copy(tmpFile, limitReader)
if err != nil {
os.Remove(tmpFile.Name())
return fmt.Errorf("failed to write database file: %w", err)
}
if written > maxTotalSize {
os.Remove(tmpFile.Name())
return errors.New("total database size exceeds maximum allowed limit")
}
// Validate the downloaded database file
if db, err := maxminddb.Open(tmpFile.Name()); err == nil {
db.Close()
} else {
os.Remove(tmpFile.Name())
return fmt.Errorf("failed to open downloaded database file: %w", err)
}
// Ensure atomic replacement of the old database file
s.mutex.Lock()
err = os.Rename(tmpFile.Name(), common.EnvConfig.GeoLiteDBPath)
s.mutex.Unlock()
if err != nil {
os.Remove(tmpFile.Name())
return fmt.Errorf("failed to replace database file: %w", err)
}
return nil
}

View File

@@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/utils"
)
@@ -31,6 +32,10 @@ func NewVersionService(httpClient *http.Client) *VersionService {
}
func (s *VersionService) GetLatestVersion(ctx context.Context) (string, error) {
if common.EnvConfig.VersionCheckDisabled {
return "", nil
}
version, err := s.cache.GetOrFetch(ctx, func(ctx context.Context) (string, error) {
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

View File

@@ -1,14 +1,32 @@
package utils
import (
"log/slog"
"net"
"net/url"
"path"
"regexp"
"strconv"
"strings"
"github.com/dunglas/go-urlpattern"
)
// GetCallbackURLFromList returns the first callback URL that matches the input callback URL
// ValidateCallbackURLPattern checks if the given callback URL pattern
// is valid according to the rules defined in this package.
func ValidateCallbackURLPattern(pattern string) error {
if pattern == "*" {
return nil
}
pattern, _, _ = strings.Cut(pattern, "#")
pattern = normalizeToURLPatternStandard(pattern)
_, err := urlpattern.New(pattern, "", nil)
return err
}
// GetCallbackURLFromList returns the first callback URL that matches the input callback URL.
func GetCallbackURLFromList(urls []string, inputCallbackURL string) (callbackURL string, err error) {
// Special case for Loopback Interface Redirection. Quoting from RFC 8252 section 7.3:
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
@@ -24,7 +42,12 @@ func GetCallbackURLFromList(urls []string, inputCallbackURL string) (callbackURL
host := u.Hostname()
ip := net.ParseIP(host)
if host == "localhost" || (ip != nil && ip.IsLoopback()) {
u.Host = host
// For IPv6 loopback hosts, brackets are required when serializing without a port.
if strings.Contains(host, ":") {
u.Host = "[" + host + "]"
} else {
u.Host = host
}
loopbackCallbackURLWithoutPort = u.String()
}
}
@@ -64,143 +87,135 @@ func matchCallbackURL(pattern string, inputCallbackURL string) (matches bool, er
return true, nil
}
// Strip fragment part
// Strip fragment part.
// The endpoint URI MUST NOT include a fragment component.
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2
pattern, _, _ = strings.Cut(pattern, "#")
inputCallbackURL, _, _ = strings.Cut(inputCallbackURL, "#")
// Store and strip query part
var patternQuery url.Values
if i := strings.Index(pattern, "?"); i >= 0 {
patternQuery, err = url.ParseQuery(pattern[i+1:])
if err != nil {
return false, err
}
pattern = pattern[:i]
}
var inputQuery url.Values
if i := strings.Index(inputCallbackURL, "?"); i >= 0 {
inputQuery, err = url.ParseQuery(inputCallbackURL[i+1:])
if err != nil {
return false, err
}
inputCallbackURL = inputCallbackURL[:i]
}
// Split both pattern and input parts
patternParts, patternPath := splitParts(pattern)
inputParts, inputPath := splitParts(inputCallbackURL)
// Verify everything except the path and query parameters
if len(patternParts) != len(inputParts) {
return false, nil
}
for i, patternPart := range patternParts {
matched, err := path.Match(patternPart, inputParts[i])
if err != nil || !matched {
return false, err
}
}
// Verify path with wildcard support
matched, err := matchPath(patternPath, inputPath)
if err != nil || !matched {
pattern, patternQuery, err := extractQueryParams(pattern)
if err != nil {
return false, err
}
// Verify query parameters
if len(patternQuery) != len(inputQuery) {
inputCallbackURL, inputQuery, err := extractQueryParams(inputCallbackURL)
if err != nil {
return false, err
}
pattern = normalizeToURLPatternStandard(pattern)
// Validate query params
v := validateQueryParams(patternQuery, inputQuery)
if !v {
return false, nil
}
for patternKey, patternValues := range patternQuery {
inputValues, exists := inputQuery[patternKey]
if !exists {
return false, nil
}
if len(patternValues) != len(inputValues) {
return false, nil
}
for i := range patternValues {
matched, err := path.Match(patternValues[i], inputValues[i])
if err != nil || !matched {
return false, err
}
}
// Validate the rest of the URL using urlpattern
p, err := urlpattern.New(pattern, "", nil)
if err != nil {
//nolint:nilerr
slog.Warn("invalid callback URL pattern, skipping", "pattern", pattern, "error", err)
return false, nil
}
return true, nil
return p.Test(inputCallbackURL, ""), nil
}
// matchPath matches the input path against the pattern with wildcard support
// Supported wildcards:
//
// '*' matches any sequence of characters except '/'
// '**' matches any sequence of characters including '/'
func matchPath(pattern string, input string) (matches bool, err error) {
var regexPattern strings.Builder
regexPattern.WriteString("^")
// normalizeToURLPatternStandard converts patterns with single asterisk wildcards and globstar wildcards
// into a format that can be parsed by the urlpattern package, which uses :param for single segment wildcards
// and ** for multi-segment wildcards.
func normalizeToURLPatternStandard(pattern string) string {
patternBase, patternPath := extractPath(pattern)
runes := []rune(pattern)
n := len(runes)
for i := 0; i < n; {
switch runes[i] {
case '*':
// Check if it's a ** (globstar)
if i+1 < n && runes[i+1] == '*' {
// globstar = .* (match slashes too)
regexPattern.WriteString(".*")
i += 2
// Replace single asterisk wildcards with :p{index} and keep globstar wildcards as **.
var result strings.Builder
for i := 0; i < len(patternPath); i++ {
if patternPath[i] == '*' {
// Check if it's a globstar (**)
if i+1 < len(patternPath) && patternPath[i+1] == '*' {
result.WriteString("**")
i++ // skip next *
} else {
// single * = [^/]* (no slash)
regexPattern.WriteString(`[^/]*`)
i++
result.WriteString(":p")
result.WriteString(strconv.Itoa(i))
}
default:
regexPattern.WriteString(regexp.QuoteMeta(string(runes[i])))
i++
} else {
result.WriteByte(patternPath[i])
}
}
patternPath = result.String()
regexPattern.WriteString("$")
// Replace globstar wildcards (**) with a single *
re := regexp.MustCompile(`\*{2}`)
patternPath = re.ReplaceAllStringFunc(patternPath, func(_ string) string {
return "*"
})
matched, err := regexp.MatchString(regexPattern.String(), input)
return matched, err
return patternBase + patternPath
}
// splitParts splits the URL into parts by special characters and returns the path separately
func splitParts(s string) (parts []string, path string) {
split := func(r rune) bool {
return r == ':' || r == '/' || r == '[' || r == ']' || r == '@' || r == '.'
}
func extractPath(url string) (base string, path string) {
pathStart := -1
// Look for scheme:// first
if i := strings.Index(s, "://"); i >= 0 {
if i := strings.Index(url, "://"); i >= 0 {
// Look for the next slash after scheme://
rest := s[i+3:]
rest := url[i+3:]
if j := strings.IndexRune(rest, '/'); j >= 0 {
pathStart = i + 3 + j
}
} else {
// Otherwise, first slash is path start
pathStart = strings.IndexRune(s, '/')
pathStart = strings.IndexRune(url, '/')
}
if pathStart >= 0 {
path = s[pathStart:]
base := s[:pathStart]
parts = strings.FieldsFunc(base, split)
path = url[pathStart:]
base = url[:pathStart]
} else {
parts = strings.FieldsFunc(s, split)
path = ""
base = url
}
return parts, path
return base, path
}
func extractQueryParams(rawUrl string) (base string, query url.Values, err error) {
if i := strings.Index(rawUrl, "?"); i >= 0 {
query, err = url.ParseQuery(rawUrl[i+1:])
if err != nil {
return "", nil, err
}
rawUrl = rawUrl[:i]
}
return rawUrl, query, nil
}
func validateQueryParams(patternQuery, inputQuery url.Values) bool {
if len(patternQuery) != len(inputQuery) {
return false
}
for patternKey, patternValues := range patternQuery {
inputValues, exists := inputQuery[patternKey]
if !exists {
return false
}
if len(patternValues) != len(inputValues) {
return false
}
for i := range patternValues {
matched, err := path.Match(patternValues[i], inputValues[i])
if err != nil || !matched {
return false
}
}
}
return true
}

View File

@@ -7,6 +7,77 @@ import (
"github.com/stretchr/testify/require"
)
func TestValidateCallbackURLPattern(t *testing.T) {
tests := []struct {
name string
pattern string
shouldError bool
}{
{
name: "exact URL",
pattern: "https://example.com/callback",
shouldError: false,
},
{
name: "wildcard scheme",
pattern: "*://example.com/callback",
shouldError: false,
},
{
name: "wildcard port",
pattern: "https://example.com:*/callback",
shouldError: false,
},
{
name: "partial wildcard port",
pattern: "https://example.com:80*/callback",
shouldError: false,
},
{
name: "wildcard userinfo",
pattern: "https://user:*@example.com/callback",
shouldError: false,
},
{
name: "glob wildcard",
pattern: "*",
shouldError: false,
},
{
name: "relative URL",
pattern: "/callback",
shouldError: true,
},
{
name: "missing scheme separator",
pattern: "https//example.com/callback",
shouldError: true,
},
{
name: "malformed wildcard host glob",
pattern: "https://exa[mple.com/callback",
shouldError: true,
},
{
name: "malformed authority",
pattern: "https://[::1/callback",
shouldError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateCallbackURLPattern(tt.pattern)
if tt.shouldError {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}
func TestMatchCallbackURL(t *testing.T) {
tests := []struct {
name string
@@ -187,12 +258,6 @@ func TestMatchCallbackURL(t *testing.T) {
"https://example.com/callback",
false,
},
{
"unexpected credentials",
"https://example.com/callback",
"https://user:pass@example.com/callback",
false,
},
{
"wildcard password",
"https://user:*@example.com/callback",
@@ -347,7 +412,7 @@ func TestMatchCallbackURL(t *testing.T) {
"backslash instead of forward slash",
"https://example.com/callback",
"https://example.com\\callback",
false,
true,
},
{
"double slash in hostname (protocol smuggling)",
@@ -546,246 +611,3 @@ func TestGetCallbackURLFromList_MultiplePatterns(t *testing.T) {
})
}
}
func TestMatchPath(t *testing.T) {
tests := []struct {
name string
pattern string
input string
shouldMatch bool
}{
// Exact matches
{
name: "exact match",
pattern: "/callback",
input: "/callback",
shouldMatch: true,
},
{
name: "exact mismatch",
pattern: "/callback",
input: "/other",
shouldMatch: false,
},
{
name: "empty paths",
pattern: "",
input: "",
shouldMatch: true,
},
// Single wildcard (*)
{
name: "single wildcard matches segment",
pattern: "/api/*/callback",
input: "/api/v1/callback",
shouldMatch: true,
},
{
name: "single wildcard doesn't match multiple segments",
pattern: "/api/*/callback",
input: "/api/v1/v2/callback",
shouldMatch: false,
},
{
name: "single wildcard at end",
pattern: "/callback/*",
input: "/callback/test",
shouldMatch: true,
},
{
name: "single wildcard at start",
pattern: "/*/callback",
input: "/api/callback",
shouldMatch: true,
},
{
name: "multiple single wildcards",
pattern: "/*/test/*",
input: "/api/test/callback",
shouldMatch: true,
},
{
name: "partial wildcard prefix",
pattern: "/test*",
input: "/testing",
shouldMatch: true,
},
{
name: "partial wildcard suffix",
pattern: "/*-callback",
input: "/oauth-callback",
shouldMatch: true,
},
{
name: "partial wildcard middle",
pattern: "/api-*-v1",
input: "/api-internal-v1",
shouldMatch: true,
},
// Double wildcard (**)
{
name: "double wildcard matches multiple segments",
pattern: "/api/**/callback",
input: "/api/v1/v2/v3/callback",
shouldMatch: true,
},
{
name: "double wildcard matches single segment",
pattern: "/api/**/callback",
input: "/api/v1/callback",
shouldMatch: true,
},
{
name: "double wildcard doesn't match when pattern has extra slashes",
pattern: "/api/**/callback",
input: "/api/callback",
shouldMatch: false,
},
{
name: "double wildcard at end",
pattern: "/api/**",
input: "/api/v1/v2/callback",
shouldMatch: true,
},
{
name: "double wildcard in middle",
pattern: "/api/**/v2/**/callback",
input: "/api/v1/v2/v3/v4/callback",
shouldMatch: true,
},
// Complex patterns
{
name: "mix of single and double wildcards",
pattern: "/*/api/**/callback",
input: "/app/api/v1/v2/callback",
shouldMatch: true,
},
{
name: "wildcard with special characters",
pattern: "/callback-*",
input: "/callback-123",
shouldMatch: true,
},
{
name: "path with query-like string (no special handling)",
pattern: "/callback?code=*",
input: "/callback?code=abc",
shouldMatch: true,
},
// Edge cases
{
name: "single wildcard matches empty segment",
pattern: "/api/*/callback",
input: "/api//callback",
shouldMatch: true,
},
{
name: "pattern longer than input",
pattern: "/api/v1/callback",
input: "/api",
shouldMatch: false,
},
{
name: "input longer than pattern",
pattern: "/api",
input: "/api/v1/callback",
shouldMatch: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matches, err := matchPath(tt.pattern, tt.input)
require.NoError(t, err)
assert.Equal(t, tt.shouldMatch, matches)
})
}
}
func TestSplitParts(t *testing.T) {
tests := []struct {
name string
input string
expectedParts []string
expectedPath string
}{
{
name: "simple https URL",
input: "https://example.com/callback",
expectedParts: []string{"https", "example", "com"},
expectedPath: "/callback",
},
{
name: "URL with port",
input: "https://example.com:8080/callback",
expectedParts: []string{"https", "example", "com", "8080"},
expectedPath: "/callback",
},
{
name: "URL with subdomain",
input: "https://api.example.com/callback",
expectedParts: []string{"https", "api", "example", "com"},
expectedPath: "/callback",
},
{
name: "URL with credentials",
input: "https://user:pass@example.com/callback",
expectedParts: []string{"https", "user", "pass", "example", "com"},
expectedPath: "/callback",
},
{
name: "URL without path",
input: "https://example.com",
expectedParts: []string{"https", "example", "com"},
expectedPath: "",
},
{
name: "URL with deep path",
input: "https://example.com/api/v1/callback",
expectedParts: []string{"https", "example", "com"},
expectedPath: "/api/v1/callback",
},
{
name: "URL with path and query",
input: "https://example.com/callback?code=123",
expectedParts: []string{"https", "example", "com"},
expectedPath: "/callback?code=123",
},
{
name: "URL with trailing slash",
input: "https://example.com/",
expectedParts: []string{"https", "example", "com"},
expectedPath: "/",
},
{
name: "URL with multiple subdomains",
input: "https://api.v1.staging.example.com/callback",
expectedParts: []string{"https", "api", "v1", "staging", "example", "com"},
expectedPath: "/callback",
},
{
name: "URL with port and credentials",
input: "https://user:pass@example.com:8080/callback",
expectedParts: []string{"https", "user", "pass", "example", "com", "8080"},
expectedPath: "/callback",
},
{
name: "scheme with authority separator but no slash",
input: "http://example.com",
expectedParts: []string{"http", "example", "com"},
expectedPath: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parts, path := splitParts(tt.input)
assert.Equal(t, tt.expectedParts, parts, "parts mismatch")
assert.Equal(t, tt.expectedPath, path, "path mismatch")
})
}
}

View File

@@ -2,6 +2,7 @@ package utils
import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
@@ -21,6 +22,27 @@ func BearerAuth(r *http.Request) (string, bool) {
return "", false
}
// OAuthClientBasicAuth returns the OAuth client ID and secret provided in the request's
// Authorization header, if present. See RFC 6749, Section 2.3.
func OAuthClientBasicAuth(r *http.Request) (clientID, clientSecret string, ok bool) {
clientID, clientSecret, ok = r.BasicAuth()
if !ok {
return "", "", false
}
clientID, err := url.QueryUnescape(clientID)
if err != nil {
return "", "", false
}
clientSecret, err = url.QueryUnescape(clientSecret)
if err != nil {
return "", "", false
}
return clientID, clientSecret, true
}
// SetCacheControlHeader sets the Cache-Control header for the response.
func SetCacheControlHeader(ctx *gin.Context, maxAge, staleWhileRevalidate time.Duration) {
_, ok := ctx.GetQuery("skipCache")

View File

@@ -63,3 +63,62 @@ func TestBearerAuth(t *testing.T) {
})
}
}
func TestOAuthClientBasicAuth(t *testing.T) {
tests := []struct {
name string
authHeader string
expectedClientID string
expectedClientSecret string
expectedOk bool
}{
{
name: "Valid client ID and secret in header (example from RFC 6749)",
authHeader: "Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3",
expectedClientID: "s6BhdRkqt3",
expectedClientSecret: "7Fjfp0ZBr1KtDRbnfVdmIw",
expectedOk: true,
},
{
name: "Valid client ID and secret in header (escaped values)",
authHeader: "Basic ZTUwOTcyYmQtNmUzMi00OTU3LWJhZmMtMzU0MTU3ZjI1NDViOislMjUlMjYlMkIlQzIlQTMlRTIlODIlQUM=",
expectedClientID: "e50972bd-6e32-4957-bafc-354157f2545b",
// This is the example string from RFC 6749, Appendix B.
expectedClientSecret: " %&+£€",
expectedOk: true,
},
{
name: "Empty auth header",
authHeader: "",
expectedClientID: "",
expectedClientSecret: "",
expectedOk: false,
},
{
name: "Basic prefix only",
authHeader: "Basic ",
expectedClientID: "",
expectedClientSecret: "",
expectedOk: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "http://example.com", nil)
require.NoError(t, err, "Failed to create request")
if tt.authHeader != "" {
req.Header.Set("Authorization", tt.authHeader)
}
clientId, clientSecret, ok := OAuthClientBasicAuth(req)
assert.Equal(t, tt.expectedOk, ok)
if tt.expectedOk {
assert.Equal(t, tt.expectedClientID, clientId)
assert.Equal(t, tt.expectedClientSecret, clientSecret)
}
})
}
}

File diff suppressed because one or more lines are too long

View File

@@ -356,8 +356,8 @@
"login_code_email_success": "Der Login-Code wurde an den Benutzer gesendet.",
"send_email": "E-Mail senden",
"show_code": "Code anzeigen",
"callback_url_description": "Die URL(s) von deinem Kunden. Wenn du das Feld leer lässt, werden sie automatisch hinzugefügt. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
"logout_callback_url_description": "Von deinem Kunden angegebene URL(s) zum Abmelden. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
"callback_url_description": "Die URL(s) von deinem Client. Wenn du das Feld leer lässt, werden sie automatisch hinzugefügt. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
"logout_callback_url_description": "Von deinem Client angegebene URL(s) zum Abmelden. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
"api_key_expiration": "API-Schlüssel-Ablauf",
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Sende eine E-Mail an den Benutzer, wenn sein API-Schlüssel ablaufen wird.",
"authorize_device": "Gerät autorisieren",
@@ -397,21 +397,21 @@
"color_value": "Farbwert",
"apply": "Übernehmen",
"signup_token": "Anmeldungstoken",
"create_a_signup_token_to_allow_new_user_registration": "Erstell ein Anmeldetoken, damit sich neue Benutzer registrieren können.",
"create_a_signup_token_to_allow_new_user_registration": "Erstell einen Registrierungstoken, damit sich neue Benutzer registrieren können.",
"usage_limit": "Nutzungsbeschränkung",
"number_of_times_token_can_be_used": "Wie oft der Anmeldetoken benutzt werden kann.",
"number_of_times_token_can_be_used": "Wie oft der Registrierungstoken benutzt werden kann.",
"expires": "Läuft ab",
"signup": "Anmelden",
"signup": "Registrieren",
"user_creation": "Benutzererstellung",
"configure_user_creation": "Verwalte die Einstellungen für die Benutzererstellung, einschließlich der Anmeldemethoden und Standardberechtigungen für neue Benutzer.",
"user_creation_groups_description": "Weise diese Gruppen neuen Benutzern bei der Anmeldung automatisch zu.",
"user_creation_claims_description": "Weise diese benutzerdefinierten Ansprüche neuen Benutzern bei der Anmeldung automatisch zu.",
"configure_user_creation": "Verwalte die Einstellungen für die Benutzererstellung, einschließlich der Registrierungsmethoden und Standardberechtigungen für neue Benutzer.",
"user_creation_groups_description": "Weise diese Gruppen neuen Benutzern bei der Registrierung automatisch zu.",
"user_creation_claims_description": "Weise diese benutzerdefinierten Ansprüche neuen Benutzern bei der Registrierung automatisch zu.",
"user_creation_updated_successfully": "Einstellungen für die Benutzererstellung erfolgreich aktualisiert.",
"signup_disabled_description": "Benutzeranmeldungen sind komplett deaktiviert. Nur Admins können neue Benutzerkonten erstellen.",
"signup_requires_valid_token": "Zum Erstellen eines Kontos brauchst du einen gültigen Anmeldetoken.",
"signup_requires_valid_token": "Zum Erstellen eines Kontos brauchst du einen gültigen Registrierungstoken.",
"validating_signup_token": "Anmeldungstoken bestätigen",
"go_to_login": "Zum Login gehen",
"signup_to_appname": "Melde dich bei „ {appName}“ an",
"signup_to_appname": "Registriere dich bei „ {appName}“",
"create_your_account_to_get_started": "Erstell dein Konto, um loszulegen.",
"initial_account_creation_description": "Erstell dein Konto, um loszulegen. Du kannst später einen Passkey einrichten.",
"setup_your_passkey": "Passkey einrichten",
@@ -419,12 +419,12 @@
"skip_for_now": "Jetzt überspringen",
"account_created": "Konto erstellt",
"enable_user_signups": "Benutzeranmeldungen aktivieren",
"enable_user_signups_description": "Entscheide, wie sich Leute für neue Konten in Pocket ID anmelden können.",
"enable_user_signups_description": "Entscheide, wie sich Leute für neue Konten in Pocket ID registrieren können.",
"user_signups_are_disabled": "Benutzeranmeldungen sind im Moment deaktiviert.",
"create_signup_token": "Anmeldungstoken erstellen",
"view_active_signup_tokens": "Aktive Anmeldetoken anzeigen",
"view_active_signup_tokens": "Aktive Registrierungstoken anzeigen",
"manage_signup_tokens": "Anmeldungstoken verwalten",
"view_and_manage_active_signup_tokens": "Aktive Anmeldetoken anzeigen und verwalten.",
"view_and_manage_active_signup_tokens": "Aktive Registrierungstoken anzeigen und verwalten.",
"signup_token_deleted_successfully": "Anmeldungstoken erfolgreich gelöscht.",
"expired": "Abgelaufen",
"used_up": "Aufgebraucht",
@@ -434,9 +434,9 @@
"token": "Token",
"loading": "Laden",
"delete_signup_token": "Anmeldungstoken löschen",
"are_you_sure_you_want_to_delete_this_signup_token": "Willst du diesen Anmeldetoken wirklich löschen? Das kannst du nicht rückgängig machen.",
"signup_with_token": "Mit Token anmelden",
"signup_with_token_description": "Benutzer können sich nur mit einem gültigen Anmeldetoken anmelden, das von einem Administrator erstellt wurde.",
"are_you_sure_you_want_to_delete_this_signup_token": "Willst du diesen Registrierungstoken wirklich löschen? Das kannst du nicht rückgängig machen.",
"signup_with_token": "Mit Token registrieren",
"signup_with_token_description": "Benutzer können sich nur mit einem gültigen Registrierungstoken anmelden, das von einem Administrator erstellt wurde.",
"signup_open": "Anmeldung offen",
"signup_open_description": "Jeder kann ohne Einschränkungen ein neues Konto erstellen.",
"of": "von",
@@ -477,7 +477,7 @@
"light": "Hell",
"dark": "Dunkel",
"system": "System",
"signup_token_user_groups_description": "Weise diese Gruppen automatisch den Leuten zu, die sich mit diesem Token anmelden.",
"signup_token_user_groups_description": "Weise diese Gruppen automatisch den Leuten zu, die sich mit diesem Token registrieren.",
"allowed_oidc_clients": "Zugelassene OIDC-Clients",
"allowed_oidc_clients_description": "Wähle die OIDC-Clients aus, bei denen sich Mitglieder dieser Benutzergruppe anmelden dürfen.",
"unrestrict_oidc_client": "Uneingeschränkt {clientName}",
@@ -513,7 +513,7 @@
"email_verification_warning": "Bestätige deine E-Mail-Adresse",
"email_verification_warning_description": "Deine E-Mail-Adresse ist noch nicht bestätigt. Bitte bestätige sie so schnell wie möglich.",
"email_verification": "E-Mail-Bestätigung",
"email_verification_description": "Schick den Nutzern eine Bestätigungs-E-Mail, wenn sie sich anmelden oder ihre E-Mail-Adresse ändern.",
"email_verification_description": "Schick den Nutzern eine Bestätigungs-E-Mail, wenn sie sich registrieren oder ihre E-Mail-Adresse ändern.",
"email_verification_success_title": "E-Mail erfolgreich bestätigt",
"email_verification_success_description": "Deine E-Mail-Adresse wurde erfolgreich bestätigt.",
"email_verification_error_title": "E-Mail-Verifizierung ist schiefgegangen",

525
frontend/messages/et.json Normal file
View File

@@ -0,0 +1,525 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"my_account": "My Account",
"logout": "Logout",
"confirm": "Confirm",
"docs": "Docs",
"key": "Key",
"value": "Value",
"remove_custom_claim": "Remove custom claim",
"add_custom_claim": "Add custom claim",
"add_another": "Add another",
"select_a_date": "Select a date",
"select_file": "Select File",
"profile_picture": "Profile Picture",
"profile_picture_is_managed_by_ldap_server": "The profile picture is managed by the LDAP server and cannot be changed here.",
"click_profile_picture_to_upload_custom": "Click on the profile picture to upload a custom one from your files.",
"image_should_be_in_format": "The image should be in PNG, JPEG or WEBP format.",
"items_per_page": "Items per page",
"no_items_found": "No items found",
"select_items": "Select items...",
"search": "Search...",
"expand_card": "Expand card",
"copied": "Copied",
"click_to_copy": "Click to copy",
"something_went_wrong": "Something went wrong",
"go_back_to_home": "Go back to home",
"alternative_sign_in_methods": "Alternative Sign In Methods",
"login_background": "Login background",
"logo": "Logo",
"login_code": "Login Code",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Create a login code that the user can use to sign in without a passkey once.",
"one_hour": "1 hour",
"twelve_hours": "12 hours",
"one_day": "1 day",
"one_week": "1 week",
"one_month": "1 month",
"expiration": "Expiration",
"generate_code": "Generate Code",
"name": "Name",
"browser_unsupported": "Browser unsupported",
"this_browser_does_not_support_passkeys": "This browser doesn't support passkeys. Please use an alternative sign in method.",
"an_unknown_error_occurred": "An unknown error occurred",
"authentication_process_was_aborted": "The authentication process was aborted",
"error_occurred_with_authenticator": "An error occurred with the authenticator",
"authenticator_does_not_support_discoverable_credentials": "The authenticator does not support discoverable credentials",
"authenticator_does_not_support_resident_keys": "The authenticator does not support resident keys",
"passkey_was_previously_registered": "This passkey was previously registered",
"authenticator_does_not_support_any_of_the_requested_algorithms": "The authenticator does not support any of the requested algorithms",
"webauthn_error_invalid_rp_id": "The configured relying party ID is invalid.",
"webauthn_error_invalid_domain": "The configured domain is invalid.",
"contact_administrator_to_fix": "Contact your administrator to fix this issue.",
"webauthn_operation_not_allowed_or_timed_out": "The operation was not allowed or timed out",
"webauthn_not_supported_by_browser": "Passkeys are not supported by this browser. Please use an alternative sign in method.",
"critical_error_occurred_contact_administrator": "A critical error occurred. Please contact your administrator.",
"sign_in_to": "Sign in to {name}",
"client_not_found": "Client not found",
"client_wants_to_access_the_following_information": "<b>{client}</b> wants to access the following information:",
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Do you want to sign in to <b>{client}</b> with your {appName} account?",
"email": "Email",
"view_your_email_address": "View your email address",
"profile": "Profile",
"view_your_profile_information": "View your profile information",
"groups": "Groups",
"view_the_groups_you_are_a_member_of": "View the groups you are a member of",
"cancel": "Cancel",
"sign_in": "Sign in",
"try_again": "Try again",
"client_logo": "Client Logo",
"sign_out": "Sign out",
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Do you want to sign out of {appName} with the account <b>{username}</b>?",
"sign_in_to_appname": "Sign in to {appName}",
"please_try_to_sign_in_again": "Please try to sign in again.",
"authenticate_with_passkey_to_access_account": "Authenticate yourself with your passkey to access your account.",
"authenticate": "Authenticate",
"please_try_again": "Please try again.",
"continue": "Continue",
"alternative_sign_in": "Alternative Sign In",
"if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "If you don't have access to your passkey, you can sign in using one of the following methods.",
"use_your_passkey_instead": "Use your passkey instead?",
"email_login": "Email Login",
"enter_a_login_code_to_sign_in": "Enter a login code to sign in.",
"sign_in_with_login_code": "Sign in with login code",
"request_a_login_code_via_email": "Request a login code via email.",
"go_back": "Go back",
"an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system": "An email has been sent to the provided email, if it exists in the system.",
"enter_code": "Enter code",
"enter_your_email_address_to_receive_an_email_with_a_login_code": "Enter your email address to receive an email with a login code.",
"your_email": "Your email",
"submit": "Submit",
"enter_the_code_you_received_to_sign_in": "Enter the code you received to sign in.",
"code": "Code",
"invalid_redirect_url": "Invalid redirect URL",
"audit_log": "Audit Log",
"users": "Users",
"user_groups": "User Groups",
"oidc_clients": "OIDC Clients",
"api_keys": "API Keys",
"application_configuration": "Application Configuration",
"settings": "Settings",
"update_pocket_id": "Update Pocket ID",
"powered_by": "Powered by",
"see_your_recent_account_activities": "See your account activities within the configured retention period.",
"time": "Time",
"event": "Event",
"approximate_location": "Approximate Location",
"ip_address": "IP Address",
"device": "Device",
"client": "Client",
"unknown": "Unknown",
"account_details_updated_successfully": "Account details updated successfully",
"profile_picture_updated_successfully": "Profile picture updated successfully. It may take a few minutes to update.",
"account_settings": "Account Settings",
"passkey_missing": "Passkey missing",
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Please add a passkey to prevent losing access to your account.",
"single_passkey_configured": "Single Passkey Configured",
"it_is_recommended_to_add_more_than_one_passkey": "It is recommended to add more than one passkey to avoid losing access to your account.",
"account_details": "Account Details",
"passkeys": "Passkeys",
"manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Manage your passkeys that you can use to authenticate yourself.",
"add_passkey": "Add Passkey",
"create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Create a one-time login code to sign in from a different device without a passkey.",
"create": "Create",
"first_name": "First name",
"last_name": "Last name",
"username": "Username",
"save": "Save",
"username_can_only_contain": "Username can only contain lowercase letters, numbers, underscores, dots, hyphens, and '@' symbols",
"username_must_start_with": "Username must start with an alphanumeric character",
"username_must_end_with": "Username must end with an alphanumeric character",
"sign_in_using_the_following_code_the_code_will_expire_in_minutes": "Sign in using the following code. The code will expire in 15 minutes.",
"or_visit": "or visit",
"added_on": "Added on",
"rename": "Rename",
"delete": "Delete",
"are_you_sure_you_want_to_delete_this_passkey": "Are you sure you want to delete this passkey?",
"passkey_deleted_successfully": "Passkey deleted successfully",
"delete_passkey_name": "Delete {passkeyName}",
"passkey_name_updated_successfully": "Passkey name updated successfully",
"name_passkey": "Name Passkey",
"name_your_passkey_to_easily_identify_it_later": "Name your passkey to easily identify it later.",
"create_api_key": "Create API Key",
"add_a_new_api_key_for_programmatic_access": "Add a new API key for programmatic access to the <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
"add_api_key": "Add API Key",
"manage_api_keys": "Manage API Keys",
"api_key_created": "API Key Created",
"for_security_reasons_this_key_will_only_be_shown_once": "For security reasons, this key will only be shown once. Please store it securely.",
"description": "Description",
"api_key": "API Key",
"close": "Close",
"name_to_identify_this_api_key": "Name to identify this API key.",
"expires_at": "Expires At",
"when_this_api_key_will_expire": "When this API key will expire.",
"optional_description_to_help_identify_this_keys_purpose": "Optional description to help identify this key's purpose.",
"expiration_date_must_be_in_the_future": "Expiration date must be in the future",
"revoke_api_key": "Revoke API Key",
"never": "Never",
"revoke": "Revoke",
"api_key_revoked_successfully": "API key revoked successfully",
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Are you sure you want to revoke the API key \"{apiKeyName}\"? This will break any integrations using this key.",
"last_used": "Last Used",
"actions": "Actions",
"images_updated_successfully": "Images updated successfully. It may take a few minutes to update.",
"general": "General",
"configure_smtp_to_send_emails": "Enable email notifications to alert users when a login is detected from a new device or location.",
"ldap": "LDAP",
"configure_ldap_settings_to_sync_users_and_groups_from_an_ldap_server": "Configure LDAP settings to sync users and groups from an LDAP server.",
"images": "Images",
"update": "Update",
"email_configuration_updated_successfully": "Email configuration updated successfully",
"save_changes_question": "Save changes?",
"you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "You have to save the changes before sending a test email. Do you want to save now?",
"save_and_send": "Save and send",
"test_email_sent_successfully": "Test email sent successfully to your email address.",
"failed_to_send_test_email": "Failed to send test email. Check the server logs for more information.",
"smtp_configuration": "SMTP Configuration",
"smtp_host": "SMTP Host",
"smtp_port": "SMTP Port",
"smtp_user": "SMTP User",
"smtp_password": "SMTP Password",
"smtp_from": "SMTP From",
"smtp_tls_option": "SMTP TLS Option",
"email_tls_option": "Email TLS Option",
"skip_certificate_verification": "Skip Certificate Verification",
"this_can_be_useful_for_selfsigned_certificates": "This can be useful for self-signed certificates.",
"enabled_emails": "Enabled Emails",
"email_login_notification": "Email Login Notification",
"send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Send an email to the user when they log in from a new device.",
"emai_login_code_requested_by_user": "Email Login Code Requested by User",
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Allows users to bypass passkeys by requesting a login code sent to their email. This significantly reduces security as anyone with access to the user's email can gain entry.",
"email_login_code_from_admin": "Email Login Code from Admin",
"allows_an_admin_to_send_a_login_code_to_the_user": "Allows an admin to send a login code to the user via email.",
"send_test_email": "Send test email",
"application_configuration_updated_successfully": "Application configuration updated successfully",
"application_name": "Application Name",
"session_duration": "Session Duration",
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "The duration of a session in minutes before the user has to sign in again.",
"enable_self_account_editing": "Enable Self-Account Editing",
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Whether the users should be able to edit their own account details.",
"ldap_configuration_updated_successfully": "LDAP configuration updated successfully",
"ldap_disabled_successfully": "LDAP disabled successfully",
"ldap_sync_finished": "LDAP sync finished",
"client_configuration": "Client Configuration",
"ldap_url": "LDAP URL",
"ldap_bind_dn": "LDAP Bind DN",
"ldap_bind_password": "LDAP Bind Password",
"ldap_base_dn": "LDAP Base DN",
"user_search_filter": "User Search Filter",
"the_search_filter_to_use_to_search_or_sync_users": "The Search filter to use to search/sync users.",
"groups_search_filter": "Groups Search Filter",
"the_search_filter_to_use_to_search_or_sync_groups": "The Search filter to use to search/sync groups.",
"attribute_mapping": "Attribute Mapping",
"user_unique_identifier_attribute": "User Unique Identifier Attribute",
"the_value_of_this_attribute_should_never_change": "The value of this attribute should never change.",
"username_attribute": "Username Attribute",
"user_mail_attribute": "User Mail Attribute",
"user_first_name_attribute": "User First Name Attribute",
"user_last_name_attribute": "User Last Name Attribute",
"user_profile_picture_attribute": "User Profile Picture Attribute",
"the_value_of_this_attribute_can_either_be_a_url_binary_or_base64_encoded_image": "The value of this attribute can either be a URL, a binary or a base64 encoded image.",
"group_members_attribute": "Group Members Attribute",
"the_attribute_to_use_for_querying_members_of_a_group": "The attribute to use for querying members of a group.",
"group_unique_identifier_attribute": "Group Unique Identifier Attribute",
"group_rdn_attribute": "Group RDN Attribute (in DN)",
"admin_group_name": "Admin Group Name",
"members_of_this_group_will_have_admin_privileges_in_pocketid": "Members of this group will have Admin Privileges in Pocket ID.",
"disable": "Disable",
"sync_now": "Sync now",
"enable": "Enable",
"user_created_successfully": "User created successfully",
"create_user": "Create User",
"add_a_new_user_to_appname": "Add a new user to {appName}",
"add_user": "Add User",
"manage_users": "Manage Users",
"admin_privileges": "Admin Privileges",
"admins_have_full_access_to_the_admin_panel": "Admins have full access to the admin panel.",
"delete_firstname_lastname": "Delete {firstName} {lastName}",
"are_you_sure_you_want_to_delete_this_user": "Are you sure you want to delete this user?",
"user_deleted_successfully": "User deleted successfully",
"role": "Role",
"source": "Source",
"admin": "Admin",
"user": "User",
"local": "Local",
"toggle_menu": "Toggle menu",
"edit": "Edit",
"user_groups_updated_successfully": "User groups updated successfully",
"user_updated_successfully": "User updated successfully",
"custom_claims_updated_successfully": "Custom claims updated successfully",
"back": "Back",
"user_details_firstname_lastname": "User Details {firstName} {lastName}",
"manage_which_groups_this_user_belongs_to": "Manage which groups this user belongs to.",
"custom_claims": "Custom Claims",
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested.",
"user_group_created_successfully": "User group created successfully",
"create_user_group": "Create User Group",
"create_a_new_group_that_can_be_assigned_to_users": "Create a new group that can be assigned to users.",
"add_group": "Add Group",
"manage_user_groups": "Manage User Groups",
"friendly_name": "Friendly Name",
"name_that_will_be_displayed_in_the_ui": "Name that will be displayed in the UI",
"name_that_will_be_in_the_groups_claim": "Name that will be in the \"groups\" claim",
"delete_name": "Delete {name}",
"are_you_sure_you_want_to_delete_this_user_group": "Are you sure you want to delete this user group?",
"user_group_deleted_successfully": "User group deleted successfully",
"user_count": "User Count",
"user_group_updated_successfully": "User group updated successfully",
"users_updated_successfully": "Users updated successfully",
"user_group_details_name": "User Group Details {name}",
"assign_users_to_this_group": "Assign users to this group.",
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user_prioritized": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested. Custom claims defined on the user will be prioritized if there are conflicts.",
"oidc_client_created_successfully": "OIDC client created successfully",
"create_oidc_client": "Create OIDC Client",
"add_a_new_oidc_client_to_appname": "Add a new OIDC client to {appName}.",
"add_oidc_client": "Add OIDC Client",
"manage_oidc_clients": "Manage OIDC Clients",
"one_time_link": "One Time Link",
"use_this_link_to_sign_in_once": "Use this link to sign in once. This is needed for users who haven't added a passkey yet or have lost it.",
"add": "Add",
"callback_urls": "Callback URLs",
"logout_callback_urls": "Logout Callback URLs",
"public_client": "Public Client",
"public_clients_description": "Public clients do not have a client secret. They are designed for mobile, web, and native applications where secrets cannot be securely stored.",
"pkce": "PKCE",
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange is a security feature to prevent CSRF and authorization code interception attacks.",
"requires_reauthentication": "Requires Re-Authentication",
"requires_users_to_authenticate_again_on_each_authorization": "Requires users to authenticate again on each authorization, even if already signed in",
"name_logo": "{name} logo",
"change_logo": "Change Logo",
"upload_logo": "Upload Logo",
"remove_logo": "Remove Logo",
"are_you_sure_you_want_to_delete_this_oidc_client": "Are you sure you want to delete this OIDC client?",
"oidc_client_deleted_successfully": "OIDC client deleted successfully",
"authorization_url": "Authorization URL",
"oidc_discovery_url": "OIDC Discovery URL",
"token_url": "Token URL",
"userinfo_url": "Userinfo URL",
"logout_url": "Logout URL",
"certificate_url": "Certificate URL",
"enabled": "Enabled",
"disabled": "Disabled",
"oidc_client_updated_successfully": "OIDC client updated successfully",
"create_new_client_secret": "Create new client secret",
"are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.",
"generate": "Generate",
"new_client_secret_created_successfully": "New client secret created successfully",
"oidc_client_name": "OIDC Client {name}",
"client_id": "Client ID",
"client_secret": "Client secret",
"show_more_details": "Show more details",
"allowed_user_groups": "Allowed User Groups",
"allowed_user_groups_description": "Select the user groups whose members are allowed to sign in to this client.",
"allowed_user_groups_status_unrestricted_description": "No user group restrictions are applied. Any user can sign in to this client.",
"unrestrict": "Unrestrict",
"restrict": "Restrict",
"user_groups_restriction_updated_successfully": "User groups restriction updated successfully",
"allowed_user_groups_updated_successfully": "Allowed user groups updated successfully",
"favicon": "Favicon",
"light_mode_logo": "Light Mode Logo",
"dark_mode_logo": "Dark Mode Logo",
"email_logo": "Email Logo",
"background_image": "Background Image",
"language": "Language",
"reset_profile_picture_question": "Reset profile picture?",
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "This will remove the uploaded image and reset the profile picture to default. Do you want to continue?",
"reset": "Reset",
"reset_to_default": "Reset to default",
"profile_picture_has_been_reset": "Profile picture has been reset. It may take a few minutes to update.",
"select_the_language_you_want_to_use": "Select the language you want to use. Please note that some text may be automatically translated and could be inaccurate.",
"contribute_to_translation": "If you find an issue you're welcome to contribute to the translation on <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
"personal": "Personal",
"global": "Global",
"all_users": "All Users",
"all_events": "All Events",
"all_clients": "All Clients",
"all_locations": "All Locations",
"global_audit_log": "Global Audit Log",
"see_all_recent_account_activities": "View the account activities of all users during the set retention period.",
"token_sign_in": "Token Sign In",
"client_authorization": "Client Authorization",
"new_client_authorization": "New Client Authorization",
"device_code_authorization": "Device Code Authorization",
"new_device_code_authorization": "New Device Code Authorization",
"passkey_added": "Passkey Added",
"passkey_removed": "Passkey Removed",
"disable_animations": "Disable Animations",
"turn_off_ui_animations": "Turn off animations throughout the UI.",
"user_disabled": "Account Disabled",
"disabled_users_cannot_log_in_or_use_services": "Disabled users cannot log in or use services.",
"user_disabled_successfully": "User has been disabled successfully.",
"user_enabled_successfully": "User has been enabled successfully.",
"status": "Status",
"disable_firstname_lastname": "Disable {firstName} {lastName}",
"are_you_sure_you_want_to_disable_this_user": "Are you sure you want to disable this user? They will not be able to log in or access any services.",
"ldap_soft_delete_users": "Keep disabled users from LDAP.",
"ldap_soft_delete_users_description": "When enabled, users removed from LDAP will be disabled rather than deleted from the system.",
"login_code_email_success": "The login code has been sent to the user.",
"send_email": "Send Email",
"show_code": "Show Code",
"callback_url_description": "URL(s) provided by your client. Will be automatically added if left blank. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
"logout_callback_url_description": "URL(s) provided by your client for logout. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
"api_key_expiration": "API Key Expiration",
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Send an email to the user when their API key is about to expire.",
"authorize_device": "Authorize Device",
"the_device_has_been_authorized": "The device has been authorized.",
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
"authorize": "Authorize",
"federated_client_credentials": "Federated Client Credentials",
"federated_client_credentials_description": "Using federated client credentials, you can authenticate OIDC clients using JWT tokens issued by third-party authorities.",
"add_federated_client_credential": "Add Federated Client Credential",
"add_another_federated_client_credential": "Add another federated client credential",
"oidc_allowed_group_count": "Allowed Group Count",
"unrestricted": "Unrestricted",
"show_advanced_options": "Show Advanced Options",
"hide_advanced_options": "Hide Advanced Options",
"oidc_data_preview": "OIDC Data Preview",
"preview_the_oidc_data_that_would_be_sent_for_different_users": "Preview the OIDC data that would be sent for different users",
"id_token": "ID Token",
"access_token": "Access Token",
"userinfo": "Userinfo",
"id_token_payload": "ID Token Payload",
"access_token_payload": "Access Token Payload",
"userinfo_endpoint_response": "Userinfo Endpoint Response",
"copy": "Copy",
"no_preview_data_available": "No preview data available",
"copy_all": "Copy All",
"preview": "Preview",
"preview_for_user": "Preview for {name}",
"preview_the_oidc_data_that_would_be_sent_for_this_user": "Preview the OIDC data that would be sent for this user",
"show": "Show",
"select_an_option": "Select an option",
"select_user": "Select User",
"error": "Error",
"select_an_accent_color_to_customize_the_appearance_of_pocket_id": "Select an accent color to customize the appearance of Pocket ID.",
"accent_color": "Accent Color",
"custom_accent_color": "Custom Accent Color",
"custom_accent_color_description": "Enter a custom color using valid CSS color formats (e.g., hex, rgb, hsl).",
"color_value": "Color Value",
"apply": "Apply",
"signup_token": "Signup Token",
"create_a_signup_token_to_allow_new_user_registration": "Create a signup token to allow new user registration.",
"usage_limit": "Usage Limit",
"number_of_times_token_can_be_used": "Number of times the signup token can be used.",
"expires": "Expires",
"signup": "Sign Up",
"user_creation": "User Creation",
"configure_user_creation": "Manage user creation settings, including signup methods and default permissions for new users.",
"user_creation_groups_description": "Assign these groups automatically to new users upon signup.",
"user_creation_claims_description": "Assign these custom claims automatically to new users upon signup.",
"user_creation_updated_successfully": "User creation settings updated successfully.",
"signup_disabled_description": "User signups are completely disabled. Only administrators can create new user accounts.",
"signup_requires_valid_token": "A valid signup token is required to create an account",
"validating_signup_token": "Validating signup token",
"go_to_login": "Go to login",
"signup_to_appname": "Sign Up to {appName}",
"create_your_account_to_get_started": "Create your account to get started.",
"initial_account_creation_description": "Please create your account to get started. You will be able to set up a passkey later.",
"setup_your_passkey": "Set up your passkey",
"create_a_passkey_to_securely_access_your_account": "Create a passkey to securely access your account. This will be your primary way to sign in.",
"skip_for_now": "Skip for now",
"account_created": "Account Created",
"enable_user_signups": "Enable User Signups",
"enable_user_signups_description": "Decide how users can sign up for new accounts in Pocket ID.",
"user_signups_are_disabled": "User signups are currently disabled",
"create_signup_token": "Create Signup Token",
"view_active_signup_tokens": "View Active Signup Tokens",
"manage_signup_tokens": "Manage Signup Tokens",
"view_and_manage_active_signup_tokens": "View and manage active signup tokens.",
"signup_token_deleted_successfully": "Signup token deleted successfully.",
"expired": "Expired",
"used_up": "Used Up",
"active": "Active",
"usage": "Usage",
"created": "Created",
"token": "Token",
"loading": "Loading",
"delete_signup_token": "Delete Signup Token",
"are_you_sure_you_want_to_delete_this_signup_token": "Are you sure you want to delete this signup token? This action cannot be undone.",
"signup_with_token": "Signup with token",
"signup_with_token_description": "Users can only sign up using a valid signup token created by an administrator.",
"signup_open": "Open Signup",
"signup_open_description": "Anyone can create a new account without restrictions.",
"of": "of",
"skip_passkey_setup": "Skip Passkey Setup",
"skip_passkey_setup_description": "It's highly recommended to set up a passkey because without one, you will be locked out of your account as soon as the session expires.",
"my_apps": "My Apps",
"no_apps_available": "No apps available",
"contact_your_administrator_for_app_access": "Contact your administrator to get access to applications.",
"launch": "Launch",
"client_launch_url": "Client Launch URL",
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
"revoke_access": "Revoke Access",
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
"last_signed_in_ago": "Last signed in {time} ago",
"invalid_client_id": "Client ID can only contain letters, numbers, underscores, and hyphens",
"custom_client_id_description": "Set a custom client ID if this is required by your application. Otherwise, leave it blank to generate a random one.",
"generated": "Generated",
"administration": "Administration",
"group_rdn_attribute_description": "The attribute used in the groups distinguished name (DN).",
"display_name_attribute": "Display Name Attribute",
"display_name": "Display Name",
"configure_application_images": "Configure Application Images",
"ui_config_disabled_info_title": "UI Configuration Disabled",
"ui_config_disabled_info_description": "The UI configuration is disabled because the application configuration settings are managed through environment variables. Some settings may not be editable.",
"logo_from_url_description": "Paste a direct image URL (svg, png, webp). Find icons at <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> or <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
"invalid_url": "Invalid URL",
"require_user_email": "Require Email Address",
"require_user_email_description": "Requires users to have an email address. If disabled, the users without an email address won't be able to use features that require an email address.",
"view": "View",
"toggle_columns": "Toggle columns",
"locale": "Locale",
"ldap_id": "LDAP ID",
"reauthentication": "Re-authentication",
"clear_filters": "Clear Filters",
"default_profile_picture": "Default Profile Picture",
"light": "Light",
"dark": "Dark",
"system": "System",
"signup_token_user_groups_description": "Automatically assign these groups to users who sign up using this token.",
"allowed_oidc_clients": "Allowed OIDC Clients",
"allowed_oidc_clients_description": "Select the OIDC clients that members of this user group are allowed to sign in to.",
"unrestrict_oidc_client": "Unrestrict {clientName}",
"confirm_unrestrict_oidc_client_description": "Are you sure you want to unrestrict the OIDC client <b>{clientName}</b>? This will remove all group assignments for this client and any user will be able to sign in.",
"allowed_oidc_clients_updated_successfully": "Allowed OIDC clients updated successfully",
"yes": "Yes",
"no": "No",
"restricted": "Restricted",
"scim_provisioning": "SCIM Provisioning",
"scim_provisioning_description": "SCIM provisioning allows you to automatically provision and deprovision users and groups from your OIDC client. Learn more in the <link href='https://pocket-id.org/docs/configuration/scim'>docs</link>.",
"scim_endpoint": "SCIM Endpoint",
"scim_token": "SCIM Token",
"last_successful_sync_at": "Last successful sync: {time}",
"scim_configuration_updated_successfully": "SCIM configuration updated successfully.",
"scim_enabled_successfully": "SCIM enabled successfully.",
"scim_disabled_successfully": "SCIM disabled successfully.",
"disable_scim_provisioning": "Disable SCIM Provisioning",
"disable_scim_provisioning_confirm_description": "Are you sure you want to disable SCIM provisioning for <b>{clientName}</b>? This will stop all automatic user and group provisioning and deprovisioning.",
"scim_sync_failed": "SCIM sync failed. Check the server logs for more information.",
"scim_sync_successful": "The SCIM sync has been completed successfully.",
"save_and_sync": "Save and Sync",
"scim_save_changes_description": "You have to save the changes before starting a SCIM sync. Do you want to save now?",
"scopes": "Scopes",
"issuer_url": "Issuer URL",
"smtp_field_required_when_other_provided": "Required when any SMTP setting is provided",
"smtp_field_required_when_email_enabled": "Required when email notifications are enabled",
"renew": "Renew",
"renew_api_key": "Renew API Key",
"renew_api_key_description": "Renewing the API key will generate a new key. Make sure to update any integrations using this key.",
"api_key_renewed": "API key renewed",
"app_config_home_page": "Home Page",
"app_config_home_page_description": "The page users are redirected to after signing in.",
"email_verification_warning": "Verify your email address",
"email_verification_warning_description": "Your email address is not verified yet. Please verify it as soon as possible.",
"email_verification": "Email Verification",
"email_verification_description": "Send a verification email to users when they sign up or change their email address.",
"email_verification_success_title": "Email Verified Successfully",
"email_verification_success_description": "Your email address has been verified successfully.",
"email_verification_error_title": "Email Verification Failed",
"mark_as_unverified": "Mark as unverified",
"mark_as_verified": "Mark as verified",
"email_verification_sent": "Verification email sent successfully.",
"emails_verified_by_default": "Emails verified by default",
"emails_verified_by_default_description": "When enabled, users' email addresses will be marked as verified by default upon signup or when their email address is changed."
}

View File

@@ -311,7 +311,7 @@
"allowed_user_groups_description": "이 클라이언트에 로그인할 수 있는 사용자 그룹을 선택하십시오.",
"allowed_user_groups_status_unrestricted_description": "사용자 그룹 제한이 적용되지 않습니다. 모든 사용자가 이 클라이언트에 로그인할 수 있습니다.",
"unrestrict": "제한 해제",
"restrict": "제한하다",
"restrict": "제한",
"user_groups_restriction_updated_successfully": "사용자 그룹 제한이 성공적으로 업데이트되었습니다.",
"allowed_user_groups_updated_successfully": "허용된 사용자 그룹이 성공적으로 변경되었습니다",
"favicon": "파비콘",
@@ -356,8 +356,8 @@
"login_code_email_success": "로그인 코드가 사용자에게 전송되었습니다.",
"send_email": "이메일 전송",
"show_code": "코드 표시",
"callback_url_description": "고객이 제공 URL. 비워두면 자동으로 추가됩니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link> 지원됩니다.",
"logout_callback_url_description": "로그아웃을 위해 클라이언트 제공하는 URL(들). <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link> 지원됩니다.",
"callback_url_description": "클라이언트에서 제공 URL입니다. 비워두면 자동으로 추가됩니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link> 지원됩니다.",
"logout_callback_url_description": "클라이언트에서 제공된 로그아웃 URL입니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link> 지원됩니다.",
"api_key_expiration": "API 키 만료",
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "API 키가 만료되기 전에 사용자에게 이메일을 전송합니다.",
"authorize_device": "기기 승인",
@@ -480,11 +480,11 @@
"signup_token_user_groups_description": "이 토큰을 사용하여 가입하는 사용자에게 자동으로 이 그룹들을 할당합니다.",
"allowed_oidc_clients": "허용된 OIDC 클라이언트",
"allowed_oidc_clients_description": "이 사용자 그룹의 구성원이 로그인할 수 있는 OIDC 클라이언트를 선택하십시오.",
"unrestrict_oidc_client": "제한 해제 {clientName}",
"unrestrict_oidc_client": "{clientName} 제한 해제",
"confirm_unrestrict_oidc_client_description": "OIDC 클라이언트의 제한을 해제하시겠습니까? <b>{clientName}</b>? 이 작업은 해당 클라이언트의 모든 그룹 할당을 제거하며, 모든 사용자가 로그인할 수 있게 됩니다.",
"allowed_oidc_clients_updated_successfully": "허용된 OIDC 클라이언트 업데이트 성공",
"yes": "",
"no": "아니",
"yes": "",
"no": "아니",
"restricted": "제한됨",
"scim_provisioning": "SCIM 프로비저닝",
"scim_provisioning_description": "SCIM 프로비저닝을 통해 OIDC 클라이언트에서 사용자 및 그룹을 자동으로 프로비저닝 및 디프로비저닝할 수 있습니다. 자세한 내용은 <link href='https://pocket-id.org/docs/configuration/scim'>문서를</link> 참조하세요.",
@@ -504,7 +504,7 @@
"issuer_url": "발행자 URL",
"smtp_field_required_when_other_provided": "어떤 SMTP 설정이라도 제공될 때 필수",
"smtp_field_required_when_email_enabled": "이메일 알림이 활성화된 경우 필수",
"renew": "갱신하다",
"renew": "갱신",
"renew_api_key": "API 키 갱신",
"renew_api_key_description": "API 키를 갱신하면 새 키가 생성됩니다. 이 키를 사용하는 모든 통합 기능을 반드시 업데이트하십시오.",
"api_key_renewed": "API 키 갱신됨",

525
frontend/messages/no.json Normal file
View File

@@ -0,0 +1,525 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"my_account": "My Account",
"logout": "Logg ut",
"confirm": "Confirm",
"docs": "Docs",
"key": "Nøkkel",
"value": "Verdi",
"remove_custom_claim": "Remove custom claim",
"add_custom_claim": "Add custom claim",
"add_another": "Add another",
"select_a_date": "Velg dato",
"select_file": "Velg fil",
"profile_picture": "Profilbilde",
"profile_picture_is_managed_by_ldap_server": "Profilbildet administreres av LDAP serveren og kan ikke endres her.",
"click_profile_picture_to_upload_custom": "Klikk på profilbildet for å laste opp et bilde fra filene dine.",
"image_should_be_in_format": "Bildet kan være i PNG, JPEG eller WEBP format.",
"items_per_page": "Items per page",
"no_items_found": "No items found",
"select_items": "Select items...",
"search": "Søk...",
"expand_card": "Utvid kort",
"copied": "Kopiert",
"click_to_copy": "Klikk for å kopiere",
"something_went_wrong": "Noe gikk galt",
"go_back_to_home": "Go back to home",
"alternative_sign_in_methods": "Alternative innloggingingsmetoder",
"login_background": "Login background",
"logo": "Logo",
"login_code": "Innloggingskode",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Lag en innloggingskode som brukeren kan bruke for å logge inn uten en passnøkkel.",
"one_hour": "1 time",
"twelve_hours": "12 timer",
"one_day": "1 dag",
"one_week": "1 uke",
"one_month": "1 måned",
"expiration": "Expiration",
"generate_code": "Generer kode",
"name": "Navn",
"browser_unsupported": "Nettleser ikke støttet",
"this_browser_does_not_support_passkeys": "Denne nettleseren støtter ikke passnøkler. Vennligst bruk en annen metode for å logge inn.",
"an_unknown_error_occurred": "En ukjent feil oppstod",
"authentication_process_was_aborted": "Autentiseringsprosessen ble avbrutt",
"error_occurred_with_authenticator": "An error occurred with the authenticator",
"authenticator_does_not_support_discoverable_credentials": "The authenticator does not support discoverable credentials",
"authenticator_does_not_support_resident_keys": "The authenticator does not support resident keys",
"passkey_was_previously_registered": "Denne passnøkkelen er allerede registrert",
"authenticator_does_not_support_any_of_the_requested_algorithms": "The authenticator does not support any of the requested algorithms",
"webauthn_error_invalid_rp_id": "The configured relying party ID is invalid.",
"webauthn_error_invalid_domain": "Det konfigurerte domenet er ugyldig.",
"contact_administrator_to_fix": "Kontakt administratoren for å fikse feilen.",
"webauthn_operation_not_allowed_or_timed_out": "The operation was not allowed or timed out",
"webauthn_not_supported_by_browser": "Passkeys are not supported by this browser. Please use an alternative sign in method.",
"critical_error_occurred_contact_administrator": "A critical error occurred. Please contact your administrator.",
"sign_in_to": "Logg inn til {name}",
"client_not_found": "Fant ikke klient",
"client_wants_to_access_the_following_information": "<b>{client}</b> ønsker tilgang til følgende informasjon:",
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Do you want to sign in to <b>{client}</b> with your {appName} account?",
"email": "E-post",
"view_your_email_address": "Vis E-post adressen din",
"profile": "Profil",
"view_your_profile_information": "Vis brukerinformasjonen din",
"groups": "Grupper",
"view_the_groups_you_are_a_member_of": "Vis grupper du er medlem i",
"cancel": "Avbryt",
"sign_in": "Logg inn",
"try_again": "Prøv på nytt",
"client_logo": "Klient logo",
"sign_out": "Logg ut",
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Do you want to sign out of {appName} with the account <b>{username}</b>?",
"sign_in_to_appname": "Sign in to {appName}",
"please_try_to_sign_in_again": "Vennligst prøv å logge inn på nytt.",
"authenticate_with_passkey_to_access_account": "Authenticate yourself with your passkey to access your account.",
"authenticate": "Autentiser",
"please_try_again": "Vennligst prøv på nytt.",
"continue": "Fortsett",
"alternative_sign_in": "Alternativ innloggingsmetode",
"if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "Om du ikke har tilgang til passnøkkelen din, så kan du bruke en av følgende innloggingsmetoder.",
"use_your_passkey_instead": "Bruk passnøkkelen din i stedet for?",
"email_login": "E-post innlogging",
"enter_a_login_code_to_sign_in": "Enter a login code to sign in.",
"sign_in_with_login_code": "Sign in with login code",
"request_a_login_code_via_email": "Request a login code via email.",
"go_back": "Go back",
"an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system": "An email has been sent to the provided email, if it exists in the system.",
"enter_code": "Enter code",
"enter_your_email_address_to_receive_an_email_with_a_login_code": "Enter your email address to receive an email with a login code.",
"your_email": "Your email",
"submit": "Submit",
"enter_the_code_you_received_to_sign_in": "Enter the code you received to sign in.",
"code": "Code",
"invalid_redirect_url": "Invalid redirect URL",
"audit_log": "Audit Log",
"users": "Users",
"user_groups": "User Groups",
"oidc_clients": "OIDC Clients",
"api_keys": "API Keys",
"application_configuration": "Application Configuration",
"settings": "Settings",
"update_pocket_id": "Update Pocket ID",
"powered_by": "Powered by",
"see_your_recent_account_activities": "See your account activities within the configured retention period.",
"time": "Time",
"event": "Event",
"approximate_location": "Approximate Location",
"ip_address": "IP adresse",
"device": "Enhet",
"client": "Klient",
"unknown": "Ukjent",
"account_details_updated_successfully": "Brukerdetaljer oppdatert",
"profile_picture_updated_successfully": "Profilbildet er oppdatert. Det kan ta noen minutter før det vises overalt.",
"account_settings": "Kontoinnstillinger",
"passkey_missing": "Finner ingen passnøkkel",
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Please add a passkey to prevent losing access to your account.",
"single_passkey_configured": "Revoker API nøkkel",
"it_is_recommended_to_add_more_than_one_passkey": "Det er anbefalt å legge til mer enn én passnøkkel for å forhindre at du mister tilgang til kontoen din.",
"account_details": "Kontodetaljer",
"passkeys": "Passnøkler",
"manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Manage your passkeys that you can use to authenticate yourself.",
"add_passkey": "Legg til passnøkkel",
"create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Create a one-time login code to sign in from a different device without a passkey.",
"create": "Opprett",
"first_name": "Fornavn",
"last_name": "Etternavn",
"username": "Brukernavn",
"save": "Lagre",
"username_can_only_contain": "Username can only contain lowercase letters, numbers, underscores, dots, hyphens, and '@' symbols",
"username_must_start_with": "Username must start with an alphanumeric character",
"username_must_end_with": "Username must end with an alphanumeric character",
"sign_in_using_the_following_code_the_code_will_expire_in_minutes": "Sign in using the following code. The code will expire in 15 minutes.",
"or_visit": "or visit",
"added_on": "Lagt til på",
"rename": "Endre navn",
"delete": "Slett",
"are_you_sure_you_want_to_delete_this_passkey": "Er du sikker på at du vil slette denne passnøkkelen?",
"passkey_deleted_successfully": "Passnøkkelen er slettet",
"delete_passkey_name": "Slett {passkeyName}",
"passkey_name_updated_successfully": "Kallenavnet til passnøkkelen er oppdatert",
"name_passkey": "Navngi passnøkkel",
"name_your_passkey_to_easily_identify_it_later": "Gi et navn til passnøkkelen så den blir lettere å identifisere senere.",
"create_api_key": "Opprett en API nøkkel",
"add_a_new_api_key_for_programmatic_access": "Add a new API key for programmatic access to the <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
"add_api_key": "Legg til API nøkkel",
"manage_api_keys": "Administrer API nøkler",
"api_key_created": "API Key Created",
"for_security_reasons_this_key_will_only_be_shown_once": "For security reasons, this key will only be shown once. Please store it securely.",
"description": "Beskrivelse",
"api_key": "API nøkkel",
"close": "Lukk",
"name_to_identify_this_api_key": "Name to identify this API key.",
"expires_at": "Expires At",
"when_this_api_key_will_expire": "When this API key will expire.",
"optional_description_to_help_identify_this_keys_purpose": "Optional description to help identify this key's purpose.",
"expiration_date_must_be_in_the_future": "Expiration date must be in the future",
"revoke_api_key": "Revoker API nøkkel",
"never": "Never",
"revoke": "Revoke",
"api_key_revoked_successfully": "API key revoked successfully",
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Are you sure you want to revoke the API key \"{apiKeyName}\"? This will break any integrations using this key.",
"last_used": "Last Used",
"actions": "Actions",
"images_updated_successfully": "Images updated successfully. It may take a few minutes to update.",
"general": "General",
"configure_smtp_to_send_emails": "Enable email notifications to alert users when a login is detected from a new device or location.",
"ldap": "LDAP",
"configure_ldap_settings_to_sync_users_and_groups_from_an_ldap_server": "Configure LDAP settings to sync users and groups from an LDAP server.",
"images": "Images",
"update": "Update",
"email_configuration_updated_successfully": "Email configuration updated successfully",
"save_changes_question": "Save changes?",
"you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "You have to save the changes before sending a test email. Do you want to save now?",
"save_and_send": "Save and send",
"test_email_sent_successfully": "Test email sent successfully to your email address.",
"failed_to_send_test_email": "Failed to send test email. Check the server logs for more information.",
"smtp_configuration": "SMTP Configuration",
"smtp_host": "SMTP Host",
"smtp_port": "SMTP Port",
"smtp_user": "SMTP User",
"smtp_password": "SMTP Password",
"smtp_from": "SMTP From",
"smtp_tls_option": "SMTP TLS Option",
"email_tls_option": "Email TLS Option",
"skip_certificate_verification": "Skip Certificate Verification",
"this_can_be_useful_for_selfsigned_certificates": "This can be useful for self-signed certificates.",
"enabled_emails": "Enabled Emails",
"email_login_notification": "Email Login Notification",
"send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Send an email to the user when they log in from a new device.",
"emai_login_code_requested_by_user": "Email Login Code Requested by User",
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Allows users to bypass passkeys by requesting a login code sent to their email. This significantly reduces security as anyone with access to the user's email can gain entry.",
"email_login_code_from_admin": "Email Login Code from Admin",
"allows_an_admin_to_send_a_login_code_to_the_user": "Allows an admin to send a login code to the user via email.",
"send_test_email": "Send test E-post",
"application_configuration_updated_successfully": "Application configuration updated successfully",
"application_name": "Applikasjonsnavn",
"session_duration": "Varighet på sesjon",
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Varighet på sesjon i minutter før brukeren må logge inn på nytt.",
"enable_self_account_editing": "Enable Self-Account Editing",
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Whether the users should be able to edit their own account details.",
"ldap_configuration_updated_successfully": "LDAP konfigurasjon oppdatert",
"ldap_disabled_successfully": "LDAP er slått av",
"ldap_sync_finished": "LDAP synkronisert",
"client_configuration": "Klient konfigurasjon",
"ldap_url": "LDAP URL",
"ldap_bind_dn": "LDAP Bind DN",
"ldap_bind_password": "LDAP Bind Password",
"ldap_base_dn": "LDAP Base DN",
"user_search_filter": "User Search Filter",
"the_search_filter_to_use_to_search_or_sync_users": "The Search filter to use to search/sync users.",
"groups_search_filter": "Groups Search Filter",
"the_search_filter_to_use_to_search_or_sync_groups": "The Search filter to use to search/sync groups.",
"attribute_mapping": "Attribute Mapping",
"user_unique_identifier_attribute": "User Unique Identifier Attribute",
"the_value_of_this_attribute_should_never_change": "The value of this attribute should never change.",
"username_attribute": "Username Attribute",
"user_mail_attribute": "User Mail Attribute",
"user_first_name_attribute": "User First Name Attribute",
"user_last_name_attribute": "User Last Name Attribute",
"user_profile_picture_attribute": "User Profile Picture Attribute",
"the_value_of_this_attribute_can_either_be_a_url_binary_or_base64_encoded_image": "The value of this attribute can either be a URL, a binary or a base64 encoded image.",
"group_members_attribute": "Group Members Attribute",
"the_attribute_to_use_for_querying_members_of_a_group": "The attribute to use for querying members of a group.",
"group_unique_identifier_attribute": "Group Unique Identifier Attribute",
"group_rdn_attribute": "Group RDN Attribute (in DN)",
"admin_group_name": "Admin Group Name",
"members_of_this_group_will_have_admin_privileges_in_pocketid": "Members of this group will have Admin Privileges in Pocket ID.",
"disable": "Slå av",
"sync_now": "Synkroniser nå",
"enable": "Slå på",
"user_created_successfully": "Bruker er opprettet",
"create_user": "Opprett bruker",
"add_a_new_user_to_appname": "Legg til bruker i {appName}",
"add_user": "Legg til bruker",
"manage_users": "Administrer brukere",
"admin_privileges": "Admin Privileges",
"admins_have_full_access_to_the_admin_panel": "Administratorene har full tilgang til administratorpanelet.",
"delete_firstname_lastname": "Slett {firstName} {lastName}",
"are_you_sure_you_want_to_delete_this_user": "Er du sikker på at du vil slette denne brukeren?",
"user_deleted_successfully": "Bruker slettet",
"role": "Rolle",
"source": "Source",
"admin": "Admin",
"user": "User",
"local": "Local",
"toggle_menu": "Toggle menu",
"edit": "Edit",
"user_groups_updated_successfully": "User groups updated successfully",
"user_updated_successfully": "User updated successfully",
"custom_claims_updated_successfully": "Custom claims updated successfully",
"back": "Back",
"user_details_firstname_lastname": "User Details {firstName} {lastName}",
"manage_which_groups_this_user_belongs_to": "Manage which groups this user belongs to.",
"custom_claims": "Custom Claims",
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested.",
"user_group_created_successfully": "User group created successfully",
"create_user_group": "Create User Group",
"create_a_new_group_that_can_be_assigned_to_users": "Create a new group that can be assigned to users.",
"add_group": "Add Group",
"manage_user_groups": "Manage User Groups",
"friendly_name": "Friendly Name",
"name_that_will_be_displayed_in_the_ui": "Name that will be displayed in the UI",
"name_that_will_be_in_the_groups_claim": "Name that will be in the \"groups\" claim",
"delete_name": "Slett {name}",
"are_you_sure_you_want_to_delete_this_user_group": "Er du sikker på at du vil slette denne brukergruppen?",
"user_group_deleted_successfully": "User group deleted successfully",
"user_count": "Antall brukere",
"user_group_updated_successfully": "User group updated successfully",
"users_updated_successfully": "Brukere er oppdatert",
"user_group_details_name": "User Group Details {name}",
"assign_users_to_this_group": "Legg brukerne til i denne gruppen.",
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user_prioritized": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested. Custom claims defined on the user will be prioritized if there are conflicts.",
"oidc_client_created_successfully": "OIDC klient er opprettet",
"create_oidc_client": "Opprett OIDC klient",
"add_a_new_oidc_client_to_appname": "Add a new OIDC client to {appName}.",
"add_oidc_client": "Add OIDC Client",
"manage_oidc_clients": "Manage OIDC Clients",
"one_time_link": "Engangslenke",
"use_this_link_to_sign_in_once": "Use this link to sign in once. This is needed for users who haven't added a passkey yet or have lost it.",
"add": "Legg til",
"callback_urls": "Callback URLs",
"logout_callback_urls": "Logout Callback URLs",
"public_client": "Public Client",
"public_clients_description": "Public clients do not have a client secret. They are designed for mobile, web, and native applications where secrets cannot be securely stored.",
"pkce": "PKCE",
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange is a security feature to prevent CSRF and authorization code interception attacks.",
"requires_reauthentication": "Requires Re-Authentication",
"requires_users_to_authenticate_again_on_each_authorization": "Requires users to authenticate again on each authorization, even if already signed in",
"name_logo": "{name} logo",
"change_logo": "Bytt logo",
"upload_logo": "Last opp logo",
"remove_logo": "Fjern logo",
"are_you_sure_you_want_to_delete_this_oidc_client": "Are you sure you want to delete this OIDC client?",
"oidc_client_deleted_successfully": "OIDC client deleted successfully",
"authorization_url": "Authorization URL",
"oidc_discovery_url": "OIDC Discovery URL",
"token_url": "Token URL",
"userinfo_url": "Userinfo URL",
"logout_url": "Logout URL",
"certificate_url": "Certificate URL",
"enabled": "Aktivert",
"disabled": "Deaktivert",
"oidc_client_updated_successfully": "OIDC client updated successfully",
"create_new_client_secret": "Create new client secret",
"are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.",
"generate": "Generer",
"new_client_secret_created_successfully": "New client secret created successfully",
"oidc_client_name": "OIDC klient {name}",
"client_id": "Client ID",
"client_secret": "Client secret",
"show_more_details": "Vis mer",
"allowed_user_groups": "Tillatte brukergrupper",
"allowed_user_groups_description": "Velg brukergruppene som skal kunne logge inn med denne klienten.",
"allowed_user_groups_status_unrestricted_description": "No user group restrictions are applied. Any user can sign in to this client.",
"unrestrict": "Unrestrict",
"restrict": "Restrict",
"user_groups_restriction_updated_successfully": "User groups restriction updated successfully",
"allowed_user_groups_updated_successfully": "Allowed user groups updated successfully",
"favicon": "Favicon",
"light_mode_logo": "Light Mode Logo",
"dark_mode_logo": "Dark Mode Logo",
"email_logo": "Email Logo",
"background_image": "Background Image",
"language": "Language",
"reset_profile_picture_question": "Reset profile picture?",
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "This will remove the uploaded image and reset the profile picture to default. Do you want to continue?",
"reset": "Reset",
"reset_to_default": "Reset to default",
"profile_picture_has_been_reset": "Profile picture has been reset. It may take a few minutes to update.",
"select_the_language_you_want_to_use": "Select the language you want to use. Please note that some text may be automatically translated and could be inaccurate.",
"contribute_to_translation": "If you find an issue you're welcome to contribute to the translation on <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
"personal": "Personal",
"global": "Global",
"all_users": "All Users",
"all_events": "All Events",
"all_clients": "All Clients",
"all_locations": "All Locations",
"global_audit_log": "Global Audit Log",
"see_all_recent_account_activities": "View the account activities of all users during the set retention period.",
"token_sign_in": "Token Sign In",
"client_authorization": "Client Authorization",
"new_client_authorization": "New Client Authorization",
"device_code_authorization": "Device Code Authorization",
"new_device_code_authorization": "New Device Code Authorization",
"passkey_added": "Passnøkkel lagt til",
"passkey_removed": "Passnøkkel fjernet",
"disable_animations": "Deaktiver animasjoner",
"turn_off_ui_animations": "Slå av animasjoner i brukergrensesnittet.",
"user_disabled": "Konto deaktivert",
"disabled_users_cannot_log_in_or_use_services": "Deaktiverte brukere kan ikke logge inn eller bruke tjenester.",
"user_disabled_successfully": "Bruker har blitt deaktivert.",
"user_enabled_successfully": "Bruker har blitt aktivert.",
"status": "Status",
"disable_firstname_lastname": "Deaktiver {firstName} {lastName}",
"are_you_sure_you_want_to_disable_this_user": "Are you sure you want to disable this user? They will not be able to log in or access any services.",
"ldap_soft_delete_users": "Keep disabled users from LDAP.",
"ldap_soft_delete_users_description": "When enabled, users removed from LDAP will be disabled rather than deleted from the system.",
"login_code_email_success": "The login code has been sent to the user.",
"send_email": "Send E-post",
"show_code": "Vis kode",
"callback_url_description": "URL(s) provided by your client. Will be automatically added if left blank. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
"logout_callback_url_description": "URL(s) provided by your client for logout. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
"api_key_expiration": "API Key Expiration",
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Send an email to the user when their API key is about to expire.",
"authorize_device": "Authorize Device",
"the_device_has_been_authorized": "The device has been authorized.",
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
"authorize": "Authorize",
"federated_client_credentials": "Federated Client Credentials",
"federated_client_credentials_description": "Using federated client credentials, you can authenticate OIDC clients using JWT tokens issued by third-party authorities.",
"add_federated_client_credential": "Add Federated Client Credential",
"add_another_federated_client_credential": "Add another federated client credential",
"oidc_allowed_group_count": "Allowed Group Count",
"unrestricted": "Unrestricted",
"show_advanced_options": "Show Advanced Options",
"hide_advanced_options": "Hide Advanced Options",
"oidc_data_preview": "OIDC Data Preview",
"preview_the_oidc_data_that_would_be_sent_for_different_users": "Preview the OIDC data that would be sent for different users",
"id_token": "ID Token",
"access_token": "Access Token",
"userinfo": "Brukerinformasjon",
"id_token_payload": "ID Token Payload",
"access_token_payload": "Access Token Payload",
"userinfo_endpoint_response": "Userinfo Endpoint Response",
"copy": "Copy",
"no_preview_data_available": "No preview data available",
"copy_all": "Copy All",
"preview": "Preview",
"preview_for_user": "Preview for {name}",
"preview_the_oidc_data_that_would_be_sent_for_this_user": "Preview the OIDC data that would be sent for this user",
"show": "Show",
"select_an_option": "Select an option",
"select_user": "Select User",
"error": "Error",
"select_an_accent_color_to_customize_the_appearance_of_pocket_id": "Select an accent color to customize the appearance of Pocket ID.",
"accent_color": "Accent Color",
"custom_accent_color": "Custom Accent Color",
"custom_accent_color_description": "Enter a custom color using valid CSS color formats (e.g., hex, rgb, hsl).",
"color_value": "Color Value",
"apply": "Apply",
"signup_token": "Signup Token",
"create_a_signup_token_to_allow_new_user_registration": "Create a signup token to allow new user registration.",
"usage_limit": "Bruksgrense",
"number_of_times_token_can_be_used": "Number of times the signup token can be used.",
"expires": "Expires",
"signup": "Registrer",
"user_creation": "User Creation",
"configure_user_creation": "Manage user creation settings, including signup methods and default permissions for new users.",
"user_creation_groups_description": "Assign these groups automatically to new users upon signup.",
"user_creation_claims_description": "Assign these custom claims automatically to new users upon signup.",
"user_creation_updated_successfully": "User creation settings updated successfully.",
"signup_disabled_description": "User signups are completely disabled. Only administrators can create new user accounts.",
"signup_requires_valid_token": "A valid signup token is required to create an account",
"validating_signup_token": "Validating signup token",
"go_to_login": "Gå til innlogging",
"signup_to_appname": "Registrer for {appName}",
"create_your_account_to_get_started": "Opprett kontoen din for å komme i gang.",
"initial_account_creation_description": "Please create your account to get started. You will be able to set up a passkey later.",
"setup_your_passkey": "Opprett din passnøkkel",
"create_a_passkey_to_securely_access_your_account": "Create a passkey to securely access your account. This will be your primary way to sign in.",
"skip_for_now": "Hopp over for denne gang",
"account_created": "Konto opprettet",
"enable_user_signups": "Enable User Signups",
"enable_user_signups_description": "Decide how users can sign up for new accounts in Pocket ID.",
"user_signups_are_disabled": "User signups are currently disabled",
"create_signup_token": "Create Signup Token",
"view_active_signup_tokens": "View Active Signup Tokens",
"manage_signup_tokens": "Manage Signup Tokens",
"view_and_manage_active_signup_tokens": "View and manage active signup tokens.",
"signup_token_deleted_successfully": "Signup token deleted successfully.",
"expired": "Expired",
"used_up": "Used Up",
"active": "Active",
"usage": "Usage",
"created": "Created",
"token": "Token",
"loading": "Loading",
"delete_signup_token": "Delete Signup Token",
"are_you_sure_you_want_to_delete_this_signup_token": "Are you sure you want to delete this signup token? This action cannot be undone.",
"signup_with_token": "Signup with token",
"signup_with_token_description": "Users can only sign up using a valid signup token created by an administrator.",
"signup_open": "Open Signup",
"signup_open_description": "Anyone can create a new account without restrictions.",
"of": "of",
"skip_passkey_setup": "Skip Passkey Setup",
"skip_passkey_setup_description": "It's highly recommended to set up a passkey because without one, you will be locked out of your account as soon as the session expires.",
"my_apps": "My Apps",
"no_apps_available": "No apps available",
"contact_your_administrator_for_app_access": "Contact your administrator to get access to applications.",
"launch": "Launch",
"client_launch_url": "Client Launch URL",
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
"revoke_access": "Revoke Access",
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
"last_signed_in_ago": "Last signed in {time} ago",
"invalid_client_id": "Client ID can only contain letters, numbers, underscores, and hyphens",
"custom_client_id_description": "Set a custom client ID if this is required by your application. Otherwise, leave it blank to generate a random one.",
"generated": "Generated",
"administration": "Administration",
"group_rdn_attribute_description": "The attribute used in the groups distinguished name (DN).",
"display_name_attribute": "Display Name Attribute",
"display_name": "Display Name",
"configure_application_images": "Configure Application Images",
"ui_config_disabled_info_title": "UI Configuration Disabled",
"ui_config_disabled_info_description": "The UI configuration is disabled because the application configuration settings are managed through environment variables. Some settings may not be editable.",
"logo_from_url_description": "Paste a direct image URL (svg, png, webp). Find icons at <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> or <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
"invalid_url": "Invalid URL",
"require_user_email": "Require Email Address",
"require_user_email_description": "Requires users to have an email address. If disabled, the users without an email address won't be able to use features that require an email address.",
"view": "View",
"toggle_columns": "Toggle columns",
"locale": "Locale",
"ldap_id": "LDAP ID",
"reauthentication": "Re-authentication",
"clear_filters": "Clear Filters",
"default_profile_picture": "Default Profile Picture",
"light": "Light",
"dark": "Dark",
"system": "System",
"signup_token_user_groups_description": "Automatically assign these groups to users who sign up using this token.",
"allowed_oidc_clients": "Allowed OIDC Clients",
"allowed_oidc_clients_description": "Select the OIDC clients that members of this user group are allowed to sign in to.",
"unrestrict_oidc_client": "Unrestrict {clientName}",
"confirm_unrestrict_oidc_client_description": "Are you sure you want to unrestrict the OIDC client <b>{clientName}</b>? This will remove all group assignments for this client and any user will be able to sign in.",
"allowed_oidc_clients_updated_successfully": "Allowed OIDC clients updated successfully",
"yes": "Yes",
"no": "No",
"restricted": "Restricted",
"scim_provisioning": "SCIM Provisioning",
"scim_provisioning_description": "SCIM provisioning allows you to automatically provision and deprovision users and groups from your OIDC client. Learn more in the <link href='https://pocket-id.org/docs/configuration/scim'>docs</link>.",
"scim_endpoint": "SCIM Endpoint",
"scim_token": "SCIM Token",
"last_successful_sync_at": "Last successful sync: {time}",
"scim_configuration_updated_successfully": "SCIM configuration updated successfully.",
"scim_enabled_successfully": "SCIM enabled successfully.",
"scim_disabled_successfully": "SCIM disabled successfully.",
"disable_scim_provisioning": "Disable SCIM Provisioning",
"disable_scim_provisioning_confirm_description": "Are you sure you want to disable SCIM provisioning for <b>{clientName}</b>? This will stop all automatic user and group provisioning and deprovisioning.",
"scim_sync_failed": "SCIM sync failed. Check the server logs for more information.",
"scim_sync_successful": "The SCIM sync has been completed successfully.",
"save_and_sync": "Save and Sync",
"scim_save_changes_description": "You have to save the changes before starting a SCIM sync. Do you want to save now?",
"scopes": "Scopes",
"issuer_url": "Issuer URL",
"smtp_field_required_when_other_provided": "Required when any SMTP setting is provided",
"smtp_field_required_when_email_enabled": "Required when email notifications are enabled",
"renew": "Renew",
"renew_api_key": "Renew API Key",
"renew_api_key_description": "Renewing the API key will generate a new key. Make sure to update any integrations using this key.",
"api_key_renewed": "API key renewed",
"app_config_home_page": "Home Page",
"app_config_home_page_description": "The page users are redirected to after signing in.",
"email_verification_warning": "Verify your email address",
"email_verification_warning_description": "Your email address is not verified yet. Please verify it as soon as possible.",
"email_verification": "Email Verification",
"email_verification_description": "Send a verification email to users when they sign up or change their email address.",
"email_verification_success_title": "Email Verified Successfully",
"email_verification_success_description": "Your email address has been verified successfully.",
"email_verification_error_title": "Email Verification Failed",
"mark_as_unverified": "Mark as unverified",
"mark_as_verified": "Mark as verified",
"email_verification_sent": "Verification email sent successfully.",
"emails_verified_by_default": "Emails verified by default",
"emails_verified_by_default_description": "When enabled, users' email addresses will be marked as verified by default upon signup or when their email address is changed."
}

View File

@@ -28,7 +28,7 @@
"login_background": "Фон страницы входа",
"logo": "Логотип",
"login_code": "Код входа",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Создайте код входа, с которым пользователь сможет войти без пасскея один раз.",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Создайте код входа, с которым пользователь сможет войти без ключа доступа один раз.",
"one_hour": "1 час",
"twelve_hours": "12 часов",
"one_day": "1 день",
@@ -38,19 +38,19 @@
"generate_code": "Сгенерировать код",
"name": "Имя",
"browser_unsupported": "Браузер не поддерживается",
"this_browser_does_not_support_passkeys": "Этот браузер не поддерживает пасскеи. Пожалуйста, воспользуйтесь альтернативным способом входа.",
"this_browser_does_not_support_passkeys": "Этот браузер не поддерживает ключи доступа. Пожалуйста, воспользуйтесь альтернативным способом входа.",
"an_unknown_error_occurred": "Произошла неизвестная ошибка",
"authentication_process_was_aborted": "Процесс аутентификации был прерван",
"error_occurred_with_authenticator": "Произошла ошибка аутентификатора",
"authenticator_does_not_support_discoverable_credentials": "Аутентификатор не поддерживает обнаруживаемые учетные данные",
"authenticator_does_not_support_resident_keys": "Аутентификатор не поддерживает резидентные ключи",
"passkey_was_previously_registered": "Этот пасскей был ранее зарегистрирован",
"passkey_was_previously_registered": "Этот ключ доступа был ранее зарегистрирован",
"authenticator_does_not_support_any_of_the_requested_algorithms": "Аутентификатор не поддерживает ни один из запрошенных алгоритмов",
"webauthn_error_invalid_rp_id": "Идентификатор настроенной полагающейся стороны неверный.",
"webauthn_error_invalid_domain": "Настроенный домен не работает.",
"webauthn_error_invalid_rp_id": "Настроенный идентификатор доверяющей стороны является недопустимым.",
"webauthn_error_invalid_domain": "Настроенный домен является недопустимым.",
"contact_administrator_to_fix": "Обратись к своему администратору, чтобы решить эту проблему.",
"webauthn_operation_not_allowed_or_timed_out": "Операция не разрешена или истекло время ожидания",
"webauthn_not_supported_by_browser": "Этот браузер не поддерживает пароли. Попробуй войти другим способом.",
"webauthn_not_supported_by_browser": "Этот браузер не поддерживает ключи доступа. Попробуйте войти другим способом.",
"critical_error_occurred_contact_administrator": "Произошла критическая ошибка. Обратитесь к администратору.",
"sign_in_to": "Войти в {name}",
"client_not_found": "Клиент не найден",
@@ -70,13 +70,13 @@
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Вы хотите выйти из {appName} с учетной записью <b>{username}</b>?",
"sign_in_to_appname": "Войти в {appName}",
"please_try_to_sign_in_again": "Пожалуйста, попробуйте войти снова.",
"authenticate_with_passkey_to_access_account": "Авторизуйтесь с использованием пасскея для доступа к вашей учетной записи.",
"authenticate_with_passkey_to_access_account": "Авторизуйтесь с помощью ключа доступа для входа в свою учетную запись.",
"authenticate": "Авторизоваться",
"please_try_again": "Пожалуйста, повторите попытку.",
"continue": "Продолжить",
"alternative_sign_in": "Альтернативный вход",
"if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "Если у вас нет доступа к вашему пасскею, вы можете войти одним из следующих способов.",
"use_your_passkey_instead": "Воспользоваться пасскеем вместо этого?",
"if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "Если вы не можете использовать свой ключ доступа, вы можете войти одним из следующих способов.",
"use_your_passkey_instead": "Использовать вместо этого ключ доступа?",
"email_login": "Вход через электронную почту",
"enter_a_login_code_to_sign_in": "Введите код входа, чтобы войти.",
"sign_in_with_login_code": "Войти с помощью кода входа",
@@ -99,7 +99,7 @@
"settings": "Настройки",
"update_pocket_id": "Обновите Pocket ID",
"powered_by": "Работает на",
"see_your_recent_account_activities": "Проверь, что происходит с твоей учетной записью в течение того времени, которое ты установил.",
"see_your_recent_account_activities": "Смотрите действия вашей учетной записи в установленный период хранения.",
"time": "Время",
"event": "Событие",
"approximate_location": "Примерное местоположение",
@@ -110,15 +110,15 @@
"account_details_updated_successfully": "Данные учетной записи успешно обновлены",
"profile_picture_updated_successfully": "Изображение профиля успешно обновлено. Обновление может занять несколько минут.",
"account_settings": "Настройки учетной записи",
"passkey_missing": "Пасскей отсутствует",
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Пожалуйста, добавьте пасскей, чтобы избежать утери доступа к вашей учетной записи.",
"single_passkey_configured": "Настроен один пасскей",
"it_is_recommended_to_add_more_than_one_passkey": "Рекомендуется добавить более одного пасскея во избежание потери доступа к вашей учетной записи.",
"passkey_missing": "Ключ доступа отсутствует",
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Пожалуйста, добавьте ключ доступа, чтобы не потерять доступ к своей учетной записи.",
"single_passkey_configured": "Настроен только один ключ доступа",
"it_is_recommended_to_add_more_than_one_passkey": "Рекомендуется добавить более одного ключа доступа, чтобы не потерять доступ к вашей учетной записи.",
"account_details": "Детали учетной записи",
"passkeys": "Пасскеи",
"manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Управляйте пасскеями, которые вы можете использовать для аутентификации себя.",
"add_passkey": "Добавить пасскей",
"create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Создайте одноразовый код входа, чтобы войти с другого устройства без пасскея.",
"passkeys": "Ключи доступа",
"manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Управляйте своими ключами доступа, которые вы можете использовать для аутентификации.",
"add_passkey": "Добавить ключ доступа",
"create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Создайте одноразовый код входа, чтобы войти с другого устройства без ключа доступа.",
"create": "Создать",
"first_name": "Имя",
"last_name": "Фамилия",
@@ -132,12 +132,12 @@
"added_on": "Добавлен",
"rename": "Переименовать",
"delete": "Удалить",
"are_you_sure_you_want_to_delete_this_passkey": "Вы уверены, что хотите удалить этот пасскей?",
"passkey_deleted_successfully": "Пасскей успешно удален",
"are_you_sure_you_want_to_delete_this_passkey": "Вы уверены, что хотите удалить этот ключ доступа?",
"passkey_deleted_successfully": "Ключ доступа успешно удален",
"delete_passkey_name": "Удалить {passkeyName}",
"passkey_name_updated_successfully": "Имя пасскея успешно обновлено",
"name_passkey": "Имя пасскея",
"name_your_passkey_to_easily_identify_it_later": "Назовите ваш пасскей, чтобы легко идентифицировать его позже.",
"passkey_name_updated_successfully": "Имя ключа доступа успешно обновлено",
"name_passkey": "Имя ключа доступа",
"name_your_passkey_to_easily_identify_it_later": "Назовите ваш ключ доступа, чтобы легко идентифицировать его позже.",
"create_api_key": "Создать ключ API",
"add_a_new_api_key_for_programmatic_access": "Добавить новый ключ API для программного доступа к <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
"add_api_key": "Добавить ключ API",
@@ -186,7 +186,7 @@
"email_login_notification": "Уведомление о логине по электронной почте",
"send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Отправлять пользователю письмо при входе с нового устройства.",
"emai_login_code_requested_by_user": "Код входа по электронной почте, запрошенный пользователем",
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Позволяет пользователям обходить вход через пасскей, запросив код входа, отправляемый на их электронную почту. Это значительно снижает безопасность так как любой человек, имеющий доступ к электронной почте пользователя, может получить доступ.",
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Позволяет пользователям обойти ключи доступа, запросив код входа, отправляемый на их электронную почту. Это значительно снижает безопасность так как любой человек, имеющий доступ к электронной почте пользователя, сможет получить доступ.",
"email_login_code_from_admin": "Код входа по электронной почте от администратора",
"allows_an_admin_to_send_a_login_code_to_the_user": "Позволяет администратору отправлять код входа пользователю по электронной почте.",
"send_test_email": "Отправить тестовое письмо",
@@ -274,7 +274,7 @@
"add_oidc_client": "Добавить OIDC клиент",
"manage_oidc_clients": "Управление OIDC клиентами",
"one_time_link": "Одноразовая ссылка",
"use_this_link_to_sign_in_once": "Используйте эту ссылку, чтобы войти единожды. Это необходимо для пользователей, которые ещё не добавили пасскей или потеряли его.",
"use_this_link_to_sign_in_once": "Используйте эту ссылку, чтобы войти один раз. Это необходимо для пользователей, которые ещё не добавили ключ доступа или потеряли его.",
"add": "Добавить",
"callback_urls": "URL-адреса обратного вызова",
"logout_callback_urls": "URL-адреса обратного вызова при выходе",
@@ -308,16 +308,16 @@
"client_secret": "Секрет клиента",
"show_more_details": "Показать больше деталей",
"allowed_user_groups": "Разрешенные группы пользователей",
"allowed_user_groups_description": "Выбери группы пользователей, члены которых могут входить в этот клиент.",
"allowed_user_groups_description": "Выберите группы пользователей, члены которых могут входить в этот клиент.",
"allowed_user_groups_status_unrestricted_description": "Никаких ограничений по группам пользователей нет. Любой может зайти в этот клиент.",
"unrestrict": "Без ограничений",
"unrestrict": "Снять ограничения",
"restrict": "Ограничить",
"user_groups_restriction_updated_successfully": "Ограничение групп пользователей обновлено успешно",
"user_groups_restriction_updated_successfully": "Ограничение группами пользователей обновлено успешно",
"allowed_user_groups_updated_successfully": "Разрешенные группы пользователей успешно обновлены",
"favicon": "Значок",
"light_mode_logo": "Логотип светлого режима",
"dark_mode_logo": "Логотип темного режима",
"email_logo": "Логотип электронной почты",
"email_logo": "Логотип E-Mail",
"background_image": "Фоновое изображение",
"language": "Язык",
"reset_profile_picture_question": "Сбросить изображение профиля?",
@@ -334,14 +334,14 @@
"all_clients": "Все клиенты",
"all_locations": "Все местоположения",
"global_audit_log": "Глобальный журнал аудита",
"see_all_recent_account_activities": "Просмотри, что делали все пользователи на аккаунтах за период, который ты выбрал.",
"see_all_recent_account_activities": "Просмотр активности всех пользователей в установленный период хранения.",
"token_sign_in": "Вход с помощью токена",
"client_authorization": "Авторизация клиента",
"new_client_authorization": "Авторизация нового клиента",
"device_code_authorization": "Авторизация через код устройства",
"new_device_code_authorization": "Новая авторизация через код устройства",
"passkey_added": "Пасскей добавлен",
"passkey_removed": "Пасскей удален",
"passkey_added": "Добавлен ключ доступа",
"passkey_removed": "Удален ключ доступа",
"disable_animations": "Отключить анимации",
"turn_off_ui_animations": "Отключить все анимации в интерфейсе.",
"user_disabled": "Учетная запись отключена",
@@ -356,8 +356,8 @@
"login_code_email_success": "Код входа был отправлен пользователю.",
"send_email": "Отправить письмо",
"show_code": "Показать код",
"callback_url_description": "URL-адреса, которые дал твой клиент. Если поле оставить пустым, они добавятся автоматически. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>подстановочные знаки</link>.",
"logout_callback_url_description": "URL-адреса, которые твой клиент дает для выхода из системы. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>подстановочные знаки</link>.",
"callback_url_description": "URL-адрес(а), предоставленный вашим клиентом. Будет добавлен автоматически, если оставить поле пустым. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>шаблоны</link>.",
"logout_callback_url_description": "URL-адрес(а) для выхода из системы, указанный(-е) в вашем клиенте. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>шаблоны</link>.",
"api_key_expiration": "Истечение срока действия ключа API",
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Отправлять пользователю письмо, когда срок действия его ключа API истекает.",
"authorize_device": "Авторизовать устройство",
@@ -413,9 +413,9 @@
"go_to_login": "Перейти ко входу",
"signup_to_appname": "Зарегистрироваться в {appName}",
"create_your_account_to_get_started": "Создайте свою учетную запись, чтобы начать.",
"initial_account_creation_description": "Пожалуйста, создайте свою учетную запись, чтобы начать. Вы сможете настроить пасскей позже.",
"setup_your_passkey": "Настройте ваш пасскей",
"create_a_passkey_to_securely_access_your_account": "Создайте пасскей для безопасного доступа к учетной записи. Это будет ваш основной способ входа.",
"initial_account_creation_description": "Пожалуйста, создайте свою учетную запись, чтобы начать. Вы сможете настроить ключ доступа позже.",
"setup_your_passkey": "Настройте ваш ключ доступа",
"create_a_passkey_to_securely_access_your_account": "Создайте ключ доступа для безопасного доступа к учетной записи. Это будет ваш основной способ входа.",
"skip_for_now": "Пока пропустить",
"account_created": "Учетная запись создана",
"enable_user_signups": "Включить регистрацию пользователей",
@@ -440,8 +440,8 @@
"signup_open": "Открытая регистрация",
"signup_open_description": "Любой может создать новую учетную запись без ограничений.",
"of": "из",
"skip_passkey_setup": "Пропустить настройку пасскея",
"skip_passkey_setup_description": "Настоятельно рекомендуется настроить пасскей, так как без него вы более не сможете войти в учетную запись после истечения сессии.",
"skip_passkey_setup": "Пропустить настройку ключа доступа",
"skip_passkey_setup_description": "Настоятельно рекомендуется настроить ключ доступа, так как без него вы не сможете войти в свою учетную запись по истечении сессии.",
"my_apps": "Мои приложения",
"no_apps_available": "Нет доступных приложений",
"contact_your_administrator_for_app_access": "Свяжись с администратором, чтобы получить доступ к приложениям.",
@@ -477,49 +477,49 @@
"light": "Светлая",
"dark": "Темная",
"system": "Системная",
"signup_token_user_groups_description": "Автоматически добавляй эти группы к пользователям, которые регистрируются с помощью этого токена.",
"signup_token_user_groups_description": "Автоматически добавляйте эти группы к пользователям, которые регистрируются с помощью этого токена.",
"allowed_oidc_clients": "Разрешенные клиенты OIDC",
"allowed_oidc_clients_description": "Выбери клиентов OIDC, к которым могут подключаться участники этой группы пользователей.",
"allowed_oidc_clients_description": "Выберите клиенты OIDC, в которые участникам этой группы пользователей разрешено входить.",
"unrestrict_oidc_client": "Снять ограничения с {clientName}",
"confirm_unrestrict_oidc_client_description": "Ты уверен, что хочешь снять ограничения с клиента OIDC <b>{clientName}</b>? Это удалит все групповые назначения для этого клиента, и любой пользователь сможет войти в систему.",
"allowed_oidc_clients_updated_successfully": "Разрешенные клиенты OIDC обновились без проблем",
"confirm_unrestrict_oidc_client_description": "Ты уверен, что хочешь снять ограничения с клиента OIDC <b>{clientName}</b>? Это удалит все назначенные группы для этого клиента, и любой пользователь сможет войти в систему.",
"allowed_oidc_clients_updated_successfully": "Разрешенные OIDC клиенты успешно обновлены",
"yes": "Да",
"no": "Нет",
"restricted": "Ограниченный",
"scim_provisioning": "Настройка SCIM",
"scim_provisioning_description": "SCIM позволяет автоматически добавлять и удалять пользователей и группы из твоего клиента OIDC. Подробнее читай в <link href='https://pocket-id.org/docs/configuration/scim'>документации</link>.",
"scim_provisioning": "SCIM-провижининг",
"scim_provisioning_description": "Провижининг по протоколу SCIM позволяет автоматически создавать и удалять пользователей и группы из вашего OIDC-клиента. Узнайте больше в <link href='https://pocket-id.org/docs/configuration/scim'>документации</link>.",
"scim_endpoint": "Конечная точка SCIM",
"scim_token": "Токен SCIM",
"last_successful_sync_at": "Последняя удачная синхронизация: {time}",
"scim_configuration_updated_successfully": "Настройки SCIM обновились без проблем.",
"scim_enabled_successfully": "SCIM включен, все работает.",
"scim_disabled_successfully": "SCIM отключен, все нормально.",
"disable_scim_provisioning": "Отключить настройку SCIM",
"scim_configuration_updated_successfully": "Конфигурация SCIM успешно обновлена.",
"scim_enabled_successfully": "SCIM успешно включен.",
"scim_disabled_successfully": "SCIM успешно отключен.",
"disable_scim_provisioning": "Отключить SCIM-провижининг",
"disable_scim_provisioning_confirm_description": "Ты уверен, что хочешь отключить SCIM-провижининг для <b>{clientName}</b>? Это остановит все автоматические действия по предоставлению и отмене доступа пользователей и групп.",
"scim_sync_failed": "Синхронизация SCIM не получилась. Посмотри в журналах сервера, там будет больше инфо.",
"scim_sync_successful": "Синхронизация SCIM прошла без проблем.",
"scim_sync_failed": "Сбой синхронизации SCIM. Проверьте журналы сервера для получения дополнительной информации.",
"scim_sync_successful": "Синхронизация SCIM успешно завершена.",
"save_and_sync": "Сохранить и синхронизировать",
"scim_save_changes_description": "Перед тем, как начать синхронизацию SCIM, нужно сохранить изменения. Хочешь сохранить сейчас?",
"scopes": "Области применения",
"issuer_url": "URL эмитента",
"smtp_field_required_when_other_provided": "Нужно, если есть какие-то настройки SMTP",
"smtp_field_required_when_email_enabled": "Нужно, если включены уведомления по электронной почте",
"renew": "Обновлять",
"renew_api_key": "Обнови ключ API",
"scim_save_changes_description": "Вы должны сохранить изменения перед началом синхронизации SCIM. Сохранить сейчас?",
"scopes": "Области доступа",
"issuer_url": "URL издателя",
"smtp_field_required_when_other_provided": "Требуется при указании любых настроек SMTP",
"smtp_field_required_when_email_enabled": "Требуется, если включены уведомления по электронной почте",
"renew": "Обновить",
"renew_api_key": "Обновить ключ API",
"renew_api_key_description": "При обновлении ключа API будет сгенерирован новый ключ. Не забудь обновить все интеграции, которые используют этот ключ.",
"api_key_renewed": "Ключ API обновлен",
"app_config_home_page": "Главная страница",
"app_config_home_page_description": "Страница, куда пользователи попадают после входа в систему.",
"email_verification_warning": роверь свой адрес электронной почты",
"email_verification_warning_description": "Твой адрес электронной почты ещё не подтверждён. Пожалуйста, подтверди его как можно скорее.",
"email_verification": роверка электронной почты",
"email_verification_description": "Отправляй пользователям письмо с подтверждением, когда они регистрируются или меняют свой адрес электронной почты.",
"email_verification_success_title": "Электронная почта подтверждена",
"email_verification_success_description": "Твой адрес электронной почты подтвержден.",
"email_verification_error_title": "Не получилось подтвердить почту",
"mark_as_unverified": "Пометить как непроверенное",
"mark_as_verified": "Пометить как проверенное",
"email_verification_sent": "Письмо с подтверждением отправлено.",
"emails_verified_by_default": "Электронные письма проверяются по умолчанию",
"emails_verified_by_default_description": "Если эта функция включена, адреса электронной почты пользователей будут по умолчанию отмечаться как подтвержденные при регистрации или при изменении адреса электронной почты."
"app_config_home_page_description": "Страница, на которую пользователи перенаправляются после входа.",
"email_verification_warning": одтвердите ваш адрес электронной почты",
"email_verification_warning_description": "Ваш адрес электронной почты ещё не подтверждён. Пожалуйста, подтвердите его как можно скорее.",
"email_verification": одтверждение электронной почты",
"email_verification_description": "Отправлять пользователям письмо с подтверждением при регистрации или изменении их адреса электронной почты.",
"email_verification_success_title": "Электронная почта успешно подтверждена",
"email_verification_success_description": "Ваш адрес электронной почты успешно подтвержден.",
"email_verification_error_title": "Не удалось подтвердить электронную почту",
"mark_as_unverified": "Пометить как неподтвержденную",
"mark_as_verified": "Пометить как подтвержденную",
"email_verification_sent": "Письмо с подтверждением успешно отправлено.",
"emails_verified_by_default": "Электронные почты подтверждены по умолчанию",
"emails_verified_by_default_description": "Если эта функция включена, адреса электронной почты пользователей будут по умолчанию помечаться как подтверждённые при регистрации или при смене адреса."
}

View File

@@ -11,8 +11,8 @@
"add_another": "Додати ще",
"select_a_date": "Обрати дату",
"select_file": "Обрати файл",
"profile_picture": "Фотографія профілю",
"profile_picture_is_managed_by_ldap_server": "Фотографія профілю управляється сервером LDAP і не може бути змінена тут.",
"profile_picture": "Зображення профілю",
"profile_picture_is_managed_by_ldap_server": "Зображення профілю керується сервером LDAP і не може бути змінене тут.",
"click_profile_picture_to_upload_custom": "Натисніть на зображення профілю, щоб завантажити власне зображення.",
"image_should_be_in_format": "Зображення повинно бути у форматі PNG, JPEG або WEBP.",
"items_per_page": "Елементів на сторінці",
@@ -28,7 +28,7 @@
"login_background": "Фон сторінки входу",
"logo": "Логотип",
"login_code": "Код входу",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Створіть код входу, який користувач може використовувати для входу без ключа доступу одноразово.",
"create_a_login_code_to_sign_in_without_a_passkey_once": "Створіть код входу, який користувач може одноразово використати для входу без ключа доступу.",
"one_hour": "1 година",
"twelve_hours": "12 годин",
"one_day": "1 день",
@@ -50,10 +50,10 @@
"webauthn_error_invalid_domain": "Налаштований домен є недійсним.",
"contact_administrator_to_fix": "Зверніться до адміністратора, щоб вирішити цю проблему.",
"webauthn_operation_not_allowed_or_timed_out": "Операція не була дозволена або закінчився час очікування",
"webauthn_not_supported_by_browser": "Цей браузер не підтримує паролі. Будь ласка, скористайтеся альтернативним методом входу.",
"webauthn_not_supported_by_browser": "Цей браузер не підтримує ключі доступу. Будь ласка, скористайтеся альтернативним методом входу.",
"critical_error_occurred_contact_administrator": "Виникла критична помилка. Будь ласка, зверніться до адміністратора.",
"sign_in_to": "Увійти в {name}",
"client_not_found": "Клієнта не знайдено",
"client_not_found": "Клієнт не знайдений",
"client_wants_to_access_the_following_information": "<b>{client}</b> хоче отримати доступ до наступної інформації:",
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Бажаєте увійти до <b>{client}</b> за допомогою облікового запису {appName}?",
"email": "Електронна пошта",
@@ -90,7 +90,7 @@
"enter_the_code_you_received_to_sign_in": "Введіть отриманий код, щоб увійти.",
"code": "Код",
"invalid_redirect_url": "Неправильна URL-адреса перенаправлення",
"audit_log": "Журнал авдиту",
"audit_log": "Журнал аудиту",
"users": "Користувачі",
"user_groups": "Групи користувачів",
"oidc_clients": "Клієнти OIDC",
@@ -135,14 +135,14 @@
"are_you_sure_you_want_to_delete_this_passkey": "Ви впевнені, що хочете видалити цей ключ доступу?",
"passkey_deleted_successfully": "Ключ доступу успішно видалено",
"delete_passkey_name": "Видалити {passkeyName}",
"passkey_name_updated_successfully": "Назва ключа доступу успішно оновлено",
"passkey_name_updated_successfully": "Назву ключа доступу успішно оновлено",
"name_passkey": "Назва ключа доступу",
"name_your_passkey_to_easily_identify_it_later": "Назвіть свій ключ доступу, щоб легко пізнати його пізніше.",
"name_your_passkey_to_easily_identify_it_later": "Назвіть свій ключ доступу, щоб легко розпізнати його пізніше.",
"create_api_key": "Створити API-ключ",
"add_a_new_api_key_for_programmatic_access": "Додайте новий ключ API для програмного доступу до <link href='https://pocket-id.org/docs/api'>API Pocket ID</link>.",
"add_a_new_api_key_for_programmatic_access": "Додайте новий API-ключ для програмного доступу до <link href='https://pocket-id.org/docs/api'>API Pocket ID</link>.",
"add_api_key": "Додати API-ключ",
"manage_api_keys": "Керувати ключами API",
"api_key_created": "Створено API-ключ",
"manage_api_keys": "Керувати API-ключами",
"api_key_created": "API-ключ створено",
"for_security_reasons_this_key_will_only_be_shown_once": "З міркувань безпеки цей ключ буде показано лише один раз. Будь ласка, збережіть його в безпечному місці.",
"description": "Опис",
"api_key": "API-ключ",
@@ -152,11 +152,11 @@
"when_this_api_key_will_expire": "Коли спливе термін дії цього API-ключа.",
"optional_description_to_help_identify_this_keys_purpose": "Додатковий опис для допомоги в ідентифікації призначення цього ключа (необов’язково).",
"expiration_date_must_be_in_the_future": "Дата закінчення терміну дії повинна бути в майбутньому",
"revoke_api_key": "Анулювати API-ключ",
"revoke_api_key": "Відкликати API-ключ",
"never": "Ніколи",
"revoke": "Анулювати",
"api_key_revoked_successfully": "API-ключ успішно анульовано",
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Ви впевнені, що хочете анулювати API-ключ «{apiKeyName}»? Це призведе до зупинки всіх інтеграцій, які використовують цей ключ.",
"revoke": "Відкликати",
"api_key_revoked_successfully": "API-ключ успішно відкликано",
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Ви впевнені, що хочете відкликати API-ключ «{apiKeyName}»? Це призведе до зупинки всіх інтеграцій, які використовують цей ключ.",
"last_used": "Останнє використання",
"actions": "Дії",
"images_updated_successfully": "Зображення успішно оновлено. Оновлення може зайняти кілька хвилин.",
@@ -170,7 +170,7 @@
"save_changes_question": "Зберегти зміни?",
"you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "Ви повинні зберегти зміни перед надсиланням тестового листа. Зберегти зараз?",
"save_and_send": "Зберегти та надіслати",
"test_email_sent_successfully": "Тестовий лист успішно відправлено на вашу електронну адресу.",
"test_email_sent_successfully": "Тестовий лист успішно надіслано на вашу електронну адресу.",
"failed_to_send_test_email": "Не вдалося надіслати тестовий лист. Перевірте журнали сервера для отримання додаткової інформації.",
"smtp_configuration": "Налаштування SMTP",
"smtp_host": "SMTP хост",
@@ -185,17 +185,17 @@
"enabled_emails": "Увімкнені електронні листи",
"email_login_notification": "Сповіщення електронною поштою про вхід",
"send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Надіслати електронний лист користувачеві після входу з нового пристрою.",
"emai_login_code_requested_by_user": "Надіслати коду входу, згенерований користувачем, електронною поштою",
"emai_login_code_requested_by_user": "Надіслати код входу, згенерований користувачем, електронною поштою",
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Дозволяє користувачам обходити ключі доступу шляхом запиту коду для входу, який був відправлений на їх електронну пошту. Це суттєво зменшує безпеку, оскільки будь-хто, хто має доступ до електронної пошти користувача, може отримати доступ.",
"email_login_code_from_admin": "Надіслати коду входу, згенерований адміністратором, електронною поштою",
"email_login_code_from_admin": "Надіслати код входу, згенерований адміністратором, електронною поштою",
"allows_an_admin_to_send_a_login_code_to_the_user": "Дозволяє адміністратору надсилати код для входу користувачеві електронною поштою.",
"send_test_email": "Відправити тестового листа",
"application_configuration_updated_successfully": "Налаштування додатку успішно оновлено",
"application_name": "Назва додатку",
"application_configuration_updated_successfully": "Налаштування застосунку успішно оновлено",
"application_name": "Назва застосунку",
"session_duration": "Тривалість сеансу",
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Тривалість сесії у хвилинах до повторного входу користувача.",
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Тривалість сеансу у хвилинах до повторного входу користувача.",
"enable_self_account_editing": "Увімкнути редагування власного облікового запису",
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Чи повинні користувачі мати можливість редагувати власні дані облікового запису.",
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Чи повинні користувачі мати можливість редагувати дані свого облікового запису.",
"ldap_configuration_updated_successfully": "Налаштування LDAP успішно оновлено",
"ldap_disabled_successfully": "LDAP успішно вимкнено",
"ldap_sync_finished": "Синхронізація LDAP завершена",
@@ -279,7 +279,7 @@
"callback_urls": "URL-адреси зворотного виклику",
"logout_callback_urls": "URL-адреси зворотного виклику для виходу",
"public_client": "Публічний клієнт",
"public_clients_description": "Публічні клієнти не мають секретного ключа. Вони призначені для мобільних, веб та нативних додатків, де секретний ключ не може надійно зберігатись.",
"public_clients_description": "Публічні клієнти не мають секретного ключа. Вони призначені для мобільних, веб та нативних застосунків, де секретний ключ не може надійно зберігатись.",
"pkce": "PKCE",
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange — це функція безпеки, що запобігає атакам типу CSRF та перехопленню коду авторизації.",
"requires_reauthentication": "Потрібна повторна автентифікація",
@@ -321,10 +321,10 @@
"background_image": "Фонове зображення",
"language": "Мова",
"reset_profile_picture_question": "Скинути зображення профілю?",
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "Це видалить завантажене зображення та скине фото профілю на стандартне. Продовжити?",
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "Це видалить завантажене зображення та скине зображення профілю на стандартне. Продовжити?",
"reset": "Скинути",
"reset_to_default": "Відновити налаштування за замовчуванням",
"profile_picture_has_been_reset": "Фотографію профілю скинуто. Оновлення може зайняти кілька хвилин.",
"profile_picture_has_been_reset": "Зображення профілю скинуто. Оновлення може зайняти кілька хвилин.",
"select_the_language_you_want_to_use": "Виберіть мову, яку бажаєте використовувати. Зверніть увагу, що деякий текст може бути автоматично перекладений і може містити неточності.",
"contribute_to_translation": "Якщо ви знайдете помилку, ви можете долучитися до перекладу на <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
"personal": "Особисте",
@@ -333,26 +333,26 @@
"all_events": "Усі події",
"all_clients": "Усі клієнти",
"all_locations": "Усі місця розташування",
"global_audit_log": "Глобальний журнал авдиту",
"global_audit_log": "Глобальний журнал аудиту",
"see_all_recent_account_activities": "Перегляньте активність облікових записів усіх користувачів протягом встановленого періоду зберігання.",
"token_sign_in": "Вхід за допомогою токена",
"client_authorization": "Авторизація клієнта",
"new_client_authorization": "Нова авторизація клієнта",
"device_code_authorization": "Авторизація коду пристрою",
"new_device_code_authorization": "Авторизація нового коду пристрою",
"passkey_added": "Додано пароль",
"passkey_added": "Ключ доступу додано",
"passkey_removed": "Ключ доступу видалено",
"disable_animations": "Вимкнути анімацію",
"disable_animations": "Вимкнути анімації",
"turn_off_ui_animations": "Вимкнути анімації у всьому інтерфейсі.",
"user_disabled": "Обліковий запис вимкнено",
"disabled_users_cannot_log_in_or_use_services": "Вимкнені користувачі не можуть увійти в систему або користуватися послугами.",
"user_disabled": "Обліковий запис деактивовано",
"disabled_users_cannot_log_in_or_use_services": "Деактивовані користувачі не можуть увійти в систему або користуватися сервісами.",
"user_disabled_successfully": "Користувача успішно деактивовано.",
"user_enabled_successfully": "Користувача успішно активовано.",
"status": "Статус",
"disable_firstname_lastname": "Деактивувати {firstName} {lastName}",
"are_you_sure_you_want_to_disable_this_user": "Ви впевнені, що хочете вимкнути цього користувача? Він не зможе увійти в систему або користуватися будь-якими послугами.",
"are_you_sure_you_want_to_disable_this_user": "Ви впевнені, що хочете деактивувати цього користувача? Він не зможе увійти в систему або отримати доступ до будь-яких сервісів.",
"ldap_soft_delete_users": "Зберігати вимкнених користувачів із LDAP.",
"ldap_soft_delete_users_description": "Якщо увімкнено, користувачів, видалених з LDAP, буде вимкнено, а не видалено з системи.",
"ldap_soft_delete_users_description": "Якщо увімкнено, користувачів, видалених з LDAP, буде деактивовано, а не видалено з системи.",
"login_code_email_success": "Код для входу було надіслано користувачеві.",
"send_email": "Надіслати електронного листа",
"show_code": "Показати код",
@@ -379,7 +379,7 @@
"userinfo": "Userinfo",
"id_token_payload": "Вміст ID-токена",
"access_token_payload": "Вміст токена доступу",
"userinfo_endpoint_response": "Відповідь сервісу Userinfo",
"userinfo_endpoint_response": "Відповідь кінцевої точки Userinfo",
"copy": "Копіювати",
"no_preview_data_available": "Попередній перегляд даних недоступний",
"copy_all": "Скопіювати все",
@@ -404,8 +404,8 @@
"signup": "Зареєструватися",
"user_creation": "Створення користувача",
"configure_user_creation": "Керуйте налаштуваннями створення користувачів, включаючи методи реєстрації та права доступу за замовчуванням для нових користувачів.",
"user_creation_groups_description": "Призначте ці групи автоматично новим користувачам під час реєстрації.",
"user_creation_claims_description": "Призначте ці власні вимоги автоматично новим користувачам під час реєстрації.",
"user_creation_groups_description": "Призначати ці групи автоматично новим користувачам під час реєстрації.",
"user_creation_claims_description": "Призначати ці власні атрибути автоматично новим користувачам під час реєстрації.",
"user_creation_updated_successfully": "Налаштування створення користувача успішно оновлено.",
"signup_disabled_description": "Реєстрація користувачів повністю вимкнена. Нові облікові записи можуть створювати лише адміністратори.",
"signup_requires_valid_token": "Для створення облікового запису потрібен дійсний токен реєстрації",
@@ -413,10 +413,10 @@
"go_to_login": "Перейти до входу",
"signup_to_appname": "Зареєструватися в {appName}",
"create_your_account_to_get_started": "Створіть свій обліковий запис, щоб розпочати.",
"initial_account_creation_description": "Будь ласка, створіть свій обліковий запис, щоб почати. Ви зможете налаштувати ключ доступу пізніше.",
"initial_account_creation_description": "Будь ласка, створіть свій обліковий запис, щоб розпочати. Ви зможете налаштувати ключ доступу пізніше.",
"setup_your_passkey": "Налаштуйте свій ключ доступу",
"create_a_passkey_to_securely_access_your_account": "Створіть ключ доступу для безпечного входу до свого облікового запису. Це буде ваш основний спосіб увійти.",
"skip_for_now": "Пропустити наразі",
"skip_for_now": оки що пропустити",
"account_created": "Обліковий запис створено",
"enable_user_signups": "Дозволити реєстрацію користувачів",
"enable_user_signups_description": "Визначте, як користувачі можуть реєструвати нові облікові записи в Pocket ID.",
@@ -442,29 +442,29 @@
"of": "з",
"skip_passkey_setup": "Пропустити налаштування ключа доступу",
"skip_passkey_setup_description": "Рекомендується налаштувати ключ доступу, оскільки без нього ви не зможете увійти у свій обліковий запис після закінчення сеансу.",
"my_apps": "Мої додатки",
"no_apps_available": "Немає доступних додатків",
"contact_your_administrator_for_app_access": "Зверніться до адміністратора, щоб отримати доступ до додатків.",
"launch": "Запуск",
"my_apps": "Мої застосунки",
"no_apps_available": "Немає доступних застосунків",
"contact_your_administrator_for_app_access": "Зверніться до адміністратора, щоб отримати доступ до застосунків.",
"launch": "Запустити",
"client_launch_url": "URL-адреса для запуску клієнта",
"client_launch_url_description": "URL-адреса, яка відкриється, коли користувач запустить програму зі сторінки «Мої програми».",
"client_name_description": "Назва клієнта, яке відображається в інтерфейсі Pocket ID.",
"revoke_access": "Скасувати доступ",
"revoke_access_description": "Скасувати доступ для <b>{clientName}</b>. <b>{clientName}</b> більше не зможе отримати доступ до інформації вашого облікового запису.",
"revoke_access_successful": "Доступ для {clientName} було успішно скасовано.",
"client_name_description": "Назва клієнта, яка відображається в інтерфейсі Pocket ID.",
"revoke_access": "Відкликати доступ",
"revoke_access_description": "Відкликати доступ для <b>{clientName}</b>. <b>{clientName}</b> більше не зможе отримати доступ до інформації вашого облікового запису.",
"revoke_access_successful": "Доступ для {clientName} був успішно відкликаний.",
"last_signed_in_ago": "Останній вхід {time} тому",
"invalid_client_id": "Ідентифікатор клієнта може містити тільки літери, цифри, підкреслення та дефіси.",
"custom_client_id_description": "Встановіть власний ідентифікатор клієнта, якщо це потрібно для вашої програми. В іншому випадку залиште поле порожнім, щоб створити випадковий ідентифікатор.",
"invalid_client_id": "Ідентифікатор клієнта може містити тільки літери, цифри, підкреслення та дефіси",
"custom_client_id_description": "Встановіть власний ідентифікатор клієнта, якщо це вимагається вашим застосунком. В іншому випадку залиште поле порожнім, щоб згенерувати випадковий.",
"generated": "Створено",
"administration": "Адміністрування",
"group_rdn_attribute_description": "Атрибут, що використовується в розрізнювальному імені групи (DN).",
"display_name_attribute": "Атрибут імені для відображення",
"display_name": "Ім'я для відображення",
"configure_application_images": "Налаштування зображень додатків",
"configure_application_images": "Налаштування зображень застосунку",
"ui_config_disabled_info_title": "Конфігурація інтерфейсу користувача вимкнена",
"ui_config_disabled_info_description": "Конфігурація інтерфейсу користувача вимкнена, оскільки налаштування конфігурації програми керуються через змінні середовища. Деякі налаштування можуть бути недоступними для редагування.",
"logo_from_url_description": "Вставте прямий URL-адресу зображення (svg, png, webp). Знайдіть іконки на <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> або <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
"invalid_url": "Недійсний URL-адреса",
"logo_from_url_description": "Вставте пряму URL-адресу зображення (svg, png, webp). Знайдіть іконки на <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> або <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
"invalid_url": "Недійсна URL-адреса",
"require_user_email": "Потрібна адреса електронної пошти",
"require_user_email_description": "Вимагає від користувачів наявність адреси електронної пошти. Якщо ця опція вимкнена, користувачі без адреси електронної пошти не зможуть користуватися функціями, для яких потрібна адреса електронної пошти.",
"view": "Перегляд",
@@ -474,13 +474,13 @@
"reauthentication": "Повторна аутентифікація",
"clear_filters": "Очистити фільтри",
"default_profile_picture": "Стандартне зображення профілю",
"light": "Світло",
"dark": "Темний",
"system": "Система",
"signup_token_user_groups_description": "Автоматично призначайте ці групи користувачам, які реєструються за допомогою цього токена.",
"light": "Світла",
"dark": "Темна",
"system": "Системна",
"signup_token_user_groups_description": "Автоматично призначати ці групи користувачам, які реєструються за допомогою цього токена.",
"allowed_oidc_clients": "Дозволені клієнти OIDC",
"allowed_oidc_clients_description": "Виберіть клієнти OIDC, до яких члени цієї групи користувачів мають право входити.",
"unrestrict_oidc_client": "Без обмежень {clientName}",
"unrestrict_oidc_client": "Не обмежувати {clientName}",
"confirm_unrestrict_oidc_client_description": "Ви впевнені, що хочете зняти обмеження з клієнта OIDC <b>{clientName}</b>? Це призведе до видалення всіх групових призначень для цього клієнта, і будь-який користувач зможе увійти в систему.",
"allowed_oidc_clients_updated_successfully": "Дозволені клієнти OIDC успішно оновлені",
"yes": "Так",
@@ -505,9 +505,9 @@
"smtp_field_required_when_other_provided": "Необхідно, якщо вказано будь-яке налаштування SMTP",
"smtp_field_required_when_email_enabled": "Необхідно, якщо увімкнено сповіщення електронною поштою",
"renew": "Оновити",
"renew_api_key": "Оновити ключ API",
"renew_api_key": "Оновити API-ключ",
"renew_api_key_description": "Оновлення API-ключа призведе до створення нового ключа. Обов'язково оновіть усі інтеграції, що використовують цей ключ.",
"api_key_renewed": "Ключ API оновлено",
"api_key_renewed": "API-ключ оновлено",
"app_config_home_page": "Головна сторінка",
"app_config_home_page_description": "Сторінка, на яку перенаправляють користувачів після входу в систему.",
"email_verification_warning": "Підтвердьте свою адресу електронної пошти",

View File

@@ -474,8 +474,8 @@
"reauthentication": "重新驗證",
"clear_filters": "清除篩選條件",
"default_profile_picture": "預設個人資料照片",
"light": "",
"dark": "暗",
"light": "亮色",
"dark": "暗",
"system": "系統",
"signup_token_user_groups_description": "自動將這些群組指派給使用此代幣註冊的用戶。",
"allowed_oidc_clients": "允許的 OIDC 客戶端",

View File

@@ -1,63 +1,63 @@
{
"name": "pocket-id-frontend",
"version": "2.2.0",
"private": true,
"type": "module",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite dev --port 3000",
"build": "vite build",
"preview": "vite preview --port 3000",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"dependencies": {
"@simplewebauthn/browser": "^13.2.2",
"@tailwindcss/vite": "^4.1.18",
"axios": "^1.13.2",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"jose": "^6.1.3",
"qrcode": "^1.5.4",
"runed": "^0.37.1",
"sveltekit-superforms": "^2.29.1",
"tailwind-merge": "^3.4.0",
"zod": "^4.3.4"
},
"devDependencies": {
"@inlang/paraglide-js": "^2.7.1",
"@inlang/plugin-m-function-matcher": "^2.1.0",
"@inlang/plugin-message-format": "^4.0.0",
"@internationalized/date": "^3.10.1",
"@lucide/svelte": "^0.559.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.49.2",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@types/eslint": "^9.6.1",
"@types/node": "^24.10.4",
"@types/qrcode": "^1.5.6",
"bits-ui": "^2.14.4",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.13.1",
"formsnap": "^2.0.1",
"globals": "^16.5.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.7.4",
"prettier-plugin-svelte": "^3.4.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"rollup": "^4.54.0",
"svelte": "^5.46.1",
"svelte-check": "^4.3.5",
"svelte-sonner": "^1.0.7",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.18",
"tslib": "^2.8.1",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.51.0",
"vite": "^7.3.0"
}
"name": "pocket-id-frontend",
"version": "2.2.0",
"private": true,
"type": "module",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite dev --port 3000",
"build": "vite build",
"preview": "vite preview --port 3000",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"dependencies": {
"@simplewebauthn/browser": "^13.2.2",
"@tailwindcss/vite": "^4.2.0",
"axios": "^1.13.5",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"jose": "^6.1.3",
"qrcode": "^1.5.4",
"runed": "^0.37.1",
"sveltekit-superforms": "^2.30.0",
"tailwind-merge": "^3.5.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@inlang/paraglide-js": "^2.12.0",
"@inlang/plugin-m-function-matcher": "^2.2.1",
"@inlang/plugin-message-format": "^4.3.0",
"@internationalized/date": "^3.11.0",
"@lucide/svelte": "^0.559.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.53.0",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@types/eslint": "^9.6.1",
"@types/node": "^24.10.13",
"@types/qrcode": "^1.5.6",
"bits-ui": "^2.16.2",
"eslint": "^9.39.3",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.15.0",
"formsnap": "^2.0.1",
"globals": "^16.5.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.8.1",
"prettier-plugin-svelte": "^3.5.0",
"prettier-plugin-tailwindcss": "^0.7.2",
"rollup": "^4.59.0",
"svelte": "^5.53.2",
"svelte-check": "^4.4.3",
"svelte-sonner": "^1.0.7",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.2.0",
"tslib": "^2.8.1",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.0",
"vite": "^7.3.1"
}
}

View File

@@ -1 +0,0 @@
cache

View File

@@ -7,12 +7,14 @@
"de",
"en",
"es",
"et",
"fi",
"fr",
"it",
"ja",
"ko",
"nl",
"no",
"pl",
"pt-BR",
"ru",

View File

@@ -41,7 +41,7 @@
placeholder?: string;
disabled?: boolean;
inputClass?: string;
type?: 'text' | 'password' | 'email' | 'number' | 'checkbox' | 'date';
type?: 'text' | 'password' | 'email' | 'number' | 'checkbox' | 'date' | 'url';
onInput?: (e: FormInputEvent) => void;
} = $props();

View File

@@ -74,6 +74,7 @@
oninput={(e) => (url = e.currentTarget.value)}
onfocusout={handleUrlChange}
aria-invalid={hasError}
type="url"
/>
{#if hasError}
<p class="text-destructive mt-1 text-start text-xs">{m.invalid_url()}</p>

View File

@@ -27,10 +27,7 @@
>
<div class="flex h-16 items-center">
{#if !isAuthPage}
<a
href="/"
class="flex items-center gap-3 transition-opacity hover:opacity-80"
>
<a href="/" class="flex items-center gap-3 transition-opacity hover:opacity-80">
<Logo class="size-8" />
<h1 class="text-lg font-semibold tracking-tight" data-testid="application-name">
{$appConfigStore.appName}

View File

@@ -1,13 +1,13 @@
import Root from "./toggle.svelte";
import Root from './toggle.svelte';
export {
toggleVariants,
type ToggleSize,
type ToggleVariant,
type ToggleVariants,
} from "./toggle.svelte";
type ToggleVariants
} from './toggle.svelte';
export {
Root,
//
Root as Toggle,
Root as Toggle
};

View File

@@ -1,41 +1,41 @@
<script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants";
import { type VariantProps, tv } from 'tailwind-variants';
export const toggleVariants = tv({
base: "hover:bg-muted hover:text-muted-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-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 inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
variants: {
variant: {
default: "bg-transparent",
default: 'bg-transparent',
outline:
"border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs",
'border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs'
},
size: {
default: "h-9 min-w-9 px-2",
sm: "h-8 min-w-8 px-1.5",
lg: "h-10 min-w-10 px-2.5",
},
default: 'h-9 min-w-9 px-2',
sm: 'h-8 min-w-8 px-1.5',
lg: 'h-10 min-w-10 px-2.5'
}
},
defaultVariants: {
variant: "default",
size: "default",
},
variant: 'default',
size: 'default'
}
});
export type ToggleVariant = VariantProps<typeof toggleVariants>["variant"];
export type ToggleSize = VariantProps<typeof toggleVariants>["size"];
export type ToggleVariant = VariantProps<typeof toggleVariants>['variant'];
export type ToggleSize = VariantProps<typeof toggleVariants>['size'];
export type ToggleVariants = VariantProps<typeof toggleVariants>;
</script>
<script lang="ts">
import { Toggle as TogglePrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
import { Toggle as TogglePrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
let {
ref = $bindable(null),
pressed = $bindable(false),
class: className,
size = "default",
variant = "default",
size = 'default',
variant = 'default',
...restProps
}: TogglePrimitive.RootProps & {
variant?: ToggleVariant;

View File

@@ -20,7 +20,7 @@ export type User = {
export type UserCreate = Omit<User, 'id' | 'customClaims' | 'ldapId' | 'userGroups'>;
export type AccountUpdate = Omit<UserCreate, 'isAdmin' | 'disabled' | 'emailVerified'>
export type AccountUpdate = Omit<UserCreate, 'isAdmin' | 'disabled' | 'emailVerified'>;
export type UserSignUp = Omit<
UserCreate,

View File

@@ -10,8 +10,13 @@ export const load: LayoutLoad = async () => {
let isUpToDate = true;
try {
newestVersion = await versionService.getNewestVersion();
isUpToDate = newestVersion === currentVersion;
} catch {}
// If newestVersion is empty, it means the check is disabled or failed.
// In this case, we assume the version is up to date.
isUpToDate = newestVersion === '' || newestVersion === currentVersion;
} catch {
// If the request fails, assume up-to-date to avoid showing a warning.
isUpToDate = true;
}
const versionInformation: AppVersionInformation = {
currentVersion: versionService.getCurrentVersion(),

View File

@@ -14,12 +14,14 @@
de: 'Deutsch',
en: 'English',
es: 'Español',
et: 'Eesti',
fi: 'Suomi',
fr: 'Français',
it: 'Italiano',
ja: '日本語',
ko: '한국어',
nl: 'Nederlands',
no: 'Norsk',
pl: 'Polski',
'pt-BR': 'Português brasileiro',
ru: 'Русский',

View File

@@ -31,6 +31,7 @@
<Input
aria-invalid={!!error}
data-testid={`callback-url-${i + 1}`}
type="url"
bind:value={callbackURLs[i]}
/>
<Button

View File

@@ -181,6 +181,7 @@
label={m.client_launch_url()}
description={m.client_launch_url_description()}
class="w-full"
type="url"
bind:input={$inputs.launchURL}
/>
<OidcCallbackUrlInput

1670
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,11 @@ packages:
- email-templates
overrides:
cookie@<0.7.0: '>=0.7.0'
devalue: ^5.3.2
glob@>=11.0.0 <11.1.0: '>=11.1.0'
js-yaml@>=4.0.0 <4.1.1: '>=4.1.1'
valibot@>=0.31.0 <1.2.0: '>=1.2.0'
validator@<13.15.20: '>=13.15.20'
cookie@<0.7.0: ">=0.7.0"
devalue: ^5.6.2
glob@>=11.0.0 <11.1.0: ">=11.1.0"
js-yaml@>=4.0.0 <4.1.1: ">=4.1.1"
valibot@>=0.31.0 <1.2.0: ">=1.2.0"
validator@<13.15.20: ">=13.15.20"
"@isaacs/brace-expansion": ">=5.0.1"
next: ">=16.1.5"