mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-03-22 20:15:07 +00:00
Merge branch 'main' into chore/depot
This commit is contained in:
41
CHANGELOG.md
41
CHANGELOG.md
@@ -1,3 +1,44 @@
|
|||||||
|
## v2.3.0
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- ENCRYPTION_KEY needed for version and help commands ([#1256](https://github.com/pocket-id/pocket-id/pull/1256) by @kmendell)
|
||||||
|
- prevent deletion of OIDC provider logo for non admin/anonymous users ([#1267](https://github.com/pocket-id/pocket-id/pull/1267) by @HiMoritz)
|
||||||
|
- add `type="url"` to url inputs ([bb7b0d5](https://github.com/pocket-id/pocket-id/commit/bb7b0d56084df49b6a003cc3eaf076884e2cbf60) by @stonith404)
|
||||||
|
- increase rate limit for frontend and api requests ([aab7e36](https://github.com/pocket-id/pocket-id/commit/aab7e364e85f1ce13950da93cc50324328cdd96d) by @stonith404)
|
||||||
|
- decode URL-encoded client ID and secret in Basic auth ([#1263](https://github.com/pocket-id/pocket-id/pull/1263) by @ypomortsev)
|
||||||
|
- token endpoint must not accept params as query string args ([#1321](https://github.com/pocket-id/pocket-id/pull/1321) by @ItalyPaleAle)
|
||||||
|
- left align input error messages ([b3fe143](https://github.com/pocket-id/pocket-id/commit/b3fe14313684f9d8c389ed93ea8e479e3681b5c6) by @stonith404)
|
||||||
|
- disallow API key renewal and creation with API key authentication ([#1334](https://github.com/pocket-id/pocket-id/pull/1334) by @stonith404)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- add VERSION_CHECK_DISABLED environment variable ([#1254](https://github.com/pocket-id/pocket-id/pull/1254) by @dihmandrake)
|
||||||
|
- add support for HTTP/2 ([56afebc](https://github.com/pocket-id/pocket-id/commit/56afebc242be7ed14b58185425d6445bf18f640a) by @stonith404)
|
||||||
|
- manageability of uncompressed geolite db file ([#1234](https://github.com/pocket-id/pocket-id/pull/1234) by @gucheen)
|
||||||
|
- add JWT ID for generated tokens ([#1322](https://github.com/pocket-id/pocket-id/pull/1322) by @imnotjames)
|
||||||
|
- current version api endpoint ([#1310](https://github.com/pocket-id/pocket-id/pull/1310) by @kmendell)
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- bump @sveltejs/kit from 2.49.2 to 2.49.5 in the npm_and_yarn group across 1 directory ([#1240](https://github.com/pocket-id/pocket-id/pull/1240) by @dependabot[bot])
|
||||||
|
- bump svelte from 5.46.1 to 5.46.4 in the npm_and_yarn group across 1 directory ([#1242](https://github.com/pocket-id/pocket-id/pull/1242) by @dependabot[bot])
|
||||||
|
- bump devalue to 5.6.2 ([9dbc02e](https://github.com/pocket-id/pocket-id/commit/9dbc02e56871b2de6a39c443e1455efc26a949f7) by @kmendell)
|
||||||
|
- upgrade deps ([4811625](https://github.com/pocket-id/pocket-id/commit/4811625cdd64b47ea67b7a9b03396e455896ccd6) by @kmendell)
|
||||||
|
- add Estonian files ([53ef61a](https://github.com/pocket-id/pocket-id/commit/53ef61a3e5c4b77edec49d41ab94302bfec84269) by @kmendell)
|
||||||
|
- update AAGUIDs ([#1257](https://github.com/pocket-id/pocket-id/pull/1257) by @github-actions[bot])
|
||||||
|
- add Norwegian language files ([80558c5](https://github.com/pocket-id/pocket-id/commit/80558c562533e7b4d658d5baa4221d8cd209b47d) by @stonith404)
|
||||||
|
- run formatter ([60825c5](https://github.com/pocket-id/pocket-id/commit/60825c5743b0e233ab622fd4d0ea04eb7ab59529) by @kmendell)
|
||||||
|
- bump axios from 1.13.2 to 1.13.5 in the npm_and_yarn group across 1 directory ([#1309](https://github.com/pocket-id/pocket-id/pull/1309) by @dependabot[bot])
|
||||||
|
- update dependenicies ([94a4897](https://github.com/pocket-id/pocket-id/commit/94a48977ba24e099b6221838d620c365eb1d4bf4) by @kmendell)
|
||||||
|
- update AAGUIDs ([#1316](https://github.com/pocket-id/pocket-id/pull/1316) by @github-actions[bot])
|
||||||
|
- bump svelte from 5.46.4 to 5.51.5 in the npm_and_yarn group across 1 directory ([#1324](https://github.com/pocket-id/pocket-id/pull/1324) by @dependabot[bot])
|
||||||
|
- bump @sveltejs/kit from 2.49.5 to 2.52.2 in the npm_and_yarn group across 1 directory ([#1327](https://github.com/pocket-id/pocket-id/pull/1327) by @dependabot[bot])
|
||||||
|
- upgrade dependencies ([0678699](https://github.com/pocket-id/pocket-id/commit/0678699d0cce5448c425b2c16bedab5fc242cbf0) by @stonith404)
|
||||||
|
- upgrade to node 24 and go 1.26.0 ([#1328](https://github.com/pocket-id/pocket-id/pull/1328) by @kmendell)
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/pocket-id/pocket-id/compare/v2.2.0...v2.3.0
|
||||||
|
|
||||||
## v2.2.0
|
## v2.2.0
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -58,9 +60,16 @@ func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) e
|
|||||||
return fmt.Errorf("failed to create sub FS: %w", err)
|
return fmt.Errorf("failed to create sub FS: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheMaxAge := time.Hour * 24
|
// Load a map of all files to see which ones are available pre-compressed
|
||||||
fileServer := NewFileServerWithCaching(http.FS(distFS), int(cacheMaxAge.Seconds()))
|
preCompressed, err := listPreCompressedAssets(distFS)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to index pre-compressed frontend assets: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init the file server
|
||||||
|
fileServer := NewFileServerWithCaching(http.FS(distFS), preCompressed)
|
||||||
|
|
||||||
|
// Handler for Gin
|
||||||
handler := func(c *gin.Context) {
|
handler := func(c *gin.Context) {
|
||||||
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
||||||
|
|
||||||
@@ -108,34 +117,138 @@ func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) e
|
|||||||
type FileServerWithCaching struct {
|
type FileServerWithCaching struct {
|
||||||
root http.FileSystem
|
root http.FileSystem
|
||||||
lastModified time.Time
|
lastModified time.Time
|
||||||
cacheMaxAge int
|
|
||||||
lastModifiedHeaderValue string
|
lastModifiedHeaderValue string
|
||||||
cacheControlHeaderValue string
|
preCompressed preCompressedMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileServerWithCaching(root http.FileSystem, maxAge int) *FileServerWithCaching {
|
func NewFileServerWithCaching(root http.FileSystem, preCompressed preCompressedMap) *FileServerWithCaching {
|
||||||
return &FileServerWithCaching{
|
return &FileServerWithCaching{
|
||||||
root: root,
|
root: root,
|
||||||
lastModified: time.Now(),
|
lastModified: time.Now(),
|
||||||
cacheMaxAge: maxAge,
|
|
||||||
lastModifiedHeaderValue: time.Now().UTC().Format(http.TimeFormat),
|
lastModifiedHeaderValue: time.Now().UTC().Format(http.TimeFormat),
|
||||||
cacheControlHeaderValue: fmt.Sprintf("public, max-age=%d", maxAge),
|
preCompressed: preCompressed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileServerWithCaching) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (f *FileServerWithCaching) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// Check if the client has a cached version
|
// First, set cache headers
|
||||||
if ifModifiedSince := r.Header.Get("If-Modified-Since"); ifModifiedSince != "" {
|
// Check if the request is for an immutable asset
|
||||||
ifModifiedSinceTime, err := time.Parse(http.TimeFormat, ifModifiedSince)
|
if isImmutableAsset(r) {
|
||||||
if err == nil && f.lastModified.Before(ifModifiedSinceTime.Add(1*time.Second)) {
|
// Set the cache control header as immutable with a long expiration
|
||||||
// Client's cached version is up to date
|
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||||||
w.WriteHeader(http.StatusNotModified)
|
} else {
|
||||||
return
|
// Check if the client has a cached version
|
||||||
|
ifModifiedSince := r.Header.Get("If-Modified-Since")
|
||||||
|
if ifModifiedSince != "" {
|
||||||
|
ifModifiedSinceTime, err := time.Parse(http.TimeFormat, ifModifiedSince)
|
||||||
|
if err == nil && f.lastModified.Before(ifModifiedSinceTime.Add(1*time.Second)) {
|
||||||
|
// Client's cached version is up to date
|
||||||
|
w.WriteHeader(http.StatusNotModified)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache other assets for up to 24 hours, but set Last-Modified too
|
||||||
|
w.Header().Set("Last-Modified", f.lastModifiedHeaderValue)
|
||||||
|
w.Header().Set("Cache-Control", "public, max-age=86400")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the asset is available pre-compressed
|
||||||
|
_, ok := f.preCompressed[r.URL.Path]
|
||||||
|
if ok {
|
||||||
|
// Add a "Vary" with "Accept-Encoding" so CDNs are aware that content is pre-compressed
|
||||||
|
w.Header().Add("Vary", "Accept-Encoding")
|
||||||
|
|
||||||
|
// Select the encoding if any
|
||||||
|
ext, ce := f.selectEncoding(r)
|
||||||
|
if ext != "" {
|
||||||
|
// Set the content type explicitly before changing the path
|
||||||
|
ct := mime.TypeByExtension(path.Ext(r.URL.Path))
|
||||||
|
if ct != "" {
|
||||||
|
w.Header().Set("Content-Type", ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the serve return the encoded content
|
||||||
|
w.Header().Set("Content-Encoding", ce)
|
||||||
|
r.URL.Path += "." + ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Last-Modified", f.lastModifiedHeaderValue)
|
|
||||||
w.Header().Set("Cache-Control", f.cacheControlHeaderValue)
|
|
||||||
|
|
||||||
http.FileServer(f.root).ServeHTTP(w, r)
|
http.FileServer(f.root).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FileServerWithCaching) selectEncoding(r *http.Request) (ext string, contentEnc string) {
|
||||||
|
available, ok := f.preCompressed[r.URL.Path]
|
||||||
|
if !ok {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the client accepts compressed files
|
||||||
|
acceptEncoding := strings.TrimSpace(strings.ToLower(r.Header.Get("Accept-Encoding")))
|
||||||
|
if acceptEncoding == "" {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer brotli over gzip when both are accepted.
|
||||||
|
if available.br && (acceptEncoding == "*" || acceptEncoding == "br" || strings.Contains(acceptEncoding, "br")) {
|
||||||
|
return "br", "br"
|
||||||
|
}
|
||||||
|
if available.gz && (acceptEncoding == "gzip" || strings.Contains(acceptEncoding, "gzip")) {
|
||||||
|
return "gz", "gzip"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isImmutableAsset(r *http.Request) bool {
|
||||||
|
switch {
|
||||||
|
// Fonts
|
||||||
|
case strings.HasPrefix(r.URL.Path, "/fonts/"):
|
||||||
|
return true
|
||||||
|
|
||||||
|
// Compiled SvelteKit assets
|
||||||
|
case strings.HasPrefix(r.URL.Path, "/_app/immutable/"):
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type preCompressedMap map[string]struct {
|
||||||
|
br bool
|
||||||
|
gz bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func listPreCompressedAssets(distFS fs.FS) (preCompressedMap, error) {
|
||||||
|
preCompressed := make(preCompressedMap, 0)
|
||||||
|
err := fs.WalkDir(distFS, ".", func(path string, d fs.DirEntry, walkErr error) error {
|
||||||
|
if walkErr != nil {
|
||||||
|
return walkErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(path, ".br"):
|
||||||
|
originalPath := "/" + strings.TrimSuffix(path, ".br")
|
||||||
|
entry := preCompressed[originalPath]
|
||||||
|
entry.br = true
|
||||||
|
preCompressed[originalPath] = entry
|
||||||
|
case strings.HasSuffix(path, ".gz"):
|
||||||
|
originalPath := "/" + strings.TrimSuffix(path, ".gz")
|
||||||
|
entry := preCompressed[originalPath]
|
||||||
|
entry.gz = true
|
||||||
|
preCompressed[originalPath] = entry
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return preCompressed, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ require (
|
|||||||
github.com/cenkalti/backoff/v5 v5.0.3
|
github.com/cenkalti/backoff/v5 v5.0.3
|
||||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
|
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
|
||||||
github.com/disintegration/imaging v1.6.2
|
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-sasl v0.0.0-20241020182733-b788ff22d5a6
|
||||||
github.com/emersion/go-smtp v0.24.0
|
github.com/emersion/go-smtp v0.24.0
|
||||||
github.com/gin-contrib/slog v1.2.0
|
github.com/gin-contrib/slog v1.2.0
|
||||||
@@ -74,6 +75,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // 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/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // 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/gopkg v0.1.3 // indirect
|
||||||
github.com/bytedance/sonic v1.15.0 // indirect
|
github.com/bytedance/sonic v1.15.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||||
@@ -123,6 +125,7 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/ncruces/go-strftime v1.0.0 // 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/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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_golang v1.23.2 // indirect
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0=
|
|||||||
github.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
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 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||||
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||||
@@ -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-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
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 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
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=
|
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3DfFi4EXdT+B+gTtzx8GC9xsc26Znk=
|
||||||
@@ -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/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 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
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 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
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=
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
@@ -320,6 +327,7 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT
|
|||||||
github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
|
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 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
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 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
|
||||||
@@ -385,6 +393,9 @@ golang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y=
|
|||||||
golang.org/x/arch v0.24.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
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-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.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
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 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
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 h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||||
@@ -392,34 +403,65 @@ golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkN
|
|||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
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/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 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
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-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.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
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 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
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.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
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 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
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-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-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-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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
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 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
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-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.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.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.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
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 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
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 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
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.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.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 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
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=
|
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 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type AlreadyInUseError struct {
|
|||||||
func (e *AlreadyInUseError) Error() string {
|
func (e *AlreadyInUseError) Error() string {
|
||||||
return e.Property + " is already in use"
|
return e.Property + " is already in use"
|
||||||
}
|
}
|
||||||
func (e *AlreadyInUseError) HttpStatusCode() int { return 400 }
|
func (e *AlreadyInUseError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
func (e *AlreadyInUseError) Is(target error) bool {
|
func (e *AlreadyInUseError) Is(target error) bool {
|
||||||
// Ignore the field property when checking if an error is of the type AlreadyInUseError
|
// Ignore the field property when checking if an error is of the type AlreadyInUseError
|
||||||
@@ -31,26 +31,26 @@ func (e *AlreadyInUseError) Is(target error) bool {
|
|||||||
type SetupAlreadyCompletedError struct{}
|
type SetupAlreadyCompletedError struct{}
|
||||||
|
|
||||||
func (e *SetupAlreadyCompletedError) Error() string { return "setup already completed" }
|
func (e *SetupAlreadyCompletedError) Error() string { return "setup already completed" }
|
||||||
func (e *SetupAlreadyCompletedError) HttpStatusCode() int { return 400 }
|
func (e *SetupAlreadyCompletedError) HttpStatusCode() int { return http.StatusConflict }
|
||||||
|
|
||||||
type TokenInvalidOrExpiredError struct{}
|
type TokenInvalidOrExpiredError struct{}
|
||||||
|
|
||||||
func (e *TokenInvalidOrExpiredError) Error() string { return "token is invalid or expired" }
|
func (e *TokenInvalidOrExpiredError) Error() string { return "token is invalid or expired" }
|
||||||
func (e *TokenInvalidOrExpiredError) HttpStatusCode() int { return 400 }
|
func (e *TokenInvalidOrExpiredError) HttpStatusCode() int { return http.StatusUnauthorized }
|
||||||
|
|
||||||
type DeviceCodeInvalid struct{}
|
type DeviceCodeInvalid struct{}
|
||||||
|
|
||||||
func (e *DeviceCodeInvalid) Error() string {
|
func (e *DeviceCodeInvalid) Error() string {
|
||||||
return "one time access code must be used on the device it was generated for"
|
return "one time access code must be used on the device it was generated for"
|
||||||
}
|
}
|
||||||
func (e *DeviceCodeInvalid) HttpStatusCode() int { return 400 }
|
func (e *DeviceCodeInvalid) HttpStatusCode() int { return http.StatusUnauthorized }
|
||||||
|
|
||||||
type TokenInvalidError struct{}
|
type TokenInvalidError struct{}
|
||||||
|
|
||||||
func (e *TokenInvalidError) Error() string {
|
func (e *TokenInvalidError) Error() string {
|
||||||
return "Token is invalid"
|
return "Token is invalid"
|
||||||
}
|
}
|
||||||
func (e *TokenInvalidError) HttpStatusCode() int { return 400 }
|
func (e *TokenInvalidError) HttpStatusCode() int { return http.StatusUnauthorized }
|
||||||
|
|
||||||
type OidcMissingAuthorizationError struct{}
|
type OidcMissingAuthorizationError struct{}
|
||||||
|
|
||||||
@@ -60,46 +60,51 @@ func (e *OidcMissingAuthorizationError) HttpStatusCode() int { return http.Statu
|
|||||||
type OidcGrantTypeNotSupportedError struct{}
|
type OidcGrantTypeNotSupportedError struct{}
|
||||||
|
|
||||||
func (e *OidcGrantTypeNotSupportedError) Error() string { return "grant type not supported" }
|
func (e *OidcGrantTypeNotSupportedError) Error() string { return "grant type not supported" }
|
||||||
func (e *OidcGrantTypeNotSupportedError) HttpStatusCode() int { return 400 }
|
func (e *OidcGrantTypeNotSupportedError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type OidcMissingClientCredentialsError struct{}
|
type OidcMissingClientCredentialsError struct{}
|
||||||
|
|
||||||
func (e *OidcMissingClientCredentialsError) Error() string { return "client id or secret not provided" }
|
func (e *OidcMissingClientCredentialsError) Error() string { return "client id or secret not provided" }
|
||||||
func (e *OidcMissingClientCredentialsError) HttpStatusCode() int { return 400 }
|
func (e *OidcMissingClientCredentialsError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type OidcClientSecretInvalidError struct{}
|
type OidcClientSecretInvalidError struct{}
|
||||||
|
|
||||||
func (e *OidcClientSecretInvalidError) Error() string { return "invalid client secret" }
|
func (e *OidcClientSecretInvalidError) Error() string { return "invalid client secret" }
|
||||||
func (e *OidcClientSecretInvalidError) HttpStatusCode() int { return 400 }
|
func (e *OidcClientSecretInvalidError) HttpStatusCode() int { return http.StatusUnauthorized }
|
||||||
|
|
||||||
type OidcClientAssertionInvalidError struct{}
|
type OidcClientAssertionInvalidError struct{}
|
||||||
|
|
||||||
func (e *OidcClientAssertionInvalidError) Error() string { return "invalid client assertion" }
|
func (e *OidcClientAssertionInvalidError) Error() string { return "invalid client assertion" }
|
||||||
func (e *OidcClientAssertionInvalidError) HttpStatusCode() int { return 400 }
|
func (e *OidcClientAssertionInvalidError) HttpStatusCode() int { return http.StatusUnauthorized }
|
||||||
|
|
||||||
type OidcInvalidAuthorizationCodeError struct{}
|
type OidcInvalidAuthorizationCodeError struct{}
|
||||||
|
|
||||||
func (e *OidcInvalidAuthorizationCodeError) Error() string { return "invalid authorization code" }
|
func (e *OidcInvalidAuthorizationCodeError) Error() string { return "invalid authorization code" }
|
||||||
func (e *OidcInvalidAuthorizationCodeError) HttpStatusCode() int { return 400 }
|
func (e *OidcInvalidAuthorizationCodeError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
|
type OidcClientNotFoundError struct{}
|
||||||
|
|
||||||
|
func (e *OidcClientNotFoundError) Error() string { return "client not found" }
|
||||||
|
func (e *OidcClientNotFoundError) HttpStatusCode() int { return http.StatusNotFound }
|
||||||
|
|
||||||
type OidcMissingCallbackURLError struct{}
|
type OidcMissingCallbackURLError struct{}
|
||||||
|
|
||||||
func (e *OidcMissingCallbackURLError) Error() string {
|
func (e *OidcMissingCallbackURLError) Error() string {
|
||||||
return "unable to detect callback url, it might be necessary for an admin to fix this"
|
return "unable to detect callback url, it might be necessary for an admin to fix this"
|
||||||
}
|
}
|
||||||
func (e *OidcMissingCallbackURLError) HttpStatusCode() int { return 400 }
|
func (e *OidcMissingCallbackURLError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type OidcInvalidCallbackURLError struct{}
|
type OidcInvalidCallbackURLError struct{}
|
||||||
|
|
||||||
func (e *OidcInvalidCallbackURLError) Error() string {
|
func (e *OidcInvalidCallbackURLError) Error() string {
|
||||||
return "invalid callback URL, it might be necessary for an admin to fix this"
|
return "invalid callback URL, it might be necessary for an admin to fix this"
|
||||||
}
|
}
|
||||||
func (e *OidcInvalidCallbackURLError) HttpStatusCode() int { return 400 }
|
func (e *OidcInvalidCallbackURLError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type FileTypeNotSupportedError struct{}
|
type FileTypeNotSupportedError struct{}
|
||||||
|
|
||||||
func (e *FileTypeNotSupportedError) Error() string { return "file type not supported" }
|
func (e *FileTypeNotSupportedError) Error() string { return "file type not supported" }
|
||||||
func (e *FileTypeNotSupportedError) HttpStatusCode() int { return 400 }
|
func (e *FileTypeNotSupportedError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type FileTooLargeError struct {
|
type FileTooLargeError struct {
|
||||||
MaxSize string
|
MaxSize string
|
||||||
@@ -280,6 +285,13 @@ func (e *APIKeyExpirationDateError) Error() string {
|
|||||||
}
|
}
|
||||||
func (e *APIKeyExpirationDateError) HttpStatusCode() int { return http.StatusBadRequest }
|
func (e *APIKeyExpirationDateError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
|
type APIKeyAuthNotAllowedError struct{}
|
||||||
|
|
||||||
|
func (e *APIKeyAuthNotAllowedError) Error() string {
|
||||||
|
return "API key authentication is not allowed for this endpoint"
|
||||||
|
}
|
||||||
|
func (e *APIKeyAuthNotAllowedError) HttpStatusCode() int { return http.StatusForbidden }
|
||||||
|
|
||||||
type OidcInvalidRefreshTokenError struct{}
|
type OidcInvalidRefreshTokenError struct{}
|
||||||
|
|
||||||
func (e *OidcInvalidRefreshTokenError) Error() string {
|
func (e *OidcInvalidRefreshTokenError) Error() string {
|
||||||
|
|||||||
@@ -26,12 +26,11 @@ func NewApiKeyController(group *gin.RouterGroup, authMiddleware *middleware.Auth
|
|||||||
uc := &ApiKeyController{apiKeyService: apiKeyService}
|
uc := &ApiKeyController{apiKeyService: apiKeyService}
|
||||||
|
|
||||||
apiKeyGroup := group.Group("/api-keys")
|
apiKeyGroup := group.Group("/api-keys")
|
||||||
apiKeyGroup.Use(authMiddleware.WithAdminNotRequired().Add())
|
|
||||||
{
|
{
|
||||||
apiKeyGroup.GET("", uc.listApiKeysHandler)
|
apiKeyGroup.GET("", authMiddleware.WithAdminNotRequired().Add(), uc.listApiKeysHandler)
|
||||||
apiKeyGroup.POST("", uc.createApiKeyHandler)
|
apiKeyGroup.POST("", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), uc.createApiKeyHandler)
|
||||||
apiKeyGroup.POST("/:id/renew", uc.renewApiKeyHandler)
|
apiKeyGroup.POST("/:id/renew", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), uc.renewApiKeyHandler)
|
||||||
apiKeyGroup.DELETE("/:id", uc.revokeApiKeyHandler)
|
apiKeyGroup.DELETE("/:id", authMiddleware.WithAdminNotRequired().Add(), uc.revokeApiKeyHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -335,11 +335,13 @@ func (oc *OidcController) introspectTokenHandler(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
creds.ClientID, creds.ClientSecret, ok = utils.OAuthClientBasicAuth(c.Request)
|
creds.ClientID, creds.ClientSecret, ok = utils.OAuthClientBasicAuth(c.Request)
|
||||||
if !ok {
|
if !ok {
|
||||||
// If there's no basic auth, check if we have a bearer token
|
// If there's no basic auth, check if we have a bearer token (used as client assertion)
|
||||||
bearer, ok := utils.BearerAuth(c.Request)
|
bearer, ok := utils.BearerAuth(c.Request)
|
||||||
if ok {
|
if ok {
|
||||||
creds.ClientAssertionType = service.ClientAssertionTypeJWTBearer
|
creds.ClientAssertionType = service.ClientAssertionTypeJWTBearer
|
||||||
creds.ClientAssertion = bearer
|
creds.ClientAssertion = bearer
|
||||||
|
// When using client assertions, client_id can be passed as a form field
|
||||||
|
creds.ClientID = input.ClientID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,8 +664,13 @@ func (oc *OidcController) updateAllowedUserGroupsHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) {
|
func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) {
|
||||||
|
// Per RFC 8628 (OAuth 2.0 Device Authorization Grant), parameters for the device authorization request MUST be sent in the body of the POST 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.OidcDeviceAuthorizationRequestDto
|
var input dto.OidcDeviceAuthorizationRequestDto
|
||||||
if err := c.ShouldBind(&input); err != nil {
|
err := c.ShouldBind(&input)
|
||||||
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ type OidcCreateTokensDto struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OidcIntrospectDto struct {
|
type OidcIntrospectDto struct {
|
||||||
Token string `form:"token" binding:"required"`
|
Token string `form:"token" binding:"required"`
|
||||||
|
ClientID string `form:"client_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OidcUpdateAllowedUserGroupsDto struct {
|
type OidcUpdateAllowedUserGroupsDto struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dto
|
|||||||
type SignUpDto struct {
|
type SignUpDto struct {
|
||||||
Username string `json:"username" binding:"required,username,min=2,max=50" unorm:"nfc"`
|
Username string `json:"username" binding:"required,username,min=2,max=50" unorm:"nfc"`
|
||||||
Email *string `json:"email" binding:"omitempty,email" unorm:"nfc"`
|
Email *string `json:"email" binding:"omitempty,email" unorm:"nfc"`
|
||||||
FirstName string `json:"firstName" binding:"required,min=1,max=50" unorm:"nfc"`
|
FirstName string `json:"firstName" binding:"max=50" unorm:"nfc"`
|
||||||
LastName string `json:"lastName" binding:"max=50" unorm:"nfc"`
|
LastName string `json:"lastName" binding:"max=50" unorm:"nfc"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ type UserCreateDto struct {
|
|||||||
Username string `json:"username" binding:"required,username,min=2,max=50" unorm:"nfc"`
|
Username string `json:"username" binding:"required,username,min=2,max=50" unorm:"nfc"`
|
||||||
Email *string `json:"email" binding:"omitempty,email" unorm:"nfc"`
|
Email *string `json:"email" binding:"omitempty,email" unorm:"nfc"`
|
||||||
EmailVerified bool `json:"emailVerified"`
|
EmailVerified bool `json:"emailVerified"`
|
||||||
FirstName string `json:"firstName" binding:"required,min=1,max=50" unorm:"nfc"`
|
FirstName string `json:"firstName" binding:"max=50" unorm:"nfc"`
|
||||||
LastName string `json:"lastName" binding:"max=50" unorm:"nfc"`
|
LastName string `json:"lastName" binding:"max=50" unorm:"nfc"`
|
||||||
DisplayName string `json:"displayName" binding:"required,min=1,max=100" unorm:"nfc"`
|
DisplayName string `json:"displayName" binding:"max=100" unorm:"nfc"`
|
||||||
IsAdmin bool `json:"isAdmin"`
|
IsAdmin bool `json:"isAdmin"`
|
||||||
Locale *string `json:"locale"`
|
Locale *string `json:"locale"`
|
||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
|
|||||||
@@ -33,14 +33,24 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: "Field validation for 'Username' failed on the 'required' tag",
|
wantErr: "Field validation for 'Username' failed on the 'required' tag",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "missing first name",
|
||||||
|
input: UserCreateDto{
|
||||||
|
Username: "testuser",
|
||||||
|
Email: new("test@example.com"),
|
||||||
|
LastName: "Doe",
|
||||||
|
},
|
||||||
|
wantErr: "",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "missing display name",
|
name: "missing display name",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
|
Username: "testuser",
|
||||||
Email: new("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
},
|
},
|
||||||
wantErr: "Field validation for 'DisplayName' failed on the 'required' tag",
|
wantErr: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "username contains invalid characters",
|
name: "username contains invalid characters",
|
||||||
@@ -73,7 +83,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
},
|
},
|
||||||
wantErr: "Field validation for 'FirstName' failed on the 'required' tag",
|
wantErr: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "last name too long",
|
name: "last name too long",
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
"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
|
// ValidateCallbackURL validates callback URLs with support for wildcards
|
||||||
func ValidateCallbackURL(raw string) bool {
|
func ValidateCallbackURL(raw string) bool {
|
||||||
// Don't validate if it contains a wildcard
|
err := utils.ValidateCallbackURLPattern(raw)
|
||||||
if strings.Contains(raw, "*") {
|
return err == nil
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(raw)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !u.IsAbs() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type AuthMiddleware struct {
|
|||||||
type AuthOptions struct {
|
type AuthOptions struct {
|
||||||
AdminRequired bool
|
AdminRequired bool
|
||||||
SuccessOptional bool
|
SuccessOptional bool
|
||||||
|
AllowApiKeyAuth bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthMiddleware(
|
func NewAuthMiddleware(
|
||||||
@@ -31,6 +32,7 @@ func NewAuthMiddleware(
|
|||||||
options: AuthOptions{
|
options: AuthOptions{
|
||||||
AdminRequired: true,
|
AdminRequired: true,
|
||||||
SuccessOptional: false,
|
SuccessOptional: false,
|
||||||
|
AllowApiKeyAuth: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +61,17 @@ func (m *AuthMiddleware) WithSuccessOptional() *AuthMiddleware {
|
|||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithApiKeyAuthDisabled disables API key authentication fallback and requires JWT auth.
|
||||||
|
func (m *AuthMiddleware) WithApiKeyAuthDisabled() *AuthMiddleware {
|
||||||
|
clone := &AuthMiddleware{
|
||||||
|
apiKeyMiddleware: m.apiKeyMiddleware,
|
||||||
|
jwtMiddleware: m.jwtMiddleware,
|
||||||
|
options: m.options,
|
||||||
|
}
|
||||||
|
clone.options.AllowApiKeyAuth = false
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
func (m *AuthMiddleware) Add() gin.HandlerFunc {
|
func (m *AuthMiddleware) Add() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
userID, isAdmin, err := m.jwtMiddleware.Verify(c, m.options.AdminRequired)
|
userID, isAdmin, err := m.jwtMiddleware.Verify(c, m.options.AdminRequired)
|
||||||
@@ -79,6 +92,21 @@ func (m *AuthMiddleware) Add() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !m.options.AllowApiKeyAuth {
|
||||||
|
if m.options.SuccessOptional {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Abort()
|
||||||
|
if c.GetHeader("X-API-Key") != "" {
|
||||||
|
_ = c.Error(&common.APIKeyAuthNotAllowedError{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = c.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// JWT auth failed, try API key auth
|
// JWT auth failed, try API key auth
|
||||||
userID, isAdmin, err = m.apiKeyMiddleware.Verify(c, m.options.AdminRequired)
|
userID, isAdmin, err = m.apiKeyMiddleware.Verify(c, m.options.AdminRequired)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
104
backend/internal/middleware/auth_middleware_test.go
Normal file
104
backend/internal/middleware/auth_middleware_test.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"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/model"
|
||||||
|
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||||
|
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithApiKeyAuthDisabled(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
originalEnvConfig := common.EnvConfig
|
||||||
|
defer func() {
|
||||||
|
common.EnvConfig = originalEnvConfig
|
||||||
|
}()
|
||||||
|
common.EnvConfig.AppURL = "https://test.example.com"
|
||||||
|
common.EnvConfig.EncryptionKey = []byte("0123456789abcdef0123456789abcdef")
|
||||||
|
|
||||||
|
db := testutils.NewDatabaseForTest(t)
|
||||||
|
|
||||||
|
appConfigService, err := service.NewAppConfigService(t.Context(), db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
jwtService, err := service.NewJwtService(t.Context(), db, appConfigService)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
userService := service.NewUserService(db, jwtService, nil, nil, appConfigService, nil, nil, nil, nil)
|
||||||
|
apiKeyService, err := service.NewApiKeyService(t.Context(), db, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
authMiddleware := NewAuthMiddleware(apiKeyService, userService, jwtService)
|
||||||
|
|
||||||
|
user := createUserForAuthMiddlewareTest(t, db)
|
||||||
|
jwtToken, err := jwtService.GenerateAccessToken(user)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, apiKeyToken, err := apiKeyService.CreateApiKey(t.Context(), user.ID, dto.ApiKeyCreateDto{
|
||||||
|
Name: "Middleware API Key",
|
||||||
|
ExpiresAt: datatype.DateTime(time.Now().Add(24 * time.Hour)),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
router := gin.New()
|
||||||
|
router.Use(NewErrorHandlerMiddleware().Add())
|
||||||
|
router.GET("/api/protected", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), func(c *gin.Context) {
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rejects API key auth when API key auth is disabled", func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/protected", nil)
|
||||||
|
req.Header.Set("X-API-Key", apiKeyToken)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusForbidden, recorder.Code)
|
||||||
|
|
||||||
|
var body map[string]string
|
||||||
|
err := json.Unmarshal(recorder.Body.Bytes(), &body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "API key authentication is not allowed for this endpoint", body["error"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("allows JWT auth when API key auth is disabled", func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/protected", nil)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+jwtToken)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusNoContent, recorder.Code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUserForAuthMiddlewareTest(t *testing.T, db *gorm.DB) model.User {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
email := "auth@example.com"
|
||||||
|
user := model.User{
|
||||||
|
Username: "auth-user",
|
||||||
|
Email: &email,
|
||||||
|
FirstName: "Auth",
|
||||||
|
LastName: "User",
|
||||||
|
DisplayName: "Auth User",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.Create(&user).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ func (u User) WebAuthnDisplayName() string {
|
|||||||
if u.DisplayName != "" {
|
if u.DisplayName != "" {
|
||||||
return u.DisplayName
|
return u.DisplayName
|
||||||
}
|
}
|
||||||
return u.FirstName + " " + u.LastName
|
return u.FullName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) WebAuthnIcon() string { return "" }
|
func (u User) WebAuthnIcon() string { return "" }
|
||||||
@@ -76,7 +76,16 @@ func (u User) WebAuthnCredentialDescriptors() (descriptors []protocol.Credential
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u User) FullName() string {
|
func (u User) FullName() string {
|
||||||
return u.FirstName + " " + u.LastName
|
fullname := strings.TrimSpace(u.FirstName + " " + u.LastName)
|
||||||
|
if fullname != "" {
|
||||||
|
return fullname
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.DisplayName != "" {
|
||||||
|
return u.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) Initials() string {
|
func (u User) Initials() string {
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ func (s *ApiKeyService) CreateApiKey(ctx context.Context, userID string, input d
|
|||||||
Create(&apiKey).
|
Create(&apiKey).
|
||||||
Error
|
Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||||
|
return model.ApiKey{}, "", &common.AlreadyInUseError{Property: "API key name"}
|
||||||
|
}
|
||||||
return model.ApiKey{}, "", err
|
return model.ApiKey{}, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1644,34 +1644,19 @@ func clientAuthCredentialsFromCreateTokensDto(d *dto.OidcCreateTokensDto) Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *OidcService) verifyClientCredentialsInternal(ctx context.Context, tx *gorm.DB, input ClientAuthCredentials, allowPublicClientsWithoutAuth bool) (client *model.OidcClient, err error) {
|
func (s *OidcService) verifyClientCredentialsInternal(ctx context.Context, tx *gorm.DB, input ClientAuthCredentials, allowPublicClientsWithoutAuth bool) (client *model.OidcClient, err error) {
|
||||||
isClientAssertion := input.ClientAssertionType == ClientAssertionTypeJWTBearer && input.ClientAssertion != ""
|
if input.ClientID == "" {
|
||||||
|
|
||||||
// Determine the client ID based on the authentication method
|
|
||||||
var clientID string
|
|
||||||
switch {
|
|
||||||
case isClientAssertion:
|
|
||||||
// Extract client ID from the JWT assertion's 'sub' claim
|
|
||||||
clientID, err = s.extractClientIDFromAssertion(input.ClientAssertion)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to extract client ID from assertion", "error", err)
|
|
||||||
return nil, &common.OidcClientAssertionInvalidError{}
|
|
||||||
}
|
|
||||||
case input.ClientID != "":
|
|
||||||
// Use the provided client ID for other authentication methods
|
|
||||||
clientID = input.ClientID
|
|
||||||
default:
|
|
||||||
return nil, &common.OidcMissingClientCredentialsError{}
|
return nil, &common.OidcMissingClientCredentialsError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the OIDC client's configuration
|
// Load the OIDC client's configuration
|
||||||
err = tx.
|
err = tx.
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
First(&client, "id = ?", clientID).
|
First(&client, "id = ?", input.ClientID).
|
||||||
Error
|
Error
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) && isClientAssertion {
|
slog.WarnContext(ctx, "Client not found", slog.String("client", input.ClientID))
|
||||||
return nil, &common.OidcClientAssertionInvalidError{}
|
return nil, &common.OidcClientNotFoundError{}
|
||||||
}
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1686,7 +1671,7 @@ func (s *OidcService) verifyClientCredentialsInternal(ctx context.Context, tx *g
|
|||||||
return client, nil
|
return client, nil
|
||||||
|
|
||||||
// Next, check if we want to use client assertions from federated identities
|
// Next, check if we want to use client assertions from federated identities
|
||||||
case isClientAssertion:
|
case input.ClientAssertionType == ClientAssertionTypeJWTBearer && input.ClientAssertion != "":
|
||||||
err = s.verifyClientAssertionFromFederatedIdentities(ctx, client, input)
|
err = s.verifyClientAssertionFromFederatedIdentities(ctx, client, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.WarnContext(ctx, "Invalid assertion for client", slog.String("client", client.ID), slog.Any("error", err))
|
slog.WarnContext(ctx, "Invalid assertion for client", slog.String("client", client.ID), slog.Any("error", err))
|
||||||
@@ -1783,36 +1768,20 @@ func (s *OidcService) verifyClientAssertionFromFederatedIdentities(ctx context.C
|
|||||||
// (Note: we don't use jwt.WithIssuer() because that would be redundant)
|
// (Note: we don't use jwt.WithIssuer() because that would be redundant)
|
||||||
_, err = jwt.Parse(assertion,
|
_, err = jwt.Parse(assertion,
|
||||||
jwt.WithValidate(true),
|
jwt.WithValidate(true),
|
||||||
|
|
||||||
jwt.WithAcceptableSkew(clockSkew),
|
jwt.WithAcceptableSkew(clockSkew),
|
||||||
jwt.WithKeySet(jwks, jws.WithInferAlgorithmFromKey(true), jws.WithUseDefault(true)),
|
jwt.WithKeySet(jwks, jws.WithInferAlgorithmFromKey(true), jws.WithUseDefault(true)),
|
||||||
jwt.WithAudience(audience),
|
jwt.WithAudience(audience),
|
||||||
jwt.WithSubject(subject),
|
jwt.WithSubject(subject),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("client assertion is not valid: %w", err)
|
return fmt.Errorf("client assertion could not be verified: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're here, the assertion is valid
|
// If we're here, the assertion is valid
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractClientIDFromAssertion extracts the client_id from the JWT assertion's 'sub' claim
|
|
||||||
func (s *OidcService) extractClientIDFromAssertion(assertion string) (string, error) {
|
|
||||||
// Parse the JWT without verification first to get the claims
|
|
||||||
insecureToken, err := jwt.ParseInsecure([]byte(assertion))
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to parse JWT assertion: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the subject claim which must be the client_id according to RFC 7523
|
|
||||||
sub, ok := insecureToken.Subject()
|
|
||||||
if !ok || sub == "" {
|
|
||||||
return "", fmt.Errorf("missing or invalid 'sub' claim in JWT assertion")
|
|
||||||
}
|
|
||||||
|
|
||||||
return sub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *OidcService) GetClientPreview(ctx context.Context, clientID string, userID string, scopes []string) (*dto.OidcClientPreviewDto, error) {
|
func (s *OidcService) GetClientPreview(ctx context.Context, clientID string, userID string, scopes []string) (*dto.OidcClientPreviewDto, error) {
|
||||||
tx := s.db.Begin()
|
tx := s.db.Begin()
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@@ -229,6 +229,12 @@ func TestOidcService_verifyClientCredentialsInternal(t *testing.T) {
|
|||||||
Subject: federatedClient.ID,
|
Subject: federatedClient.ID,
|
||||||
JWKS: federatedClientIssuer + "/jwks.json",
|
JWKS: federatedClientIssuer + "/jwks.json",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Issuer: "federated-issuer-2",
|
||||||
|
Audience: federatedClientAudience,
|
||||||
|
Subject: "my-federated-client",
|
||||||
|
JWKS: federatedClientIssuer + "/jwks.json",
|
||||||
|
},
|
||||||
{Issuer: federatedClientIssuerDefaults},
|
{Issuer: federatedClientIssuerDefaults},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -461,6 +467,43 @@ func TestOidcService_verifyClientCredentialsInternal(t *testing.T) {
|
|||||||
|
|
||||||
// Generate a token
|
// Generate a token
|
||||||
input := dto.OidcCreateTokensDto{
|
input := dto.OidcCreateTokensDto{
|
||||||
|
ClientID: federatedClient.ID,
|
||||||
|
ClientAssertion: string(signedToken),
|
||||||
|
ClientAssertionType: ClientAssertionTypeJWTBearer,
|
||||||
|
}
|
||||||
|
createdToken, err := s.createTokenFromClientCredentials(t.Context(), input)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, token)
|
||||||
|
|
||||||
|
// Verify the token
|
||||||
|
claims, err := s.jwtService.VerifyOAuthAccessToken(createdToken.AccessToken)
|
||||||
|
require.NoError(t, err, "Failed to verify generated token")
|
||||||
|
|
||||||
|
// Check the claims
|
||||||
|
subject, ok := claims.Subject()
|
||||||
|
_ = assert.True(t, ok, "User ID not found in token") &&
|
||||||
|
assert.Equal(t, "client-"+federatedClient.ID, subject, "Token subject should match federated client ID with prefix")
|
||||||
|
audience, ok := claims.Audience()
|
||||||
|
_ = assert.True(t, ok, "Audience not found in token") &&
|
||||||
|
assert.Equal(t, []string{federatedClient.ID}, audience, "Audience should contain the federated client ID")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Succeeds with valid assertion and custom subject", func(t *testing.T) {
|
||||||
|
// Create JWT for federated identity
|
||||||
|
token, err := jwt.NewBuilder().
|
||||||
|
Issuer("federated-issuer-2").
|
||||||
|
Audience([]string{federatedClientAudience}).
|
||||||
|
Subject("my-federated-client").
|
||||||
|
IssuedAt(time.Now()).
|
||||||
|
Expiration(time.Now().Add(10 * time.Minute)).
|
||||||
|
Build()
|
||||||
|
require.NoError(t, err)
|
||||||
|
signedToken, err := jwt.Sign(token, jwt.WithKey(jwa.ES256(), privateJWK))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Generate a token
|
||||||
|
input := dto.OidcCreateTokensDto{
|
||||||
|
ClientID: federatedClient.ID,
|
||||||
ClientAssertion: string(signedToken),
|
ClientAssertion: string(signedToken),
|
||||||
ClientAssertionType: ClientAssertionTypeJWTBearer,
|
ClientAssertionType: ClientAssertionTypeJWTBearer,
|
||||||
}
|
}
|
||||||
@@ -483,6 +526,7 @@ func TestOidcService_verifyClientCredentialsInternal(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Fails with invalid assertion", func(t *testing.T) {
|
t.Run("Fails with invalid assertion", func(t *testing.T) {
|
||||||
input := dto.OidcCreateTokensDto{
|
input := dto.OidcCreateTokensDto{
|
||||||
|
ClientID: confidentialClient.ID,
|
||||||
ClientAssertion: "invalid.jwt.token",
|
ClientAssertion: "invalid.jwt.token",
|
||||||
ClientAssertionType: ClientAssertionTypeJWTBearer,
|
ClientAssertionType: ClientAssertionTypeJWTBearer,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,31 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"strconv"
|
||||||
"strings"
|
"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) {
|
func GetCallbackURLFromList(urls []string, inputCallbackURL string) (callbackURL string, err error) {
|
||||||
// Special case for Loopback Interface Redirection. Quoting from RFC 8252 section 7.3:
|
// Special case for Loopback Interface Redirection. Quoting from RFC 8252 section 7.3:
|
||||||
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
||||||
@@ -17,17 +34,7 @@ func GetCallbackURLFromList(urls []string, inputCallbackURL string) (callbackURL
|
|||||||
// time of the request for loopback IP redirect URIs, to accommodate
|
// time of the request for loopback IP redirect URIs, to accommodate
|
||||||
// clients that obtain an available ephemeral port from the operating
|
// clients that obtain an available ephemeral port from the operating
|
||||||
// system at the time of the request.
|
// system at the time of the request.
|
||||||
loopbackCallbackURLWithoutPort := ""
|
loopbackCallbackURLWithoutPort := loopbackURLWithWildcardPort(inputCallbackURL)
|
||||||
u, _ := url.Parse(inputCallbackURL)
|
|
||||||
|
|
||||||
if u != nil && u.Scheme == "http" {
|
|
||||||
host := u.Hostname()
|
|
||||||
ip := net.ParseIP(host)
|
|
||||||
if host == "localhost" || (ip != nil && ip.IsLoopback()) {
|
|
||||||
u.Host = host
|
|
||||||
loopbackCallbackURLWithoutPort = u.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pattern := range urls {
|
for _, pattern := range urls {
|
||||||
// Try the original callback first
|
// Try the original callback first
|
||||||
@@ -54,6 +61,28 @@ func GetCallbackURLFromList(urls []string, inputCallbackURL string) (callbackURL
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loopbackURLWithWildcardPort(input string) string {
|
||||||
|
u, _ := url.Parse(input)
|
||||||
|
|
||||||
|
if u == nil || u.Scheme != "http" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
host := u.Hostname()
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if host != "localhost" && (ip == nil || !ip.IsLoopback()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// For IPv6 loopback hosts, brackets are required when serializing without a port.
|
||||||
|
if strings.Contains(host, ":") {
|
||||||
|
u.Host = "[" + host + "]"
|
||||||
|
} else {
|
||||||
|
u.Host = host
|
||||||
|
}
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
// matchCallbackURL checks if the input callback URL matches the given pattern.
|
// matchCallbackURL checks if the input callback URL matches the given pattern.
|
||||||
// It supports wildcard matching for paths and query parameters.
|
// It supports wildcard matching for paths and query parameters.
|
||||||
//
|
//
|
||||||
@@ -64,143 +93,176 @@ func matchCallbackURL(pattern string, inputCallbackURL string) (matches bool, er
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip fragment part
|
// Strip fragment part.
|
||||||
// The endpoint URI MUST NOT include a fragment component.
|
// The endpoint URI MUST NOT include a fragment component.
|
||||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2
|
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2
|
||||||
pattern, _, _ = strings.Cut(pattern, "#")
|
pattern, _, _ = strings.Cut(pattern, "#")
|
||||||
inputCallbackURL, _, _ = strings.Cut(inputCallbackURL, "#")
|
inputCallbackURL, _, _ = strings.Cut(inputCallbackURL, "#")
|
||||||
|
|
||||||
// Store and strip query part
|
// Store and strip query part
|
||||||
var patternQuery url.Values
|
pattern, patternQuery, err := extractQueryParams(pattern)
|
||||||
if i := strings.Index(pattern, "?"); i >= 0 {
|
if err != nil {
|
||||||
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 {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify query parameters
|
inputCallbackURL, inputQuery, err := extractQueryParams(inputCallbackURL)
|
||||||
if len(patternQuery) != len(inputQuery) {
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = normalizeToURLPatternStandard(pattern)
|
||||||
|
|
||||||
|
// Validate query params
|
||||||
|
v := validateQueryParams(patternQuery, inputQuery)
|
||||||
|
if !v {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 p.Test(inputCallbackURL, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// Additionally, it escapes ":" with a backslash inside IPv6 addresses
|
||||||
|
func normalizeToURLPatternStandard(pattern string) string {
|
||||||
|
patternBase, patternPath := extractPath(pattern)
|
||||||
|
|
||||||
|
var result strings.Builder
|
||||||
|
result.Grow(len(pattern) + 5) // Add 5 for some extra capacity, hoping to avoid many re-allocations
|
||||||
|
|
||||||
|
// First, process the base
|
||||||
|
|
||||||
|
// 0 = scheme
|
||||||
|
// 1 = hostname (optionally with username/password) - before IPv6 start (no `[` found)
|
||||||
|
// 2 = is matching IPv6 (until `]`)
|
||||||
|
// 3 = after hostname
|
||||||
|
var step int
|
||||||
|
for i := 0; i < len(patternBase); i++ {
|
||||||
|
switch step {
|
||||||
|
case 0:
|
||||||
|
if i > 3 && patternBase[i] == '/' && patternBase[i-1] == '/' && patternBase[i-2] == ':' {
|
||||||
|
// We just passed the scheme
|
||||||
|
step = 1
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
switch patternBase[i] {
|
||||||
|
case '/', ']':
|
||||||
|
// No IPv6, skip to end of this logic
|
||||||
|
step = 3
|
||||||
|
case '[':
|
||||||
|
// Start of IPv6 match
|
||||||
|
step = 2
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if patternBase[i] == '/' || patternBase[i] == ']' || patternBase[i] == '[' {
|
||||||
|
// End of IPv6 match
|
||||||
|
step = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
switch patternBase[i] {
|
||||||
|
case ':':
|
||||||
|
// We are matching an IPv6 block and there's a colon, so escape that
|
||||||
|
result.WriteByte('\\')
|
||||||
|
case '/', ']', '[':
|
||||||
|
// End of IPv6 match
|
||||||
|
step = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the byte
|
||||||
|
result.WriteByte(patternBase[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, process the path
|
||||||
|
for i := 0; i < len(patternPath); i++ {
|
||||||
|
if patternPath[i] == '*' {
|
||||||
|
// Replace globstar with a single asterisk
|
||||||
|
if i+1 < len(patternPath) && patternPath[i+1] == '*' {
|
||||||
|
result.WriteString("*")
|
||||||
|
i++ // skip next *
|
||||||
|
} else {
|
||||||
|
// Replace single asterisk with :p{index}
|
||||||
|
result.WriteString(":p")
|
||||||
|
result.WriteString(strconv.Itoa(i))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add the byte
|
||||||
|
result.WriteByte(patternPath[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPath(url string) (base string, path string) {
|
||||||
|
pathStart := -1
|
||||||
|
|
||||||
|
// Look for scheme:// first
|
||||||
|
i := strings.Index(url, "://")
|
||||||
|
if i >= 0 {
|
||||||
|
// Look for the next slash after scheme://
|
||||||
|
rest := url[i+3:]
|
||||||
|
if j := strings.IndexByte(rest, '/'); j >= 0 {
|
||||||
|
pathStart = i + 3 + j
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, first slash is path start
|
||||||
|
pathStart = strings.IndexByte(url, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
if pathStart >= 0 {
|
||||||
|
path = url[pathStart:]
|
||||||
|
base = url[:pathStart]
|
||||||
|
} else {
|
||||||
|
path = ""
|
||||||
|
base = url
|
||||||
|
}
|
||||||
|
|
||||||
|
return base, path
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractQueryParams(rawUrl string) (base string, query url.Values, err error) {
|
||||||
|
if i := strings.IndexByte(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 {
|
for patternKey, patternValues := range patternQuery {
|
||||||
inputValues, exists := inputQuery[patternKey]
|
inputValues, exists := inputQuery[patternKey]
|
||||||
if !exists {
|
if !exists {
|
||||||
return false, nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(patternValues) != len(inputValues) {
|
if len(patternValues) != len(inputValues) {
|
||||||
return false, nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range patternValues {
|
for i := range patternValues {
|
||||||
matched, err := path.Match(patternValues[i], inputValues[i])
|
matched, err := path.Match(patternValues[i], inputValues[i])
|
||||||
if err != nil || !matched {
|
if err != nil || !matched {
|
||||||
return false, err
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true
|
||||||
}
|
|
||||||
|
|
||||||
// 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("^")
|
|
||||||
|
|
||||||
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
|
|
||||||
} else {
|
|
||||||
// single * = [^/]* (no slash)
|
|
||||||
regexPattern.WriteString(`[^/]*`)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
regexPattern.WriteString(regexp.QuoteMeta(string(runes[i])))
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regexPattern.WriteString("$")
|
|
||||||
|
|
||||||
matched, err := regexp.MatchString(regexPattern.String(), input)
|
|
||||||
return matched, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 == '.'
|
|
||||||
}
|
|
||||||
|
|
||||||
pathStart := -1
|
|
||||||
|
|
||||||
// Look for scheme:// first
|
|
||||||
if i := strings.Index(s, "://"); i >= 0 {
|
|
||||||
// Look for the next slash after scheme://
|
|
||||||
rest := s[i+3:]
|
|
||||||
if j := strings.IndexRune(rest, '/'); j >= 0 {
|
|
||||||
pathStart = i + 3 + j
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Otherwise, first slash is path start
|
|
||||||
pathStart = strings.IndexRune(s, '/')
|
|
||||||
}
|
|
||||||
|
|
||||||
if pathStart >= 0 {
|
|
||||||
path = s[pathStart:]
|
|
||||||
base := s[:pathStart]
|
|
||||||
parts = strings.FieldsFunc(base, split)
|
|
||||||
} else {
|
|
||||||
parts = strings.FieldsFunc(s, split)
|
|
||||||
path = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts, path
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,142 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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 TestNormalizeToURLPatternStandard(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "exact URL unchanged",
|
||||||
|
input: "https://example.com/callback",
|
||||||
|
expected: "https://example.com/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single wildcard path segment converted to named parameter",
|
||||||
|
input: "https://example.com/api/*/callback",
|
||||||
|
expected: "https://example.com/api/:p5/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single wildcard in path suffix converted to named parameter",
|
||||||
|
input: "https://example.com/test*",
|
||||||
|
expected: "https://example.com/test:p5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "globstar converted to single asterisk",
|
||||||
|
input: "https://example.com/**/callback",
|
||||||
|
expected: "https://example.com/*/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed globstar and single wildcard conversion",
|
||||||
|
input: "https://example.com/**/v1/**/callback/*",
|
||||||
|
expected: "https://example.com/*/v1/*/callback/:p19",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "URL without path unchanged",
|
||||||
|
input: "https://example.com",
|
||||||
|
expected: "https://example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative path conversion",
|
||||||
|
input: "/foo/*/bar",
|
||||||
|
expected: "/foo/:p5/bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wildcard in hostname is not normalized by this function",
|
||||||
|
input: "https://*.example.com/callback",
|
||||||
|
expected: "https://*.example.com/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 hostname escapes all colons inside address",
|
||||||
|
input: "https://[2001:db8:1:1::a:1]/callback",
|
||||||
|
expected: "https://[2001\\:db8\\:1\\:1\\:\\:a\\:1]/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 hostname with port escapes only address colons",
|
||||||
|
input: "https://[::1]:8080/callback",
|
||||||
|
expected: "https://[\\:\\:1]:8080/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wildcard in query is converted when query is part of input",
|
||||||
|
input: "https://example.com/callback?code=*",
|
||||||
|
expected: "https://example.com/callback?code=:p15",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.expected, normalizeToURLPatternStandard(tt.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMatchCallbackURL(t *testing.T) {
|
func TestMatchCallbackURL(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -27,6 +163,18 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
"https://example.com/callback",
|
"https://example.com/callback",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"exact match - IPv4",
|
||||||
|
"https://10.1.0.1/callback",
|
||||||
|
"https://10.1.0.1/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exact match - IPv6",
|
||||||
|
"https://[2001:db8:1:1::a:1]/callback",
|
||||||
|
"https://[2001:db8:1:1::a:1]/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
// Scheme
|
// Scheme
|
||||||
{
|
{
|
||||||
@@ -111,6 +259,30 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
"https://example.com:8080/callback",
|
"https://example.com:8080/callback",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"wildcard port - IPv4",
|
||||||
|
"https://10.1.0.1:*/callback",
|
||||||
|
"https://10.1.0.1:8080/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partial wildcard in port prefix - IPv4",
|
||||||
|
"https://10.1.0.1:80*/callback",
|
||||||
|
"https://10.1.0.1:8080/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wildcard port - IPv6",
|
||||||
|
"https://[2001:db8:1:1::a:1]:*/callback",
|
||||||
|
"https://[2001:db8:1:1::a:1]:8080/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partial wildcard in port prefix - IPv6",
|
||||||
|
"https://[2001:db8:1:1::a:1]:80*/callback",
|
||||||
|
"https://[2001:db8:1:1::a:1]:8080/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
{
|
{
|
||||||
@@ -131,6 +303,18 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
"https://example.com/callback",
|
"https://example.com/callback",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"wildcard entire path - IPv4",
|
||||||
|
"https://10.1.0.1/*",
|
||||||
|
"https://10.1.0.1/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wildcard entire path - IPv6",
|
||||||
|
"https://[2001:db8:1:1::a:1]/*",
|
||||||
|
"https://[2001:db8:1:1::a:1]/callback",
|
||||||
|
true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"partial wildcard in path prefix",
|
"partial wildcard in path prefix",
|
||||||
"https://example.com/test*",
|
"https://example.com/test*",
|
||||||
@@ -187,12 +371,6 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
"https://example.com/callback",
|
"https://example.com/callback",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"unexpected credentials",
|
|
||||||
"https://example.com/callback",
|
|
||||||
"https://user:pass@example.com/callback",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"wildcard password",
|
"wildcard password",
|
||||||
"https://user:*@example.com/callback",
|
"https://user:*@example.com/callback",
|
||||||
@@ -347,7 +525,7 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
"backslash instead of forward slash",
|
"backslash instead of forward slash",
|
||||||
"https://example.com/callback",
|
"https://example.com/callback",
|
||||||
"https://example.com\\callback",
|
"https://example.com\\callback",
|
||||||
false,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"double slash in hostname (protocol smuggling)",
|
"double slash in hostname (protocol smuggling)",
|
||||||
@@ -370,10 +548,11 @@ func TestMatchCallbackURL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
matches, err := matchCallbackURL(tt.pattern, tt.input)
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
require.NoError(t, err, tt.name)
|
matches, err := matchCallbackURL(tt.pattern, tt.input)
|
||||||
assert.Equal(t, tt.shouldMatch, matches, tt.name)
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.shouldMatch, matches)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,14 +586,21 @@ func TestGetCallbackURLFromList_LoopbackSpecialHandling(t *testing.T) {
|
|||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6 loopback with dynamic port",
|
name: "IPv6 loopback with dynamic port - exact match",
|
||||||
urls: []string{"http://[::1]/callback"},
|
urls: []string{"http://[::1]/callback"},
|
||||||
inputCallbackURL: "http://[::1]:8080/callback",
|
inputCallbackURL: "http://[::1]:8080/callback",
|
||||||
expectedURL: "http://[::1]:8080/callback",
|
expectedURL: "http://[::1]:8080/callback",
|
||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6 loopback with wildcard path",
|
name: "IPv6 loopback with same port - exact match",
|
||||||
|
urls: []string{"http://[::1]:8080/callback"},
|
||||||
|
inputCallbackURL: "http://[::1]:8080/callback",
|
||||||
|
expectedURL: "http://[::1]:8080/callback",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback with path match",
|
||||||
urls: []string{"http://[::1]/auth/*"},
|
urls: []string{"http://[::1]/auth/*"},
|
||||||
inputCallbackURL: "http://[::1]:8080/auth/callback",
|
inputCallbackURL: "http://[::1]:8080/auth/callback",
|
||||||
expectedURL: "http://[::1]:8080/auth/callback",
|
expectedURL: "http://[::1]:8080/auth/callback",
|
||||||
@@ -441,6 +627,20 @@ func TestGetCallbackURLFromList_LoopbackSpecialHandling(t *testing.T) {
|
|||||||
expectedURL: "http://127.0.0.1:3000/auth/callback",
|
expectedURL: "http://127.0.0.1:3000/auth/callback",
|
||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "loopback with path port",
|
||||||
|
urls: []string{"http://127.0.0.1:*/auth/callback"},
|
||||||
|
inputCallbackURL: "http://127.0.0.1:3000/auth/callback",
|
||||||
|
expectedURL: "http://127.0.0.1:3000/auth/callback",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback with path port",
|
||||||
|
urls: []string{"http://[::1]:*/auth/callback"},
|
||||||
|
inputCallbackURL: "http://[::1]:3000/auth/callback",
|
||||||
|
expectedURL: "http://[::1]:3000/auth/callback",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "loopback with path mismatch",
|
name: "loopback with path mismatch",
|
||||||
urls: []string{"http://127.0.0.1/callback"},
|
urls: []string{"http://127.0.0.1/callback"},
|
||||||
@@ -484,6 +684,76 @@ func TestGetCallbackURLFromList_LoopbackSpecialHandling(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoopbackURLWithWildcardPort(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "localhost http with port strips port",
|
||||||
|
input: "http://localhost:3000/callback",
|
||||||
|
output: "http://localhost/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "localhost http without port stays same",
|
||||||
|
input: "http://localhost/callback",
|
||||||
|
output: "http://localhost/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 loopback with port strips port",
|
||||||
|
input: "http://127.0.0.1:8080/callback",
|
||||||
|
output: "http://127.0.0.1/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 loopback without port stays same",
|
||||||
|
input: "http://127.0.0.1/callback",
|
||||||
|
output: "http://127.0.0.1/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback with port strips port and keeps brackets",
|
||||||
|
input: "http://[::1]:8080/callback",
|
||||||
|
output: "http://[::1]/callback",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback preserves path query and fragment",
|
||||||
|
input: "http://[::1]:8080/auth/callback?code=123#state",
|
||||||
|
output: "http://[::1]/auth/callback?code=123#state",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "https loopback returns empty",
|
||||||
|
input: "https://127.0.0.1:8080/callback",
|
||||||
|
output: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non loopback host returns empty",
|
||||||
|
input: "http://example.com:8080/callback",
|
||||||
|
output: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non loopback IP returns empty",
|
||||||
|
input: "http://192.168.1.10:8080/callback",
|
||||||
|
output: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "malformed URL returns empty",
|
||||||
|
input: "http://[::1:8080/callback",
|
||||||
|
output: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative URL returns empty",
|
||||||
|
input: "/callback",
|
||||||
|
output: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.output, loopbackURLWithWildcardPort(tt.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetCallbackURLFromList_MultiplePatterns(t *testing.T) {
|
func TestGetCallbackURLFromList_MultiplePatterns(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -553,246 +823,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")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -5,4 +5,5 @@ yarn.lock
|
|||||||
|
|
||||||
# Compiled files
|
# Compiled files
|
||||||
.svelte-kit/
|
.svelte-kit/
|
||||||
build/
|
build/
|
||||||
|
src/lib/paraglide/messages
|
||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Zadejte kód, který byl zobrazen v předchozím kroku.",
|
"enter_code_displayed_in_previous_step": "Zadejte kód, který byl zobrazen v předchozím kroku.",
|
||||||
"authorize": "Autorizovat",
|
"authorize": "Autorizovat",
|
||||||
"federated_client_credentials": "Údaje o klientovi ve federaci",
|
"federated_client_credentials": "Údaje o klientovi ve federaci",
|
||||||
"federated_client_credentials_description": "Pomocí federovaných přihlašovacích údajů klienta můžete ověřit klienty OIDC pomocí JWT tokenů vydaných třetí stranou.",
|
|
||||||
"add_federated_client_credential": "Přidat údaje federovaného klienta",
|
"add_federated_client_credential": "Přidat údaje federovaného klienta",
|
||||||
"add_another_federated_client_credential": "Přidat dalšího federovaného klienta",
|
"add_another_federated_client_credential": "Přidat dalšího federovaného klienta",
|
||||||
"oidc_allowed_group_count": "Počet povolených skupin",
|
"oidc_allowed_group_count": "Počet povolených skupin",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Indtast koden, der blev vist i det forrige trin.",
|
"enter_code_displayed_in_previous_step": "Indtast koden, der blev vist i det forrige trin.",
|
||||||
"authorize": "Godkend",
|
"authorize": "Godkend",
|
||||||
"federated_client_credentials": "Federated klientlegitimationsoplysninger",
|
"federated_client_credentials": "Federated klientlegitimationsoplysninger",
|
||||||
"federated_client_credentials_description": "Ved hjælp af federated klientlegitimationsoplysninger kan du godkende OIDC-klienter med JWT-tokens udstedt af tredjepartsudbydere.",
|
|
||||||
"add_federated_client_credential": "Tilføj federated klientlegitimation",
|
"add_federated_client_credential": "Tilføj federated klientlegitimation",
|
||||||
"add_another_federated_client_credential": "Tilføj endnu en federated klientlegitimation",
|
"add_another_federated_client_credential": "Tilføj endnu en federated klientlegitimation",
|
||||||
"oidc_allowed_group_count": "Tilladt antal grupper",
|
"oidc_allowed_group_count": "Tilladt antal grupper",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Gib den Code ein, der im vorherigen Schritt angezeigt wurde.",
|
"enter_code_displayed_in_previous_step": "Gib den Code ein, der im vorherigen Schritt angezeigt wurde.",
|
||||||
"authorize": "Autorisieren",
|
"authorize": "Autorisieren",
|
||||||
"federated_client_credentials": "Federated Client Credentials",
|
"federated_client_credentials": "Federated Client Credentials",
|
||||||
"federated_client_credentials_description": "Mit Hilfe von Verbund-Client-Anmeldeinformationen kannst du OIDC-Clients mit JWT-Tokens authentifizieren, die von Drittanbietern ausgestellt wurden.",
|
|
||||||
"add_federated_client_credential": "Föderierte Client-Anmeldeinfos hinzufügen",
|
"add_federated_client_credential": "Föderierte Client-Anmeldeinfos hinzufügen",
|
||||||
"add_another_federated_client_credential": "Weitere Anmeldeinformationen für einen Verbundclient hinzufügen",
|
"add_another_federated_client_credential": "Weitere Anmeldeinformationen für einen Verbundclient hinzufügen",
|
||||||
"oidc_allowed_group_count": "Erlaubte Gruppenanzahl",
|
"oidc_allowed_group_count": "Erlaubte Gruppenanzahl",
|
||||||
|
|||||||
@@ -365,7 +365,7 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
||||||
"authorize": "Authorize",
|
"authorize": "Authorize",
|
||||||
"federated_client_credentials": "Federated Client Credentials",
|
"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.",
|
"federated_client_credentials_description": "Federated client credentials allow authenticating OIDC clients without managing long-lived secrets. They leverage JWT tokens issued by third-party authorities for client assertions, e.g. workload identity tokens.",
|
||||||
"add_federated_client_credential": "Add Federated Client Credential",
|
"add_federated_client_credential": "Add Federated Client Credential",
|
||||||
"add_another_federated_client_credential": "Add another federated client credential",
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
"oidc_allowed_group_count": "Allowed Group Count",
|
"oidc_allowed_group_count": "Allowed Group Count",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Introduce el código que se mostró en el paso anterior.",
|
"enter_code_displayed_in_previous_step": "Introduce el código que se mostró en el paso anterior.",
|
||||||
"authorize": "Autorizar",
|
"authorize": "Autorizar",
|
||||||
"federated_client_credentials": "Credenciales de cliente federadas",
|
"federated_client_credentials": "Credenciales de cliente federadas",
|
||||||
"federated_client_credentials_description": "Mediante credenciales de cliente federadas, puedes autenticar clientes OIDC utilizando tokens JWT emitidos por autoridades de terceros.",
|
|
||||||
"add_federated_client_credential": "Añadir credenciales de cliente federado",
|
"add_federated_client_credential": "Añadir credenciales de cliente federado",
|
||||||
"add_another_federated_client_credential": "Añadir otra credencial de cliente federado",
|
"add_another_federated_client_credential": "Añadir otra credencial de cliente federado",
|
||||||
"oidc_allowed_group_count": "Recuento de grupos permitidos",
|
"oidc_allowed_group_count": "Recuento de grupos permitidos",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
||||||
"authorize": "Authorize",
|
"authorize": "Authorize",
|
||||||
"federated_client_credentials": "Federated Client Credentials",
|
"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_federated_client_credential": "Add Federated Client Credential",
|
||||||
"add_another_federated_client_credential": "Add another federated client credential",
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
"oidc_allowed_group_count": "Allowed Group Count",
|
"oidc_allowed_group_count": "Allowed Group Count",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Syötä edellisessä vaiheessa näkynyt koodi.",
|
"enter_code_displayed_in_previous_step": "Syötä edellisessä vaiheessa näkynyt koodi.",
|
||||||
"authorize": "Salli",
|
"authorize": "Salli",
|
||||||
"federated_client_credentials": "Federoidut asiakastunnukset",
|
"federated_client_credentials": "Federoidut asiakastunnukset",
|
||||||
"federated_client_credentials_description": "Yhdistettyjen asiakastunnistetietojen avulla voit todentaa OIDC-asiakkaat kolmannen osapuolen myöntämillä JWT-tunnuksilla.",
|
|
||||||
"add_federated_client_credential": "Lisää federoitu asiakastunnus",
|
"add_federated_client_credential": "Lisää federoitu asiakastunnus",
|
||||||
"add_another_federated_client_credential": "Lisää toinen federoitu asiakastunnus",
|
"add_another_federated_client_credential": "Lisää toinen federoitu asiakastunnus",
|
||||||
"oidc_allowed_group_count": "Sallittujen ryhmien määrä",
|
"oidc_allowed_group_count": "Sallittujen ryhmien määrä",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Entrez le code affiché à l'étape précédente.",
|
"enter_code_displayed_in_previous_step": "Entrez le code affiché à l'étape précédente.",
|
||||||
"authorize": "Autoriser",
|
"authorize": "Autoriser",
|
||||||
"federated_client_credentials": "Identifiants client fédérés",
|
"federated_client_credentials": "Identifiants client fédérés",
|
||||||
"federated_client_credentials_description": "Avec des identifiants clients fédérés, vous pouvez authentifier des clients OIDC avec des tokens JWT émis par des autorités tierces.",
|
|
||||||
"add_federated_client_credential": "Ajouter un identifiant client fédéré",
|
"add_federated_client_credential": "Ajouter un identifiant client fédéré",
|
||||||
"add_another_federated_client_credential": "Ajouter un autre identifiant client fédéré",
|
"add_another_federated_client_credential": "Ajouter un autre identifiant client fédéré",
|
||||||
"oidc_allowed_group_count": "Nombre de groupes autorisés",
|
"oidc_allowed_group_count": "Nombre de groupes autorisés",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Inserisci il codice visualizzato nel passaggio precedente.",
|
"enter_code_displayed_in_previous_step": "Inserisci il codice visualizzato nel passaggio precedente.",
|
||||||
"authorize": "Autorizza",
|
"authorize": "Autorizza",
|
||||||
"federated_client_credentials": "Identità Federate",
|
"federated_client_credentials": "Identità Federate",
|
||||||
"federated_client_credentials_description": "Utilizzando identità federate, è possibile autenticare i client OIDC utilizzando i token JWT emessi da autorità di terze parti.",
|
|
||||||
"add_federated_client_credential": "Aggiungi Identità Federata",
|
"add_federated_client_credential": "Aggiungi Identità Federata",
|
||||||
"add_another_federated_client_credential": "Aggiungi un'altra identità federata",
|
"add_another_federated_client_credential": "Aggiungi un'altra identità federata",
|
||||||
"oidc_allowed_group_count": "Numero Gruppi Consentiti",
|
"oidc_allowed_group_count": "Numero Gruppi Consentiti",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "前のステップで表示されたコードを入力してください。",
|
"enter_code_displayed_in_previous_step": "前のステップで表示されたコードを入力してください。",
|
||||||
"authorize": "Authorize",
|
"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_federated_client_credential": "Add Federated Client Credential",
|
||||||
"add_another_federated_client_credential": "Add another federated client credential",
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
"oidc_allowed_group_count": "許可されたグループ数",
|
"oidc_allowed_group_count": "許可されたグループ数",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "이전 단계에 표시된 코드를 입력하세요.",
|
"enter_code_displayed_in_previous_step": "이전 단계에 표시된 코드를 입력하세요.",
|
||||||
"authorize": "승인",
|
"authorize": "승인",
|
||||||
"federated_client_credentials": "연동 클라이언트 자격 증명",
|
"federated_client_credentials": "연동 클라이언트 자격 증명",
|
||||||
"federated_client_credentials_description": "연동 클라이언트 자격 증명을 이용하여, OIDC 클라이언트를 제3자 인증 기관에서 발급한 JWT 토큰을 이용해 인증할 수 있습니다.",
|
|
||||||
"add_federated_client_credential": "연동 클라이언트 자격 증명 추가",
|
"add_federated_client_credential": "연동 클라이언트 자격 증명 추가",
|
||||||
"add_another_federated_client_credential": "다른 연동 클라이언트 자격 증명 추가",
|
"add_another_federated_client_credential": "다른 연동 클라이언트 자격 증명 추가",
|
||||||
"oidc_allowed_group_count": "허용된 그룹 수",
|
"oidc_allowed_group_count": "허용된 그룹 수",
|
||||||
|
|||||||
525
frontend/messages/lv.json
Normal file
525
frontend/messages/lv.json
Normal 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": "Federated client credentials allow authenticating OIDC clients without managing long-lived secrets. They leverage JWT tokens issued by third-party authorities for client assertions, e.g. workload identity tokens.",
|
||||||
|
"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."
|
||||||
|
}
|
||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Voer de code in die in de vorige stap werd getoond.",
|
"enter_code_displayed_in_previous_step": "Voer de code in die in de vorige stap werd getoond.",
|
||||||
"authorize": "Autoriseren",
|
"authorize": "Autoriseren",
|
||||||
"federated_client_credentials": "Federatieve clientreferenties",
|
"federated_client_credentials": "Federatieve clientreferenties",
|
||||||
"federated_client_credentials_description": "Met federatieve clientreferenties kun je OIDC-clients verifiëren met JWT-tokens die zijn uitgegeven door andere instanties.",
|
|
||||||
"add_federated_client_credential": "Federatieve clientreferenties toevoegen",
|
"add_federated_client_credential": "Federatieve clientreferenties toevoegen",
|
||||||
"add_another_federated_client_credential": "Voeg nog een federatieve clientreferentie toe",
|
"add_another_federated_client_credential": "Voeg nog een federatieve clientreferentie toe",
|
||||||
"oidc_allowed_group_count": "Aantal groepen met toegang",
|
"oidc_allowed_group_count": "Aantal groepen met toegang",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
||||||
"authorize": "Authorize",
|
"authorize": "Authorize",
|
||||||
"federated_client_credentials": "Federated Client Credentials",
|
"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_federated_client_credential": "Add Federated Client Credential",
|
||||||
"add_another_federated_client_credential": "Add another federated client credential",
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
"oidc_allowed_group_count": "Allowed Group Count",
|
"oidc_allowed_group_count": "Allowed Group Count",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Wprowadź kod wyświetlony w poprzednim kroku.",
|
"enter_code_displayed_in_previous_step": "Wprowadź kod wyświetlony w poprzednim kroku.",
|
||||||
"authorize": "Autoryzuj",
|
"authorize": "Autoryzuj",
|
||||||
"federated_client_credentials": "Połączone poświadczenia klienta",
|
"federated_client_credentials": "Połączone poświadczenia klienta",
|
||||||
"federated_client_credentials_description": "Korzystając z połączonych poświadczeń klienta, możecie uwierzytelnić klientów OIDC za pomocą tokenów JWT wydanych przez zewnętrzne organy.",
|
|
||||||
"add_federated_client_credential": "Dodaj poświadczenia klienta federacyjnego",
|
"add_federated_client_credential": "Dodaj poświadczenia klienta federacyjnego",
|
||||||
"add_another_federated_client_credential": "Dodaj kolejne poświadczenia klienta federacyjnego",
|
"add_another_federated_client_credential": "Dodaj kolejne poświadczenia klienta federacyjnego",
|
||||||
"oidc_allowed_group_count": "Dopuszczalna liczba grup",
|
"oidc_allowed_group_count": "Dopuszczalna liczba grup",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Digite o código que apareceu na etapa anterior.",
|
"enter_code_displayed_in_previous_step": "Digite o código que apareceu na etapa anterior.",
|
||||||
"authorize": "Autorizar",
|
"authorize": "Autorizar",
|
||||||
"federated_client_credentials": "Credenciais de Cliente Federadas",
|
"federated_client_credentials": "Credenciais de Cliente Federadas",
|
||||||
"federated_client_credentials_description": "Ao utilizar credenciais de cliente federadas, é possível autenticar clientes OIDC usando tokens JWT emitidos por autoridades de terceiros.",
|
|
||||||
"add_federated_client_credential": "Adicionar credencial de cliente federado",
|
"add_federated_client_credential": "Adicionar credencial de cliente federado",
|
||||||
"add_another_federated_client_credential": "Adicionar outra credencial de cliente federado",
|
"add_another_federated_client_credential": "Adicionar outra credencial de cliente federado",
|
||||||
"oidc_allowed_group_count": "Total de grupos permitidos",
|
"oidc_allowed_group_count": "Total de grupos permitidos",
|
||||||
|
|||||||
525
frontend/messages/pt.json
Normal file
525
frontend/messages/pt.json
Normal 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": "Federated client credentials allow authenticating OIDC clients without managing long-lived secrets. They leverage JWT tokens issued by third-party authorities for client assertions, e.g. workload identity tokens.",
|
||||||
|
"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."
|
||||||
|
}
|
||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Введите код, который был отображен на предыдущем шаге.",
|
"enter_code_displayed_in_previous_step": "Введите код, который был отображен на предыдущем шаге.",
|
||||||
"authorize": "Авторизовать",
|
"authorize": "Авторизовать",
|
||||||
"federated_client_credentials": "Федеративные учетные данные клиента",
|
"federated_client_credentials": "Федеративные учетные данные клиента",
|
||||||
"federated_client_credentials_description": "Используя федеративные учетные данные клиента, вы можете аутентифицировать клиентов OIDC с помощью токенов JWT, выпущенных сторонними поставщиками удостоверений.",
|
|
||||||
"add_federated_client_credential": "Добавить федеративные учетные данные клиента",
|
"add_federated_client_credential": "Добавить федеративные учетные данные клиента",
|
||||||
"add_another_federated_client_credential": "Добавить другие федеративные учетные данные клиента",
|
"add_another_federated_client_credential": "Добавить другие федеративные учетные данные клиента",
|
||||||
"oidc_allowed_group_count": "Число разрешенных групп",
|
"oidc_allowed_group_count": "Число разрешенных групп",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Ange koden som visades i föregående steg.",
|
"enter_code_displayed_in_previous_step": "Ange koden som visades i föregående steg.",
|
||||||
"authorize": "Godkänn",
|
"authorize": "Godkänn",
|
||||||
"federated_client_credentials": "Federerade klientuppgifter",
|
"federated_client_credentials": "Federerade klientuppgifter",
|
||||||
"federated_client_credentials_description": "Med hjälp av federerade klientuppgifter kan du autentisera OIDC-klienter med JWT-tokens som utfärdats av externa auktoriteter.",
|
|
||||||
"add_federated_client_credential": "Lägg till federerad klientuppgift",
|
"add_federated_client_credential": "Lägg till federerad klientuppgift",
|
||||||
"add_another_federated_client_credential": "Lägg till ytterligare en federerad klientuppgift",
|
"add_another_federated_client_credential": "Lägg till ytterligare en federerad klientuppgift",
|
||||||
"oidc_allowed_group_count": "Tillåtet antal grupper",
|
"oidc_allowed_group_count": "Tillåtet antal grupper",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Önceki adımda görüntülenen kodu girin.",
|
"enter_code_displayed_in_previous_step": "Önceki adımda görüntülenen kodu girin.",
|
||||||
"authorize": "Yetkilendir",
|
"authorize": "Yetkilendir",
|
||||||
"federated_client_credentials": "Birleştirilmiş İstemci Kimlik Bilgileri",
|
"federated_client_credentials": "Birleştirilmiş İstemci Kimlik Bilgileri",
|
||||||
"federated_client_credentials_description": "Birleşik istemci kimlik bilgilerini kullanarak, üçüncü taraf otoriteleri tarafından verilen JWT token'ları kullanarak OIDC istemcilerinin kimliklerini doğrulayabilirsiniz.",
|
|
||||||
"add_federated_client_credential": "Birleştirilmiş İstemci Kimlik Bilgisi Ekle",
|
"add_federated_client_credential": "Birleştirilmiş İstemci Kimlik Bilgisi Ekle",
|
||||||
"add_another_federated_client_credential": "Başka bir birleştirilmiş istemci kimlik bilgisi ekle",
|
"add_another_federated_client_credential": "Başka bir birleştirilmiş istemci kimlik bilgisi ekle",
|
||||||
"oidc_allowed_group_count": "İzin Verilen Grup Sayısı",
|
"oidc_allowed_group_count": "İzin Verilen Grup Sayısı",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Введіть код, який було показано на попередньому кроці.",
|
"enter_code_displayed_in_previous_step": "Введіть код, який було показано на попередньому кроці.",
|
||||||
"authorize": "Авторизувати",
|
"authorize": "Авторизувати",
|
||||||
"federated_client_credentials": "Федеративні облікові дані клієнта",
|
"federated_client_credentials": "Федеративні облікові дані клієнта",
|
||||||
"federated_client_credentials_description": "За допомогою федеративних облікових даних клієнта ви можете автентифікувати клієнтів OIDC за допомогою токенів JWT, виданих третіми сторонами.",
|
|
||||||
"add_federated_client_credential": "Додати федеративний обліковий запис клієнта",
|
"add_federated_client_credential": "Додати федеративний обліковий запис клієнта",
|
||||||
"add_another_federated_client_credential": "Додати ще один федеративний обліковий запис клієнта",
|
"add_another_federated_client_credential": "Додати ще один федеративний обліковий запис клієнта",
|
||||||
"oidc_allowed_group_count": "Кількість дозволених груп",
|
"oidc_allowed_group_count": "Кількість дозволених груп",
|
||||||
@@ -457,69 +456,69 @@
|
|||||||
"custom_client_id_description": "Встановіть власний ідентифікатор клієнта, якщо це вимагається вашим застосунком. В іншому випадку залиште поле порожнім, щоб згенерувати випадковий.",
|
"custom_client_id_description": "Встановіть власний ідентифікатор клієнта, якщо це вимагається вашим застосунком. В іншому випадку залиште поле порожнім, щоб згенерувати випадковий.",
|
||||||
"generated": "Створено",
|
"generated": "Створено",
|
||||||
"administration": "Адміністрування",
|
"administration": "Адміністрування",
|
||||||
"group_rdn_attribute_description": "Атрибут, що використовується в розрізнювальному імені групи (DN).",
|
"group_rdn_attribute_description": "Атрибут, який використовується в DN (Distinguished Name) групи.",
|
||||||
"display_name_attribute": "Атрибут імені для відображення",
|
"display_name_attribute": "Атрибут імені для відображення",
|
||||||
"display_name": "Ім'я для відображення",
|
"display_name": "Ім'я для відображення",
|
||||||
"configure_application_images": "Налаштування зображень застосунку",
|
"configure_application_images": "Налаштування зображень застосунку",
|
||||||
"ui_config_disabled_info_title": "Конфігурація інтерфейсу користувача вимкнена",
|
"ui_config_disabled_info_title": "Налаштування через UI вимкнено",
|
||||||
"ui_config_disabled_info_description": "Конфігурація інтерфейсу користувача вимкнена, оскільки налаштування конфігурації програми керуються через змінні середовища. Деякі налаштування можуть бути недоступними для редагування.",
|
"ui_config_disabled_info_description": "Налаштування через UI вимкнено, оскільки параметри конфігурації застосунку керуються через змінні середовища. Деякі налаштування можуть бути недоступні для редагування.",
|
||||||
"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>.",
|
"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-адреса",
|
"invalid_url": "Недійсна URL-адреса",
|
||||||
"require_user_email": "Потрібна адреса електронної пошти",
|
"require_user_email": "Потрібна адреса електронної пошти",
|
||||||
"require_user_email_description": "Вимагає від користувачів наявність адреси електронної пошти. Якщо ця опція вимкнена, користувачі без адреси електронної пошти не зможуть користуватися функціями, для яких потрібна адреса електронної пошти.",
|
"require_user_email_description": "Вимагає наявності електронної адреси у користувачів. Якщо вимкнено, користувачі без електронної адреси не зможуть користуватися функціями, які її вимагають.",
|
||||||
"view": "Перегляд",
|
"view": "Перегляд",
|
||||||
"toggle_columns": "Перемикання стовпців",
|
"toggle_columns": "Налаштувати стовпці",
|
||||||
"locale": "Локаль",
|
"locale": "Мова",
|
||||||
"ldap_id": "LDAP-ідентифікатор",
|
"ldap_id": "LDAP-ідентифікатор",
|
||||||
"reauthentication": "Повторна аутентифікація",
|
"reauthentication": "Повторна автентифікація",
|
||||||
"clear_filters": "Очистити фільтри",
|
"clear_filters": "Очистити фільтри",
|
||||||
"default_profile_picture": "Стандартне зображення профілю",
|
"default_profile_picture": "Стандартне зображення профілю",
|
||||||
"light": "Світла",
|
"light": "Світла",
|
||||||
"dark": "Темна",
|
"dark": "Темна",
|
||||||
"system": "Системна",
|
"system": "Системна",
|
||||||
"signup_token_user_groups_description": "Автоматично призначати ці групи користувачам, які реєструються за допомогою цього токена.",
|
"signup_token_user_groups_description": "Автоматично призначати ці групи користувачам, які реєструються за допомогою цього токена.",
|
||||||
"allowed_oidc_clients": "Дозволені клієнти OIDC",
|
"allowed_oidc_clients": "Дозволені OIDC-клієнти",
|
||||||
"allowed_oidc_clients_description": "Виберіть клієнти OIDC, до яких члени цієї групи користувачів мають право входити.",
|
"allowed_oidc_clients_description": "Оберіть OIDC-клієнти, до яких дозволено вхід членам цієї групи користувачів.",
|
||||||
"unrestrict_oidc_client": "Не обмежувати {clientName}",
|
"unrestrict_oidc_client": "Не обмежувати {clientName}",
|
||||||
"confirm_unrestrict_oidc_client_description": "Ви впевнені, що хочете зняти обмеження з клієнта OIDC <b>{clientName}</b>? Це призведе до видалення всіх групових призначень для цього клієнта, і будь-який користувач зможе увійти в систему.",
|
"confirm_unrestrict_oidc_client_description": "Ви впевнені, що хочете зняти обмеження з OIDC-клієнта <b>{clientName}</b>? Це видалить усі призначення груп для цього клієнта, і будь-який користувач зможе виконати вхід.",
|
||||||
"allowed_oidc_clients_updated_successfully": "Дозволені клієнти OIDC успішно оновлені",
|
"allowed_oidc_clients_updated_successfully": "Дозволені OIDC-клієнти успішно оновлено",
|
||||||
"yes": "Так",
|
"yes": "Так",
|
||||||
"no": "Ні",
|
"no": "Ні",
|
||||||
"restricted": "Обмежений",
|
"restricted": "Обмежений",
|
||||||
"scim_provisioning": "Надання SCIM",
|
"scim_provisioning": "Синхронізація SCIM",
|
||||||
"scim_provisioning_description": "SCIM-провізінінг дозволяє автоматично надавати та скасовувати доступ користувачам і групам з вашого клієнта OIDC. Дізнайтеся більше в <link href='https://pocket-id.org/docs/configuration/scim'>документації</link>.",
|
"scim_provisioning_description": "Постачання користувачів через SCIM дозволяє автоматично додавати та видаляти користувачів і групи у вашому OIDC-клієнті. Дізнайтеся більше у <link href='https://pocket-id.org/docs/configuration/scim'>документації</link>.",
|
||||||
"scim_endpoint": "Кінцева точка SCIM",
|
"scim_endpoint": "Кінцева точка SCIM",
|
||||||
"scim_token": "Токен SCIM",
|
"scim_token": "Токен SCIM",
|
||||||
"last_successful_sync_at": "Остання успішна синхронізація: {time}",
|
"last_successful_sync_at": "Остання успішна синхронізація: {time}",
|
||||||
"scim_configuration_updated_successfully": "Конфігурація SCIM успішно оновлена.",
|
"scim_configuration_updated_successfully": "Конфігурацію SCIM успішно оновлено.",
|
||||||
"scim_enabled_successfully": "SCIM успішно увімкнено.",
|
"scim_enabled_successfully": "Синхронізація SCIM успішно увімкнено.",
|
||||||
"scim_disabled_successfully": "SCIM успішно вимкнено.",
|
"scim_disabled_successfully": "Синхронізація SCIM успішно вимкнено.",
|
||||||
"disable_scim_provisioning": "Вимкнути надання SCIM",
|
"disable_scim_provisioning": "Вимкнути SCIM синхронізацію",
|
||||||
"disable_scim_provisioning_confirm_description": "Ви впевнені, що хочете вимкнути надання доступу SCIM для <b>{clientName}</b>? Це зупинить всі автоматичні процеси надання та скасування доступу для користувачів і груп.",
|
"disable_scim_provisioning_confirm_description": "Ви впевнені, що хочете вимкнути постачання користувачів через SCIM для <b>{clientName}</b>? Це зупинить автоматичне додавання та видалення користувачів і груп.",
|
||||||
"scim_sync_failed": "Синхронізація SCIM не вдалася. Перевірте журнали сервера для отримання додаткової інформації.",
|
"scim_sync_failed": "Синхронізація SCIM не вдалася. Перевірте журнали сервера для отримання додаткової інформації.",
|
||||||
"scim_sync_successful": "Синхронізація SCIM успішно завершена.",
|
"scim_sync_successful": "Синхронізація SCIM успішно завершена.",
|
||||||
"save_and_sync": "Зберегти та синхронізувати",
|
"save_and_sync": "Зберегти та синхронізувати",
|
||||||
"scim_save_changes_description": "Перед початком синхронізації SCIM необхідно зберегти зміни. Чи хочете ви зберегти зараз?",
|
"scim_save_changes_description": "Необхідно зберегти зміни перед запуском синхронізації SCIM. Бажаєте зберегти зараз?",
|
||||||
"scopes": "Області застосування",
|
"scopes": "Області застосування",
|
||||||
"issuer_url": "URL емітента",
|
"issuer_url": "URL емітента",
|
||||||
"smtp_field_required_when_other_provided": "Необхідно, якщо вказано будь-яке налаштування SMTP",
|
"smtp_field_required_when_other_provided": "Обов'язково, якщо вказано будь-який параметр SMTP",
|
||||||
"smtp_field_required_when_email_enabled": "Необхідно, якщо увімкнено сповіщення електронною поштою",
|
"smtp_field_required_when_email_enabled": "Обов'язково, якщо увімкнено сповіщення електронною поштою",
|
||||||
"renew": "Оновити",
|
"renew": "Поновити",
|
||||||
"renew_api_key": "Оновити API-ключ",
|
"renew_api_key": "Поновити API-ключ",
|
||||||
"renew_api_key_description": "Оновлення API-ключа призведе до створення нового ключа. Обов'язково оновіть усі інтеграції, що використовують цей ключ.",
|
"renew_api_key_description": "Поновлення API-ключа згенерує новий ключ. Переконайтеся, що ви оновили всі інтеграції, які його використовують.",
|
||||||
"api_key_renewed": "API-ключ оновлено",
|
"api_key_renewed": "API-ключ поновлено",
|
||||||
"app_config_home_page": "Головна сторінка",
|
"app_config_home_page": "Головна сторінка",
|
||||||
"app_config_home_page_description": "Сторінка, на яку перенаправляють користувачів після входу в систему.",
|
"app_config_home_page_description": "Сторінка, на яку користувачі перенаправляються після входу.",
|
||||||
"email_verification_warning": "Підтвердьте свою адресу електронної пошти",
|
"email_verification_warning": "Підтвердьте свою адресу електронної пошти",
|
||||||
"email_verification_warning_description": "Ваша електронна адреса ще не підтверджена. Будь ласка, підтвердьте її якомога швидше.",
|
"email_verification_warning_description": "Ваша електронна адреса ще не підтверджена. Будь ласка, підтвердьте її якомога швидше.",
|
||||||
"email_verification": "Перевірка електронної адреси",
|
"email_verification": "Підтвердження електронної пошти",
|
||||||
"email_verification_description": "Надсилайте користувачам підтверджувальний лист електронною поштою, коли вони реєструються або змінюють свою адресу електронної пошти.",
|
"email_verification_description": "Надсилати лист підтвердження користувачам під час реєстрації або зміни електронної адреси.",
|
||||||
"email_verification_success_title": "Електронна адреса успішно підтверджена",
|
"email_verification_success_title": "Електронна адреса успішно підтверджена",
|
||||||
"email_verification_success_description": "Ваша електронна адреса була успішно підтверджена.",
|
"email_verification_success_description": "Ваша електронна адреса була успішно підтверджена.",
|
||||||
"email_verification_error_title": "Перевірка електронної адреси не вдалася",
|
"email_verification_error_title": "Перевірка електронної адреси не вдалася",
|
||||||
"mark_as_unverified": "Позначити як неперевірене",
|
"mark_as_unverified": "Позначити як непідтверджену",
|
||||||
"mark_as_verified": "Позначити як перевірене",
|
"mark_as_verified": "Позначити як підтверджену",
|
||||||
"email_verification_sent": "Електронний лист для підтвердження надіслано успішно.",
|
"email_verification_sent": "Електронний лист для підтвердження успішно надіслано.",
|
||||||
"emails_verified_by_default": "Електронні листи перевіряються за замовчуванням",
|
"emails_verified_by_default": "Електронні адреси підтверджені за замовчуванням",
|
||||||
"emails_verified_by_default_description": "Якщо ця опція увімкнена, адреси електронної пошти користувачів будуть позначатися як підтверджені за замовчуванням під час реєстрації або при зміні адреси електронної пошти."
|
"emails_verified_by_default_description": "Якщо увімкнено, електронні адреси користувачів будуть автоматично позначатися як підтверджені під час реєстрації або зміни електронної адреси."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "Nhập mã đã hiển thị ở bước trước.",
|
"enter_code_displayed_in_previous_step": "Nhập mã đã hiển thị ở bước trước.",
|
||||||
"authorize": "Cho phép",
|
"authorize": "Cho phép",
|
||||||
"federated_client_credentials": "Thông Tin Xác Thực Của Federated Clients",
|
"federated_client_credentials": "Thông Tin Xác Thực Của Federated Clients",
|
||||||
"federated_client_credentials_description": "Sử dụng thông tin xác thực của federated client, bạn có thể xác thực các client OIDC bằng cách sử dụng token JWT được cấp bởi các bên thứ ba.",
|
|
||||||
"add_federated_client_credential": "Thêm thông tin xác thực cho federated clients",
|
"add_federated_client_credential": "Thêm thông tin xác thực cho federated clients",
|
||||||
"add_another_federated_client_credential": "Thêm một thông tin xác thực cho federated clients khác",
|
"add_another_federated_client_credential": "Thêm một thông tin xác thực cho federated clients khác",
|
||||||
"oidc_allowed_group_count": "Số lượng nhóm được phép",
|
"oidc_allowed_group_count": "Số lượng nhóm được phép",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "输入在上一步中显示的代码",
|
"enter_code_displayed_in_previous_step": "输入在上一步中显示的代码",
|
||||||
"authorize": "授权",
|
"authorize": "授权",
|
||||||
"federated_client_credentials": "联合身份",
|
"federated_client_credentials": "联合身份",
|
||||||
"federated_client_credentials_description": "您可以使用联合身份,通过第三方授权机构签发的 JWT 令牌,对 OIDC 客户端进行认证。",
|
|
||||||
"add_federated_client_credential": "添加联合身份",
|
"add_federated_client_credential": "添加联合身份",
|
||||||
"add_another_federated_client_credential": "再添加一个联合身份",
|
"add_another_federated_client_credential": "再添加一个联合身份",
|
||||||
"oidc_allowed_group_count": "允许的群组数量",
|
"oidc_allowed_group_count": "允许的群组数量",
|
||||||
|
|||||||
@@ -365,7 +365,6 @@
|
|||||||
"enter_code_displayed_in_previous_step": "請輸入上一步顯示的代碼。",
|
"enter_code_displayed_in_previous_step": "請輸入上一步顯示的代碼。",
|
||||||
"authorize": "授權",
|
"authorize": "授權",
|
||||||
"federated_client_credentials": "聯邦身分",
|
"federated_client_credentials": "聯邦身分",
|
||||||
"federated_client_credentials_description": "使用聯邦身分,您可以透過由第三方授權機構簽發的 JWT 令牌來驗證 OIDC 客戶端。",
|
|
||||||
"add_federated_client_credential": "增加聯邦身分",
|
"add_federated_client_credential": "增加聯邦身分",
|
||||||
"add_another_federated_client_credential": "新增另一組聯邦身分",
|
"add_another_federated_client_credential": "新增另一組聯邦身分",
|
||||||
"oidc_allowed_group_count": "允許的群組數量",
|
"oidc_allowed_group_count": "允許的群組數量",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pocket-id-frontend",
|
"name": "pocket-id-frontend",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"@internationalized/date": "^3.11.0",
|
"@internationalized/date": "^3.11.0",
|
||||||
"@lucide/svelte": "^0.559.0",
|
"@lucide/svelte": "^0.559.0",
|
||||||
"@sveltejs/adapter-static": "^3.0.10",
|
"@sveltejs/adapter-static": "^3.0.10",
|
||||||
"@sveltejs/kit": "^2.53.0",
|
"@sveltejs/kit": "^2.53.4",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||||
"@types/eslint": "^9.6.1",
|
"@types/eslint": "^9.6.1",
|
||||||
"@types/node": "^24.10.13",
|
"@types/node": "^24.10.13",
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"prettier-plugin-svelte": "^3.5.0",
|
"prettier-plugin-svelte": "^3.5.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||||
"rollup": "^4.59.0",
|
"rollup": "^4.59.0",
|
||||||
"svelte": "^5.53.2",
|
"svelte": "^5.53.6",
|
||||||
"svelte-check": "^4.4.3",
|
"svelte-check": "^4.4.3",
|
||||||
"svelte-sonner": "^1.0.7",
|
"svelte-sonner": "^1.0.7",
|
||||||
"tailwind-variants": "^3.2.2",
|
"tailwind-variants": "^3.2.2",
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.56.0",
|
"typescript-eslint": "^8.56.0",
|
||||||
"vite": "^7.3.1"
|
"vite": "^7.3.1",
|
||||||
|
"vite-plugin-compression": "^0.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
"it",
|
"it",
|
||||||
"ja",
|
"ja",
|
||||||
"ko",
|
"ko",
|
||||||
|
"lv",
|
||||||
"nl",
|
"nl",
|
||||||
"no",
|
"no",
|
||||||
"pl",
|
"pl",
|
||||||
|
"pt",
|
||||||
"pt-BR",
|
"pt-BR",
|
||||||
"ru",
|
"ru",
|
||||||
"sv",
|
"sv",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
firstName: z.string().min(1).max(50),
|
firstName: z.string().max(50),
|
||||||
lastName: emptyToUndefined(z.string().max(50).optional()),
|
lastName: emptyToUndefined(z.string().max(50).optional()),
|
||||||
username: usernameSchema,
|
username: usernameSchema,
|
||||||
email: get(appConfigStore).requireUserEmail ? z.email() : emptyToUndefined(z.email().optional())
|
email: get(appConfigStore).requireUserEmail ? z.email() : emptyToUndefined(z.email().optional())
|
||||||
@@ -52,12 +52,12 @@
|
|||||||
|
|
||||||
<form id="sign-up-form" onsubmit={preventDefault(onSubmit)} class="w-full">
|
<form id="sign-up-form" onsubmit={preventDefault(onSubmit)} class="w-full">
|
||||||
<div class="mt-7 space-y-4">
|
<div class="mt-7 space-y-4">
|
||||||
|
<FormInput label={m.username()} bind:input={$inputs.username} />
|
||||||
|
<FormInput label={m.email()} bind:input={$inputs.email} type="email" />
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<FormInput label={m.first_name()} bind:input={$inputs.firstName} />
|
<FormInput label={m.first_name()} bind:input={$inputs.firstName} />
|
||||||
<FormInput label={m.last_name()} bind:input={$inputs.lastName} />
|
<FormInput label={m.last_name()} bind:input={$inputs.lastName} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormInput label={m.username()} bind:input={$inputs.username} />
|
|
||||||
<FormInput label={m.email()} bind:input={$inputs.email} type="email" />
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -122,6 +122,11 @@ export function createForm<T extends z.ZodType<any, any>>(schema: T, initialValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isRequired(fieldSchema: z.ZodTypeAny): boolean {
|
function isRequired(fieldSchema: z.ZodTypeAny): boolean {
|
||||||
|
// Handle string allow empty
|
||||||
|
if (fieldSchema instanceof z.ZodString) {
|
||||||
|
return fieldSchema.minLength !== null && fieldSchema.minLength > 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle unions like callbackUrlSchema
|
// Handle unions like callbackUrlSchema
|
||||||
if (fieldSchema instanceof z.ZodUnion) {
|
if (fieldSchema instanceof z.ZodUnion) {
|
||||||
return !fieldSchema.def.options.some((o: any) => {
|
return !fieldSchema.def.options.some((o: any) => {
|
||||||
@@ -138,6 +143,7 @@ export function createForm<T extends z.ZodType<any, any>>(schema: T, initialValu
|
|||||||
if (fieldSchema instanceof z.ZodOptional || fieldSchema instanceof z.ZodDefault) {
|
if (fieldSchema instanceof z.ZodOptional || fieldSchema instanceof z.ZodDefault) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,9 @@
|
|||||||
const userService = new UserService();
|
const userService = new UserService();
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
firstName: z.string().min(1).max(50),
|
firstName: z.string().max(50),
|
||||||
lastName: emptyToUndefined(z.string().max(50).optional()),
|
lastName: emptyToUndefined(z.string().max(50).optional()),
|
||||||
displayName: z.string().min(1).max(100),
|
displayName: z.string().max(100),
|
||||||
username: usernameSchema,
|
username: usernameSchema,
|
||||||
email: get(appConfigStore).requireUserEmail ? z.email() : emptyToUndefined(z.email().optional())
|
email: get(appConfigStore).requireUserEmail ? z.email() : emptyToUndefined(z.email().optional())
|
||||||
});
|
});
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
if (!hasManualDisplayNameEdit) {
|
if (!hasManualDisplayNameEdit) {
|
||||||
$inputs.displayName.value = `${$inputs.firstName.value}${
|
$inputs.displayName.value = `${$inputs.firstName.value}${
|
||||||
$inputs.lastName?.value ? ' ' + $inputs.lastName.value : ''
|
$inputs.lastName?.value ? ' ' + $inputs.lastName.value : ''
|
||||||
}`;
|
}`.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +91,8 @@
|
|||||||
|
|
||||||
<fieldset disabled={userInfoInputDisabled}>
|
<fieldset disabled={userInfoInputDisabled}>
|
||||||
<Field.Group class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<Field.Group class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
<FormInput label={m.username()} bind:input={$inputs.username} />
|
||||||
|
<FormInput label={m.email()} type="email" bind:input={$inputs.email} />
|
||||||
<FormInput label={m.first_name()} bind:input={$inputs.firstName} onInput={onNameInput} />
|
<FormInput label={m.first_name()} bind:input={$inputs.firstName} onInput={onNameInput} />
|
||||||
<FormInput label={m.last_name()} bind:input={$inputs.lastName} onInput={onNameInput} />
|
<FormInput label={m.last_name()} bind:input={$inputs.lastName} onInput={onNameInput} />
|
||||||
<FormInput
|
<FormInput
|
||||||
@@ -98,8 +100,6 @@
|
|||||||
bind:input={$inputs.displayName}
|
bind:input={$inputs.displayName}
|
||||||
onInput={() => (hasManualDisplayNameEdit = true)}
|
onInput={() => (hasManualDisplayNameEdit = true)}
|
||||||
/>
|
/>
|
||||||
<FormInput label={m.username()} bind:input={$inputs.username} />
|
|
||||||
<FormInput label={m.email()} type="email" bind:input={$inputs.email} />
|
|
||||||
</Field.Group>
|
</Field.Group>
|
||||||
|
|
||||||
<div class="flex justify-end pt-4">
|
<div class="flex justify-end pt-4">
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
it: 'Italiano',
|
it: 'Italiano',
|
||||||
ja: '日本語',
|
ja: '日本語',
|
||||||
ko: '한국어',
|
ko: '한국어',
|
||||||
|
lv: 'Latviešu',
|
||||||
nl: 'Nederlands',
|
nl: 'Nederlands',
|
||||||
no: 'Norsk',
|
no: 'Norsk',
|
||||||
pl: 'Polski',
|
pl: 'Polski',
|
||||||
|
pt: 'Português',
|
||||||
'pt-BR': 'Português brasileiro',
|
'pt-BR': 'Português brasileiro',
|
||||||
ru: 'Русский',
|
ru: 'Русский',
|
||||||
sv: 'Svenska',
|
sv: 'Svenska',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<Input
|
<Input
|
||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
data-testid={`callback-url-${i + 1}`}
|
data-testid={`callback-url-${i + 1}`}
|
||||||
type="url"
|
type="text"
|
||||||
bind:value={callbackURLs[i]}
|
bind:value={callbackURLs[i]}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -40,9 +40,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
firstName: z.string().min(1).max(50),
|
firstName: z.string().max(50),
|
||||||
lastName: emptyToUndefined(z.string().max(50).optional()),
|
lastName: emptyToUndefined(z.string().max(50).optional()),
|
||||||
displayName: z.string().min(1).max(100),
|
displayName: z.string().max(100),
|
||||||
username: usernameSchema,
|
username: usernameSchema,
|
||||||
email: get(appConfigStore).requireUserEmail
|
email: get(appConfigStore).requireUserEmail
|
||||||
? z.email()
|
? z.email()
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
if (!hasManualDisplayNameEdit) {
|
if (!hasManualDisplayNameEdit) {
|
||||||
$inputs.displayName.value = `${$inputs.firstName.value}${
|
$inputs.displayName.value = `${$inputs.firstName.value}${
|
||||||
$inputs.lastName?.value ? ' ' + $inputs.lastName.value : ''
|
$inputs.lastName?.value ? ' ' + $inputs.lastName.value : ''
|
||||||
}`;
|
}`.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -75,13 +75,6 @@
|
|||||||
<form onsubmit={preventDefault(onSubmit)}>
|
<form onsubmit={preventDefault(onSubmit)}>
|
||||||
<fieldset disabled={inputDisabled}>
|
<fieldset disabled={inputDisabled}>
|
||||||
<div class="grid grid-cols-1 items-start gap-5 md:grid-cols-2">
|
<div class="grid grid-cols-1 items-start gap-5 md:grid-cols-2">
|
||||||
<FormInput label={m.first_name()} oninput={onNameInput} bind:input={$inputs.firstName} />
|
|
||||||
<FormInput label={m.last_name()} oninput={onNameInput} bind:input={$inputs.lastName} />
|
|
||||||
<FormInput
|
|
||||||
label={m.display_name()}
|
|
||||||
oninput={() => (hasManualDisplayNameEdit = true)}
|
|
||||||
bind:input={$inputs.displayName}
|
|
||||||
/>
|
|
||||||
<FormInput label={m.username()} bind:input={$inputs.username} />
|
<FormInput label={m.username()} bind:input={$inputs.username} />
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<FormInput
|
<FormInput
|
||||||
@@ -111,6 +104,13 @@
|
|||||||
</Tooltip.Root>
|
</Tooltip.Root>
|
||||||
</Tooltip.Provider>
|
</Tooltip.Provider>
|
||||||
</div>
|
</div>
|
||||||
|
<FormInput label={m.first_name()} oninput={onNameInput} bind:input={$inputs.firstName} />
|
||||||
|
<FormInput label={m.last_name()} oninput={onNameInput} bind:input={$inputs.lastName} />
|
||||||
|
<FormInput
|
||||||
|
label={m.display_name()}
|
||||||
|
oninput={() => (hasManualDisplayNameEdit = true)}
|
||||||
|
bind:input={$inputs.displayName}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-5 grid grid-cols-1 items-start gap-5 md:grid-cols-2">
|
<div class="mt-5 grid grid-cols-1 items-start gap-5 md:grid-cols-2">
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
|
|||||||
@@ -2,28 +2,47 @@ import { paraglideVitePlugin } from '@inlang/paraglide-js';
|
|||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import viteCompression from 'vite-plugin-compression';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig((mode) => {
|
||||||
plugins: [
|
return {
|
||||||
sveltekit(),
|
plugins: [
|
||||||
tailwindcss(),
|
sveltekit(),
|
||||||
paraglideVitePlugin({
|
tailwindcss(),
|
||||||
project: './project.inlang',
|
paraglideVitePlugin({
|
||||||
outdir: './src/lib/paraglide',
|
project: './project.inlang',
|
||||||
cookieName: 'locale',
|
outdir: './src/lib/paraglide',
|
||||||
strategy: ['cookie', 'preferredLanguage', 'baseLocale']
|
cookieName: 'locale',
|
||||||
})
|
strategy: ['cookie', 'preferredLanguage', 'baseLocale']
|
||||||
],
|
}),
|
||||||
|
|
||||||
server: {
|
// Create gzip-compressed files
|
||||||
host: process.env.HOST,
|
viteCompression({
|
||||||
proxy: {
|
disable: mode.isPreview,
|
||||||
'/api': {
|
algorithm: 'gzip',
|
||||||
target: process.env.DEVELOPMENT_BACKEND_URL || 'http://localhost:1411'
|
ext: '.gz',
|
||||||
},
|
filter: /\.(js|mjs|json|css)$/i
|
||||||
'/.well-known': {
|
}),
|
||||||
target: process.env.DEVELOPMENT_BACKEND_URL || 'http://localhost:1411'
|
|
||||||
|
// Create brotli-compressed files
|
||||||
|
viteCompression({
|
||||||
|
disable: mode.isPreview,
|
||||||
|
algorithm: 'brotliCompress',
|
||||||
|
ext: '.br',
|
||||||
|
filter: /\.(js|mjs|json|css)$/i
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
server: {
|
||||||
|
host: process.env.HOST,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: process.env.DEVELOPMENT_BACKEND_URL || 'http://localhost:1411'
|
||||||
|
},
|
||||||
|
'/.well-known': {
|
||||||
|
target: process.env.DEVELOPMENT_BACKEND_URL || 'http://localhost:1411'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
259
pnpm-lock.yaml
generated
259
pnpm-lock.yaml
generated
@@ -77,10 +77,10 @@ importers:
|
|||||||
version: 1.5.4
|
version: 1.5.4
|
||||||
runed:
|
runed:
|
||||||
specifier: ^0.37.1
|
specifier: ^0.37.1
|
||||||
version: 0.37.1(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(zod@4.3.6)
|
version: 0.37.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(zod@4.3.6)
|
||||||
sveltekit-superforms:
|
sveltekit-superforms:
|
||||||
specifier: ^2.30.0
|
specifier: ^2.30.0
|
||||||
version: 2.30.0(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.2)(typescript@5.9.3)
|
version: 2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.6)(typescript@5.9.3)
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^3.5.0
|
specifier: ^3.5.0
|
||||||
version: 3.5.0
|
version: 3.5.0
|
||||||
@@ -102,16 +102,16 @@ importers:
|
|||||||
version: 3.11.0
|
version: 3.11.0
|
||||||
'@lucide/svelte':
|
'@lucide/svelte':
|
||||||
specifier: ^0.559.0
|
specifier: ^0.559.0
|
||||||
version: 0.559.0(svelte@5.53.2)
|
version: 0.559.0(svelte@5.53.6)
|
||||||
'@sveltejs/adapter-static':
|
'@sveltejs/adapter-static':
|
||||||
specifier: ^3.0.10
|
specifier: ^3.0.10
|
||||||
version: 3.0.10(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))
|
version: 3.0.10(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^2.53.0
|
specifier: ^2.53.4
|
||||||
version: 2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
version: 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^6.2.4
|
specifier: ^6.2.4
|
||||||
version: 6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
version: 6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
'@types/eslint':
|
'@types/eslint':
|
||||||
specifier: ^9.6.1
|
specifier: ^9.6.1
|
||||||
version: 9.6.1
|
version: 9.6.1
|
||||||
@@ -123,7 +123,7 @@ importers:
|
|||||||
version: 1.5.6
|
version: 1.5.6
|
||||||
bits-ui:
|
bits-ui:
|
||||||
specifier: ^2.16.2
|
specifier: ^2.16.2
|
||||||
version: 2.16.2(@internationalized/date@3.11.0)(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)
|
version: 2.16.2(@internationalized/date@3.11.0)(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.39.3
|
specifier: ^9.39.3
|
||||||
version: 9.39.3(jiti@2.6.1)
|
version: 9.39.3(jiti@2.6.1)
|
||||||
@@ -132,37 +132,37 @@ importers:
|
|||||||
version: 10.1.8(eslint@9.39.3(jiti@2.6.1))
|
version: 10.1.8(eslint@9.39.3(jiti@2.6.1))
|
||||||
eslint-plugin-svelte:
|
eslint-plugin-svelte:
|
||||||
specifier: ^3.15.0
|
specifier: ^3.15.0
|
||||||
version: 3.15.0(eslint@9.39.3(jiti@2.6.1))(svelte@5.53.2)
|
version: 3.15.0(eslint@9.39.3(jiti@2.6.1))(svelte@5.53.6)
|
||||||
formsnap:
|
formsnap:
|
||||||
specifier: ^2.0.1
|
specifier: ^2.0.1
|
||||||
version: 2.0.1(svelte@5.53.2)(sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.2)(typescript@5.9.3))
|
version: 2.0.1(svelte@5.53.6)(sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.6)(typescript@5.9.3))
|
||||||
globals:
|
globals:
|
||||||
specifier: ^16.5.0
|
specifier: ^16.5.0
|
||||||
version: 16.5.0
|
version: 16.5.0
|
||||||
mode-watcher:
|
mode-watcher:
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(svelte@5.53.2)
|
version: 1.1.0(svelte@5.53.6)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.8.1
|
specifier: ^3.8.1
|
||||||
version: 3.8.1
|
version: 3.8.1
|
||||||
prettier-plugin-svelte:
|
prettier-plugin-svelte:
|
||||||
specifier: ^3.5.0
|
specifier: ^3.5.0
|
||||||
version: 3.5.0(prettier@3.8.1)(svelte@5.53.2)
|
version: 3.5.0(prettier@3.8.1)(svelte@5.53.6)
|
||||||
prettier-plugin-tailwindcss:
|
prettier-plugin-tailwindcss:
|
||||||
specifier: ^0.7.2
|
specifier: ^0.7.2
|
||||||
version: 0.7.2(prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.2))(prettier@3.8.1)
|
version: 0.7.2(prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.6))(prettier@3.8.1)
|
||||||
rollup:
|
rollup:
|
||||||
specifier: ^4.59.0
|
specifier: ^4.59.0
|
||||||
version: 4.59.0
|
version: 4.59.0
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^5.53.2
|
specifier: ^5.53.6
|
||||||
version: 5.53.2
|
version: 5.53.6
|
||||||
svelte-check:
|
svelte-check:
|
||||||
specifier: ^4.4.3
|
specifier: ^4.4.3
|
||||||
version: 4.4.3(picomatch@4.0.3)(svelte@5.53.2)(typescript@5.9.3)
|
version: 4.4.3(picomatch@4.0.3)(svelte@5.53.6)(typescript@5.9.3)
|
||||||
svelte-sonner:
|
svelte-sonner:
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(svelte@5.53.2)
|
version: 1.0.7(svelte@5.53.6)
|
||||||
tailwind-variants:
|
tailwind-variants:
|
||||||
specifier: ^3.2.2
|
specifier: ^3.2.2
|
||||||
version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.0)
|
version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.0)
|
||||||
@@ -184,6 +184,9 @@ importers:
|
|||||||
vite:
|
vite:
|
||||||
specifier: ^7.3.1
|
specifier: ^7.3.1
|
||||||
version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||||
|
vite-plugin-compression:
|
||||||
|
specifier: ^0.5.1
|
||||||
|
version: 0.5.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -832,89 +835,105 @@ packages:
|
|||||||
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.2.4':
|
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||||
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||||
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||||
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.2.4':
|
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||||
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.2.4':
|
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||||
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||||
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||||
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.34.5':
|
'@img/sharp-linux-arm64@0.34.5':
|
||||||
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.34.5':
|
'@img/sharp-linux-arm@0.34.5':
|
||||||
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-ppc64@0.34.5':
|
'@img/sharp-linux-ppc64@0.34.5':
|
||||||
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-riscv64@0.34.5':
|
'@img/sharp-linux-riscv64@0.34.5':
|
||||||
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.34.5':
|
'@img/sharp-linux-s390x@0.34.5':
|
||||||
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.34.5':
|
'@img/sharp-linux-x64@0.34.5':
|
||||||
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.34.5':
|
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||||
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.34.5':
|
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||||
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-wasm32@0.34.5':
|
'@img/sharp-wasm32@0.34.5':
|
||||||
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||||
@@ -1010,24 +1029,28 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@16.1.6':
|
'@next/swc-linux-arm64-musl@16.1.6':
|
||||||
resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
|
resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@16.1.6':
|
'@next/swc-linux-x64-gnu@16.1.6':
|
||||||
resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
|
resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@16.1.6':
|
'@next/swc-linux-x64-musl@16.1.6':
|
||||||
resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
|
resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@16.1.6':
|
'@next/swc-win32-arm64-msvc@16.1.6':
|
||||||
resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
|
resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
|
||||||
@@ -1246,66 +1269,79 @@ packages:
|
|||||||
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||||
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||||
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
||||||
@@ -1375,8 +1411,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@sveltejs/kit': ^2.0.0
|
'@sveltejs/kit': ^2.0.0
|
||||||
|
|
||||||
'@sveltejs/kit@2.53.0':
|
'@sveltejs/kit@2.53.4':
|
||||||
resolution: {integrity: sha512-Brh/9h8QEg7rWIj+Nnz/2sC49NUeS8g3Qd9H5dTO3EbWG8vCEUl06jE+r5jQVDMHdr1swmCkwZkONFsWelGTpQ==}
|
resolution: {integrity: sha512-iAIPEahFgDJJyvz8g0jP08KvqnM6JvdW8YfsygZ+pMeMvyM2zssWMltcsotETvjSZ82G3VlitgDtBIvpQSZrTA==}
|
||||||
engines: {node: '>=18.13'}
|
engines: {node: '>=18.13'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1450,24 +1486,28 @@ packages:
|
|||||||
engines: {node: '>= 20'}
|
engines: {node: '>= 20'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-arm64-musl@4.2.0':
|
'@tailwindcss/oxide-linux-arm64-musl@4.2.0':
|
||||||
resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==}
|
resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==}
|
||||||
engines: {node: '>= 20'}
|
engines: {node: '>= 20'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-gnu@4.2.0':
|
'@tailwindcss/oxide-linux-x64-gnu@4.2.0':
|
||||||
resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==}
|
resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==}
|
||||||
engines: {node: '>= 20'}
|
engines: {node: '>= 20'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-musl@4.2.0':
|
'@tailwindcss/oxide-linux-x64-musl@4.2.0':
|
||||||
resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==}
|
resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==}
|
||||||
engines: {node: '>= 20'}
|
engines: {node: '>= 20'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tailwindcss/oxide-wasm32-wasi@4.2.0':
|
'@tailwindcss/oxide-wasm32-wasi@4.2.0':
|
||||||
resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==}
|
resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==}
|
||||||
@@ -1681,8 +1721,8 @@ packages:
|
|||||||
argparse@2.0.1:
|
argparse@2.0.1:
|
||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||||
|
|
||||||
aria-query@5.3.2:
|
aria-query@5.3.1:
|
||||||
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
|
resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
arkregex@0.0.5:
|
arkregex@0.0.5:
|
||||||
@@ -2162,6 +2202,10 @@ packages:
|
|||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
sveltekit-superforms: ^2.19.0
|
sveltekit-superforms: ^2.19.0
|
||||||
|
|
||||||
|
fs-extra@10.1.0:
|
||||||
|
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
fsevents@2.3.2:
|
fsevents@2.3.2:
|
||||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -2346,6 +2390,9 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsonfile@6.2.0:
|
||||||
|
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
@@ -2409,24 +2456,28 @@ packages:
|
|||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
lightningcss-linux-arm64-musl@1.31.1:
|
lightningcss-linux-arm64-musl@1.31.1:
|
||||||
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
lightningcss-linux-x64-gnu@1.31.1:
|
lightningcss-linux-x64-gnu@1.31.1:
|
||||||
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
lightningcss-linux-x64-musl@1.31.1:
|
lightningcss-linux-x64-musl@1.31.1:
|
||||||
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
lightningcss-win32-arm64-msvc@1.31.1:
|
lightningcss-win32-arm64-msvc@1.31.1:
|
||||||
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
|
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
|
||||||
@@ -3068,8 +3119,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
|
|
||||||
svelte@5.53.2:
|
svelte@5.53.6:
|
||||||
resolution: {integrity: sha512-yGONuIrcl/BMmqbm6/52Q/NYzfkta7uVlos5NSzGTfNJTTFtPPzra6rAQoQIwAqupeM3s9uuTf5PvioeiCdg9g==}
|
resolution: {integrity: sha512-lP5DGF3oDDI9fhHcSpaBiJEkFLuS16h92DhM1L5K1lFm0WjOmUh1i2sNkBBk8rkxJRpob0dBE75jRfUzGZUOGA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
sveltekit-superforms@2.30.0:
|
sveltekit-superforms@2.30.0:
|
||||||
@@ -3195,6 +3246,10 @@ packages:
|
|||||||
undici-types@7.16.0:
|
undici-types@7.16.0:
|
||||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
|
universalify@2.0.1:
|
||||||
|
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
unplugin@2.3.11:
|
unplugin@2.3.11:
|
||||||
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
|
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
|
||||||
engines: {node: '>=18.12.0'}
|
engines: {node: '>=18.12.0'}
|
||||||
@@ -3232,6 +3287,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
vite-plugin-compression@0.5.1:
|
||||||
|
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
|
||||||
|
peerDependencies:
|
||||||
|
vite: '>=2.0.0'
|
||||||
|
|
||||||
vite@7.3.1:
|
vite@7.3.1:
|
||||||
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
|
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -3910,9 +3970,9 @@ snapshots:
|
|||||||
|
|
||||||
'@lix-js/server-protocol-schema@0.1.1': {}
|
'@lix-js/server-protocol-schema@0.1.1': {}
|
||||||
|
|
||||||
'@lucide/svelte@0.559.0(svelte@5.53.2)':
|
'@lucide/svelte@0.559.0(svelte@5.53.6)':
|
||||||
dependencies:
|
dependencies:
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
'@next/env@16.1.6': {}
|
'@next/env@16.1.6': {}
|
||||||
|
|
||||||
@@ -4191,15 +4251,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.16.0
|
acorn: 8.16.0
|
||||||
|
|
||||||
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))':
|
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
|
|
||||||
'@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
'@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.1.0
|
'@standard-schema/spec': 1.1.0
|
||||||
'@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0)
|
'@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0)
|
||||||
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
'@types/cookie': 0.6.0
|
'@types/cookie': 0.6.0
|
||||||
acorn: 8.16.0
|
acorn: 8.16.0
|
||||||
cookie: 1.1.1
|
cookie: 1.1.1
|
||||||
@@ -4210,25 +4270,25 @@ snapshots:
|
|||||||
mrmime: 2.0.1
|
mrmime: 2.0.1
|
||||||
set-cookie-parser: 3.0.1
|
set-cookie-parser: 3.0.1
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
'@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
obug: 2.1.1
|
obug: 2.1.1
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
'@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
obug: 2.1.1
|
obug: 2.1.1
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||||
vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
|
|
||||||
@@ -4522,7 +4582,7 @@ snapshots:
|
|||||||
|
|
||||||
argparse@2.0.1: {}
|
argparse@2.0.1: {}
|
||||||
|
|
||||||
aria-query@5.3.2: {}
|
aria-query@5.3.1: {}
|
||||||
|
|
||||||
arkregex@0.0.5:
|
arkregex@0.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4563,15 +4623,15 @@ snapshots:
|
|||||||
|
|
||||||
baseline-browser-mapping@2.9.19: {}
|
baseline-browser-mapping@2.9.19: {}
|
||||||
|
|
||||||
bits-ui@2.16.2(@internationalized/date@3.11.0)(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2):
|
bits-ui@2.16.2(@internationalized/date@3.11.0)(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@floating-ui/core': 1.7.4
|
'@floating-ui/core': 1.7.4
|
||||||
'@floating-ui/dom': 1.7.5
|
'@floating-ui/dom': 1.7.5
|
||||||
'@internationalized/date': 3.11.0
|
'@internationalized/date': 3.11.0
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
runed: 0.35.1(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)
|
runed: 0.35.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
svelte-toolbelt: 0.10.6(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)
|
svelte-toolbelt: 0.10.6(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)
|
||||||
tabbable: 6.4.0
|
tabbable: 6.4.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@sveltejs/kit'
|
- '@sveltejs/kit'
|
||||||
@@ -4915,7 +4975,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.3(jiti@2.6.1)
|
eslint: 9.39.3(jiti@2.6.1)
|
||||||
|
|
||||||
eslint-plugin-svelte@3.15.0(eslint@9.39.3(jiti@2.6.1))(svelte@5.53.2):
|
eslint-plugin-svelte@3.15.0(eslint@9.39.3(jiti@2.6.1))(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1))
|
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1))
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
@@ -4927,9 +4987,9 @@ snapshots:
|
|||||||
postcss-load-config: 3.1.4(postcss@8.5.6)
|
postcss-load-config: 3.1.4(postcss@8.5.6)
|
||||||
postcss-safe-parser: 7.0.1(postcss@8.5.6)
|
postcss-safe-parser: 7.0.1(postcss@8.5.6)
|
||||||
semver: 7.7.4
|
semver: 7.7.4
|
||||||
svelte-eslint-parser: 1.4.1(svelte@5.53.2)
|
svelte-eslint-parser: 1.4.1(svelte@5.53.6)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- ts-node
|
- ts-node
|
||||||
|
|
||||||
@@ -5063,11 +5123,17 @@ snapshots:
|
|||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
|
|
||||||
formsnap@2.0.1(svelte@5.53.2)(sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.2)(typescript@5.9.3)):
|
formsnap@2.0.1(svelte@5.53.6)(sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.6)(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
svelte-toolbelt: 0.5.0(svelte@5.53.2)
|
svelte-toolbelt: 0.5.0(svelte@5.53.6)
|
||||||
sveltekit-superforms: 2.30.0(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.2)(typescript@5.9.3)
|
sveltekit-superforms: 2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.6)(typescript@5.9.3)
|
||||||
|
|
||||||
|
fs-extra@10.1.0:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jsonfile: 6.2.0
|
||||||
|
universalify: 2.0.1
|
||||||
|
|
||||||
fsevents@2.3.2:
|
fsevents@2.3.2:
|
||||||
optional: true
|
optional: true
|
||||||
@@ -5226,6 +5292,12 @@ snapshots:
|
|||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
|
jsonfile@6.2.0:
|
||||||
|
dependencies:
|
||||||
|
universalify: 2.0.1
|
||||||
|
optionalDependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
@@ -5365,11 +5437,11 @@ snapshots:
|
|||||||
|
|
||||||
minipass@7.1.2: {}
|
minipass@7.1.2: {}
|
||||||
|
|
||||||
mode-watcher@1.1.0(svelte@5.53.2):
|
mode-watcher@1.1.0(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
runed: 0.25.0(svelte@5.53.2)
|
runed: 0.25.0(svelte@5.53.6)
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
svelte-toolbelt: 0.7.1(svelte@5.53.2)
|
svelte-toolbelt: 0.7.1(svelte@5.53.6)
|
||||||
|
|
||||||
mri@1.2.0: {}
|
mri@1.2.0: {}
|
||||||
|
|
||||||
@@ -5544,16 +5616,16 @@ snapshots:
|
|||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.2):
|
prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
prettier: 3.8.1
|
prettier: 3.8.1
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.2))(prettier@3.8.1):
|
prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.5.0(prettier@3.8.1)(svelte@5.53.6))(prettier@3.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
prettier: 3.8.1
|
prettier: 3.8.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
prettier-plugin-svelte: 3.5.0(prettier@3.8.1)(svelte@5.53.2)
|
prettier-plugin-svelte: 3.5.0(prettier@3.8.1)(svelte@5.53.6)
|
||||||
|
|
||||||
prettier@3.7.4: {}
|
prettier@3.7.4: {}
|
||||||
|
|
||||||
@@ -5661,38 +5733,38 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
runed@0.23.4(svelte@5.53.2):
|
runed@0.23.4(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
runed@0.25.0(svelte@5.53.2):
|
runed@0.25.0(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
runed@0.28.0(svelte@5.53.2):
|
runed@0.28.0(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
runed@0.35.1(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2):
|
runed@0.35.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
lz-string: 1.5.0
|
lz-string: 1.5.0
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@sveltejs/kit': 2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
|
|
||||||
runed@0.37.1(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(zod@4.3.6):
|
runed@0.37.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(zod@4.3.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
lz-string: 1.5.0
|
lz-string: 1.5.0
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@sveltejs/kit': 2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
zod: 4.3.6
|
zod: 4.3.6
|
||||||
|
|
||||||
sade@1.8.1:
|
sade@1.8.1:
|
||||||
@@ -5853,19 +5925,19 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
|
|
||||||
svelte-check@4.4.3(picomatch@4.0.3)(svelte@5.53.2)(typescript@5.9.3):
|
svelte-check@4.4.3(picomatch@4.0.3)(svelte@5.53.6)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.31
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
chokidar: 4.0.3
|
chokidar: 4.0.3
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
sade: 1.8.1
|
sade: 1.8.1
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- picomatch
|
- picomatch
|
||||||
|
|
||||||
svelte-eslint-parser@1.4.1(svelte@5.53.2):
|
svelte-eslint-parser@1.4.1(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-scope: 8.4.0
|
eslint-scope: 8.4.0
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
@@ -5874,36 +5946,36 @@ snapshots:
|
|||||||
postcss-scss: 4.0.9(postcss@8.5.6)
|
postcss-scss: 4.0.9(postcss@8.5.6)
|
||||||
postcss-selector-parser: 7.1.1
|
postcss-selector-parser: 7.1.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
svelte-sonner@1.0.7(svelte@5.53.2):
|
svelte-sonner@1.0.7(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
runed: 0.28.0(svelte@5.53.2)
|
runed: 0.28.0(svelte@5.53.6)
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
svelte-toolbelt@0.10.6(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2):
|
svelte-toolbelt@0.10.6(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
runed: 0.35.1(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)
|
runed: 0.35.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)
|
||||||
style-to-object: 1.0.14
|
style-to-object: 1.0.14
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@sveltejs/kit'
|
- '@sveltejs/kit'
|
||||||
|
|
||||||
svelte-toolbelt@0.5.0(svelte@5.53.2):
|
svelte-toolbelt@0.5.0(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
style-to-object: 1.0.14
|
style-to-object: 1.0.14
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
svelte-toolbelt@0.7.1(svelte@5.53.2):
|
svelte-toolbelt@0.7.1(svelte@5.53.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
runed: 0.23.4(svelte@5.53.2)
|
runed: 0.23.4(svelte@5.53.6)
|
||||||
style-to-object: 1.0.14
|
style-to-object: 1.0.14
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
|
|
||||||
svelte@5.53.2:
|
svelte@5.53.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/remapping': 2.3.5
|
'@jridgewell/remapping': 2.3.5
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
@@ -5911,7 +5983,7 @@ snapshots:
|
|||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
'@types/trusted-types': 2.0.7
|
'@types/trusted-types': 2.0.7
|
||||||
acorn: 8.16.0
|
acorn: 8.16.0
|
||||||
aria-query: 5.3.2
|
aria-query: 5.3.1
|
||||||
axobject-query: 4.1.0
|
axobject-query: 4.1.0
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
devalue: 5.6.3
|
devalue: 5.6.3
|
||||||
@@ -5922,12 +5994,12 @@ snapshots:
|
|||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
zimmerframe: 1.1.4
|
zimmerframe: 1.1.4
|
||||||
|
|
||||||
sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.2)(typescript@5.9.3):
|
sveltekit-superforms@2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(@types/json-schema@7.0.15)(svelte@5.53.6)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.53.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.2)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
'@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||||
devalue: 5.6.3
|
devalue: 5.6.3
|
||||||
memoize-weak: 1.0.2
|
memoize-weak: 1.0.2
|
||||||
svelte: 5.53.2
|
svelte: 5.53.6
|
||||||
ts-deepmerge: 7.0.3
|
ts-deepmerge: 7.0.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@exodus/schemasafe': 1.3.0
|
'@exodus/schemasafe': 1.3.0
|
||||||
@@ -6050,6 +6122,8 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@7.16.0: {}
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
unplugin@2.3.11:
|
unplugin@2.3.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/remapping': 2.3.5
|
'@jridgewell/remapping': 2.3.5
|
||||||
@@ -6079,6 +6153,15 @@ snapshots:
|
|||||||
|
|
||||||
vary@1.1.2: {}
|
vary@1.1.2: {}
|
||||||
|
|
||||||
|
vite-plugin-compression@0.5.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)):
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.2
|
||||||
|
debug: 4.4.3
|
||||||
|
fs-extra: 10.1.0
|
||||||
|
vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1):
|
vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.27.3
|
esbuild: 0.27.3
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ packages:
|
|||||||
- tests
|
- tests
|
||||||
- email-templates
|
- email-templates
|
||||||
|
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
- sharp
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
cookie@<0.7.0: ">=0.7.0"
|
'@isaacs/brace-expansion': '>=5.0.1'
|
||||||
|
cookie@<0.7.0: '>=0.7.0'
|
||||||
devalue: ^5.6.2
|
devalue: ^5.6.2
|
||||||
glob@>=11.0.0 <11.1.0: ">=11.1.0"
|
glob@>=11.0.0 <11.1.0: '>=11.1.0'
|
||||||
js-yaml@>=4.0.0 <4.1.1: ">=4.1.1"
|
js-yaml@>=4.0.0 <4.1.1: '>=4.1.1'
|
||||||
valibot@>=0.31.0 <1.2.0: ">=1.2.0"
|
next: '>=16.1.5'
|
||||||
validator@<13.15.20: ">=13.15.20"
|
valibot@>=0.31.0 <1.2.0: '>=1.2.0'
|
||||||
"@isaacs/brace-expansion": ">=5.0.1"
|
validator@<13.15.20: '>=13.15.20'
|
||||||
next: ">=16.1.5"
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
environment:
|
environment:
|
||||||
- LLDAP_JWT_SECRET=secret
|
- LLDAP_JWT_SECRET=secret
|
||||||
|
- LLDAP_LDAP_USER_EMAIL=admin@pocket-id.org
|
||||||
- LLDAP_LDAP_USER_PASS=admin_password
|
- LLDAP_LDAP_USER_PASS=admin_password
|
||||||
- LLDAP_LDAP_BASE_DN=dc=pocket-id,dc=org
|
- LLDAP_LDAP_BASE_DN=dc=pocket-id,dc=org
|
||||||
scim-test-server:
|
scim-test-server:
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ test('Change Locale', async ({ page }) => {
|
|||||||
await expect(page.getByText('Taal', { exact: true })).toBeVisible();
|
await expect(page.getByText('Taal', { exact: true })).toBeVisible();
|
||||||
|
|
||||||
// Check if the validation messages are translated because they are provided by Zod
|
// Check if the validation messages are translated because they are provided by Zod
|
||||||
await page.getByRole('textbox', { name: 'Voornaam' }).fill('');
|
await page.getByRole('textbox', { name: 'Gebruikersnaam' }).fill('');
|
||||||
await page.getByRole('button', { name: 'Opslaan' }).click();
|
await page.getByRole('button', { name: 'Opslaan' }).click();
|
||||||
await expect(page.getByText('Te kort: verwacht dat string >=1 tekens heeft')).toBeVisible();
|
await expect(page.getByText('Te kort: verwacht dat string >=2 tekens heeft')).toBeVisible();
|
||||||
|
|
||||||
// Clear all cookies and sign in again to check if the language is still set to Dutch
|
// Clear all cookies and sign in again to check if the language is still set to Dutch
|
||||||
await page.context().clearCookies();
|
await page.context().clearCookies();
|
||||||
@@ -74,9 +74,9 @@ test('Change Locale', async ({ page }) => {
|
|||||||
|
|
||||||
await expect(page.getByText('Taal', { exact: true })).toBeVisible();
|
await expect(page.getByText('Taal', { exact: true })).toBeVisible();
|
||||||
|
|
||||||
await page.getByRole('textbox', { name: 'Voornaam' }).fill('');
|
await page.getByRole('textbox', { name: 'Gebruikersnaam' }).fill('');
|
||||||
await page.getByRole('button', { name: 'Opslaan' }).click();
|
await page.getByRole('button', { name: 'Opslaan' }).click();
|
||||||
await expect(page.getByText('Te kort: verwacht dat string >=1 tekens heeft')).toBeVisible();
|
await expect(page.getByText('Te kort: verwacht dat string >=2 tekens heeft')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Add passkey to an account', async ({ page }) => {
|
test('Add passkey to an account', async ({ page }) => {
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ test.describe('Introspection endpoint', () => {
|
|||||||
Authorization: 'Bearer ' + clientAssertion
|
Authorization: 'Bearer ' + clientAssertion
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
client_id: oidcClients.federated.id,
|
||||||
token: validAccessToken
|
token: validAccessToken
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -374,6 +375,7 @@ test.describe('Introspection endpoint', () => {
|
|||||||
Authorization: 'Bearer ' + clientAssertion
|
Authorization: 'Bearer ' + clientAssertion
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
client_id: oidcClients.federated.id,
|
||||||
token: validAccessToken
|
token: validAccessToken
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user