mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-04-02 04:36:37 +00:00
Compare commits
45 Commits
feat/email
...
v2.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
375f0a0c34 | ||
|
|
522a4eee00 | ||
|
|
0c41872cd4 | ||
|
|
b3fe143136 | ||
|
|
a90c8abe51 | ||
|
|
ae269371da | ||
|
|
27caaf2cac | ||
|
|
0678699d0c | ||
|
|
4f82957e13 | ||
|
|
5e2534bd6b | ||
|
|
eb0456a395 | ||
|
|
f0249377ac | ||
|
|
97f2e4eec2 | ||
|
|
adbdfcf9ff | ||
|
|
94a48977ba | ||
|
|
5ab0996475 | ||
|
|
60825c5743 | ||
|
|
310b81c277 | ||
|
|
549b487663 | ||
|
|
6eebecd85a | ||
|
|
1de231f1ff | ||
|
|
aab7e364e8 | ||
|
|
56afebc242 | ||
|
|
bb7b0d5608 | ||
|
|
80558c5625 | ||
|
|
a5629e63d2 | ||
|
|
317879bb37 | ||
|
|
c62533d388 | ||
|
|
0978a89fcc | ||
|
|
53ef61a3e5 | ||
|
|
4811625cdd | ||
|
|
9dbc02e568 | ||
|
|
43a1e4a25b | ||
|
|
e78b16d0c6 | ||
|
|
1967de6828 | ||
|
|
2c64bebf6a | ||
|
|
2a11c3e609 | ||
|
|
a0ced2443c | ||
|
|
746aa71d67 | ||
|
|
9ca3d33c88 | ||
|
|
4df4bcb645 | ||
|
|
875c5b94a6 | ||
|
|
0e2cdc393e | ||
|
|
1e7442f5df | ||
|
|
e955118a6f |
@@ -2,7 +2,9 @@
|
|||||||
"name": "pocket-id",
|
"name": "pocket-id",
|
||||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
|
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/go:1": {}
|
"ghcr.io/devcontainers/features/go:1": {
|
||||||
|
"version": "1.26"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
|
|||||||
4
.github/workflows/backend-linter.yml
vendored
4
.github/workflows/backend-linter.yml
vendored
@@ -32,9 +32,9 @@ jobs:
|
|||||||
go-version-file: backend/go.mod
|
go-version-file: backend/go.mod
|
||||||
|
|
||||||
- name: Run Golangci-lint
|
- name: Run Golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v8.0.0
|
uses: golangci/golangci-lint-action@v9.0.0
|
||||||
with:
|
with:
|
||||||
version: v2.4.0
|
version: v2.9.0
|
||||||
args: --build-tags=exclude_frontend
|
args: --build-tags=exclude_frontend
|
||||||
working-directory: backend
|
working-directory: backend
|
||||||
only-new-issues: ${{ github.event_name == 'pull_request' }}
|
only-new-issues: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|||||||
2
.github/workflows/build-next.yml
vendored
2
.github/workflows/build-next.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 24
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
|
|||||||
2
.github/workflows/e2e-tests.yml
vendored
2
.github/workflows/e2e-tests.yml
vendored
@@ -78,7 +78,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 24
|
||||||
|
|
||||||
- name: Cache Playwright Browsers
|
- name: Cache Playwright Browsers
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 24
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: "backend/go.mod"
|
go-version-file: "backend/go.mod"
|
||||||
|
|||||||
2
.github/workflows/svelte-check.yml
vendored
2
.github/workflows/svelte-check.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 24
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
||||||
|
|||||||
65
CHANGELOG.md
65
CHANGELOG.md
@@ -1,3 +1,68 @@
|
|||||||
|
## 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
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- allow changing "require email address" if no SMTP credentials present ([8c68b08](https://github.com/pocket-id/pocket-id/commit/8c68b08c12ba371deda61662e3d048d63d07c56f) by @stonith404)
|
||||||
|
- data import from sqlite to postgres fails because of wrong datatype ([1a032a8](https://github.com/pocket-id/pocket-id/commit/1a032a812ef78b250a898d14bec73a8ef7a7859a) by @stonith404)
|
||||||
|
- user can't update account if email is empty ([5828fa5](https://github.com/pocket-id/pocket-id/commit/5828fa57791314594625d52475733dce23cc2fcc) by @stonith404)
|
||||||
|
- login codes sent by an admin incorrectly requires a device token ([03f9be0](https://github.com/pocket-id/pocket-id/commit/03f9be0d125732e02a8e2c5390d9e6d0c74ce957) by @stonith404)
|
||||||
|
- allow exchanging logic code if already authenticated ([0e2cdc3](https://github.com/pocket-id/pocket-id/commit/0e2cdc393e34276bb3b8ea318cdc7261de3f2dec) by @stonith404)
|
||||||
|
- db version downgrades don't downgrade db schema ([4df4bcb](https://github.com/pocket-id/pocket-id/commit/4df4bcb6451b4bf88093e04f3222c8737f2c7be3) by @stonith404)
|
||||||
|
- use user specific email verified claim instead of global one ([2a11c3e](https://github.com/pocket-id/pocket-id/commit/2a11c3e60942d45c2e5b422d99945bce65a622a2) by @stonith404)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- add CLI command for encryption key rotation ([#1209](https://github.com/pocket-id/pocket-id/pull/1209) by @stonith404)
|
||||||
|
- improve passkey error messages ([2f25861](https://github.com/pocket-id/pocket-id/commit/2f25861d15aefa868042e70d3e21b7b38a6ae679) by @stonith404)
|
||||||
|
- make home page URL configurable ([#1215](https://github.com/pocket-id/pocket-id/pull/1215) by @stonith404)
|
||||||
|
- add option to renew API key ([#1214](https://github.com/pocket-id/pocket-id/pull/1214) by @stonith404)
|
||||||
|
- add support for email verification ([#1223](https://github.com/pocket-id/pocket-id/pull/1223) by @stonith404)
|
||||||
|
- add environment variable to disable built-in rate limiting ([9ca3d33](https://github.com/pocket-id/pocket-id/commit/9ca3d33c8897cf49a871783058205bb180529cd2) by @stonith404)
|
||||||
|
- add static api key env variable ([#1229](https://github.com/pocket-id/pocket-id/pull/1229) by @stonith404)
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/pocket-id/pocket-id/compare/v2.1.0...v2.2.0
|
||||||
|
|
||||||
## v2.1.0
|
## v2.1.0
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ Before you submit the pull request for review please ensure that
|
|||||||
```
|
```
|
||||||
|
|
||||||
Where `TYPE` can be:
|
Where `TYPE` can be:
|
||||||
|
|
||||||
- **feat** - is a new feature
|
- **feat** - is a new feature
|
||||||
- **doc** - documentation only changes
|
- **doc** - documentation only changes
|
||||||
- **fix** - a bug fix
|
- **fix** - a bug fix
|
||||||
@@ -51,8 +50,8 @@ If you use [Dev Containers](https://code.visualstudio.com/docs/remote/containers
|
|||||||
|
|
||||||
If you don't use Dev Containers, you need to install the following tools manually:
|
If you don't use Dev Containers, you need to install the following tools manually:
|
||||||
|
|
||||||
- [Node.js](https://nodejs.org/en/download/) >= 22
|
- [Node.js](https://nodejs.org/en/download/) >= 24
|
||||||
- [Go](https://golang.org/doc/install) >= 1.25
|
- [Go](https://golang.org/doc/install) >= 1.26
|
||||||
- [Git](https://git-scm.com/downloads)
|
- [Git](https://git-scm.com/downloads)
|
||||||
|
|
||||||
### 2. Setup
|
### 2. Setup
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ package frontend
|
|||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
func RegisterFrontend(router *gin.Engine) error {
|
func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) error {
|
||||||
return ErrFrontendNotIncluded
|
return ErrFrontendNotIncluded
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterFrontend(router *gin.Engine) error {
|
func RegisterFrontend(router *gin.Engine, rateLimitMiddleware gin.HandlerFunc) error {
|
||||||
distFS, err := fs.Sub(frontendFS, "dist")
|
distFS, err := fs.Sub(frontendFS, "dist")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create sub FS: %w", err)
|
return fmt.Errorf("failed to create sub FS: %w", err)
|
||||||
@@ -61,7 +61,7 @@ func RegisterFrontend(router *gin.Engine) error {
|
|||||||
cacheMaxAge := time.Hour * 24
|
cacheMaxAge := time.Hour * 24
|
||||||
fileServer := NewFileServerWithCaching(http.FS(distFS), int(cacheMaxAge.Seconds()))
|
fileServer := NewFileServerWithCaching(http.FS(distFS), int(cacheMaxAge.Seconds()))
|
||||||
|
|
||||||
router.NoRoute(func(c *gin.Context) {
|
handler := func(c *gin.Context) {
|
||||||
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
||||||
|
|
||||||
if strings.HasSuffix(path, "/") {
|
if strings.HasSuffix(path, "/") {
|
||||||
@@ -97,7 +97,9 @@ func RegisterFrontend(router *gin.Engine) error {
|
|||||||
// Serve other static assets with caching
|
// Serve other static assets with caching
|
||||||
c.Request.URL.Path = "/" + path
|
c.Request.URL.Path = "/" + path
|
||||||
fileServer.ServeHTTP(c.Writer, c.Request)
|
fileServer.ServeHTTP(c.Writer, c.Request)
|
||||||
})
|
}
|
||||||
|
|
||||||
|
router.NoRoute(rateLimitMiddleware, handler)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
140
backend/go.mod
140
backend/go.mod
@@ -1,13 +1,13 @@
|
|||||||
module github.com/pocket-id/pocket-id/backend
|
module github.com/pocket-id/pocket-id/backend
|
||||||
|
|
||||||
go 1.25
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aws/aws-sdk-go-v2 v1.41.0
|
github.com/aws/aws-sdk-go-v2 v1.41.1
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.6
|
github.com/aws/aws-sdk-go-v2/config v1.32.9
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.9
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
|
||||||
github.com/aws/smithy-go v1.24.0
|
github.com/aws/smithy-go v1.24.1
|
||||||
github.com/caarlos0/env/v11 v11.3.1
|
github.com/caarlos0/env/v11 v11.3.1
|
||||||
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
|
||||||
@@ -18,7 +18,7 @@ require (
|
|||||||
github.com/gin-gonic/gin v1.11.0
|
github.com/gin-gonic/gin v1.11.0
|
||||||
github.com/glebarez/go-sqlite v1.22.0
|
github.com/glebarez/go-sqlite v1.22.0
|
||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/go-co-op/gocron/v2 v2.19.0
|
github.com/go-co-op/gocron/v2 v2.19.1
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12
|
github.com/go-ldap/ldap/v3 v3.4.12
|
||||||
github.com/go-playground/validator/v10 v10.30.1
|
github.com/go-playground/validator/v10 v10.30.1
|
||||||
github.com/go-webauthn/webauthn v0.15.0
|
github.com/go-webauthn/webauthn v0.15.0
|
||||||
@@ -27,30 +27,31 @@ require (
|
|||||||
github.com/hashicorp/go-uuid v1.0.3
|
github.com/hashicorp/go-uuid v1.0.3
|
||||||
github.com/jinzhu/copier v0.4.0
|
github.com/jinzhu/copier v0.4.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.3
|
github.com/lestrrat-go/httprc/v3 v3.0.4
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.12
|
github.com/lestrrat-go/jwx/v3 v3.0.13
|
||||||
github.com/lmittmann/tint v1.1.2
|
github.com/lmittmann/tint v1.1.3
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mileusna/useragent v1.3.5
|
github.com/mileusna/useragent v1.3.5
|
||||||
github.com/orandin/slog-gorm v1.4.0
|
github.com/orandin/slog-gorm v1.4.0
|
||||||
github.com/oschwald/maxminddb-golang/v2 v2.1.1
|
github.com/oschwald/maxminddb-golang/v2 v2.1.1
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0
|
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0
|
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0
|
||||||
go.opentelemetry.io/otel v1.39.0
|
go.opentelemetry.io/otel v1.40.0
|
||||||
go.opentelemetry.io/otel/log v0.15.0
|
go.opentelemetry.io/otel/log v0.16.0
|
||||||
go.opentelemetry.io/otel/metric v1.39.0
|
go.opentelemetry.io/otel/metric v1.40.0
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0
|
go.opentelemetry.io/otel/sdk v1.40.0
|
||||||
go.opentelemetry.io/otel/sdk/log v0.15.0
|
go.opentelemetry.io/otel/sdk/log v0.16.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0
|
go.opentelemetry.io/otel/sdk/metric v1.40.0
|
||||||
go.opentelemetry.io/otel/trace v1.39.0
|
go.opentelemetry.io/otel/trace v1.40.0
|
||||||
golang.org/x/crypto v0.46.0
|
golang.org/x/crypto v0.48.0
|
||||||
golang.org/x/image v0.34.0
|
golang.org/x/image v0.36.0
|
||||||
|
golang.org/x/net v0.50.0
|
||||||
golang.org/x/sync v0.19.0
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/text v0.32.0
|
golang.org/x/text v0.34.0
|
||||||
golang.org/x/time v0.14.0
|
golang.org/x/time v0.14.0
|
||||||
gorm.io/driver/postgres v1.6.0
|
gorm.io/driver/postgres v1.6.0
|
||||||
gorm.io/gorm v1.31.1
|
gorm.io/gorm v1.31.1
|
||||||
@@ -59,23 +60,23 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/Azure/go-ntlmssp v0.1.0 // indirect
|
github.com/Azure/go-ntlmssp v0.1.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // 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.5 // 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/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
github.com/bytedance/sonic v1.14.2 // indirect
|
github.com/bytedance/sonic v1.15.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.4.0 // indirect
|
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
@@ -84,22 +85,22 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
github.com/go-webauthn/x v0.1.27 // indirect
|
github.com/go-webauthn/x v0.2.1 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.19.1 // indirect
|
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||||
github.com/google/go-github/v39 v39.2.0 // indirect
|
github.com/google/go-github/v39 v39.2.0 // indirect
|
||||||
github.com/google/go-querystring v1.2.0 // indirect
|
github.com/google/go-querystring v1.2.0 // indirect
|
||||||
github.com/google/go-tpm v0.9.8 // indirect
|
github.com/google/go-tpm v0.9.8 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
@@ -116,8 +117,8 @@ require (
|
|||||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
|
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||||
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
|
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.11.2 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.33 // indirect
|
github.com/mattn/go-sqlite3 v1.14.34 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
@@ -126,46 +127,45 @@ require (
|
|||||||
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
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.67.4 // indirect
|
github.com/prometheus/common v0.67.5 // indirect
|
||||||
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
||||||
github.com/prometheus/procfs v0.19.2 // indirect
|
github.com/prometheus/procfs v0.19.2 // indirect
|
||||||
github.com/quic-go/qpack v0.6.0 // indirect
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
github.com/quic-go/quic-go v0.58.0 // indirect
|
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/segmentio/asm v1.2.1 // indirect
|
github.com/segmentio/asm v1.2.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||||
github.com/valyala/fastjson v1.6.7 // indirect
|
github.com/valyala/fastjson v1.6.10 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0 // indirect
|
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.61.0 // indirect
|
go.opentelemetry.io/otel/exporters/prometheus v0.62.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
golang.org/x/arch v0.23.0 // indirect
|
golang.org/x/arch v0.24.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
|
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
|
||||||
golang.org/x/net v0.48.0 // indirect
|
golang.org/x/oauth2 v0.35.0 // indirect
|
||||||
golang.org/x/oauth2 v0.34.0 // indirect
|
golang.org/x/sys v0.41.0 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
|
google.golang.org/grpc v1.79.1 // indirect
|
||||||
google.golang.org/grpc v1.78.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.67.4 // indirect
|
modernc.org/libc v1.68.0 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.11.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.42.2 // indirect
|
modernc.org/sqlite v1.46.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
300
backend/go.sum
300
backend/go.sum
@@ -6,52 +6,52 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
|||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
|
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8=
|
github.com/aws/aws-sdk-go-v2/config v1.32.9 h1:ktda/mtAydeObvJXlHzyGpK1xcsLaP16zfUPDGoW90A=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI=
|
github.com/aws/aws-sdk-go-v2/config v1.32.9/go.mod h1:U+fCQ+9QKsLW786BCfEjYRj34VVTbPdsLP3CHSYXMOI=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.9 h1:sWvTKsyrMlJGEuj/WgrwilpoJ6Xa1+KhIpGdzw7mMU8=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.9/go.mod h1:+J44MBhmfVY/lETFiKI+klz0Vym2aCmIjqgClMmW82w=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 h1:+VTRawC4iVY58pS/lzpo0lnoa/SYNGF4/B/3/U5ro8Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
|
||||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0=
|
||||||
github.com/aws/smithy-go v1.24.0/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/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.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
|
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||||
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
|
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||||
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
|
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
|
||||||
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
@@ -98,8 +98,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
|||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/gin-contrib/slog v1.2.0 h1:vAxZfr7knD1ZYK5+pMJLP52sZXIkJXkcRPa/0dx9hSk=
|
github.com/gin-contrib/slog v1.2.0 h1:vAxZfr7knD1ZYK5+pMJLP52sZXIkJXkcRPa/0dx9hSk=
|
||||||
github.com/gin-contrib/slog v1.2.0/go.mod h1:vYK6YltmpsEFkO0zfRMLTKHrWS3DwUSn0TMpT+kMagI=
|
github.com/gin-contrib/slog v1.2.0/go.mod h1:vYK6YltmpsEFkO0zfRMLTKHrWS3DwUSn0TMpT+kMagI=
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
@@ -112,8 +112,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
|||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-co-op/gocron/v2 v2.19.0 h1:OKf2y6LXPs/BgBI2fl8PxUpNAI1DA9Mg+hSeGOS38OU=
|
github.com/go-co-op/gocron/v2 v2.19.1 h1:B4iLeA0NB/2iO3EKQ7NfKn5KsQgZfjb2fkvoZJU3yBI=
|
||||||
github.com/go-co-op/gocron/v2 v2.19.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
|
github.com/go-co-op/gocron/v2 v2.19.1/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
|
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
|
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
@@ -129,20 +129,20 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
||||||
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/go-webauthn/webauthn v0.15.0 h1:LR1vPv62E0/6+sTenX35QrCmpMCzLeVAcnXeH4MrbJY=
|
github.com/go-webauthn/webauthn v0.15.0 h1:LR1vPv62E0/6+sTenX35QrCmpMCzLeVAcnXeH4MrbJY=
|
||||||
github.com/go-webauthn/webauthn v0.15.0/go.mod h1:hcAOhVChPRG7oqG7Xj6XKN1mb+8eXTGP/B7zBLzkX5A=
|
github.com/go-webauthn/webauthn v0.15.0/go.mod h1:hcAOhVChPRG7oqG7Xj6XKN1mb+8eXTGP/B7zBLzkX5A=
|
||||||
github.com/go-webauthn/x v0.1.27 h1:CLyuB8JGn9xvw0etBl4fnclcbPTwhKpN4Xg32zaSYnI=
|
github.com/go-webauthn/x v0.2.1 h1:/oB8i0FhSANuoN+YJF5XHMtppa7zGEYaQrrf6ytotjc=
|
||||||
github.com/go-webauthn/x v0.1.27/go.mod h1:KGYJQAPPgbpDKi4N7zKMGL+Iz6WgxKg3OlhVbPtuJXI=
|
github.com/go-webauthn/x v0.2.1/go.mod h1:Wm0X0zXkzznit4gHj4m82GiBZRMEm+TDUIoJWIQLsE4=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
|
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||||
github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@@ -166,8 +166,8 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k
|
|||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
@@ -226,20 +226,20 @@ github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7
|
|||||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
|
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.3 h1:WjLHWkDkgWXeIUrKi/7lS/sGq2DjkSAwdTbH5RHXAKs=
|
github.com/lestrrat-go/httprc/v3 v3.0.4 h1:pXyH2ppK8GYYggygxJ3TvxpCZnbEUWc9qSwRTTApaLA=
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.3/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
|
github.com/lestrrat-go/httprc/v3 v3.0.4/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg=
|
github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk=
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8=
|
github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU=
|
||||||
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
|
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
|
||||||
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
|
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
|
github.com/lmittmann/tint v1.1.3 h1:Hv4EaHWXQr+GTFnOU4VKf8UvAtZgn0VuKT+G0wFlO3I=
|
||||||
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
github.com/lmittmann/tint v1.1.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
|
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
|
||||||
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
|
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
|
||||||
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
@@ -276,16 +276,16 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
|
|||||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||||
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||||
github.com/quic-go/quic-go v0.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug=
|
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||||
github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
@@ -316,62 +316,62 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||||
github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM=
|
github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4=
|
||||||
github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
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=
|
||||||
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.14.0 h1:eypSOd+0txRKCXPNyqLPsbSfA0jULgJcGmSAdFAnrCM=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0/go.mod h1:CRGvIBL/aAxpQU34ZxyQVFlovVcp67s4cAmQu8Jh9mc=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0/go.mod h1:CvaNVqIfcybc+7xqZNubbE+26K6P7AKZF/l0lE2kdCk=
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0 h1:7TYhBCu6Xz6vDJGNtEslWZLuuX2IJ/aH50hBY4MVeUg=
|
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0 h1:I/7S/yWobR3QHFLqHsJ8QOndoiFsj1VgHpQiq43KlUI=
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.64.0/go.mod h1:tHQctZfAe7e4PBPGyt3kae6mQFXNpj+iiDJa3ithM50=
|
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0/go.mod h1:jPF6gn3y1E+nozCAEQj3c6NZ8KY+tvAgSVfvoOJUFac=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0 h1:9pzPj3RFyKOxBAMkM2w84LpT+rdHam1XoFA+QhARiRw=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0 h1:2gApdml7SznX9szEKFjKjM4qGcGSvAybYLBY319XG3g=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.64.0/go.mod h1:hlVZx1btWH0XTfXpuGX9dsquB50s+tc3fYFOO5elo2M=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0/go.mod h1:0QqAGlbHXhmPYACG3n5hNzO5DnEqqtg4VcK5pr22RI0=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0 h1:7IKZbAYwlwLXAdu7SVPhzTjDjogWZxP4MIa7rovY+PU=
|
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0 h1:LSJsvNqhj2sBNFb5NWHbyDK4QJ/skQ2ydjeOZ9OYNZ4=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.64.0/go.mod h1:+TF5nf3NIv2X8PGxqfYOaRnAoMM43rUA2C3XsN2DoWA=
|
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0/go.mod h1:0Q5ocj6h/+C6KYq8cnl4tDFVd4I1HBdsJ440aeagHos=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.39.0 h1:PI7pt9pkSnimWcp5sQhUA9OzLbc3Ba4sL+VEUTNsxrk=
|
go.opentelemetry.io/contrib/propagators/b3 v1.40.0 h1:xariChe8OOVF3rNlfzGFgQc61npQmXhzZj/i82mxMfg=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.39.0/go.mod h1:5gV/EzPnfYIwjzj+6y8tbGW2PKWhcsz5e/7twptRVQY=
|
go.opentelemetry.io/contrib/propagators/b3 v1.40.0/go.mod h1:72WvbdxbOfXaELEQfonFfOL6osvcVjI7uJEE8C2nkrs=
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 h1:EKpiGphOYq3CYnIe2eX9ftUkyU+Y8Dtte8OaWyHJ4+I=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0/go.mod h1:nWFP7C+T8TygkTjJ7mAyEaFaE7wNfms3nV/vexZ6qt0=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf8jF6WbuGQWUVcqgyWtTR0kOOAWY1DYZ+UhvdmQPw=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 h1:nKP4Z2ejtHn3yShBb+2KawiXgpn8In5cT7aO2wXuOTE=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0/go.mod h1:NwjeBbNigsO4Aj9WgM0C+cKIrxsZUaRmZUO7A8I7u8o=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0/go.mod h1:eQqT90eR3X5Dbs1g9YSM30RavwLF725Ris5/XSXWvqE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0=
|
go.opentelemetry.io/otel/exporters/prometheus v0.62.0 h1:krvC4JMfIOVdEuNPTtQ0ZjCiXrybhv+uOHMfHRmnvVo=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg=
|
go.opentelemetry.io/otel/exporters/prometheus v0.62.0/go.mod h1:fgOE6FM/swEnsVQCqCnbOfRV4tOnWPg7bVeo4izBuhQ=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0 h1:0BSddrtQqLEylcErkeFrJBmwFzcqfQq9+/uxfTZq+HE=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 h1:ivlbaajBWJqhcCPniDqDJmRwj4lc6sRT+dCAVKNmxlQ=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0/go.mod h1:87sjYuAPzaRCtdd09GU5gM1U9wQLrrcYrm77mh5EBoc=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0/go.mod h1:u/G56dEKDDwXNCVLsbSrllB2o8pbtFLUC4HpR66r2dc=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0/go.mod h1:0fBG6ZJxhqByfFZDwSwpZGzJU671HkwpWaNe2t4VUPI=
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U=
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 h1:MzfofMZN8ulNqobCmCAVbqVL5syHw+eB2qPRkCMA/fQ=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g=
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0/go.mod h1:E73G9UFtKRXrxhBsHtG00TB5WxX57lpsQzogDkqBTz8=
|
||||||
go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY=
|
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
|
||||||
go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4=
|
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
||||||
go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE=
|
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
|
||||||
go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ=
|
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
|
||||||
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM=
|
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
|
||||||
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA=
|
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -381,55 +381,55 @@ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
|||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
|
golang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y=
|
||||||
golang.org/x/arch v0.23.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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
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.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.39.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/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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
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.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||||
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||||
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=
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -444,18 +444,18 @@ gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
|||||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||||
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||||
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
|
modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so=
|
||||||
modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
|
modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw=
|
||||||
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
|
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
|
||||||
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||||
modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
|
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||||
modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||||
modernc.org/libc v1.67.4 h1:zZGmCMUVPORtKv95c2ReQN5VDjvkoRm9GWPTEPuvlWg=
|
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
|
||||||
modernc.org/libc v1.67.4/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
|
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
|
||||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
@@ -464,8 +464,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
|||||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.42.2 h1:7hkZUNJvJFN2PgfUdjni9Kbvd4ef4mNLOu0B9FGxM74=
|
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
|
||||||
modernc.org/sqlite v1.42.2/go.mod h1:+VkC6v3pLOAE0A0uVucQEcbVW0I5nHCeDaBf+DpsQT8=
|
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
|
||||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
|||||||
@@ -118,11 +118,10 @@ func initOtelLogging(ctx context.Context, resource *resource.Resource) error {
|
|||||||
// Set the logger provider globally
|
// Set the logger provider globally
|
||||||
globallog.SetLoggerProvider(provider)
|
globallog.SetLoggerProvider(provider)
|
||||||
|
|
||||||
// Wrap the handler in a "fanout" one
|
handler = slog.NewMultiHandler(
|
||||||
handler = utils.LogFanoutHandler{
|
|
||||||
handler,
|
handler,
|
||||||
otelslog.NewHandler(common.Name, otelslog.WithLoggerProvider(provider)),
|
otelslog.NewHandler(common.Name, otelslog.WithLoggerProvider(provider)),
|
||||||
}
|
)
|
||||||
|
|
||||||
// Set the default slog to send logs to OTel and add the app name
|
// Set the default slog to send logs to OTel and add the app name
|
||||||
log := slog.New(handler).
|
log := slog.New(handler).
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import (
|
|||||||
sloggin "github.com/gin-contrib/slog"
|
sloggin "github.com/gin-contrib/slog"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
|
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
@@ -51,8 +53,6 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
r.Use(otelgin.Middleware(common.Name))
|
r.Use(otelgin.Middleware(common.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
rateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(time.Second), 60)
|
|
||||||
|
|
||||||
// Setup global middleware
|
// Setup global middleware
|
||||||
r.Use(middleware.HeadMiddleware())
|
r.Use(middleware.HeadMiddleware())
|
||||||
r.Use(middleware.NewCacheControlMiddleware().Add())
|
r.Use(middleware.NewCacheControlMiddleware().Add())
|
||||||
@@ -60,7 +60,8 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
r.Use(middleware.NewCspMiddleware().Add())
|
r.Use(middleware.NewCspMiddleware().Add())
|
||||||
r.Use(middleware.NewErrorHandlerMiddleware().Add())
|
r.Use(middleware.NewErrorHandlerMiddleware().Add())
|
||||||
|
|
||||||
err := frontend.RegisterFrontend(r)
|
frontendRateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(100*time.Millisecond), 300)
|
||||||
|
err := frontend.RegisterFrontend(r, frontendRateLimitMiddleware)
|
||||||
if errors.Is(err, frontend.ErrFrontendNotIncluded) {
|
if errors.Is(err, frontend.ErrFrontendNotIncluded) {
|
||||||
slog.Warn("Frontend is not included in the build. Skipping frontend registration.")
|
slog.Warn("Frontend is not included in the build. Skipping frontend registration.")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -71,8 +72,10 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
authMiddleware := middleware.NewAuthMiddleware(svc.apiKeyService, svc.userService, svc.jwtService)
|
authMiddleware := middleware.NewAuthMiddleware(svc.apiKeyService, svc.userService, svc.jwtService)
|
||||||
fileSizeLimitMiddleware := middleware.NewFileSizeLimitMiddleware()
|
fileSizeLimitMiddleware := middleware.NewFileSizeLimitMiddleware()
|
||||||
|
|
||||||
|
apiRateLimitMiddleware := middleware.NewRateLimitMiddleware().Add(rate.Every(time.Second), 100)
|
||||||
|
|
||||||
// Set up API routes
|
// Set up API routes
|
||||||
apiGroup := r.Group("/api", rateLimitMiddleware)
|
apiGroup := r.Group("/api", apiRateLimitMiddleware)
|
||||||
controller.NewApiKeyController(apiGroup, authMiddleware, svc.apiKeyService)
|
controller.NewApiKeyController(apiGroup, authMiddleware, svc.apiKeyService)
|
||||||
controller.NewWebauthnController(apiGroup, authMiddleware, middleware.NewRateLimitMiddleware(), svc.webauthnService, svc.appConfigService)
|
controller.NewWebauthnController(apiGroup, authMiddleware, middleware.NewRateLimitMiddleware(), svc.webauthnService, svc.appConfigService)
|
||||||
controller.NewOidcController(apiGroup, authMiddleware, fileSizeLimitMiddleware, svc.oidcService, svc.jwtService)
|
controller.NewOidcController(apiGroup, authMiddleware, fileSizeLimitMiddleware, svc.oidcService, svc.jwtService)
|
||||||
@@ -82,7 +85,7 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
controller.NewAuditLogController(apiGroup, svc.auditLogService, authMiddleware)
|
controller.NewAuditLogController(apiGroup, svc.auditLogService, authMiddleware)
|
||||||
controller.NewUserGroupController(apiGroup, authMiddleware, svc.userGroupService)
|
controller.NewUserGroupController(apiGroup, authMiddleware, svc.userGroupService)
|
||||||
controller.NewCustomClaimController(apiGroup, authMiddleware, svc.customClaimService)
|
controller.NewCustomClaimController(apiGroup, authMiddleware, svc.customClaimService)
|
||||||
controller.NewVersionController(apiGroup, svc.versionService)
|
controller.NewVersionController(apiGroup, authMiddleware, svc.versionService)
|
||||||
controller.NewScimController(apiGroup, authMiddleware, svc.scimService)
|
controller.NewScimController(apiGroup, authMiddleware, svc.scimService)
|
||||||
controller.NewUserSignupController(apiGroup, authMiddleware, middleware.NewRateLimitMiddleware(), svc.userSignUpService, svc.appConfigService)
|
controller.NewUserSignupController(apiGroup, authMiddleware, middleware.NewRateLimitMiddleware(), svc.userSignUpService, svc.appConfigService)
|
||||||
|
|
||||||
@@ -94,18 +97,23 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up base routes
|
// Set up base routes
|
||||||
baseGroup := r.Group("/", rateLimitMiddleware)
|
baseGroup := r.Group("/", apiRateLimitMiddleware)
|
||||||
controller.NewWellKnownController(baseGroup, svc.jwtService)
|
controller.NewWellKnownController(baseGroup, svc.jwtService)
|
||||||
|
|
||||||
// Set up healthcheck routes
|
// Set up healthcheck routes
|
||||||
// These are not rate-limited
|
// These are not rate-limited
|
||||||
controller.NewHealthzController(r)
|
controller.NewHealthzController(r)
|
||||||
|
|
||||||
|
var protocols http.Protocols
|
||||||
|
protocols.SetHTTP1(true)
|
||||||
|
protocols.SetUnencryptedHTTP2(true)
|
||||||
|
|
||||||
// Set up the server
|
// Set up the server
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
ReadHeaderTimeout: 10 * time.Second,
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
Protocols: &protocols,
|
||||||
|
Handler: h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
// HEAD requests don't get matched by Gin routes, so we convert them to GET
|
// HEAD requests don't get matched by Gin routes, so we convert them to GET
|
||||||
// middleware.HeadMiddleware will convert them back to HEAD later
|
// middleware.HeadMiddleware will convert them back to HEAD later
|
||||||
if req.Method == http.MethodHead {
|
if req.Method == http.MethodHead {
|
||||||
@@ -115,7 +123,7 @@ func initRouter(db *gorm.DB, svc *services) (utils.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.ServeHTTP(w, req)
|
r.ServeHTTP(w, req)
|
||||||
}),
|
}), &http2.Server{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the listener
|
// Set up the listener
|
||||||
|
|||||||
@@ -75,7 +75,12 @@ func initServices(ctx context.Context, db *gorm.DB, httpClient *http.Client, ima
|
|||||||
svc.userGroupService = service.NewUserGroupService(db, svc.appConfigService, svc.scimService)
|
svc.userGroupService = service.NewUserGroupService(db, svc.appConfigService, svc.scimService)
|
||||||
svc.userService = service.NewUserService(db, svc.jwtService, svc.auditLogService, svc.emailService, svc.appConfigService, svc.customClaimService, svc.appImagesService, svc.scimService, fileStorage)
|
svc.userService = service.NewUserService(db, svc.jwtService, svc.auditLogService, svc.emailService, svc.appConfigService, svc.customClaimService, svc.appImagesService, svc.scimService, fileStorage)
|
||||||
svc.ldapService = service.NewLdapService(db, httpClient, svc.appConfigService, svc.userService, svc.userGroupService, fileStorage)
|
svc.ldapService = service.NewLdapService(db, httpClient, svc.appConfigService, svc.userService, svc.userGroupService, fileStorage)
|
||||||
svc.apiKeyService = service.NewApiKeyService(db, svc.emailService)
|
|
||||||
|
svc.apiKeyService, err = service.NewApiKeyService(ctx, db, svc.emailService)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create API key service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
svc.userSignUpService = service.NewUserSignupService(db, svc.jwtService, svc.auditLogService, svc.appConfigService, svc.userService)
|
svc.userSignUpService = service.NewUserSignupService(db, svc.jwtService, svc.auditLogService, svc.appConfigService, svc.userService)
|
||||||
svc.oneTimeAccessService = service.NewOneTimeAccessService(db, svc.userService, svc.jwtService, svc.auditLogService, svc.emailService, svc.appConfigService)
|
svc.oneTimeAccessService = service.NewOneTimeAccessService(db, svc.userService, svc.jwtService, svc.auditLogService, svc.emailService, svc.appConfigService)
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ type EnvConfigSchema struct {
|
|||||||
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
||||||
InternalAppURL string `env:"INTERNAL_APP_URL"`
|
InternalAppURL string `env:"INTERNAL_APP_URL"`
|
||||||
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
|
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
|
||||||
|
DisableRateLimiting bool `env:"DISABLE_RATE_LIMITING"`
|
||||||
|
VersionCheckDisabled bool `env:"VERSION_CHECK_DISABLED"`
|
||||||
|
StaticApiKey string `env:"STATIC_API_KEY" options:"file"`
|
||||||
|
|
||||||
FileBackend string `env:"FILE_BACKEND" options:"toLower"`
|
FileBackend string `env:"FILE_BACKEND" options:"toLower"`
|
||||||
UploadPath string `env:"UPLOAD_PATH"`
|
UploadPath string `env:"UPLOAD_PATH"`
|
||||||
@@ -74,7 +77,6 @@ type EnvConfigSchema struct {
|
|||||||
MetricsEnabled bool `env:"METRICS_ENABLED"`
|
MetricsEnabled bool `env:"METRICS_ENABLED"`
|
||||||
TracingEnabled bool `env:"TRACING_ENABLED"`
|
TracingEnabled bool `env:"TRACING_ENABLED"`
|
||||||
LogJSON bool `env:"LOG_JSON"`
|
LogJSON bool `env:"LOG_JSON"`
|
||||||
DisableRateLimiting bool `env:"DISABLE_RATE_LIMITING"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var EnvConfig = defaultConfig()
|
var EnvConfig = defaultConfig()
|
||||||
@@ -104,7 +106,7 @@ func defaultConfig() EnvConfigSchema {
|
|||||||
|
|
||||||
func parseEnvConfig() error {
|
func parseEnvConfig() error {
|
||||||
parsers := map[reflect.Type]env.ParserFunc{
|
parsers := map[reflect.Type]env.ParserFunc{
|
||||||
reflect.TypeOf([]byte{}): func(value string) (interface{}, error) {
|
reflect.TypeFor[[]byte](): func(value string) (any, error) {
|
||||||
return []byte(value), nil
|
return []byte(value), nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -127,6 +129,10 @@ func parseEnvConfig() error {
|
|||||||
|
|
||||||
// ValidateEnvConfig checks the EnvConfig for required fields and valid values
|
// ValidateEnvConfig checks the EnvConfig for required fields and valid values
|
||||||
func ValidateEnvConfig(config *EnvConfigSchema) error {
|
func ValidateEnvConfig(config *EnvConfigSchema) error {
|
||||||
|
if shouldSkipEnvValidation(os.Args) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := sloggin.ParseLevel(config.LogLevel); err != nil {
|
if _, err := sloggin.ParseLevel(config.LogLevel); err != nil {
|
||||||
return errors.New("invalid LOG_LEVEL value. Must be 'debug', 'info', 'warn' or 'error'")
|
return errors.New("invalid LOG_LEVEL value. Must be 'debug', 'info', 'warn' or 'error'")
|
||||||
}
|
}
|
||||||
@@ -178,8 +184,8 @@ func ValidateEnvConfig(config *EnvConfigSchema) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate LOCAL_IPV6_RANGES
|
// Validate LOCAL_IPV6_RANGES
|
||||||
ranges := strings.Split(config.LocalIPv6Ranges, ",")
|
ranges := strings.SplitSeq(config.LocalIPv6Ranges, ",")
|
||||||
for _, rangeStr := range ranges {
|
for rangeStr := range ranges {
|
||||||
rangeStr = strings.TrimSpace(rangeStr)
|
rangeStr = strings.TrimSpace(rangeStr)
|
||||||
if rangeStr == "" {
|
if rangeStr == "" {
|
||||||
continue
|
continue
|
||||||
@@ -200,10 +206,25 @@ func ValidateEnvConfig(config *EnvConfigSchema) error {
|
|||||||
return errors.New("AUDIT_LOG_RETENTION_DAYS must be greater than 0")
|
return errors.New("AUDIT_LOG_RETENTION_DAYS must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.StaticApiKey != "" && len(config.StaticApiKey) < 16 {
|
||||||
|
return errors.New("STATIC_API_KEY must be at least 16 characters long")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldSkipEnvValidation(args []string) bool {
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
switch arg {
|
||||||
|
case "-h", "--help", "help", "version":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// prepareEnvConfig processes special options for EnvConfig fields
|
// prepareEnvConfig processes special options for EnvConfig fields
|
||||||
func prepareEnvConfig(config *EnvConfigSchema) error {
|
func prepareEnvConfig(config *EnvConfigSchema) error {
|
||||||
val := reflect.ValueOf(config).Elem()
|
val := reflect.ValueOf(config).Elem()
|
||||||
@@ -214,9 +235,9 @@ func prepareEnvConfig(config *EnvConfigSchema) error {
|
|||||||
fieldType := typ.Field(i)
|
fieldType := typ.Field(i)
|
||||||
|
|
||||||
optionsTag := fieldType.Tag.Get("options")
|
optionsTag := fieldType.Tag.Get("options")
|
||||||
options := strings.Split(optionsTag, ",")
|
options := strings.SplitSeq(optionsTag, ",")
|
||||||
|
|
||||||
for _, option := range options {
|
for option := range options {
|
||||||
switch option {
|
switch option {
|
||||||
case "toLower":
|
case "toLower":
|
||||||
if field.Kind() == reflect.String {
|
if field.Kind() == reflect.String {
|
||||||
|
|||||||
@@ -280,6 +280,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -24,7 +25,11 @@ import (
|
|||||||
// @Description Initializes all OIDC-related API endpoints for authentication and client management
|
// @Description Initializes all OIDC-related API endpoints for authentication and client management
|
||||||
// @Tags OIDC
|
// @Tags OIDC
|
||||||
func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, oidcService *service.OidcService, jwtService *service.JwtService) {
|
func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, oidcService *service.OidcService, jwtService *service.JwtService) {
|
||||||
oc := &OidcController{oidcService: oidcService, jwtService: jwtService}
|
oc := &OidcController{
|
||||||
|
oidcService: oidcService,
|
||||||
|
jwtService: jwtService,
|
||||||
|
createTokens: oidcService.CreateTokens,
|
||||||
|
}
|
||||||
|
|
||||||
group.POST("/oidc/authorize", authMiddleware.WithAdminNotRequired().Add(), oc.authorizeHandler)
|
group.POST("/oidc/authorize", authMiddleware.WithAdminNotRequired().Add(), oc.authorizeHandler)
|
||||||
group.POST("/oidc/authorization-required", authMiddleware.WithAdminNotRequired().Add(), oc.authorizationConfirmationRequiredHandler)
|
group.POST("/oidc/authorization-required", authMiddleware.WithAdminNotRequired().Add(), oc.authorizationConfirmationRequiredHandler)
|
||||||
@@ -47,7 +52,7 @@ func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMi
|
|||||||
group.POST("/oidc/clients/:id/secret", authMiddleware.Add(), oc.createClientSecretHandler)
|
group.POST("/oidc/clients/:id/secret", authMiddleware.Add(), oc.createClientSecretHandler)
|
||||||
|
|
||||||
group.GET("/oidc/clients/:id/logo", oc.getClientLogoHandler)
|
group.GET("/oidc/clients/:id/logo", oc.getClientLogoHandler)
|
||||||
group.DELETE("/oidc/clients/:id/logo", oc.deleteClientLogoHandler)
|
group.DELETE("/oidc/clients/:id/logo", authMiddleware.Add(), oc.deleteClientLogoHandler)
|
||||||
group.POST("/oidc/clients/:id/logo", authMiddleware.Add(), fileSizeLimitMiddleware.Add(2<<20), oc.updateClientLogoHandler)
|
group.POST("/oidc/clients/:id/logo", authMiddleware.Add(), fileSizeLimitMiddleware.Add(2<<20), oc.updateClientLogoHandler)
|
||||||
|
|
||||||
group.GET("/oidc/clients/:id/preview/:userId", authMiddleware.Add(), oc.getClientPreviewHandler)
|
group.GET("/oidc/clients/:id/preview/:userId", authMiddleware.Add(), oc.getClientPreviewHandler)
|
||||||
@@ -70,6 +75,7 @@ func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMi
|
|||||||
type OidcController struct {
|
type OidcController struct {
|
||||||
oidcService *service.OidcService
|
oidcService *service.OidcService
|
||||||
jwtService *service.JwtService
|
jwtService *service.JwtService
|
||||||
|
createTokens func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// authorizeHandler godoc
|
// authorizeHandler godoc
|
||||||
@@ -144,8 +150,13 @@ func (oc *OidcController) authorizationConfirmationRequiredHandler(c *gin.Contex
|
|||||||
// @Success 200 {object} dto.OidcTokenResponseDto "Token response with access_token and optional id_token and refresh_token"
|
// @Success 200 {object} dto.OidcTokenResponseDto "Token response with access_token and optional id_token and refresh_token"
|
||||||
// @Router /api/oidc/token [post]
|
// @Router /api/oidc/token [post]
|
||||||
func (oc *OidcController) createTokensHandler(c *gin.Context) {
|
func (oc *OidcController) createTokensHandler(c *gin.Context) {
|
||||||
|
// Per RFC-6749, parameters passed to the /token endpoint MUST be passed in the body of the request
|
||||||
|
// Gin's "ShouldBind" by default reads from the query string too, so we need to reset all query string args before invoking ShouldBind
|
||||||
|
c.Request.URL.RawQuery = ""
|
||||||
|
|
||||||
var input dto.OidcCreateTokensDto
|
var input dto.OidcCreateTokensDto
|
||||||
if err := c.ShouldBind(&input); err != nil {
|
err := c.ShouldBind(&input)
|
||||||
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -164,10 +175,10 @@ func (oc *OidcController) createTokensHandler(c *gin.Context) {
|
|||||||
|
|
||||||
// Client id and secret can also be passed over the Authorization header
|
// Client id and secret can also be passed over the Authorization header
|
||||||
if input.ClientID == "" && input.ClientSecret == "" {
|
if input.ClientID == "" && input.ClientSecret == "" {
|
||||||
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
|
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens, err := oc.oidcService.CreateTokens(c.Request.Context(), input)
|
tokens, err := oc.createTokens(c.Request.Context(), input)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, &common.OidcAuthorizationPendingError{}):
|
case errors.Is(err, &common.OidcAuthorizationPendingError{}):
|
||||||
@@ -322,7 +333,7 @@ func (oc *OidcController) introspectTokenHandler(c *gin.Context) {
|
|||||||
creds service.ClientAuthCredentials
|
creds service.ClientAuthCredentials
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
creds.ClientID, creds.ClientSecret, ok = c.Request.BasicAuth()
|
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
|
||||||
bearer, ok := utils.BearerAuth(c.Request)
|
bearer, ok := utils.BearerAuth(c.Request)
|
||||||
@@ -659,7 +670,7 @@ func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) {
|
|||||||
|
|
||||||
// Client id and secret can also be passed over the Authorization header
|
// Client id and secret can also be passed over the Authorization header
|
||||||
if input.ClientID == "" && input.ClientSecret == "" {
|
if input.ClientID == "" && input.ClientSecret == "" {
|
||||||
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
|
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := oc.oidcService.CreateDeviceAuthorization(c.Request.Context(), input)
|
response, err := oc.oidcService.CreateDeviceAuthorization(c.Request.Context(), input)
|
||||||
|
|||||||
227
backend/internal/controller/oidc_controller_test.go
Normal file
227
backend/internal/controller/oidc_controller_test.go
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateTokensHandler(t *testing.T) {
|
||||||
|
createTestContext := func(t *testing.T, rawURL string, form url.Values, authHeader string, noCT bool) (*gin.Context, *httptest.ResponseRecorder) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
mode := gin.Mode()
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
t.Cleanup(func() { gin.SetMode(mode) })
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
c, _ := gin.CreateTestContext(recorder)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, rawURL, strings.NewReader(form.Encode()))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if !noCT {
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
}
|
||||||
|
if authHeader != "" {
|
||||||
|
req.Header.Set("Authorization", authHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Request = req
|
||||||
|
return c, recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Ignores Query String Parameters For Binding", func(t *testing.T) {
|
||||||
|
oc := &OidcController{}
|
||||||
|
|
||||||
|
c, _ := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token?grant_type=refresh_token&refresh_token=query-value",
|
||||||
|
url.Values{},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Len(t, c.Errors, 1)
|
||||||
|
assert.Contains(t, c.Errors[0].Err.Error(), "GrantType")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Missing Authorization Code", func(t *testing.T) {
|
||||||
|
oc := &OidcController{}
|
||||||
|
|
||||||
|
c, _ := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeAuthorizationCode},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Len(t, c.Errors, 1)
|
||||||
|
var missingCodeErr *common.OidcMissingAuthorizationCodeError
|
||||||
|
require.ErrorAs(t, c.Errors[0].Err, &missingCodeErr)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Missing Refresh Token", func(t *testing.T) {
|
||||||
|
oc := &OidcController{}
|
||||||
|
|
||||||
|
c, _ := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeRefreshToken},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Len(t, c.Errors, 1)
|
||||||
|
var missingRefreshErr *common.OidcMissingRefreshTokenError
|
||||||
|
require.ErrorAs(t, c.Errors[0].Err, &missingRefreshErr)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Uses Basic Auth Credentials When Body Credentials Missing", func(t *testing.T) {
|
||||||
|
var capturedInput dto.OidcCreateTokensDto
|
||||||
|
oc := &OidcController{
|
||||||
|
createTokens: func(_ context.Context, input dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
|
||||||
|
capturedInput = input
|
||||||
|
return service.CreatedTokens{
|
||||||
|
AccessToken: "access-token",
|
||||||
|
IdToken: "id-token",
|
||||||
|
RefreshToken: "refresh-token",
|
||||||
|
ExpiresIn: 2 * time.Minute,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte("client-id:client-secret"))
|
||||||
|
c, recorder := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeRefreshToken},
|
||||||
|
"refresh_token": {"input-refresh-token"},
|
||||||
|
},
|
||||||
|
basicAuth,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Empty(t, c.Errors)
|
||||||
|
assert.Equal(t, "client-id", capturedInput.ClientID)
|
||||||
|
assert.Equal(t, "client-secret", capturedInput.ClientSecret)
|
||||||
|
assert.Equal(t, "input-refresh-token", capturedInput.RefreshToken)
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
var response dto.OidcTokenResponseDto
|
||||||
|
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
|
||||||
|
assert.Equal(t, "access-token", response.AccessToken)
|
||||||
|
assert.Equal(t, "Bearer", response.TokenType)
|
||||||
|
assert.Equal(t, "id-token", response.IdToken)
|
||||||
|
assert.Equal(t, "refresh-token", response.RefreshToken)
|
||||||
|
assert.Equal(t, 120, response.ExpiresIn)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Maps Authorization Pending Error", func(t *testing.T) {
|
||||||
|
oc := &OidcController{
|
||||||
|
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
|
||||||
|
return service.CreatedTokens{}, &common.OidcAuthorizationPendingError{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, recorder := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeRefreshToken},
|
||||||
|
"refresh_token": {"input-refresh-token"},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Empty(t, c.Errors)
|
||||||
|
require.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||||
|
var response map[string]string
|
||||||
|
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
|
||||||
|
assert.Equal(t, "authorization_pending", response["error"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Maps Slow Down Error", func(t *testing.T) {
|
||||||
|
oc := &OidcController{
|
||||||
|
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
|
||||||
|
return service.CreatedTokens{}, &common.OidcSlowDownError{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, recorder := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeRefreshToken},
|
||||||
|
"refresh_token": {"input-refresh-token"},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Empty(t, c.Errors)
|
||||||
|
require.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||||
|
var response map[string]string
|
||||||
|
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response))
|
||||||
|
assert.Equal(t, "slow_down", response["error"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns Generic Service Error In Context", func(t *testing.T) {
|
||||||
|
expectedErr := errors.New("boom")
|
||||||
|
oc := &OidcController{
|
||||||
|
createTokens: func(context.Context, dto.OidcCreateTokensDto) (service.CreatedTokens, error) {
|
||||||
|
return service.CreatedTokens{}, expectedErr
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, _ := createTestContext(
|
||||||
|
t,
|
||||||
|
"http://example.com/oidc/token",
|
||||||
|
url.Values{
|
||||||
|
"grant_type": {service.GrantTypeRefreshToken},
|
||||||
|
"refresh_token": {"input-refresh-token"},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
oc.createTokensHandler(c)
|
||||||
|
|
||||||
|
require.Len(t, c.Errors, 1)
|
||||||
|
assert.ErrorIs(t, c.Errors[0].Err, expectedErr)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -5,14 +5,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewVersionController registers version-related routes.
|
// NewVersionController registers version-related routes.
|
||||||
func NewVersionController(group *gin.RouterGroup, versionService *service.VersionService) {
|
func NewVersionController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, versionService *service.VersionService) {
|
||||||
vc := &VersionController{versionService: versionService}
|
vc := &VersionController{versionService: versionService}
|
||||||
group.GET("/version/latest", vc.getLatestVersionHandler)
|
group.GET("/version/latest", vc.getLatestVersionHandler)
|
||||||
|
group.GET("/version/current", authMiddleware.WithAdminNotRequired().Add(), vc.getCurrentVersionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type VersionController struct {
|
type VersionController struct {
|
||||||
@@ -38,3 +41,16 @@ func (vc *VersionController) getLatestVersionHandler(c *gin.Context) {
|
|||||||
"latestVersion": tag,
|
"latestVersion": tag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getCurrentVersionHandler godoc
|
||||||
|
// @Summary Get current deployed version of Pocket ID
|
||||||
|
// @Tags Version
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} map[string]string "Current version information"
|
||||||
|
// @Router /api/version/current [get]
|
||||||
|
func (vc *VersionController) getCurrentVersionHandler(c *gin.Context) {
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"currentVersion": common.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||||
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type sourceStruct struct {
|
type sourceStruct struct {
|
||||||
@@ -60,11 +59,11 @@ type embeddedStruct struct {
|
|||||||
func TestMapStruct(t *testing.T) {
|
func TestMapStruct(t *testing.T) {
|
||||||
src := sourceStruct{
|
src := sourceStruct{
|
||||||
AString: "abcd",
|
AString: "abcd",
|
||||||
AStringPtr: utils.Ptr("xyz"),
|
AStringPtr: new("xyz"),
|
||||||
ABool: true,
|
ABool: true,
|
||||||
ABoolPtr: utils.Ptr(false),
|
ABoolPtr: new(false),
|
||||||
ACustomDateTime: datatype.DateTime(time.Date(2025, 1, 2, 3, 4, 5, 0, time.UTC)),
|
ACustomDateTime: datatype.DateTime(time.Date(2025, 1, 2, 3, 4, 5, 0, time.UTC)),
|
||||||
ACustomDateTimePtr: utils.Ptr(datatype.DateTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC))),
|
ACustomDateTimePtr: new(datatype.DateTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC))),
|
||||||
ANilStringPtr: nil,
|
ANilStringPtr: nil,
|
||||||
ASlice: []string{"a", "b", "c"},
|
ASlice: []string{"a", "b", "c"},
|
||||||
AMap: map[string]int{
|
AMap: map[string]int{
|
||||||
@@ -80,8 +79,8 @@ func TestMapStruct(t *testing.T) {
|
|||||||
Bar: 111,
|
Bar: 111,
|
||||||
},
|
},
|
||||||
|
|
||||||
StringPtrToString: utils.Ptr("foobar"),
|
StringPtrToString: new("foobar"),
|
||||||
EmptyStringPtrToString: utils.Ptr(""),
|
EmptyStringPtrToString: new(""),
|
||||||
NilStringPtrToString: nil,
|
NilStringPtrToString: nil,
|
||||||
IntToInt64: 99,
|
IntToInt64: 99,
|
||||||
AuditLogEventToString: model.AuditLogEventAccountCreated,
|
AuditLogEventToString: model.AuditLogEventAccountCreated,
|
||||||
@@ -118,11 +117,11 @@ func TestMapStructList(t *testing.T) {
|
|||||||
sources := []sourceStruct{
|
sources := []sourceStruct{
|
||||||
{
|
{
|
||||||
AString: "first",
|
AString: "first",
|
||||||
AStringPtr: utils.Ptr("one"),
|
AStringPtr: new("one"),
|
||||||
ABool: true,
|
ABool: true,
|
||||||
ABoolPtr: utils.Ptr(false),
|
ABoolPtr: new(false),
|
||||||
ACustomDateTime: datatype.DateTime(time.Date(2025, 1, 2, 3, 4, 5, 0, time.UTC)),
|
ACustomDateTime: datatype.DateTime(time.Date(2025, 1, 2, 3, 4, 5, 0, time.UTC)),
|
||||||
ACustomDateTimePtr: utils.Ptr(datatype.DateTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC))),
|
ACustomDateTimePtr: new(datatype.DateTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC))),
|
||||||
ASlice: []string{"a", "b"},
|
ASlice: []string{"a", "b"},
|
||||||
AMap: map[string]int{
|
AMap: map[string]int{
|
||||||
"a": 1,
|
"a": 1,
|
||||||
@@ -136,11 +135,11 @@ func TestMapStructList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
AString: "second",
|
AString: "second",
|
||||||
AStringPtr: utils.Ptr("two"),
|
AStringPtr: new("two"),
|
||||||
ABool: false,
|
ABool: false,
|
||||||
ABoolPtr: utils.Ptr(true),
|
ABoolPtr: new(true),
|
||||||
ACustomDateTime: datatype.DateTime(time.Date(2026, 6, 7, 8, 9, 10, 0, time.UTC)),
|
ACustomDateTime: datatype.DateTime(time.Date(2026, 6, 7, 8, 9, 10, 0, time.UTC)),
|
||||||
ACustomDateTimePtr: utils.Ptr(datatype.DateTime(time.Date(2023, 6, 7, 8, 9, 10, 0, time.UTC))),
|
ACustomDateTimePtr: new(datatype.DateTime(time.Date(2023, 6, 7, 8, 9, 10, 0, time.UTC))),
|
||||||
ASlice: []string{"c", "d", "e"},
|
ASlice: []string{"c", "d", "e"},
|
||||||
AMap: map[string]int{
|
AMap: map[string]int{
|
||||||
"c": 3,
|
"c": 3,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// Normalize iterates through an object and performs Unicode normalization on all string fields with the `unorm` tag.
|
// Normalize iterates through an object and performs Unicode normalization on all string fields with the `unorm` tag.
|
||||||
func Normalize(obj any) {
|
func Normalize(obj any) {
|
||||||
v := reflect.ValueOf(obj)
|
v := reflect.ValueOf(obj)
|
||||||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
if v.Kind() != reflect.Pointer || v.IsNil() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
@@ -21,7 +21,7 @@ func Normalize(obj any) {
|
|||||||
if v.Kind() == reflect.Slice {
|
if v.Kind() == reflect.Slice {
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
elem := v.Index(i)
|
elem := v.Index(i)
|
||||||
if elem.Kind() == reflect.Ptr && !elem.IsNil() && elem.Elem().Kind() == reflect.Struct {
|
if elem.Kind() == reflect.Pointer && !elem.IsNil() && elem.Elem().Kind() == reflect.Struct {
|
||||||
Normalize(elem.Interface())
|
Normalize(elem.Interface())
|
||||||
} else if elem.Kind() == reflect.Struct && elem.CanAddr() {
|
} else if elem.Kind() == reflect.Struct && elem.CanAddr() {
|
||||||
Normalize(elem.Addr().Interface())
|
Normalize(elem.Addr().Interface())
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ type ScimResourceData struct {
|
|||||||
type ScimResourceMeta struct {
|
type ScimResourceMeta struct {
|
||||||
Location string `json:"location,omitempty"`
|
Location string `json:"location,omitempty"`
|
||||||
ResourceType string `json:"resourceType,omitempty"`
|
ResourceType string `json:"resourceType,omitempty"`
|
||||||
Created time.Time `json:"created,omitempty"`
|
Created time.Time `json:"created"`
|
||||||
LastModified time.Time `json:"lastModified,omitempty"`
|
LastModified time.Time `json:"lastModified,omitempty"`
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package dto
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
name: "valid input",
|
name: "valid input",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Username: "testuser",
|
Username: "testuser",
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
@@ -27,7 +26,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "missing username",
|
name: "missing username",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
@@ -37,7 +36,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "missing display name",
|
name: "missing display name",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
},
|
},
|
||||||
@@ -47,7 +46,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
name: "username contains invalid characters",
|
name: "username contains invalid characters",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Username: "test/ser",
|
Username: "test/ser",
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
@@ -58,7 +57,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
name: "invalid email",
|
name: "invalid email",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Username: "testuser",
|
Username: "testuser",
|
||||||
Email: utils.Ptr("not-an-email"),
|
Email: new("not-an-email"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
@@ -69,7 +68,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
name: "first name too short",
|
name: "first name too short",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Username: "testuser",
|
Username: "testuser",
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "",
|
FirstName: "",
|
||||||
LastName: "Doe",
|
LastName: "Doe",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
@@ -80,7 +79,7 @@ func TestUserCreateDto_Validate(t *testing.T) {
|
|||||||
name: "last name too long",
|
name: "last name too long",
|
||||||
input: UserCreateDto{
|
input: UserCreateDto{
|
||||||
Username: "testuser",
|
Username: "testuser",
|
||||||
Email: utils.Ptr("test@example.com"),
|
Email: new("test@example.com"),
|
||||||
FirstName: "John",
|
FirstName: "John",
|
||||||
LastName: "abcdfghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
|
LastName: "abcdfghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
|
||||||
DisplayName: "John Doe",
|
DisplayName: "John Doe",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (m *ApiKeyAuthMiddleware) Add(adminRequired bool) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ApiKeyAuthMiddleware) Verify(c *gin.Context, adminRequired bool) (userID string, isAdmin bool, err error) {
|
func (m *ApiKeyAuthMiddleware) Verify(c *gin.Context, adminRequired bool) (userID string, isAdmin bool, err error) {
|
||||||
apiKey := c.GetHeader("X-API-KEY")
|
apiKey := c.GetHeader("X-API-Key")
|
||||||
|
|
||||||
user, err := m.apiKeyService.ValidateApiKey(c.Request.Context(), apiKey)
|
user, err := m.apiKeyService.ValidateApiKey(c.Request.Context(), apiKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ func NewRateLimitMiddleware() *RateLimitMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *RateLimitMiddleware) Add(limit rate.Limit, burst int) gin.HandlerFunc {
|
func (m *RateLimitMiddleware) Add(limit rate.Limit, burst int) gin.HandlerFunc {
|
||||||
if common.EnvConfig.DisableRateLimiting == true {
|
if common.EnvConfig.DisableRateLimiting {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,13 +70,12 @@ func TestAppConfigVariable_AsMinutesDuration(t *testing.T) {
|
|||||||
// - dto.AppConfigDto should not include "internal" fields from model.AppConfig
|
// - dto.AppConfigDto should not include "internal" fields from model.AppConfig
|
||||||
// This test is primarily meant to catch discrepancies between the two structs as fields are added or removed over time
|
// This test is primarily meant to catch discrepancies between the two structs as fields are added or removed over time
|
||||||
func TestAppConfigStructMatchesUpdateDto(t *testing.T) {
|
func TestAppConfigStructMatchesUpdateDto(t *testing.T) {
|
||||||
appConfigType := reflect.TypeOf(model.AppConfig{})
|
appConfigType := reflect.TypeFor[model.AppConfig]()
|
||||||
updateDtoType := reflect.TypeOf(dto.AppConfigUpdateDto{})
|
updateDtoType := reflect.TypeFor[dto.AppConfigUpdateDto]()
|
||||||
|
|
||||||
// Process AppConfig fields
|
// Process AppConfig fields
|
||||||
appConfigFields := make(map[string]string)
|
appConfigFields := make(map[string]string)
|
||||||
for i := 0; i < appConfigType.NumField(); i++ {
|
for field := range appConfigType.Fields() {
|
||||||
field := appConfigType.Field(i)
|
|
||||||
if field.Tag.Get("key") == "" {
|
if field.Tag.Get("key") == "" {
|
||||||
// Skip internal fields
|
// Skip internal fields
|
||||||
continue
|
continue
|
||||||
@@ -91,9 +90,7 @@ func TestAppConfigStructMatchesUpdateDto(t *testing.T) {
|
|||||||
|
|
||||||
// Process AppConfigUpdateDto fields
|
// Process AppConfigUpdateDto fields
|
||||||
dtoFields := make(map[string]string)
|
dtoFields := make(map[string]string)
|
||||||
for i := 0; i < updateDtoType.NumField(); i++ {
|
for field := range updateDtoType.Fields() {
|
||||||
field := updateDtoType.Field(i)
|
|
||||||
|
|
||||||
// Extract the json name from the tag (takes the part before any binding constraints)
|
// Extract the json name from the tag (takes the part before any binding constraints)
|
||||||
jsonTag := field.Tag.Get("json")
|
jsonTag := field.Tag.Get("json")
|
||||||
jsonName, _, _ := strings.Cut(jsonTag, ",")
|
jsonName, _, _ := strings.Cut(jsonTag, ",")
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ type ReauthenticationToken struct {
|
|||||||
type AuthenticatorTransportList []protocol.AuthenticatorTransport //nolint:recvcheck
|
type AuthenticatorTransportList []protocol.AuthenticatorTransport //nolint:recvcheck
|
||||||
|
|
||||||
// Scan and Value methods for GORM to handle the custom type
|
// Scan and Value methods for GORM to handle the custom type
|
||||||
func (atl *AuthenticatorTransportList) Scan(value interface{}) error {
|
func (atl *AuthenticatorTransportList) Scan(value any) error {
|
||||||
return utils.UnmarshalJSONFromDatabase(atl, value)
|
return utils.UnmarshalJSONFromDatabase(atl, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ func (atl AuthenticatorTransportList) Value() (driver.Value, error) {
|
|||||||
type CredentialParameters []protocol.CredentialParameter //nolint:recvcheck
|
type CredentialParameters []protocol.CredentialParameter //nolint:recvcheck
|
||||||
|
|
||||||
// Scan and Value methods for GORM to handle the custom type
|
// Scan and Value methods for GORM to handle the custom type
|
||||||
func (cp *CredentialParameters) Scan(value interface{}) error {
|
func (cp *CredentialParameters) Scan(value any) error {
|
||||||
return utils.UnmarshalJSONFromDatabase(cp, value)
|
return utils.UnmarshalJSONFromDatabase(cp, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,25 @@ import (
|
|||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const staticApiKeyUserID = "00000000-0000-0000-0000-000000000000"
|
||||||
|
|
||||||
type ApiKeyService struct {
|
type ApiKeyService struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
emailService *EmailService
|
emailService *EmailService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApiKeyService(db *gorm.DB, emailService *EmailService) *ApiKeyService {
|
func NewApiKeyService(ctx context.Context, db *gorm.DB, emailService *EmailService) (*ApiKeyService, error) {
|
||||||
return &ApiKeyService{db: db, emailService: emailService}
|
s := &ApiKeyService{db: db, emailService: emailService}
|
||||||
|
|
||||||
|
if common.EnvConfig.StaticApiKey == "" {
|
||||||
|
err := s.deleteStaticApiKeyUser(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ApiKeyService) ListApiKeys(ctx context.Context, userID string, listRequestOptions utils.ListRequestOptions) ([]model.ApiKey, utils.PaginationResponse, error) {
|
func (s *ApiKeyService) ListApiKeys(ctx context.Context, userID string, listRequestOptions utils.ListRequestOptions) ([]model.ApiKey, utils.PaginationResponse, error) {
|
||||||
@@ -65,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +159,10 @@ func (s *ApiKeyService) ValidateApiKey(ctx context.Context, apiKey string) (mode
|
|||||||
return model.User{}, &common.NoAPIKeyProvidedError{}
|
return model.User{}, &common.NoAPIKeyProvidedError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if common.EnvConfig.StaticApiKey != "" && apiKey == common.EnvConfig.StaticApiKey {
|
||||||
|
return s.initStaticApiKeyUser(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
hashedKey := utils.CreateSha256Hash(apiKey)
|
hashedKey := utils.CreateSha256Hash(apiKey)
|
||||||
|
|
||||||
@@ -154,7 +173,7 @@ func (s *ApiKeyService) ValidateApiKey(ctx context.Context, apiKey string) (mode
|
|||||||
Clauses(clause.Returning{}).
|
Clauses(clause.Returning{}).
|
||||||
Where("key = ? AND expires_at > ?", hashedKey, datatype.DateTime(now)).
|
Where("key = ? AND expires_at > ?", hashedKey, datatype.DateTime(now)).
|
||||||
Updates(&model.ApiKey{
|
Updates(&model.ApiKey{
|
||||||
LastUsedAt: utils.Ptr(datatype.DateTime(now)),
|
LastUsedAt: new(datatype.DateTime(now)),
|
||||||
}).
|
}).
|
||||||
Preload("User").
|
Preload("User").
|
||||||
First(&key).
|
First(&key).
|
||||||
@@ -217,3 +236,47 @@ func (s *ApiKeyService) SendApiKeyExpiringSoonEmail(ctx context.Context, apiKey
|
|||||||
Update("expiration_email_sent", true).
|
Update("expiration_email_sent", true).
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ApiKeyService) initStaticApiKeyUser(ctx context.Context) (user model.User, err error) {
|
||||||
|
err = s.db.
|
||||||
|
WithContext(ctx).
|
||||||
|
First(&user, "id = ?", staticApiKeyUserID).
|
||||||
|
Error
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return model.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameSuffix, err := utils.GenerateRandomAlphanumericString(6)
|
||||||
|
if err != nil {
|
||||||
|
return model.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user = model.User{
|
||||||
|
Base: model.Base{
|
||||||
|
ID: staticApiKeyUserID,
|
||||||
|
},
|
||||||
|
FirstName: "Static API User",
|
||||||
|
Username: "static-api-user-" + usernameSuffix,
|
||||||
|
DisplayName: "Static API User",
|
||||||
|
IsAdmin: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.db.
|
||||||
|
WithContext(ctx).
|
||||||
|
Create(&user).
|
||||||
|
Error
|
||||||
|
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ApiKeyService) deleteStaticApiKeyUser(ctx context.Context) error {
|
||||||
|
return s.db.
|
||||||
|
WithContext(ctx).
|
||||||
|
Delete(&model.User{}, "id = ?", staticApiKeyUserID).
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|||||||
@@ -186,8 +186,7 @@ func (s *AppConfigService) UpdateAppConfig(ctx context.Context, input dto.AppCon
|
|||||||
rt := reflect.ValueOf(input).Type()
|
rt := reflect.ValueOf(input).Type()
|
||||||
rv := reflect.ValueOf(input)
|
rv := reflect.ValueOf(input)
|
||||||
dbUpdate := make([]model.AppConfigVariable, 0, rt.NumField())
|
dbUpdate := make([]model.AppConfigVariable, 0, rt.NumField())
|
||||||
for i := range rt.NumField() {
|
for field := range rt.Fields() {
|
||||||
field := rt.Field(i)
|
|
||||||
value := rv.FieldByName(field.Name).String()
|
value := rv.FieldByName(field.Name).String()
|
||||||
|
|
||||||
// Get the value of the json tag, taking only what's before the comma
|
// Get the value of the json tag, taking only what's before the comma
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
ID: "f4b89dc2-62fb-46bf-9f5f-c34f4eafe93e",
|
ID: "f4b89dc2-62fb-46bf-9f5f-c34f4eafe93e",
|
||||||
},
|
},
|
||||||
Username: "tim",
|
Username: "tim",
|
||||||
Email: utils.Ptr("tim.cook@test.com"),
|
Email: new("tim.cook@test.com"),
|
||||||
EmailVerified: true,
|
EmailVerified: true,
|
||||||
FirstName: "Tim",
|
FirstName: "Tim",
|
||||||
LastName: "Cook",
|
LastName: "Cook",
|
||||||
@@ -93,7 +93,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
ID: "1cd19686-f9a6-43f4-a41f-14a0bf5b4036",
|
ID: "1cd19686-f9a6-43f4-a41f-14a0bf5b4036",
|
||||||
},
|
},
|
||||||
Username: "craig",
|
Username: "craig",
|
||||||
Email: utils.Ptr("craig.federighi@test.com"),
|
Email: new("craig.federighi@test.com"),
|
||||||
EmailVerified: false,
|
EmailVerified: false,
|
||||||
FirstName: "Craig",
|
FirstName: "Craig",
|
||||||
LastName: "Federighi",
|
LastName: "Federighi",
|
||||||
@@ -105,7 +105,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
ID: "d9256384-98ad-49a7-bc58-99ad0b4dc23c",
|
ID: "d9256384-98ad-49a7-bc58-99ad0b4dc23c",
|
||||||
},
|
},
|
||||||
Username: "eddy",
|
Username: "eddy",
|
||||||
Email: utils.Ptr("eddy.cue@test.com"),
|
Email: new("eddy.cue@test.com"),
|
||||||
FirstName: "Eddy",
|
FirstName: "Eddy",
|
||||||
LastName: "Cue",
|
LastName: "Cue",
|
||||||
DisplayName: "Eddy Cue",
|
DisplayName: "Eddy Cue",
|
||||||
@@ -171,12 +171,12 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
ID: "3654a746-35d4-4321-ac61-0bdcff2b4055",
|
ID: "3654a746-35d4-4321-ac61-0bdcff2b4055",
|
||||||
},
|
},
|
||||||
Name: "Nextcloud",
|
Name: "Nextcloud",
|
||||||
LaunchURL: utils.Ptr("https://nextcloud.local"),
|
LaunchURL: new("https://nextcloud.local"),
|
||||||
Secret: "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC", // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
|
Secret: "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC", // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
|
||||||
CallbackURLs: model.UrlList{"http://nextcloud/auth/callback"},
|
CallbackURLs: model.UrlList{"http://nextcloud/auth/callback"},
|
||||||
LogoutCallbackURLs: model.UrlList{"http://nextcloud/auth/logout/callback"},
|
LogoutCallbackURLs: model.UrlList{"http://nextcloud/auth/logout/callback"},
|
||||||
ImageType: utils.StringPointer("png"),
|
ImageType: new("png"),
|
||||||
CreatedByID: utils.Ptr(users[0].ID),
|
CreatedByID: new(users[0].ID),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Base: model.Base{
|
Base: model.Base{
|
||||||
@@ -185,7 +185,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
Name: "Immich",
|
Name: "Immich",
|
||||||
Secret: "$2a$10$Ak.FP8riD1ssy2AGGbG.gOpnp/rBpymd74j0nxNMtW0GG1Lb4gzxe", // PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x
|
Secret: "$2a$10$Ak.FP8riD1ssy2AGGbG.gOpnp/rBpymd74j0nxNMtW0GG1Lb4gzxe", // PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x
|
||||||
CallbackURLs: model.UrlList{"http://immich/auth/callback"},
|
CallbackURLs: model.UrlList{"http://immich/auth/callback"},
|
||||||
CreatedByID: utils.Ptr(users[1].ID),
|
CreatedByID: new(users[1].ID),
|
||||||
IsGroupRestricted: true,
|
IsGroupRestricted: true,
|
||||||
AllowedUserGroups: []model.UserGroup{
|
AllowedUserGroups: []model.UserGroup{
|
||||||
userGroups[1],
|
userGroups[1],
|
||||||
@@ -200,7 +200,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
CallbackURLs: model.UrlList{"http://tailscale/auth/callback"},
|
CallbackURLs: model.UrlList{"http://tailscale/auth/callback"},
|
||||||
LogoutCallbackURLs: model.UrlList{"http://tailscale/auth/logout/callback"},
|
LogoutCallbackURLs: model.UrlList{"http://tailscale/auth/logout/callback"},
|
||||||
IsGroupRestricted: true,
|
IsGroupRestricted: true,
|
||||||
CreatedByID: utils.Ptr(users[0].ID),
|
CreatedByID: new(users[0].ID),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Base: model.Base{
|
Base: model.Base{
|
||||||
@@ -209,7 +209,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
Name: "Federated",
|
Name: "Federated",
|
||||||
Secret: "$2a$10$Ak.FP8riD1ssy2AGGbG.gOpnp/rBpymd74j0nxNMtW0GG1Lb4gzxe", // PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x
|
Secret: "$2a$10$Ak.FP8riD1ssy2AGGbG.gOpnp/rBpymd74j0nxNMtW0GG1Lb4gzxe", // PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x
|
||||||
CallbackURLs: model.UrlList{"http://federated/auth/callback"},
|
CallbackURLs: model.UrlList{"http://federated/auth/callback"},
|
||||||
CreatedByID: utils.Ptr(users[1].ID),
|
CreatedByID: new(users[1].ID),
|
||||||
AllowedUserGroups: []model.UserGroup{},
|
AllowedUserGroups: []model.UserGroup{},
|
||||||
Credentials: model.OidcClientCredentials{
|
Credentials: model.OidcClientCredentials{
|
||||||
FederatedIdentities: []model.OidcClientFederatedIdentity{
|
FederatedIdentities: []model.OidcClientFederatedIdentity{
|
||||||
@@ -229,7 +229,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
Name: "SCIM Client",
|
Name: "SCIM Client",
|
||||||
Secret: "$2a$10$h4wfa8gI7zavDAxwzSq1sOwYU4e8DwK1XZ8ZweNnY5KzlJ3Iz.qdK", // nQbiuMRG7FpdK2EnDd5MBivWQeKFXohn
|
Secret: "$2a$10$h4wfa8gI7zavDAxwzSq1sOwYU4e8DwK1XZ8ZweNnY5KzlJ3Iz.qdK", // nQbiuMRG7FpdK2EnDd5MBivWQeKFXohn
|
||||||
CallbackURLs: model.UrlList{"http://scimclient/auth/callback"},
|
CallbackURLs: model.UrlList{"http://scimclient/auth/callback"},
|
||||||
CreatedByID: utils.Ptr(users[0].ID),
|
CreatedByID: new(users[0].ID),
|
||||||
IsGroupRestricted: true,
|
IsGroupRestricted: true,
|
||||||
AllowedUserGroups: []model.UserGroup{
|
AllowedUserGroups: []model.UserGroup{
|
||||||
userGroups[0],
|
userGroups[0],
|
||||||
@@ -458,7 +458,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
{
|
{
|
||||||
Key: jwkutils.PrivateKeyDBKey,
|
Key: jwkutils.PrivateKeyDBKey,
|
||||||
// {"alg":"RS256","d":"mvMDWSdPPvcum0c0iEHE2gbqtV2NKMmLwrl9E6K7g8lTV95SePLnW_bwyMPV7EGp7PQk3l17I5XRhFjze7GqTnFIOgKzMianPs7jv2ELtBMGK0xOPATgu1iGb70xZ6vcvuEfRyY3dJ0zr4jpUdVuXwKmx9rK4IdZn2dFCKfvSuspqIpz11RhF1ALrqDLkxGVv7ZwNh0_VhJZU9hcjG5l6xc7rQEKpPRkZp0IdjkGS8Z0FskoVaiRIWAbZuiVFB9WCW8k1czC4HQTPLpII01bUQx2ludbm0UlXRgVU9ptUUbU7GAImQqTOW8LfPGklEvcgzlIlR_oqw4P9yBxLi-yMQ","dp":"pvNCSnnhbo8Igw9psPR-DicxFnkXlu_ix4gpy6efTrxA-z1VDFDioJ814vKQNioYDzpyAP1gfMPhRkvG_q0hRZsJah3Sb9dfA-WkhSWY7lURQP4yIBTMU0PF_rEATuS7lRciYk1SOx5fqXZd3m_LP0vpBC4Ujlq6NAq6CIjCnms","dq":"TtUVGCCkPNgfOLmkYXu7dxxUCV5kB01-xAEK2OY0n0pG8vfDophH4_D_ZC7nvJ8J9uDhs_3JStexq1lIvaWtG99RNTChIEDzpdn6GH9yaVcb_eB4uJjrNm64FhF8PGCCwxA-xMCZMaARKwhMB2_IOMkxUbWboL3gnhJ2rDO_QO0","e":"AQAB","kid":"8uHDw3M6rf8","kty":"RSA","n":"yaeEL0VKoPBXIAaWXsUgmu05lAvEIIdJn0FX9lHh4JE5UY9B83C5sCNdhs9iSWzpeP11EVjWp8i3Yv2CF7c7u50BXnVBGtxpZpFC-585UXacoJ0chUmarL9GRFJcM1nPHBTFu68aRrn1rIKNHUkNaaxFo0NFGl_4EDDTO8HwawTjwkPoQlRzeByhlvGPVvwgB3Fn93B8QJ_cZhXKxJvjjrC_8Pk76heC_ntEMru71Ix77BoC3j2TuyiN7m9RNBW8BU5q6lKoIdvIeZfTFLzi37iufyfvMrJTixp9zhNB1NxlLCeOZl2MXegtiGqd2H3cbAyqoOiv9ihUWTfXj7SxJw","p":"_Yylc9e07CKdqNRD2EosMC2mrhrEa9j5oY_l00Qyy4-jmCA59Q9viyqvveRo0U7cRvFA5BWgWN6GGLh1DG3X-QBqVr0dnk3uzbobb55RYUXyPLuBZI2q6w2oasbiDwPdY7KpkVv_H-bpITQlyDvO8hhucA6rUV7F6KTQVz8M3Ms","q":"y5p3hch-7jJ21TkAhp_Vk1fLCAuD4tbErwQs2of9ja8sB4iJOs5Wn6HD3P7Mc8Plye7qaLHvzc8I5g0tPKWvC0DPd_FLPXiWwMVAzee3NUX_oGeJNOQp11y1w_KqdO9qZqHSEPZ3NcFL_SZMFgggxhM1uzRiPzsVN0lnD_6prZU","qi":"2Grt6uXHm61ji3xSdkBWNtUnj19vS1-7rFJp5SoYztVQVThf_W52BAiXKBdYZDRVoItC_VS2NvAOjeJjhYO_xQ_q3hK7MdtuXfEPpLnyXKkmWo3lrJ26wbeF6l05LexCkI7ShsOuSt-dsyaTJTszuKDIA6YOfWvfo3aVZmlWRaI","use":"sig"}
|
// {"alg":"RS256","d":"mvMDWSdPPvcum0c0iEHE2gbqtV2NKMmLwrl9E6K7g8lTV95SePLnW_bwyMPV7EGp7PQk3l17I5XRhFjze7GqTnFIOgKzMianPs7jv2ELtBMGK0xOPATgu1iGb70xZ6vcvuEfRyY3dJ0zr4jpUdVuXwKmx9rK4IdZn2dFCKfvSuspqIpz11RhF1ALrqDLkxGVv7ZwNh0_VhJZU9hcjG5l6xc7rQEKpPRkZp0IdjkGS8Z0FskoVaiRIWAbZuiVFB9WCW8k1czC4HQTPLpII01bUQx2ludbm0UlXRgVU9ptUUbU7GAImQqTOW8LfPGklEvcgzlIlR_oqw4P9yBxLi-yMQ","dp":"pvNCSnnhbo8Igw9psPR-DicxFnkXlu_ix4gpy6efTrxA-z1VDFDioJ814vKQNioYDzpyAP1gfMPhRkvG_q0hRZsJah3Sb9dfA-WkhSWY7lURQP4yIBTMU0PF_rEATuS7lRciYk1SOx5fqXZd3m_LP0vpBC4Ujlq6NAq6CIjCnms","dq":"TtUVGCCkPNgfOLmkYXu7dxxUCV5kB01-xAEK2OY0n0pG8vfDophH4_D_ZC7nvJ8J9uDhs_3JStexq1lIvaWtG99RNTChIEDzpdn6GH9yaVcb_eB4uJjrNm64FhF8PGCCwxA-xMCZMaARKwhMB2_IOMkxUbWboL3gnhJ2rDO_QO0","e":"AQAB","kid":"8uHDw3M6rf8","kty":"RSA","n":"yaeEL0VKoPBXIAaWXsUgmu05lAvEIIdJn0FX9lHh4JE5UY9B83C5sCNdhs9iSWzpeP11EVjWp8i3Yv2CF7c7u50BXnVBGtxpZpFC-585UXacoJ0chUmarL9GRFJcM1nPHBTFu68aRrn1rIKNHUkNaaxFo0NFGl_4EDDTO8HwawTjwkPoQlRzeByhlvGPVvwgB3Fn93B8QJ_cZhXKxJvjjrC_8Pk76heC_ntEMru71Ix77BoC3j2TuyiN7m9RNBW8BU5q6lKoIdvIeZfTFLzi37iufyfvMrJTixp9zhNB1NxlLCeOZl2MXegtiGqd2H3cbAyqoOiv9ihUWTfXj7SxJw","p":"_Yylc9e07CKdqNRD2EosMC2mrhrEa9j5oY_l00Qyy4-jmCA59Q9viyqvveRo0U7cRvFA5BWgWN6GGLh1DG3X-QBqVr0dnk3uzbobb55RYUXyPLuBZI2q6w2oasbiDwPdY7KpkVv_H-bpITQlyDvO8hhucA6rUV7F6KTQVz8M3Ms","q":"y5p3hch-7jJ21TkAhp_Vk1fLCAuD4tbErwQs2of9ja8sB4iJOs5Wn6HD3P7Mc8Plye7qaLHvzc8I5g0tPKWvC0DPd_FLPXiWwMVAzee3NUX_oGeJNOQp11y1w_KqdO9qZqHSEPZ3NcFL_SZMFgggxhM1uzRiPzsVN0lnD_6prZU","qi":"2Grt6uXHm61ji3xSdkBWNtUnj19vS1-7rFJp5SoYztVQVThf_W52BAiXKBdYZDRVoItC_VS2NvAOjeJjhYO_xQ_q3hK7MdtuXfEPpLnyXKkmWo3lrJ26wbeF6l05LexCkI7ShsOuSt-dsyaTJTszuKDIA6YOfWvfo3aVZmlWRaI","use":"sig"}
|
||||||
Value: utils.Ptr("7d/5hl7diJ2rnFL14hEAQf9tzpu29aqXQ8jpJ2iqqKUNFZpdOkEpud0CmRv4H3r8yyk2u/Gqqj9klSy58DJkYXGF5PAYgLyoBIb7L3JXWRbxg4cQ3QJCug13l2OTmpAKoVc+rmX8c3j3h1sNqyJ+7Ql5sS0jSeyiYgIsFNCdnK5alBDyvtcpe/QDpklmP4JCeVpvmf2rLGplk3g5UO5ydJ8UiDXxfDmi+gF6NKJvrGnnah8Ar3G/x88z+tTJtp0DIQFwxXwUM2XZqzEVGm8K2r0w5o9/Keh6bBBaiuH2C78ZOaijGV3DovhR+e9J0cYUYGwT42MZMx9fSWQ/lvWGGnf+Uq3MXJfjWSREfhkp8KTQwR9F7+dnVJWswOEk7jPR8I7hCWTMxJyvaFX3wgAXIVmhrgXZQQbYOqTt56IoqUl0xOJku8dA8opg2UcLlmmuOh6+hfkXKsiiS/H/9c1BVIGj1fCOiT6IePh4wKKSTbwJnPD5EKmdJpgTsUpjcDnXQKY4ReO0UpdRdKxwRDDLeQuG6j+ljGxR9GPudCU9Nmci6rFVI6n5LWYkQxBA1O73RpmXRZPDzntDfpXMEonkmSvOoxaCK2Id7CRKMdqvR0kEouwnhk5WSFtsfi3sA0pkXzPFxwZeWM8vFtbffZOZzXaOhxCOfcj1NClZohlZhyc4jvkxmrpY7PSaAzih0AmHI7y0LYFi6fZu/K4EheVa1+KF55nWZ8ARikHMWKAKkyExkTak7xyN884TDmzURRaPlQg4jzQte5WMNjAG/hlHibdMBNvgwiYd49ZxteJ8ABdbiXVRl+2JGbdjl2ubpQZwOn7bJKlqO56bIwsZ+e4+pXsuOGdBahkHrUjtMEmH3DZbGc6CJLbcmdhdpApLQRRcLAazxJhzAwJ47FRYsHsj57LnYNvmcKdIxw8rxCdLUuzz95uw0T3ankEO5J9sjem+HMEuKdwXK1UcuOn2rjR8Sd/BuvQmeso27dFbPXqXYNS90Ml45YyTvcKSiopD181oZR703TFUSpR7dsiqROMr+p/2jN9h6a8WbQ8xpksyclaQByY/M77AssbXnG6wfhRsntNIINCZLbBnjXOyz6ZHIC5K4tSTdcnWaiYPeRPQmnw9UUvHAcNU2yMWsy0eU377yDS0WstTxOdQutTdkczl8kv5Lo26JiEK7mSIuRK19ffF9Zz8FG8+eKv5zdyIPjyQRDYBysUoDv5huKe2eoxJu/MWS2Pql/ZtUGeD6Ozm3mCvh0vQ9ceagBkY6Ocm3du0ziAKP29Ri0mjg4DizVorbLzsh+EQH/s2Pi9MnjUZDlEmuLl2Xfp7/w4j/8u0N0tVR70VDFuGdKpTjFY3vS8EJrPtyMTM51x1D9rb8gIql8aR/rJw4YF+huxg1mv5n6+tGVqg5msbPmF12eJijP4lkmaRwIpLW5pJTtaDkUj7uOeu1mm4k+Dt5nh0/0jPHzrv6bcTCcbV7UjMHDoTXXqEpFAAJ66rHR7zdAJu+YKsnTIZyLmOpcowq7LL8G9qTvV0OSpyQWUIavRSgbDHFqEqRs+JU94jAzkq8nCY5MTd9m5sIv9InfdT3k+pwpsE/FKge8nghFLtbUrafGkzTky8SE2druvVcIvbfXMfLIKRUYjJgnWc0gQzF5J6pzXM7D2r/RG6JDzASqjlbURq6v9bhNerlOVdMujWKEEVcKWIzlbt4RkihRjM8AUqIZQOyicGQ+4yfIjAHw5viuABONYs3OIWULnFqJxdvS9rNKhfxSjIq9cfqyzevq2xrRoMXEonobh6M3bD2Vang8OAeVeD1OXWPERi4pepCYFS9RJ/Xa/UWxptsqSNuGcb3fAzQSmLpXLGdWRoKXvSe7EYgc0bGcLOjSTu5RURKo+EF9i4KT9EJauf6VXw5dTf/CCIJRXE1bWzXhSCFYntohYhX2ldOCDYpi/jFBC6Vtkw0ud3/xq8Nmhd5gUk+SpngByCZH3Pm3H+jvlbMpiqkDkm1v74hDX13Xhrcw2eWyuqKBVoRCCniUvwpYNbGvBfjC6Hcizv0Aybciwj+4nybt5EPoEUm6S6Gs7fG7QpPdvrzpAxX70MlmdkF/gwyuhbEeJhLK+WL7qAsN5CvHPzVbsIf90x+nGTtMJPgpxVr0tJMj+vprXV4WxutfARBiOnqe58MhA857sd+MzKBgKnoLOBRTiC3qc/0/ULwbG2HCCD7nmwzz7M4nUuMvo8rgS7z0BF68OClT8X3JwSXbL5Wg=="),
|
Value: new("7d/5hl7diJ2rnFL14hEAQf9tzpu29aqXQ8jpJ2iqqKUNFZpdOkEpud0CmRv4H3r8yyk2u/Gqqj9klSy58DJkYXGF5PAYgLyoBIb7L3JXWRbxg4cQ3QJCug13l2OTmpAKoVc+rmX8c3j3h1sNqyJ+7Ql5sS0jSeyiYgIsFNCdnK5alBDyvtcpe/QDpklmP4JCeVpvmf2rLGplk3g5UO5ydJ8UiDXxfDmi+gF6NKJvrGnnah8Ar3G/x88z+tTJtp0DIQFwxXwUM2XZqzEVGm8K2r0w5o9/Keh6bBBaiuH2C78ZOaijGV3DovhR+e9J0cYUYGwT42MZMx9fSWQ/lvWGGnf+Uq3MXJfjWSREfhkp8KTQwR9F7+dnVJWswOEk7jPR8I7hCWTMxJyvaFX3wgAXIVmhrgXZQQbYOqTt56IoqUl0xOJku8dA8opg2UcLlmmuOh6+hfkXKsiiS/H/9c1BVIGj1fCOiT6IePh4wKKSTbwJnPD5EKmdJpgTsUpjcDnXQKY4ReO0UpdRdKxwRDDLeQuG6j+ljGxR9GPudCU9Nmci6rFVI6n5LWYkQxBA1O73RpmXRZPDzntDfpXMEonkmSvOoxaCK2Id7CRKMdqvR0kEouwnhk5WSFtsfi3sA0pkXzPFxwZeWM8vFtbffZOZzXaOhxCOfcj1NClZohlZhyc4jvkxmrpY7PSaAzih0AmHI7y0LYFi6fZu/K4EheVa1+KF55nWZ8ARikHMWKAKkyExkTak7xyN884TDmzURRaPlQg4jzQte5WMNjAG/hlHibdMBNvgwiYd49ZxteJ8ABdbiXVRl+2JGbdjl2ubpQZwOn7bJKlqO56bIwsZ+e4+pXsuOGdBahkHrUjtMEmH3DZbGc6CJLbcmdhdpApLQRRcLAazxJhzAwJ47FRYsHsj57LnYNvmcKdIxw8rxCdLUuzz95uw0T3ankEO5J9sjem+HMEuKdwXK1UcuOn2rjR8Sd/BuvQmeso27dFbPXqXYNS90Ml45YyTvcKSiopD181oZR703TFUSpR7dsiqROMr+p/2jN9h6a8WbQ8xpksyclaQByY/M77AssbXnG6wfhRsntNIINCZLbBnjXOyz6ZHIC5K4tSTdcnWaiYPeRPQmnw9UUvHAcNU2yMWsy0eU377yDS0WstTxOdQutTdkczl8kv5Lo26JiEK7mSIuRK19ffF9Zz8FG8+eKv5zdyIPjyQRDYBysUoDv5huKe2eoxJu/MWS2Pql/ZtUGeD6Ozm3mCvh0vQ9ceagBkY6Ocm3du0ziAKP29Ri0mjg4DizVorbLzsh+EQH/s2Pi9MnjUZDlEmuLl2Xfp7/w4j/8u0N0tVR70VDFuGdKpTjFY3vS8EJrPtyMTM51x1D9rb8gIql8aR/rJw4YF+huxg1mv5n6+tGVqg5msbPmF12eJijP4lkmaRwIpLW5pJTtaDkUj7uOeu1mm4k+Dt5nh0/0jPHzrv6bcTCcbV7UjMHDoTXXqEpFAAJ66rHR7zdAJu+YKsnTIZyLmOpcowq7LL8G9qTvV0OSpyQWUIavRSgbDHFqEqRs+JU94jAzkq8nCY5MTd9m5sIv9InfdT3k+pwpsE/FKge8nghFLtbUrafGkzTky8SE2druvVcIvbfXMfLIKRUYjJgnWc0gQzF5J6pzXM7D2r/RG6JDzASqjlbURq6v9bhNerlOVdMujWKEEVcKWIzlbt4RkihRjM8AUqIZQOyicGQ+4yfIjAHw5viuABONYs3OIWULnFqJxdvS9rNKhfxSjIq9cfqyzevq2xrRoMXEonobh6M3bD2Vang8OAeVeD1OXWPERi4pepCYFS9RJ/Xa/UWxptsqSNuGcb3fAzQSmLpXLGdWRoKXvSe7EYgc0bGcLOjSTu5RURKo+EF9i4KT9EJauf6VXw5dTf/CCIJRXE1bWzXhSCFYntohYhX2ldOCDYpi/jFBC6Vtkw0ud3/xq8Nmhd5gUk+SpngByCZH3Pm3H+jvlbMpiqkDkm1v74hDX13Xhrcw2eWyuqKBVoRCCniUvwpYNbGvBfjC6Hcizv0Aybciwj+4nybt5EPoEUm6S6Gs7fG7QpPdvrzpAxX70MlmdkF/gwyuhbEeJhLK+WL7qAsN5CvHPzVbsIf90x+nGTtMJPgpxVr0tJMj+vprXV4WxutfARBiOnqe58MhA857sd+MzKBgKnoLOBRTiC3qc/0/ULwbG2HCCD7nmwzz7M4nUuMvo8rgS7z0BF68OClT8X3JwSXbL5Wg=="),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,39 +129,39 @@ func (s *ExportService) getScanValuesForTable(cols []string, types utils.DBSchem
|
|||||||
case "boolean", "bool":
|
case "boolean", "bool":
|
||||||
var x bool
|
var x bool
|
||||||
if types[col].Nullable {
|
if types[col].Nullable {
|
||||||
res[i] = utils.Ptr(utils.Ptr(x))
|
res[i] = new(new(x))
|
||||||
} else {
|
} else {
|
||||||
res[i] = utils.Ptr(x)
|
res[i] = new(x)
|
||||||
}
|
}
|
||||||
case "blob", "bytea", "jsonb":
|
case "blob", "bytea", "jsonb":
|
||||||
// Treat jsonb columns as binary too
|
// Treat jsonb columns as binary too
|
||||||
var x []byte
|
var x []byte
|
||||||
if types[col].Nullable {
|
if types[col].Nullable {
|
||||||
res[i] = utils.Ptr(utils.Ptr(x))
|
res[i] = new(new(x))
|
||||||
} else {
|
} else {
|
||||||
res[i] = utils.Ptr(x)
|
res[i] = new(x)
|
||||||
}
|
}
|
||||||
case "timestamp", "timestamptz", "timestamp with time zone", "datetime":
|
case "timestamp", "timestamptz", "timestamp with time zone", "datetime":
|
||||||
var x datatype.DateTime
|
var x datatype.DateTime
|
||||||
if types[col].Nullable {
|
if types[col].Nullable {
|
||||||
res[i] = utils.Ptr(utils.Ptr(x))
|
res[i] = new(new(x))
|
||||||
} else {
|
} else {
|
||||||
res[i] = utils.Ptr(x)
|
res[i] = new(x)
|
||||||
}
|
}
|
||||||
case "integer", "int", "bigint":
|
case "integer", "int", "bigint":
|
||||||
var x int64
|
var x int64
|
||||||
if types[col].Nullable {
|
if types[col].Nullable {
|
||||||
res[i] = utils.Ptr(utils.Ptr(x))
|
res[i] = new(new(x))
|
||||||
} else {
|
} else {
|
||||||
res[i] = utils.Ptr(x)
|
res[i] = new(x)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Treat everything else as a string (including the "numeric" type)
|
// Treat everything else as a string (including the "numeric" type)
|
||||||
var x string
|
var x string
|
||||||
if types[col].Nullable {
|
if types[col].Nullable {
|
||||||
res[i] = utils.Ptr(utils.Ptr(x))
|
res[i] = new(new(x))
|
||||||
} else {
|
} else {
|
||||||
res[i] = utils.Ptr(x)
|
res[i] = new(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -22,6 +23,8 @@ import (
|
|||||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxTotalSize = 300 * 1024 * 1024 // 300 MB limit for total decompressed size
|
||||||
|
|
||||||
type GeoLiteService struct {
|
type GeoLiteService struct {
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
disableUpdater bool
|
disableUpdater bool
|
||||||
@@ -151,7 +154,24 @@ func (s *GeoLiteService) isDatabaseUpToDate() bool {
|
|||||||
|
|
||||||
// extractDatabase extracts the database file from the tar.gz archive directly to the target location.
|
// extractDatabase extracts the database file from the tar.gz archive directly to the target location.
|
||||||
func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
|
func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
|
||||||
gzr, err := gzip.NewReader(reader)
|
// Check for gzip magic number
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
_, err := io.ReadFull(reader, buf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read magic number: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the file starts with the gzip magic number
|
||||||
|
// Gosec returns false positive for "G602: slice index out of range"
|
||||||
|
//nolint:gosec
|
||||||
|
isGzip := buf[0] == 0x1f && buf[1] == 0x8b
|
||||||
|
|
||||||
|
if !isGzip {
|
||||||
|
// If not gzip, assume it's a regular database file
|
||||||
|
return s.writeDatabaseFile(io.MultiReader(bytes.NewReader(buf), reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
gzr, err := gzip.NewReader(io.MultiReader(bytes.NewReader(buf), reader))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create gzip reader: %w", err)
|
return fmt.Errorf("failed to create gzip reader: %w", err)
|
||||||
}
|
}
|
||||||
@@ -160,7 +180,6 @@ func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
|
|||||||
tarReader := tar.NewReader(gzr)
|
tarReader := tar.NewReader(gzr)
|
||||||
|
|
||||||
var totalSize int64
|
var totalSize int64
|
||||||
const maxTotalSize = 300 * 1024 * 1024 // 300 MB limit for total decompressed size
|
|
||||||
|
|
||||||
// Iterate over the files in the tar archive
|
// Iterate over the files in the tar archive
|
||||||
for {
|
for {
|
||||||
@@ -222,3 +241,47 @@ func (s *GeoLiteService) extractDatabase(reader io.Reader) error {
|
|||||||
|
|
||||||
return errors.New("GeoLite2-City.mmdb not found in archive")
|
return errors.New("GeoLite2-City.mmdb not found in archive")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GeoLiteService) writeDatabaseFile(reader io.Reader) error {
|
||||||
|
baseDir := filepath.Dir(common.EnvConfig.GeoLiteDBPath)
|
||||||
|
tmpFile, err := os.CreateTemp(baseDir, "geolite.*.mmdb.tmp")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create temporary database file: %w", err)
|
||||||
|
}
|
||||||
|
defer tmpFile.Close()
|
||||||
|
|
||||||
|
// Limit the amount we read to maxTotalSize.
|
||||||
|
// We read one extra byte to detect if the source is larger than the limit.
|
||||||
|
limitReader := io.LimitReader(reader, maxTotalSize+1)
|
||||||
|
|
||||||
|
// Write the file contents directly to the temporary file
|
||||||
|
written, err := io.Copy(tmpFile, limitReader)
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(tmpFile.Name())
|
||||||
|
return fmt.Errorf("failed to write database file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if written > maxTotalSize {
|
||||||
|
os.Remove(tmpFile.Name())
|
||||||
|
return errors.New("total database size exceeds maximum allowed limit")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the downloaded database file
|
||||||
|
if db, err := maxminddb.Open(tmpFile.Name()); err == nil {
|
||||||
|
db.Close()
|
||||||
|
} else {
|
||||||
|
os.Remove(tmpFile.Name())
|
||||||
|
return fmt.Errorf("failed to open downloaded database file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure atomic replacement of the old database file
|
||||||
|
s.mutex.Lock()
|
||||||
|
err = os.Rename(tmpFile.Name(), common.EnvConfig.GeoLiteDBPath)
|
||||||
|
s.mutex.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(tmpFile.Name())
|
||||||
|
return fmt.Errorf("failed to replace database file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/lestrrat-go/jwx/v3/jwa"
|
"github.com/lestrrat-go/jwx/v3/jwa"
|
||||||
"github.com/lestrrat-go/jwx/v3/jwk"
|
"github.com/lestrrat-go/jwx/v3/jwk"
|
||||||
"github.com/lestrrat-go/jwx/v3/jwt"
|
"github.com/lestrrat-go/jwx/v3/jwt"
|
||||||
@@ -193,6 +194,7 @@ func (s *JwtService) GenerateAccessToken(user model.User) (string, error) {
|
|||||||
Expiration(now.Add(s.appConfigService.GetDbConfig().SessionDuration.AsDurationMinutes())).
|
Expiration(now.Add(s.appConfigService.GetDbConfig().SessionDuration.AsDurationMinutes())).
|
||||||
IssuedAt(now).
|
IssuedAt(now).
|
||||||
Issuer(s.envConfig.AppURL).
|
Issuer(s.envConfig.AppURL).
|
||||||
|
JwtID(uuid.New().String()).
|
||||||
Build()
|
Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to build token: %w", err)
|
return "", fmt.Errorf("failed to build token: %w", err)
|
||||||
@@ -247,6 +249,7 @@ func (s *JwtService) BuildIDToken(userClaims map[string]any, clientID string, no
|
|||||||
Expiration(now.Add(1 * time.Hour)).
|
Expiration(now.Add(1 * time.Hour)).
|
||||||
IssuedAt(now).
|
IssuedAt(now).
|
||||||
Issuer(s.envConfig.AppURL).
|
Issuer(s.envConfig.AppURL).
|
||||||
|
JwtID(uuid.New().String()).
|
||||||
Build()
|
Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to build token: %w", err)
|
return nil, fmt.Errorf("failed to build token: %w", err)
|
||||||
@@ -336,6 +339,7 @@ func (s *JwtService) BuildOAuthAccessToken(user model.User, clientID string) (jw
|
|||||||
Expiration(now.Add(1 * time.Hour)).
|
Expiration(now.Add(1 * time.Hour)).
|
||||||
IssuedAt(now).
|
IssuedAt(now).
|
||||||
Issuer(s.envConfig.AppURL).
|
Issuer(s.envConfig.AppURL).
|
||||||
|
JwtID(uuid.New().String()).
|
||||||
Build()
|
Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to build token: %w", err)
|
return nil, fmt.Errorf("failed to build token: %w", err)
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ import (
|
|||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
|
||||||
jwkutils "github.com/pocket-id/pocket-id/backend/internal/utils/jwk"
|
jwkutils "github.com/pocket-id/pocket-id/backend/internal/utils/jwk"
|
||||||
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testEncryptionKey = "0123456789abcdef0123456789abcdef"
|
const testEncryptionKey = "0123456789abcdef0123456789abcdef"
|
||||||
|
|
||||||
|
const uuidRegexPattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
|
||||||
|
|
||||||
func newTestEnvConfig() *common.EnvConfigSchema {
|
func newTestEnvConfig() *common.EnvConfigSchema {
|
||||||
return &common.EnvConfigSchema{
|
return &common.EnvConfigSchema{
|
||||||
AppURL: "https://test.example.com",
|
AppURL: "https://test.example.com",
|
||||||
@@ -303,7 +304,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "user123"},
|
Base: model.Base{ID: "user123"},
|
||||||
Email: utils.Ptr("user@example.com"),
|
Email: new("user@example.com"),
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,6 +324,9 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
audience, ok := claims.Audience()
|
audience, ok := claims.Audience()
|
||||||
_ = assert.True(t, ok, "Audience not found in token") &&
|
_ = assert.True(t, ok, "Audience not found in token") &&
|
||||||
assert.Equal(t, []string{service.envConfig.AppURL}, audience, "Audience should contain the app URL")
|
assert.Equal(t, []string{service.envConfig.AppURL}, audience, "Audience should contain the app URL")
|
||||||
|
jwtID, ok := claims.JwtID()
|
||||||
|
_ = assert.True(t, ok, "JWT ID not found in token") &&
|
||||||
|
assert.Regexp(t, uuidRegexPattern, jwtID, "JWT ID is not a UUID")
|
||||||
|
|
||||||
expectedExp := time.Now().Add(1 * time.Hour)
|
expectedExp := time.Now().Add(1 * time.Hour)
|
||||||
expiration, ok := claims.Expiration()
|
expiration, ok := claims.Expiration()
|
||||||
@@ -336,7 +340,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
adminUser := model.User{
|
adminUser := model.User{
|
||||||
Base: model.Base{ID: "admin123"},
|
Base: model.Base{ID: "admin123"},
|
||||||
Email: utils.Ptr("admin@example.com"),
|
Email: new("admin@example.com"),
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +392,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "eddsauser123"},
|
Base: model.Base{ID: "eddsauser123"},
|
||||||
Email: utils.Ptr("eddsauser@example.com"),
|
Email: new("eddsauser@example.com"),
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +429,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "ecdsauser123"},
|
Base: model.Base{ID: "ecdsauser123"},
|
||||||
Email: utils.Ptr("ecdsauser@example.com"),
|
Email: new("ecdsauser@example.com"),
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +466,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "rsauser123"},
|
Base: model.Base{ID: "rsauser123"},
|
||||||
Email: utils.Ptr("rsauser@example.com"),
|
Email: new("rsauser@example.com"),
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,7 +501,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
t.Run("generates and verifies ID token with standard claims", func(t *testing.T) {
|
t.Run("generates and verifies ID token with standard claims", func(t *testing.T) {
|
||||||
service, _, _ := setupJwtService(t, mockConfig)
|
service, _, _ := setupJwtService(t, mockConfig)
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "user123",
|
"sub": "user123",
|
||||||
"name": "Test User",
|
"name": "Test User",
|
||||||
"email": "user@example.com",
|
"email": "user@example.com",
|
||||||
@@ -520,6 +524,9 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
issuer, ok := claims.Issuer()
|
issuer, ok := claims.Issuer()
|
||||||
_ = assert.True(t, ok, "Issuer not found in token") &&
|
_ = assert.True(t, ok, "Issuer not found in token") &&
|
||||||
assert.Equal(t, service.envConfig.AppURL, issuer, "Issuer should match app URL")
|
assert.Equal(t, service.envConfig.AppURL, issuer, "Issuer should match app URL")
|
||||||
|
jwtID, ok := claims.JwtID()
|
||||||
|
_ = assert.True(t, ok, "JWT ID not found in token") &&
|
||||||
|
assert.Regexp(t, uuidRegexPattern, jwtID, "JWT ID is not a UUID")
|
||||||
|
|
||||||
expectedExp := time.Now().Add(1 * time.Hour)
|
expectedExp := time.Now().Add(1 * time.Hour)
|
||||||
expiration, ok := claims.Expiration()
|
expiration, ok := claims.Expiration()
|
||||||
@@ -531,7 +538,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
t.Run("can accept expired tokens if told so", func(t *testing.T) {
|
t.Run("can accept expired tokens if told so", func(t *testing.T) {
|
||||||
service, _, _ := setupJwtService(t, mockConfig)
|
service, _, _ := setupJwtService(t, mockConfig)
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "user123",
|
"sub": "user123",
|
||||||
"name": "Test User",
|
"name": "Test User",
|
||||||
"email": "user@example.com",
|
"email": "user@example.com",
|
||||||
@@ -579,7 +586,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
t.Run("generates and verifies ID token with nonce", func(t *testing.T) {
|
t.Run("generates and verifies ID token with nonce", func(t *testing.T) {
|
||||||
service, _, _ := setupJwtService(t, mockConfig)
|
service, _, _ := setupJwtService(t, mockConfig)
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "user456",
|
"sub": "user456",
|
||||||
"name": "Another User",
|
"name": "Another User",
|
||||||
}
|
}
|
||||||
@@ -604,7 +611,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
t.Run("fails verification with incorrect issuer", func(t *testing.T) {
|
t.Run("fails verification with incorrect issuer", func(t *testing.T) {
|
||||||
service, _, _ := setupJwtService(t, mockConfig)
|
service, _, _ := setupJwtService(t, mockConfig)
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "user789",
|
"sub": "user789",
|
||||||
}
|
}
|
||||||
tokenString, err := service.GenerateIDToken(userClaims, "client-789", "")
|
tokenString, err := service.GenerateIDToken(userClaims, "client-789", "")
|
||||||
@@ -626,7 +633,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "eddsauser456",
|
"sub": "eddsauser456",
|
||||||
"name": "EdDSA User",
|
"name": "EdDSA User",
|
||||||
"email": "eddsauser@example.com",
|
"email": "eddsauser@example.com",
|
||||||
@@ -664,7 +671,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "ecdsauser456",
|
"sub": "ecdsauser456",
|
||||||
"email": "ecdsauser@example.com",
|
"email": "ecdsauser@example.com",
|
||||||
}
|
}
|
||||||
@@ -701,7 +708,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
assert.Equal(t, origKeyID, loadedKeyID, "Loaded key should have the same ID as the original")
|
||||||
|
|
||||||
userClaims := map[string]interface{}{
|
userClaims := map[string]any{
|
||||||
"sub": "rsauser456",
|
"sub": "rsauser456",
|
||||||
"name": "RSA User",
|
"name": "RSA User",
|
||||||
"email": "rsauser@example.com",
|
"email": "rsauser@example.com",
|
||||||
@@ -734,7 +741,7 @@ func TestGenerateVerifyOAuthAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "user123"},
|
Base: model.Base{ID: "user123"},
|
||||||
Email: utils.Ptr("user@example.com"),
|
Email: new("user@example.com"),
|
||||||
}
|
}
|
||||||
const clientID = "test-client-123"
|
const clientID = "test-client-123"
|
||||||
|
|
||||||
@@ -754,6 +761,9 @@ func TestGenerateVerifyOAuthAccessToken(t *testing.T) {
|
|||||||
issuer, ok := claims.Issuer()
|
issuer, ok := claims.Issuer()
|
||||||
_ = assert.True(t, ok, "Issuer not found in token") &&
|
_ = assert.True(t, ok, "Issuer not found in token") &&
|
||||||
assert.Equal(t, service.envConfig.AppURL, issuer, "Issuer should match app URL")
|
assert.Equal(t, service.envConfig.AppURL, issuer, "Issuer should match app URL")
|
||||||
|
jwtID, ok := claims.JwtID()
|
||||||
|
_ = assert.True(t, ok, "JWT ID not found in token") &&
|
||||||
|
assert.Regexp(t, uuidRegexPattern, jwtID, "JWT ID is not a UUID")
|
||||||
|
|
||||||
expectedExp := time.Now().Add(1 * time.Hour)
|
expectedExp := time.Now().Add(1 * time.Hour)
|
||||||
expiration, ok := claims.Expiration()
|
expiration, ok := claims.Expiration()
|
||||||
@@ -814,7 +824,7 @@ func TestGenerateVerifyOAuthAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "eddsauser789"},
|
Base: model.Base{ID: "eddsauser789"},
|
||||||
Email: utils.Ptr("eddsaoauth@example.com"),
|
Email: new("eddsaoauth@example.com"),
|
||||||
}
|
}
|
||||||
const clientID = "eddsa-oauth-client"
|
const clientID = "eddsa-oauth-client"
|
||||||
|
|
||||||
@@ -851,7 +861,7 @@ func TestGenerateVerifyOAuthAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "ecdsauser789"},
|
Base: model.Base{ID: "ecdsauser789"},
|
||||||
Email: utils.Ptr("ecdsaoauth@example.com"),
|
Email: new("ecdsaoauth@example.com"),
|
||||||
}
|
}
|
||||||
const clientID = "ecdsa-oauth-client"
|
const clientID = "ecdsa-oauth-client"
|
||||||
|
|
||||||
@@ -888,7 +898,7 @@ func TestGenerateVerifyOAuthAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
user := model.User{
|
user := model.User{
|
||||||
Base: model.Base{ID: "rsauser789"},
|
Base: model.Base{ID: "rsauser789"},
|
||||||
Email: utils.Ptr("rsaoauth@example.com"),
|
Email: new("rsaoauth@example.com"),
|
||||||
}
|
}
|
||||||
const clientID = "rsa-oauth-client"
|
const clientID = "rsa-oauth-client"
|
||||||
|
|
||||||
|
|||||||
@@ -529,7 +529,7 @@ func getDNProperty(property string, str string) string {
|
|||||||
// First we split at the comma
|
// First we split at the comma
|
||||||
property = strings.ToLower(property)
|
property = strings.ToLower(property)
|
||||||
l := len(property) + 1
|
l := len(property) + 1
|
||||||
for _, v := range strings.Split(str, ",") {
|
for v := range strings.SplitSeq(str, ",") {
|
||||||
v = strings.TrimSpace(v)
|
v = strings.TrimSpace(v)
|
||||||
if len(v) > l && strings.ToLower(v)[0:l] == property+"=" {
|
if len(v) > l && strings.ToLower(v)[0:l] == property+"=" {
|
||||||
return v[l:]
|
return v[l:]
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ func (s *OidcService) CreateClient(ctx context.Context, input dto.OidcClientCrea
|
|||||||
Base: model.Base{
|
Base: model.Base{
|
||||||
ID: input.ID,
|
ID: input.ID,
|
||||||
},
|
},
|
||||||
CreatedByID: utils.Ptr(userID),
|
CreatedByID: new(userID),
|
||||||
}
|
}
|
||||||
updateOIDCClientModelFromDto(&client, &input.OidcClientUpdateDto)
|
updateOIDCClientModelFromDto(&client, &input.OidcClientUpdateDto)
|
||||||
|
|
||||||
@@ -1900,7 +1900,7 @@ func (s *OidcService) getUserClaims(ctx context.Context, user *model.User, scope
|
|||||||
claims["sub"] = user.ID
|
claims["sub"] = user.ID
|
||||||
if slices.Contains(scopes, "email") {
|
if slices.Contains(scopes, "email") {
|
||||||
claims["email"] = user.Email
|
claims["email"] = user.Email
|
||||||
claims["email_verified"] = s.appConfigService.GetDbConfig().EmailsVerified.IsTrue()
|
claims["email_verified"] = user.EmailVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
if slices.Contains(scopes, "groups") {
|
if slices.Contains(scopes, "groups") {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -243,7 +244,7 @@ func (s *ScimService) SyncServiceProvider(ctx context.Context, serviceProviderID
|
|||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
provider.LastSyncedAt = utils.Ptr(datatype.DateTime(time.Now()))
|
provider.LastSyncedAt = new(datatype.DateTime(time.Now()))
|
||||||
if err := s.db.WithContext(ctx).Save(&provider).Error; err != nil {
|
if err := s.db.WithContext(ctx).Save(&provider).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -788,11 +789,9 @@ func ensureScimStatus(
|
|||||||
resp *http.Response,
|
resp *http.Response,
|
||||||
provider model.ScimServiceProvider,
|
provider model.ScimServiceProvider,
|
||||||
allowedStatuses ...int) error {
|
allowedStatuses ...int) error {
|
||||||
for _, status := range allowedStatuses {
|
if slices.Contains(allowedStatuses, resp.StatusCode) {
|
||||||
if resp.StatusCode == status {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
body := readScimErrorBody(resp.Body)
|
body := readScimErrorBody(resp.Body)
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ func (s *UserGroupService) updateInternal(ctx context.Context, id string, input
|
|||||||
|
|
||||||
group.Name = input.Name
|
group.Name = input.Name
|
||||||
group.FriendlyName = input.FriendlyName
|
group.FriendlyName = input.FriendlyName
|
||||||
group.UpdatedAt = utils.Ptr(datatype.DateTime(time.Now()))
|
group.UpdatedAt = new(datatype.DateTime(time.Now()))
|
||||||
|
|
||||||
err = tx.
|
err = tx.
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
@@ -228,7 +228,7 @@ func (s *UserGroupService) updateUsersInternal(ctx context.Context, id string, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the updated group
|
// Save the updated group
|
||||||
group.UpdatedAt = utils.Ptr(datatype.DateTime(time.Now()))
|
group.UpdatedAt = new(datatype.DateTime(time.Now()))
|
||||||
|
|
||||||
err = tx.
|
err = tx.
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ func (s *UserService) updateUserInternal(ctx context.Context, userID string, upd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user.UpdatedAt = utils.Ptr(datatype.DateTime(time.Now()))
|
user.UpdatedAt = new(datatype.DateTime(time.Now()))
|
||||||
|
|
||||||
err = tx.
|
err = tx.
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
@@ -501,9 +501,9 @@ func (s *UserService) UpdateUserGroups(ctx context.Context, id string, userGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the UpdatedAt field for all affected groups
|
// Update the UpdatedAt field for all affected groups
|
||||||
now := time.Now()
|
now := datatype.DateTime(time.Now())
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
group.UpdatedAt = utils.Ptr(datatype.DateTime(now))
|
group.UpdatedAt = &now
|
||||||
err = tx.WithContext(ctx).Save(&group).Error
|
err = tx.WithContext(ctx).Save(&group).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.User{}, err
|
return model.User{}, err
|
||||||
@@ -636,7 +636,7 @@ func (s *UserService) VerifyEmail(ctx context.Context, userID string, token stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.EmailVerified = true
|
user.EmailVerified = true
|
||||||
user.UpdatedAt = utils.Ptr(datatype.DateTime(time.Now()))
|
user.UpdatedAt = new(datatype.DateTime(time.Now()))
|
||||||
err = tx.WithContext(ctx).Save(&user).Error
|
err = tx.WithContext(ctx).Save(&user).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -125,7 +125,9 @@ func (s *UserSignUpService) SignUpInitialAdmin(ctx context.Context, signUpData d
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var userCount int64
|
var userCount int64
|
||||||
if err := tx.WithContext(ctx).Model(&model.User{}).Count(&userCount).Error; err != nil {
|
if err := tx.WithContext(ctx).Model(&model.User{}).
|
||||||
|
Where("id != ?", staticApiKeyUserID).
|
||||||
|
Count(&userCount).Error; err != nil {
|
||||||
return model.User{}, "", err
|
return model.User{}, "", err
|
||||||
}
|
}
|
||||||
if userCount != 0 {
|
if userCount != 0 {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,6 +32,10 @@ func NewVersionService(httpClient *http.Client) *VersionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *VersionService) GetLatestVersion(ctx context.Context) (string, error) {
|
func (s *VersionService) GetLatestVersion(ctx context.Context) (string, error) {
|
||||||
|
if common.EnvConfig.VersionCheckDisabled {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
version, err := s.cache.GetOrFetch(ctx, func(ctx context.Context) (string, error) {
|
version, err := s.cache.GetOrFetch(ctx, func(ctx context.Context) (string, error) {
|
||||||
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
@@ -414,10 +414,10 @@ func TestGetCallbackURLFromList_LoopbackSpecialHandling(t *testing.T) {
|
|||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6 loopback without brackets in input",
|
name: "IPv6 loopback with wildcard path",
|
||||||
urls: []string{"http://[::1]/callback"},
|
urls: []string{"http://[::1]/auth/*"},
|
||||||
inputCallbackURL: "http://::1:8080/callback",
|
inputCallbackURL: "http://[::1]:8080/auth/callback",
|
||||||
expectedURL: "http://::1:8080/callback",
|
expectedURL: "http://[::1]:8080/auth/callback",
|
||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -462,6 +462,13 @@ func TestGetCallbackURLFromList_LoopbackSpecialHandling(t *testing.T) {
|
|||||||
expectedURL: "http://127.0.0.1:8080/callback",
|
expectedURL: "http://127.0.0.1:8080/callback",
|
||||||
expectMatch: true,
|
expectMatch: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "wildcard matches IPv6 loopback",
|
||||||
|
urls: []string{"*"},
|
||||||
|
inputCallbackURL: "http://[::1]:8080/callback",
|
||||||
|
expectedURL: "http://[::1]:8080/callback",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func MigrateDatabase(sqlDb *sql.DB) error {
|
|||||||
return fmt.Errorf("database version (%d) is newer than application version (%d), downgrades are not allowed (set ALLOW_DOWNGRADE=true to enable)", currentVersion, requiredVersion)
|
return fmt.Errorf("database version (%d) is newer than application version (%d), downgrades are not allowed (set ALLOW_DOWNGRADE=true to enable)", currentVersion, requiredVersion)
|
||||||
}
|
}
|
||||||
slog.Info("Fetching migrations from GitHub to handle possible downgrades")
|
slog.Info("Fetching migrations from GitHub to handle possible downgrades")
|
||||||
return migrateDatabaseFromGitHub(sqlDb, requiredVersion)
|
return migrateDatabaseFromGitHub(sqlDb, requiredVersion, currentVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.Migrate(requiredVersion)
|
err = m.Migrate(requiredVersion)
|
||||||
@@ -92,7 +92,7 @@ func newMigrationDriver(sqlDb *sql.DB, dbProvider common.DbProvider) (driver dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// migrateDatabaseFromGitHub applies database migrations fetched from GitHub to handle downgrades.
|
// migrateDatabaseFromGitHub applies database migrations fetched from GitHub to handle downgrades.
|
||||||
func migrateDatabaseFromGitHub(sqlDb *sql.DB, version uint) error {
|
func migrateDatabaseFromGitHub(sqlDb *sql.DB, requiredVersion uint, currentVersion uint) error {
|
||||||
srcURL := "github://pocket-id/pocket-id/backend/resources/migrations/" + string(common.EnvConfig.DbProvider)
|
srcURL := "github://pocket-id/pocket-id/backend/resources/migrations/" + string(common.EnvConfig.DbProvider)
|
||||||
|
|
||||||
driver, err := newMigrationDriver(sqlDb, common.EnvConfig.DbProvider)
|
driver, err := newMigrationDriver(sqlDb, common.EnvConfig.DbProvider)
|
||||||
@@ -105,9 +105,18 @@ func migrateDatabaseFromGitHub(sqlDb *sql.DB, version uint) error {
|
|||||||
return fmt.Errorf("failed to create GitHub migration instance: %w", err)
|
return fmt.Errorf("failed to create GitHub migration instance: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.Force(int(version)); err != nil && !errors.Is(err, migrate.ErrNoChange) { //nolint:gosec
|
// Reset the dirty state before forcing the version
|
||||||
|
if err := m.Force(int(currentVersion)); err != nil { //nolint:gosec
|
||||||
|
return fmt.Errorf("failed to force database version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Migrate(requiredVersion); err != nil {
|
||||||
|
if errors.Is(err, migrate.ErrNoChange) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to apply GitHub migrations: %w", err)
|
return fmt.Errorf("failed to apply GitHub migrations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -21,6 +22,27 @@ func BearerAuth(r *http.Request) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OAuthClientBasicAuth returns the OAuth client ID and secret provided in the request's
|
||||||
|
// Authorization header, if present. See RFC 6749, Section 2.3.
|
||||||
|
func OAuthClientBasicAuth(r *http.Request) (clientID, clientSecret string, ok bool) {
|
||||||
|
clientID, clientSecret, ok = r.BasicAuth()
|
||||||
|
if !ok {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientID, err := url.QueryUnescape(clientID)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSecret, err = url.QueryUnescape(clientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientID, clientSecret, true
|
||||||
|
}
|
||||||
|
|
||||||
// SetCacheControlHeader sets the Cache-Control header for the response.
|
// SetCacheControlHeader sets the Cache-Control header for the response.
|
||||||
func SetCacheControlHeader(ctx *gin.Context, maxAge, staleWhileRevalidate time.Duration) {
|
func SetCacheControlHeader(ctx *gin.Context, maxAge, staleWhileRevalidate time.Duration) {
|
||||||
_, ok := ctx.GetQuery("skipCache")
|
_, ok := ctx.GetQuery("skipCache")
|
||||||
|
|||||||
@@ -63,3 +63,62 @@ func TestBearerAuth(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOAuthClientBasicAuth(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
authHeader string
|
||||||
|
expectedClientID string
|
||||||
|
expectedClientSecret string
|
||||||
|
expectedOk bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid client ID and secret in header (example from RFC 6749)",
|
||||||
|
authHeader: "Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3",
|
||||||
|
expectedClientID: "s6BhdRkqt3",
|
||||||
|
expectedClientSecret: "7Fjfp0ZBr1KtDRbnfVdmIw",
|
||||||
|
expectedOk: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid client ID and secret in header (escaped values)",
|
||||||
|
authHeader: "Basic ZTUwOTcyYmQtNmUzMi00OTU3LWJhZmMtMzU0MTU3ZjI1NDViOislMjUlMjYlMkIlQzIlQTMlRTIlODIlQUM=",
|
||||||
|
expectedClientID: "e50972bd-6e32-4957-bafc-354157f2545b",
|
||||||
|
// This is the example string from RFC 6749, Appendix B.
|
||||||
|
expectedClientSecret: " %&+£€",
|
||||||
|
expectedOk: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty auth header",
|
||||||
|
authHeader: "",
|
||||||
|
expectedClientID: "",
|
||||||
|
expectedClientSecret: "",
|
||||||
|
expectedOk: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic prefix only",
|
||||||
|
authHeader: "Basic ",
|
||||||
|
expectedClientID: "",
|
||||||
|
expectedClientSecret: "",
|
||||||
|
expectedOk: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "http://example.com", nil)
|
||||||
|
require.NoError(t, err, "Failed to create request")
|
||||||
|
|
||||||
|
if tt.authHeader != "" {
|
||||||
|
req.Header.Set("Authorization", tt.authHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId, clientSecret, ok := OAuthClientBasicAuth(req)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.expectedOk, ok)
|
||||||
|
|
||||||
|
if tt.expectedOk {
|
||||||
|
assert.Equal(t, tt.expectedClientID, clientId)
|
||||||
|
assert.Equal(t, tt.expectedClientSecret, clientSecret)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ func listContainsIP(ipNets []*net.IPNet, ip net.IP) bool {
|
|||||||
|
|
||||||
func loadLocalIPv6Ranges() {
|
func loadLocalIPv6Ranges() {
|
||||||
localIPv6Ranges = nil
|
localIPv6Ranges = nil
|
||||||
ranges := strings.Split(common.EnvConfig.LocalIPv6Ranges, ",")
|
ranges := strings.SplitSeq(common.EnvConfig.LocalIPv6Ranges, ",")
|
||||||
|
|
||||||
for _, rangeStr := range ranges {
|
for rangeStr := range ranges {
|
||||||
rangeStr = strings.TrimSpace(rangeStr)
|
rangeStr = strings.TrimSpace(rangeStr)
|
||||||
if rangeStr == "" {
|
if rangeStr == "" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (d *JSONDuration) UnmarshalJSON(b []byte) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalJSONFromDatabase(data interface{}, value any) error {
|
func UnmarshalJSONFromDatabase(data any, value any) error {
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case []byte:
|
case []byte:
|
||||||
return json.Unmarshal(v, data)
|
return json.Unmarshal(v, data)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func ParseListRequestOptions(ctx *gin.Context) (listRequestOptions ListRequestOp
|
|||||||
return listRequestOptions
|
return listRequestOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func PaginateFilterAndSort(params ListRequestOptions, query *gorm.DB, result interface{}) (PaginationResponse, error) {
|
func PaginateFilterAndSort(params ListRequestOptions, query *gorm.DB, result any) (PaginationResponse, error) {
|
||||||
meta := extractModelMetadata(result)
|
meta := extractModelMetadata(result)
|
||||||
|
|
||||||
query = applyFilters(params.Filters, query, meta)
|
query = applyFilters(params.Filters, query, meta)
|
||||||
@@ -52,7 +52,7 @@ func PaginateFilterAndSort(params ListRequestOptions, query *gorm.DB, result int
|
|||||||
return Paginate(params.Pagination.Page, params.Pagination.Limit, query, result)
|
return Paginate(params.Pagination.Page, params.Pagination.Limit, query, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Paginate(page int, pageSize int, query *gorm.DB, result interface{}) (PaginationResponse, error) {
|
func Paginate(page int, pageSize int, query *gorm.DB, result any) (PaginationResponse, error) {
|
||||||
if page < 1 {
|
if page < 1 {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
@@ -117,8 +117,8 @@ func parseNestedFilters(ctx *gin.Context) map[string][]any {
|
|||||||
// Keys can be "filters[field]" or "filters[field][0]"
|
// Keys can be "filters[field]" or "filters[field][0]"
|
||||||
raw := strings.TrimPrefix(key, "filters[")
|
raw := strings.TrimPrefix(key, "filters[")
|
||||||
// Take everything up to the first closing bracket
|
// Take everything up to the first closing bracket
|
||||||
if idx := strings.IndexByte(raw, ']'); idx != -1 {
|
if before, _, ok := strings.Cut(raw, "]"); ok {
|
||||||
field := raw[:idx]
|
field := before
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
result[field] = append(result[field], ConvertStringToType(v))
|
result[field] = append(result[field], ConvertStringToType(v))
|
||||||
}
|
}
|
||||||
@@ -165,12 +165,12 @@ func applySorting(sortColumn string, sortDirection string, query *gorm.DB, meta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extractModelMetadata extracts FieldMeta from the model struct using reflection
|
// extractModelMetadata extracts FieldMeta from the model struct using reflection
|
||||||
func extractModelMetadata(model interface{}) map[string]FieldMeta {
|
func extractModelMetadata(model any) map[string]FieldMeta {
|
||||||
meta := make(map[string]FieldMeta)
|
meta := make(map[string]FieldMeta)
|
||||||
|
|
||||||
// Unwrap pointers and slices to get the element struct type
|
// Unwrap pointers and slices to get the element struct type
|
||||||
t := reflect.TypeOf(model)
|
t := reflect.TypeOf(model)
|
||||||
for t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice {
|
for t.Kind() == reflect.Pointer || t.Kind() == reflect.Slice {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return meta
|
return meta
|
||||||
@@ -180,8 +180,7 @@ func extractModelMetadata(model interface{}) map[string]FieldMeta {
|
|||||||
// recursive parser that merges fields from embedded structs
|
// recursive parser that merges fields from embedded structs
|
||||||
var parseStruct func(reflect.Type)
|
var parseStruct func(reflect.Type)
|
||||||
parseStruct = func(st reflect.Type) {
|
parseStruct = func(st reflect.Type) {
|
||||||
for i := 0; i < st.NumField(); i++ {
|
for field := range st.Fields() {
|
||||||
field := st.Field(i)
|
|
||||||
ft := field.Type
|
ft := field.Type
|
||||||
|
|
||||||
// If the field is an embedded/anonymous struct, recurse into it
|
// If the field is an embedded/anonymous struct, recurse into it
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
// Ptr returns a pointer to the given value.
|
|
||||||
func Ptr[T any](v T) *T {
|
|
||||||
return &v
|
|
||||||
}
|
|
||||||
|
|
||||||
// PtrOrNil returns a pointer to v if v is not the zero value of its type,
|
// PtrOrNil returns a pointer to v if v is not the zero value of its type,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns nil.
|
||||||
func PtrOrNil[T comparable](v T) *T {
|
func PtrOrNil[T comparable](v T) *T {
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This file contains code adapted from https://github.com/samber/slog-multi
|
|
||||||
// Source: https://github.com/samber/slog-multi/blob/ced84707f45ec9848138349ed58de178eedaa6f2/pipe.go
|
|
||||||
// Copyright (C) 2023 Samuel Berthe
|
|
||||||
// License: MIT (https://github.com/samber/slog-multi/blob/ced84707f45ec9848138349ed58de178eedaa6f2/LICENSE)
|
|
||||||
|
|
||||||
// LogFanoutHandler is a slog.Handler that sends logs to multiple destinations
|
|
||||||
type LogFanoutHandler []slog.Handler
|
|
||||||
|
|
||||||
// Implements slog.Handler
|
|
||||||
func (h LogFanoutHandler) Enabled(ctx context.Context, l slog.Level) bool {
|
|
||||||
for i := range h {
|
|
||||||
if h[i].Enabled(ctx, l) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements slog.Handler
|
|
||||||
func (h LogFanoutHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
||||||
errs := make([]error, 0)
|
|
||||||
for i := range h {
|
|
||||||
if h[i].Enabled(ctx, r.Level) {
|
|
||||||
err := try(func() error {
|
|
||||||
return h[i].Handle(ctx, r.Clone())
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements slog.Handler
|
|
||||||
func (h LogFanoutHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
||||||
res := make(LogFanoutHandler, len(h))
|
|
||||||
for i, v := range h {
|
|
||||||
res[i] = v.WithAttrs(slices.Clone(attrs))
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements slog.Handler
|
|
||||||
func (h LogFanoutHandler) WithGroup(name string) slog.Handler {
|
|
||||||
// https://cs.opensource.google/go/x/exp/+/46b07846:slog/handler.go;l=247
|
|
||||||
if name == "" {
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make(LogFanoutHandler, len(h))
|
|
||||||
for i, v := range h {
|
|
||||||
res[i] = v.WithGroup(name)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func try(callback func() error) (err error) {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r != nil {
|
|
||||||
if e, ok := r.(error); ok {
|
|
||||||
err = e
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("unexpected error: %+v", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = callback()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -70,11 +70,6 @@ func GetHostnameFromURL(rawURL string) string {
|
|||||||
return parsedURL.Hostname()
|
return parsedURL.Hostname()
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringPointer creates a string pointer from a string value
|
|
||||||
func StringPointer(s string) *string {
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
|
|
||||||
func CapitalizeFirstLetter(str string) string {
|
func CapitalizeFirstLetter(str string) string {
|
||||||
if str == "" {
|
if str == "" {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
|||||||
ARG BUILD_TAGS=""
|
ARG BUILD_TAGS=""
|
||||||
|
|
||||||
# Stage 1: Build Frontend
|
# Stage 1: Build Frontend
|
||||||
FROM node:22-alpine AS frontend-builder
|
FROM node:24-alpine AS frontend-builder
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
@@ -18,7 +18,7 @@ COPY ./frontend ./frontend/
|
|||||||
RUN BUILD_OUTPUT_PATH=dist pnpm --filter pocket-id-frontend run build
|
RUN BUILD_OUTPUT_PATH=dist pnpm --filter pocket-id-frontend run build
|
||||||
|
|
||||||
# Stage 2: Build Backend
|
# Stage 2: Build Backend
|
||||||
FROM golang:1.25-alpine AS backend-builder
|
FROM golang:1.26-alpine AS backend-builder
|
||||||
ARG BUILD_TAGS
|
ARG BUILD_TAGS
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY ./backend/go.mod ./backend/go.sum ./
|
COPY ./backend/go.mod ./backend/go.sum ./
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Autentikátor nepodporuje rezidentní klíče",
|
"authenticator_does_not_support_resident_keys": "Autentikátor nepodporuje rezidentní klíče",
|
||||||
"passkey_was_previously_registered": "Tento přístupový klíč byl již dříve zaregistrován",
|
"passkey_was_previously_registered": "Tento přístupový klíč byl již dříve zaregistrován",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autentikátor nepodporuje žádný z požadovaných algoritmů",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autentikátor nepodporuje žádný z požadovaných algoritmů",
|
||||||
"authenticator_timed_out": "Vypršel časový limit autentifikátoru",
|
"webauthn_error_invalid_rp_id": "Nakonfigurované ID spoléhající strany je neplatné.",
|
||||||
|
"webauthn_error_invalid_domain": "Nakonfigurovaná doména je neplatná.",
|
||||||
|
"contact_administrator_to_fix": "Kontaktujte svého správce, aby tento problém vyřešil.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Operace nebyla povolena nebo vypršela časová lhůta.",
|
||||||
|
"webauthn_not_supported_by_browser": "Tento prohlížeč nepodporuje přístupové klíče. Použijte prosím alternativní způsob přihlášení.",
|
||||||
"critical_error_occurred_contact_administrator": "Došlo k kritické chybě. Obraťte se na správce.",
|
"critical_error_occurred_contact_administrator": "Došlo k kritické chybě. Obraťte se na správce.",
|
||||||
"sign_in_to": "Přihlásit se k {name}",
|
"sign_in_to": "Přihlásit se k {name}",
|
||||||
"client_not_found": "Klient nebyl nalezen",
|
"client_not_found": "Klient nebyl nalezen",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Doba trvání relace v minutách, než se uživatel musí znovu přihlásit.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Doba trvání relace v minutách, než se uživatel musí znovu přihlásit.",
|
||||||
"enable_self_account_editing": "Povolit úpravy vlastního účtu",
|
"enable_self_account_editing": "Povolit úpravy vlastního účtu",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Zda by uživatelé měli mít možnost upravit vlastní údaje o účtu.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Zda by uživatelé měli mít možnost upravit vlastní údaje o účtu.",
|
||||||
"emails_verified": "E-mail ověřen",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Zda má být e-mail uživatele označen jako ověřený pro OIDC klienty.",
|
|
||||||
"ldap_configuration_updated_successfully": "Nastavení LDAP bylo úspěšně aktualizováno",
|
"ldap_configuration_updated_successfully": "Nastavení LDAP bylo úspěšně aktualizováno",
|
||||||
"ldap_disabled_successfully": "LDAP úspěšně zakázán",
|
"ldap_disabled_successfully": "LDAP úspěšně zakázán",
|
||||||
"ldap_sync_finished": "LDAP synchronizace dokončena",
|
"ldap_sync_finished": "LDAP synchronizace dokončena",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Uložit a synchronizovat",
|
"save_and_sync": "Uložit a synchronizovat",
|
||||||
"scim_save_changes_description": "Před spuštěním synchronizace SCIM je nutné uložit změny. Chcete uložit nyní?",
|
"scim_save_changes_description": "Před spuštěním synchronizace SCIM je nutné uložit změny. Chcete uložit nyní?",
|
||||||
"scopes": "Rozsah",
|
"scopes": "Rozsah",
|
||||||
"issuer_url": "URL vydavatele"
|
"issuer_url": "URL vydavatele",
|
||||||
|
"smtp_field_required_when_other_provided": "Vyžadováno, pokud je zadáno jakékoli nastavení SMTP",
|
||||||
|
"smtp_field_required_when_email_enabled": "Vyžadováno, pokud jsou povolena e-mailová oznámení",
|
||||||
|
"renew": "Obnovit",
|
||||||
|
"renew_api_key": "Obnovit klíč API",
|
||||||
|
"renew_api_key_description": "Obnovením klíče API se vygeneruje nový klíč. Nezapomeňte aktualizovat všechny integrace, které tento klíč používají.",
|
||||||
|
"api_key_renewed": "API klíč obnoven",
|
||||||
|
"app_config_home_page": "Domovská stránka",
|
||||||
|
"app_config_home_page_description": "Stránka, na kterou jsou uživatelé přesměrováni po přihlášení.",
|
||||||
|
"email_verification_warning": "Ověřte svou e-mailovou adresu",
|
||||||
|
"email_verification_warning_description": "Vaše e-mailová adresa ještě nebyla ověřena. Ověřte ji prosím co nejdříve.",
|
||||||
|
"email_verification": "Ověření e-mailu",
|
||||||
|
"email_verification_description": "Po odeslání registrace nebo změně e-mailové adresy zašlete uživatelům ověřovací e-mail.",
|
||||||
|
"email_verification_success_title": "E-mail byl úspěšně ověřen",
|
||||||
|
"email_verification_success_description": "Vaše e-mailová adresa byla úspěšně ověřena.",
|
||||||
|
"email_verification_error_title": "Ověření e-mailu se nezdařilo",
|
||||||
|
"mark_as_unverified": "Označit jako neověřené",
|
||||||
|
"mark_as_verified": "Označit jako ověřené",
|
||||||
|
"email_verification_sent": "Ověřovací e-mail byl úspěšně odeslán.",
|
||||||
|
"emails_verified_by_default": "E-maily ověřené ve výchozím nastavení",
|
||||||
|
"emails_verified_by_default_description": "Pokud je tato funkce povolena, budou e-mailové adresy uživatelů při registraci nebo při změně e-mailové adresy automaticky označeny jako ověřené."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Godkenderen understøtter ikke gemte nøgler",
|
"authenticator_does_not_support_resident_keys": "Godkenderen understøtter ikke gemte nøgler",
|
||||||
"passkey_was_previously_registered": "Denne adgangsnøgle er allerede registreret",
|
"passkey_was_previously_registered": "Denne adgangsnøgle er allerede registreret",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Godkenderen understøtter ikke nogen af de algoritmer, der anmodes om",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Godkenderen understøtter ikke nogen af de algoritmer, der anmodes om",
|
||||||
"authenticator_timed_out": "Godkenderen overskred tidsgrænsen",
|
"webauthn_error_invalid_rp_id": "Den konfigurerede afhængige parts ID er ugyldig.",
|
||||||
|
"webauthn_error_invalid_domain": "Det konfigurerede domæne er ugyldigt.",
|
||||||
|
"contact_administrator_to_fix": "Kontakt din administrator for at løse dette problem.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Operationen var ikke tilladt eller timet ud",
|
||||||
|
"webauthn_not_supported_by_browser": "Passkeys understøttes ikke af denne browser. Brug en alternativ login-metode.",
|
||||||
"critical_error_occurred_contact_administrator": "En kritisk fejl opstod. Kontakt venligst din administrator.",
|
"critical_error_occurred_contact_administrator": "En kritisk fejl opstod. Kontakt venligst din administrator.",
|
||||||
"sign_in_to": "Log ind på {name}",
|
"sign_in_to": "Log ind på {name}",
|
||||||
"client_not_found": "Klient ikke fundet",
|
"client_not_found": "Klient ikke fundet",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Varighed i minutter før brugeren skal logge ind igen.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Varighed i minutter før brugeren skal logge ind igen.",
|
||||||
"enable_self_account_editing": "Aktivér redigering af egen konto",
|
"enable_self_account_editing": "Aktivér redigering af egen konto",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Om brugere må redigere deres egne kontooplysninger.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Om brugere må redigere deres egne kontooplysninger.",
|
||||||
"emails_verified": "E-mailadresser verificeret",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Om brugerens e-mail skal markeres som verificeret for OIDC-klienter.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP-konfiguration blev opdateret",
|
"ldap_configuration_updated_successfully": "LDAP-konfiguration blev opdateret",
|
||||||
"ldap_disabled_successfully": "LDAP blev deaktiveret",
|
"ldap_disabled_successfully": "LDAP blev deaktiveret",
|
||||||
"ldap_sync_finished": "LDAP-synkronisering fuldført",
|
"ldap_sync_finished": "LDAP-synkronisering fuldført",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Gem og synkroniser",
|
"save_and_sync": "Gem og synkroniser",
|
||||||
"scim_save_changes_description": "Du skal gemme ændringerne, før du starter en SCIM-synkronisering. Vil du gemme nu?",
|
"scim_save_changes_description": "Du skal gemme ændringerne, før du starter en SCIM-synkronisering. Vil du gemme nu?",
|
||||||
"scopes": "Omfang",
|
"scopes": "Omfang",
|
||||||
"issuer_url": "Udsteders URL"
|
"issuer_url": "Udsteders URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Påkrævet, når der angives en SMTP-indstilling",
|
||||||
|
"smtp_field_required_when_email_enabled": "Påkrævet, når e-mail-underretninger er aktiveret",
|
||||||
|
"renew": "Forny",
|
||||||
|
"renew_api_key": "Forny API-nøgle",
|
||||||
|
"renew_api_key_description": "Ved at forny API-nøglen genereres en ny nøgle. Sørg for at opdatere alle integrationer, der bruger denne nøgle.",
|
||||||
|
"api_key_renewed": "API-nøgle fornyet",
|
||||||
|
"app_config_home_page": "Hjemmeside",
|
||||||
|
"app_config_home_page_description": "Den side, som brugerne omdirigeres til efter at have logget ind.",
|
||||||
|
"email_verification_warning": "Bekræft din e-mailadresse",
|
||||||
|
"email_verification_warning_description": "Din e-mailadresse er endnu ikke bekræftet. Bekræft den venligst så hurtigt som muligt.",
|
||||||
|
"email_verification": "E-mail-bekræftelse",
|
||||||
|
"email_verification_description": "Send en bekræftelses-e-mail til brugere, når de tilmelder sig eller ændrer deres e-mailadresse.",
|
||||||
|
"email_verification_success_title": "E-mail bekræftet med succes",
|
||||||
|
"email_verification_success_description": "Din e-mailadresse er blevet bekræftet.",
|
||||||
|
"email_verification_error_title": "E-mail-bekræftelse mislykkedes",
|
||||||
|
"mark_as_unverified": "Marker som ikke verificeret",
|
||||||
|
"mark_as_verified": "Marker som verificeret",
|
||||||
|
"email_verification_sent": "Bekræftelses-e-mail sendt med succes.",
|
||||||
|
"emails_verified_by_default": "E-mails verificeret som standard",
|
||||||
|
"emails_verified_by_default_description": "Når denne funktion er aktiveret, vil brugernes e-mailadresser som standard blive markeret som verificerede ved tilmelding eller når deres e-mailadresse ændres."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Der Authentifikator unterstützt keine residenten Schlüssel",
|
"authenticator_does_not_support_resident_keys": "Der Authentifikator unterstützt keine residenten Schlüssel",
|
||||||
"passkey_was_previously_registered": "Dieser Passkey wurde bereits registriert",
|
"passkey_was_previously_registered": "Dieser Passkey wurde bereits registriert",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Der Authentifikator unterstützt keinen der angeforderten Algorithmen",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Der Authentifikator unterstützt keinen der angeforderten Algorithmen",
|
||||||
"authenticator_timed_out": "Der Authentifikator hat eine Zeitüberschreitung",
|
"webauthn_error_invalid_rp_id": "Die eingestellte ID der vertrauenden Seite ist nicht okay.",
|
||||||
|
"webauthn_error_invalid_domain": "Die eingestellte Domain ist nicht okay.",
|
||||||
|
"contact_administrator_to_fix": "Sprich mit deinem Administrator, um das Problem zu lösen.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Der Vorgang wurde nicht erlaubt oder ist abgelaufen.",
|
||||||
|
"webauthn_not_supported_by_browser": "Passkeys werden von diesem Browser nicht unterstützt. Bitte probier eine andere Anmeldemethode aus.",
|
||||||
"critical_error_occurred_contact_administrator": "Ein kritischer Fehler ist aufgetreten. Bitte kontaktiere deinen Administrator.",
|
"critical_error_occurred_contact_administrator": "Ein kritischer Fehler ist aufgetreten. Bitte kontaktiere deinen Administrator.",
|
||||||
"sign_in_to": "Bei {name} anmelden",
|
"sign_in_to": "Bei {name} anmelden",
|
||||||
"client_not_found": "Client nicht gefunden",
|
"client_not_found": "Client nicht gefunden",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Die Dauer einer Sitzung in Minuten, bevor sich der Benutzer erneut anmelden muss.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Die Dauer einer Sitzung in Minuten, bevor sich der Benutzer erneut anmelden muss.",
|
||||||
"enable_self_account_editing": "Selbstverwaltung des Kontos aktivieren",
|
"enable_self_account_editing": "Selbstverwaltung des Kontos aktivieren",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Gibt an, ob die Benutzer in der Lage sein sollen, ihre eigenen Kontodetails zu ändern.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Gibt an, ob die Benutzer in der Lage sein sollen, ihre eigenen Kontodetails zu ändern.",
|
||||||
"emails_verified": "E-Mail-Adressen verifiziert",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Gibt an, ob die E-Mail des Benutzers für die OIDC-Clients als verifiziert markiert werden soll.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP-Konfiguration erfolgreich aktualisiert",
|
"ldap_configuration_updated_successfully": "LDAP-Konfiguration erfolgreich aktualisiert",
|
||||||
"ldap_disabled_successfully": "LDAP erfolgreich deaktiviert",
|
"ldap_disabled_successfully": "LDAP erfolgreich deaktiviert",
|
||||||
"ldap_sync_finished": "LDAP-Synchronisation beendet",
|
"ldap_sync_finished": "LDAP-Synchronisation beendet",
|
||||||
@@ -354,8 +356,8 @@
|
|||||||
"login_code_email_success": "Der Login-Code wurde an den Benutzer gesendet.",
|
"login_code_email_success": "Der Login-Code wurde an den Benutzer gesendet.",
|
||||||
"send_email": "E-Mail senden",
|
"send_email": "E-Mail senden",
|
||||||
"show_code": "Code anzeigen",
|
"show_code": "Code anzeigen",
|
||||||
"callback_url_description": "Die URL(s) von deinem Kunden. Wenn du das Feld leer lässt, werden sie automatisch hinzugefügt. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
|
"callback_url_description": "Die URL(s) von deinem Client. Wenn du das Feld leer lässt, werden sie automatisch hinzugefügt. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
|
||||||
"logout_callback_url_description": "Von deinem Kunden angegebene URL(s) zum Abmelden. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
|
"logout_callback_url_description": "Von deinem Client angegebene URL(s) zum Abmelden. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Platzhalter</link> werden unterstützt.",
|
||||||
"api_key_expiration": "API-Schlüssel-Ablauf",
|
"api_key_expiration": "API-Schlüssel-Ablauf",
|
||||||
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Sende eine E-Mail an den Benutzer, wenn sein API-Schlüssel ablaufen wird.",
|
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Sende eine E-Mail an den Benutzer, wenn sein API-Schlüssel ablaufen wird.",
|
||||||
"authorize_device": "Gerät autorisieren",
|
"authorize_device": "Gerät autorisieren",
|
||||||
@@ -395,21 +397,21 @@
|
|||||||
"color_value": "Farbwert",
|
"color_value": "Farbwert",
|
||||||
"apply": "Übernehmen",
|
"apply": "Übernehmen",
|
||||||
"signup_token": "Anmeldungstoken",
|
"signup_token": "Anmeldungstoken",
|
||||||
"create_a_signup_token_to_allow_new_user_registration": "Erstell ein Anmeldetoken, damit sich neue Benutzer registrieren können.",
|
"create_a_signup_token_to_allow_new_user_registration": "Erstell einen Registrierungstoken, damit sich neue Benutzer registrieren können.",
|
||||||
"usage_limit": "Nutzungsbeschränkung",
|
"usage_limit": "Nutzungsbeschränkung",
|
||||||
"number_of_times_token_can_be_used": "Wie oft der Anmeldetoken benutzt werden kann.",
|
"number_of_times_token_can_be_used": "Wie oft der Registrierungstoken benutzt werden kann.",
|
||||||
"expires": "Läuft ab",
|
"expires": "Läuft ab",
|
||||||
"signup": "Anmelden",
|
"signup": "Registrieren",
|
||||||
"user_creation": "Benutzererstellung",
|
"user_creation": "Benutzererstellung",
|
||||||
"configure_user_creation": "Verwalte die Einstellungen für die Benutzererstellung, einschließlich der Anmeldemethoden und Standardberechtigungen für neue Benutzer.",
|
"configure_user_creation": "Verwalte die Einstellungen für die Benutzererstellung, einschließlich der Registrierungsmethoden und Standardberechtigungen für neue Benutzer.",
|
||||||
"user_creation_groups_description": "Weise diese Gruppen neuen Benutzern bei der Anmeldung automatisch zu.",
|
"user_creation_groups_description": "Weise diese Gruppen neuen Benutzern bei der Registrierung automatisch zu.",
|
||||||
"user_creation_claims_description": "Weise diese benutzerdefinierten Ansprüche neuen Benutzern bei der Anmeldung automatisch zu.",
|
"user_creation_claims_description": "Weise diese benutzerdefinierten Ansprüche neuen Benutzern bei der Registrierung automatisch zu.",
|
||||||
"user_creation_updated_successfully": "Einstellungen für die Benutzererstellung erfolgreich aktualisiert.",
|
"user_creation_updated_successfully": "Einstellungen für die Benutzererstellung erfolgreich aktualisiert.",
|
||||||
"signup_disabled_description": "Benutzeranmeldungen sind komplett deaktiviert. Nur Admins können neue Benutzerkonten erstellen.",
|
"signup_disabled_description": "Benutzeranmeldungen sind komplett deaktiviert. Nur Admins können neue Benutzerkonten erstellen.",
|
||||||
"signup_requires_valid_token": "Zum Erstellen eines Kontos brauchst du einen gültigen Anmeldetoken.",
|
"signup_requires_valid_token": "Zum Erstellen eines Kontos brauchst du einen gültigen Registrierungstoken.",
|
||||||
"validating_signup_token": "Anmeldungstoken bestätigen",
|
"validating_signup_token": "Anmeldungstoken bestätigen",
|
||||||
"go_to_login": "Zum Login gehen",
|
"go_to_login": "Zum Login gehen",
|
||||||
"signup_to_appname": "Melde dich bei „ {appName}“ an",
|
"signup_to_appname": "Registriere dich bei „ {appName}“",
|
||||||
"create_your_account_to_get_started": "Erstell dein Konto, um loszulegen.",
|
"create_your_account_to_get_started": "Erstell dein Konto, um loszulegen.",
|
||||||
"initial_account_creation_description": "Erstell dein Konto, um loszulegen. Du kannst später einen Passkey einrichten.",
|
"initial_account_creation_description": "Erstell dein Konto, um loszulegen. Du kannst später einen Passkey einrichten.",
|
||||||
"setup_your_passkey": "Passkey einrichten",
|
"setup_your_passkey": "Passkey einrichten",
|
||||||
@@ -417,12 +419,12 @@
|
|||||||
"skip_for_now": "Jetzt überspringen",
|
"skip_for_now": "Jetzt überspringen",
|
||||||
"account_created": "Konto erstellt",
|
"account_created": "Konto erstellt",
|
||||||
"enable_user_signups": "Benutzeranmeldungen aktivieren",
|
"enable_user_signups": "Benutzeranmeldungen aktivieren",
|
||||||
"enable_user_signups_description": "Entscheide, wie sich Leute für neue Konten in Pocket ID anmelden können.",
|
"enable_user_signups_description": "Entscheide, wie sich Leute für neue Konten in Pocket ID registrieren können.",
|
||||||
"user_signups_are_disabled": "Benutzeranmeldungen sind im Moment deaktiviert.",
|
"user_signups_are_disabled": "Benutzeranmeldungen sind im Moment deaktiviert.",
|
||||||
"create_signup_token": "Anmeldungstoken erstellen",
|
"create_signup_token": "Anmeldungstoken erstellen",
|
||||||
"view_active_signup_tokens": "Aktive Anmeldetoken anzeigen",
|
"view_active_signup_tokens": "Aktive Registrierungstoken anzeigen",
|
||||||
"manage_signup_tokens": "Anmeldungstoken verwalten",
|
"manage_signup_tokens": "Anmeldungstoken verwalten",
|
||||||
"view_and_manage_active_signup_tokens": "Aktive Anmeldetoken anzeigen und verwalten.",
|
"view_and_manage_active_signup_tokens": "Aktive Registrierungstoken anzeigen und verwalten.",
|
||||||
"signup_token_deleted_successfully": "Anmeldungstoken erfolgreich gelöscht.",
|
"signup_token_deleted_successfully": "Anmeldungstoken erfolgreich gelöscht.",
|
||||||
"expired": "Abgelaufen",
|
"expired": "Abgelaufen",
|
||||||
"used_up": "Aufgebraucht",
|
"used_up": "Aufgebraucht",
|
||||||
@@ -432,9 +434,9 @@
|
|||||||
"token": "Token",
|
"token": "Token",
|
||||||
"loading": "Laden",
|
"loading": "Laden",
|
||||||
"delete_signup_token": "Anmeldungstoken löschen",
|
"delete_signup_token": "Anmeldungstoken löschen",
|
||||||
"are_you_sure_you_want_to_delete_this_signup_token": "Willst du diesen Anmeldetoken wirklich löschen? Das kannst du nicht rückgängig machen.",
|
"are_you_sure_you_want_to_delete_this_signup_token": "Willst du diesen Registrierungstoken wirklich löschen? Das kannst du nicht rückgängig machen.",
|
||||||
"signup_with_token": "Mit Token anmelden",
|
"signup_with_token": "Mit Token registrieren",
|
||||||
"signup_with_token_description": "Benutzer können sich nur mit einem gültigen Anmeldetoken anmelden, das von einem Administrator erstellt wurde.",
|
"signup_with_token_description": "Benutzer können sich nur mit einem gültigen Registrierungstoken anmelden, das von einem Administrator erstellt wurde.",
|
||||||
"signup_open": "Anmeldung offen",
|
"signup_open": "Anmeldung offen",
|
||||||
"signup_open_description": "Jeder kann ohne Einschränkungen ein neues Konto erstellen.",
|
"signup_open_description": "Jeder kann ohne Einschränkungen ein neues Konto erstellen.",
|
||||||
"of": "von",
|
"of": "von",
|
||||||
@@ -475,7 +477,7 @@
|
|||||||
"light": "Hell",
|
"light": "Hell",
|
||||||
"dark": "Dunkel",
|
"dark": "Dunkel",
|
||||||
"system": "System",
|
"system": "System",
|
||||||
"signup_token_user_groups_description": "Weise diese Gruppen automatisch den Leuten zu, die sich mit diesem Token anmelden.",
|
"signup_token_user_groups_description": "Weise diese Gruppen automatisch den Leuten zu, die sich mit diesem Token registrieren.",
|
||||||
"allowed_oidc_clients": "Zugelassene OIDC-Clients",
|
"allowed_oidc_clients": "Zugelassene OIDC-Clients",
|
||||||
"allowed_oidc_clients_description": "Wähle die OIDC-Clients aus, bei denen sich Mitglieder dieser Benutzergruppe anmelden dürfen.",
|
"allowed_oidc_clients_description": "Wähle die OIDC-Clients aus, bei denen sich Mitglieder dieser Benutzergruppe anmelden dürfen.",
|
||||||
"unrestrict_oidc_client": "Uneingeschränkt {clientName}",
|
"unrestrict_oidc_client": "Uneingeschränkt {clientName}",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Speichern und synchronisieren",
|
"save_and_sync": "Speichern und synchronisieren",
|
||||||
"scim_save_changes_description": "Du musst die Änderungen speichern, bevor du eine SCIM-Synchronisierung startest. Willst du jetzt speichern?",
|
"scim_save_changes_description": "Du musst die Änderungen speichern, bevor du eine SCIM-Synchronisierung startest. Willst du jetzt speichern?",
|
||||||
"scopes": "Kopfsuchgeräte",
|
"scopes": "Kopfsuchgeräte",
|
||||||
"issuer_url": "Aussteller-URL"
|
"issuer_url": "Aussteller-URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Muss angegeben werden, wenn SMTP-Einstellungen gemacht werden",
|
||||||
|
"smtp_field_required_when_email_enabled": "Muss aktiviert sein, wenn du E-Mail-Benachrichtigungen nutzen willst.",
|
||||||
|
"renew": "Erneuern",
|
||||||
|
"renew_api_key": "API-Schlüssel erneuern",
|
||||||
|
"renew_api_key_description": "Wenn du den API-Schlüssel erneuerst, wird ein neuer Schlüssel erstellt. Denk dran, alle Integrationen, die diesen Schlüssel nutzen, zu aktualisieren.",
|
||||||
|
"api_key_renewed": "API-Schlüssel erneuert",
|
||||||
|
"app_config_home_page": "Startseite",
|
||||||
|
"app_config_home_page_description": "Die Seite, auf die Nutzer nach der Anmeldung weitergeleitet werden.",
|
||||||
|
"email_verification_warning": "Bestätige deine E-Mail-Adresse",
|
||||||
|
"email_verification_warning_description": "Deine E-Mail-Adresse ist noch nicht bestätigt. Bitte bestätige sie so schnell wie möglich.",
|
||||||
|
"email_verification": "E-Mail-Bestätigung",
|
||||||
|
"email_verification_description": "Schick den Nutzern eine Bestätigungs-E-Mail, wenn sie sich registrieren oder ihre E-Mail-Adresse ändern.",
|
||||||
|
"email_verification_success_title": "E-Mail erfolgreich bestätigt",
|
||||||
|
"email_verification_success_description": "Deine E-Mail-Adresse wurde erfolgreich bestätigt.",
|
||||||
|
"email_verification_error_title": "E-Mail-Verifizierung ist schiefgegangen",
|
||||||
|
"mark_as_unverified": "Als nicht überprüft markieren",
|
||||||
|
"mark_as_verified": "Als verifiziert markieren",
|
||||||
|
"email_verification_sent": "Bestätigungs-E-Mail erfolgreich verschickt.",
|
||||||
|
"emails_verified_by_default": "E-Mails sind standardmäßig verifiziert",
|
||||||
|
"emails_verified_by_default_description": "Wenn diese Option aktiviert ist, werden die E-Mail-Adressen der Nutzer bei der Anmeldung oder bei einer Änderung ihrer E-Mail-Adresse standardmäßig als verifiziert markiert."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "El autenticador no soporta claves residentes",
|
"authenticator_does_not_support_resident_keys": "El autenticador no soporta claves residentes",
|
||||||
"passkey_was_previously_registered": "Esta Passkey ha sido registrado previamente",
|
"passkey_was_previously_registered": "Esta Passkey ha sido registrado previamente",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "El autenticador no soporta ninguno de los algoritmos solicitados",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "El autenticador no soporta ninguno de los algoritmos solicitados",
|
||||||
"authenticator_timed_out": "Se agotó el tiempo de espera del autenticador",
|
"webauthn_error_invalid_rp_id": "El ID de la parte confiable configurado no es válido.",
|
||||||
|
"webauthn_error_invalid_domain": "El dominio configurado no es válido.",
|
||||||
|
"contact_administrator_to_fix": "Ponte en contacto con tu administrador para solucionar este problema.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "La operación no fue permitida o se agotó el tiempo de espera.",
|
||||||
|
"webauthn_not_supported_by_browser": "Este navegador no admite claves de acceso. Utiliza otro método para iniciar sesión.",
|
||||||
"critical_error_occurred_contact_administrator": "Ha ocurrido un error crítico. Por favor, contacte a su administrador.",
|
"critical_error_occurred_contact_administrator": "Ha ocurrido un error crítico. Por favor, contacte a su administrador.",
|
||||||
"sign_in_to": "Iniciar sesión en {name}",
|
"sign_in_to": "Iniciar sesión en {name}",
|
||||||
"client_not_found": "Cliente no encontrado",
|
"client_not_found": "Cliente no encontrado",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La duración de una sesión en minutos antes de que el usuario tenga que iniciar sesión de nuevo.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La duración de una sesión en minutos antes de que el usuario tenga que iniciar sesión de nuevo.",
|
||||||
"enable_self_account_editing": "Habilitar la edición de la cuenta personal",
|
"enable_self_account_editing": "Habilitar la edición de la cuenta personal",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Si los usuarios deberían poder editar los detalles de su propia cuenta.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Si los usuarios deberían poder editar los detalles de su propia cuenta.",
|
||||||
"emails_verified": "Correos electrónicos verificados",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Si el correo electrónico del usuario debe marcarse como verificado para los clientes OIDC.",
|
|
||||||
"ldap_configuration_updated_successfully": "Configuración LDAP actualizada correctamente",
|
"ldap_configuration_updated_successfully": "Configuración LDAP actualizada correctamente",
|
||||||
"ldap_disabled_successfully": "LDAP desactivado correctamente",
|
"ldap_disabled_successfully": "LDAP desactivado correctamente",
|
||||||
"ldap_sync_finished": "Sincronización LDAP finalizada",
|
"ldap_sync_finished": "Sincronización LDAP finalizada",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Guardar y sincronizar",
|
"save_and_sync": "Guardar y sincronizar",
|
||||||
"scim_save_changes_description": "Debes guardar los cambios antes de iniciar una sincronización SCIM. ¿Deseas guardar ahora?",
|
"scim_save_changes_description": "Debes guardar los cambios antes de iniciar una sincronización SCIM. ¿Deseas guardar ahora?",
|
||||||
"scopes": "Ámbitos",
|
"scopes": "Ámbitos",
|
||||||
"issuer_url": "URL del emisor"
|
"issuer_url": "URL del emisor",
|
||||||
|
"smtp_field_required_when_other_provided": "Necesario cuando se proporciona cualquier configuración SMTP.",
|
||||||
|
"smtp_field_required_when_email_enabled": "Requerido cuando las notificaciones por correo electrónico están habilitadas.",
|
||||||
|
"renew": "Renovar",
|
||||||
|
"renew_api_key": "Renovar clave API",
|
||||||
|
"renew_api_key_description": "Al renovar la clave API se generará una nueva clave. Asegúrate de actualizar cualquier integración que utilice esta clave.",
|
||||||
|
"api_key_renewed": "Clave API renovada",
|
||||||
|
"app_config_home_page": "Página de inicio",
|
||||||
|
"app_config_home_page_description": "La página a la que se redirige a los usuarios después de iniciar sesión.",
|
||||||
|
"email_verification_warning": "Verifica tu dirección de correo electrónico.",
|
||||||
|
"email_verification_warning_description": "Tu dirección de correo electrónico aún no está verificada. Verifícala lo antes posible.",
|
||||||
|
"email_verification": "Verificación de correo electrónico",
|
||||||
|
"email_verification_description": "Enviar un correo electrónico de verificación a los usuarios cuando se registren o cambien su dirección de correo electrónico.",
|
||||||
|
"email_verification_success_title": "Correo electrónico verificado correctamente",
|
||||||
|
"email_verification_success_description": "Tu dirección de correo electrónico ha sido verificada correctamente.",
|
||||||
|
"email_verification_error_title": "Error en la verificación del correo electrónico",
|
||||||
|
"mark_as_unverified": "Marcar como no verificado",
|
||||||
|
"mark_as_verified": "Marcar como verificado",
|
||||||
|
"email_verification_sent": "El correo electrónico de verificación se ha enviado correctamente.",
|
||||||
|
"emails_verified_by_default": "Correos electrónicos verificados de forma predeterminada",
|
||||||
|
"emails_verified_by_default_description": "Cuando esta opción está activada, las direcciones de correo electrónico de los usuarios se marcarán como verificadas de forma predeterminada al registrarse o cuando se modifique su dirección de correo electrónico."
|
||||||
}
|
}
|
||||||
|
|||||||
525
frontend/messages/et.json
Normal file
525
frontend/messages/et.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": "Using federated client credentials, you can authenticate OIDC clients using JWT tokens issued by third-party authorities.",
|
||||||
|
"add_federated_client_credential": "Add Federated Client Credential",
|
||||||
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
|
"oidc_allowed_group_count": "Allowed Group Count",
|
||||||
|
"unrestricted": "Unrestricted",
|
||||||
|
"show_advanced_options": "Show Advanced Options",
|
||||||
|
"hide_advanced_options": "Hide Advanced Options",
|
||||||
|
"oidc_data_preview": "OIDC Data Preview",
|
||||||
|
"preview_the_oidc_data_that_would_be_sent_for_different_users": "Preview the OIDC data that would be sent for different users",
|
||||||
|
"id_token": "ID Token",
|
||||||
|
"access_token": "Access Token",
|
||||||
|
"userinfo": "Userinfo",
|
||||||
|
"id_token_payload": "ID Token Payload",
|
||||||
|
"access_token_payload": "Access Token Payload",
|
||||||
|
"userinfo_endpoint_response": "Userinfo Endpoint Response",
|
||||||
|
"copy": "Copy",
|
||||||
|
"no_preview_data_available": "No preview data available",
|
||||||
|
"copy_all": "Copy All",
|
||||||
|
"preview": "Preview",
|
||||||
|
"preview_for_user": "Preview for {name}",
|
||||||
|
"preview_the_oidc_data_that_would_be_sent_for_this_user": "Preview the OIDC data that would be sent for this user",
|
||||||
|
"show": "Show",
|
||||||
|
"select_an_option": "Select an option",
|
||||||
|
"select_user": "Select User",
|
||||||
|
"error": "Error",
|
||||||
|
"select_an_accent_color_to_customize_the_appearance_of_pocket_id": "Select an accent color to customize the appearance of Pocket ID.",
|
||||||
|
"accent_color": "Accent Color",
|
||||||
|
"custom_accent_color": "Custom Accent Color",
|
||||||
|
"custom_accent_color_description": "Enter a custom color using valid CSS color formats (e.g., hex, rgb, hsl).",
|
||||||
|
"color_value": "Color Value",
|
||||||
|
"apply": "Apply",
|
||||||
|
"signup_token": "Signup Token",
|
||||||
|
"create_a_signup_token_to_allow_new_user_registration": "Create a signup token to allow new user registration.",
|
||||||
|
"usage_limit": "Usage Limit",
|
||||||
|
"number_of_times_token_can_be_used": "Number of times the signup token can be used.",
|
||||||
|
"expires": "Expires",
|
||||||
|
"signup": "Sign Up",
|
||||||
|
"user_creation": "User Creation",
|
||||||
|
"configure_user_creation": "Manage user creation settings, including signup methods and default permissions for new users.",
|
||||||
|
"user_creation_groups_description": "Assign these groups automatically to new users upon signup.",
|
||||||
|
"user_creation_claims_description": "Assign these custom claims automatically to new users upon signup.",
|
||||||
|
"user_creation_updated_successfully": "User creation settings updated successfully.",
|
||||||
|
"signup_disabled_description": "User signups are completely disabled. Only administrators can create new user accounts.",
|
||||||
|
"signup_requires_valid_token": "A valid signup token is required to create an account",
|
||||||
|
"validating_signup_token": "Validating signup token",
|
||||||
|
"go_to_login": "Go to login",
|
||||||
|
"signup_to_appname": "Sign Up to {appName}",
|
||||||
|
"create_your_account_to_get_started": "Create your account to get started.",
|
||||||
|
"initial_account_creation_description": "Please create your account to get started. You will be able to set up a passkey later.",
|
||||||
|
"setup_your_passkey": "Set up your passkey",
|
||||||
|
"create_a_passkey_to_securely_access_your_account": "Create a passkey to securely access your account. This will be your primary way to sign in.",
|
||||||
|
"skip_for_now": "Skip for now",
|
||||||
|
"account_created": "Account Created",
|
||||||
|
"enable_user_signups": "Enable User Signups",
|
||||||
|
"enable_user_signups_description": "Decide how users can sign up for new accounts in Pocket ID.",
|
||||||
|
"user_signups_are_disabled": "User signups are currently disabled",
|
||||||
|
"create_signup_token": "Create Signup Token",
|
||||||
|
"view_active_signup_tokens": "View Active Signup Tokens",
|
||||||
|
"manage_signup_tokens": "Manage Signup Tokens",
|
||||||
|
"view_and_manage_active_signup_tokens": "View and manage active signup tokens.",
|
||||||
|
"signup_token_deleted_successfully": "Signup token deleted successfully.",
|
||||||
|
"expired": "Expired",
|
||||||
|
"used_up": "Used Up",
|
||||||
|
"active": "Active",
|
||||||
|
"usage": "Usage",
|
||||||
|
"created": "Created",
|
||||||
|
"token": "Token",
|
||||||
|
"loading": "Loading",
|
||||||
|
"delete_signup_token": "Delete Signup Token",
|
||||||
|
"are_you_sure_you_want_to_delete_this_signup_token": "Are you sure you want to delete this signup token? This action cannot be undone.",
|
||||||
|
"signup_with_token": "Signup with token",
|
||||||
|
"signup_with_token_description": "Users can only sign up using a valid signup token created by an administrator.",
|
||||||
|
"signup_open": "Open Signup",
|
||||||
|
"signup_open_description": "Anyone can create a new account without restrictions.",
|
||||||
|
"of": "of",
|
||||||
|
"skip_passkey_setup": "Skip Passkey Setup",
|
||||||
|
"skip_passkey_setup_description": "It's highly recommended to set up a passkey because without one, you will be locked out of your account as soon as the session expires.",
|
||||||
|
"my_apps": "My Apps",
|
||||||
|
"no_apps_available": "No apps available",
|
||||||
|
"contact_your_administrator_for_app_access": "Contact your administrator to get access to applications.",
|
||||||
|
"launch": "Launch",
|
||||||
|
"client_launch_url": "Client Launch URL",
|
||||||
|
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
|
||||||
|
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
|
||||||
|
"revoke_access": "Revoke Access",
|
||||||
|
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
|
||||||
|
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
|
||||||
|
"last_signed_in_ago": "Last signed in {time} ago",
|
||||||
|
"invalid_client_id": "Client ID can only contain letters, numbers, underscores, and hyphens",
|
||||||
|
"custom_client_id_description": "Set a custom client ID if this is required by your application. Otherwise, leave it blank to generate a random one.",
|
||||||
|
"generated": "Generated",
|
||||||
|
"administration": "Administration",
|
||||||
|
"group_rdn_attribute_description": "The attribute used in the groups distinguished name (DN).",
|
||||||
|
"display_name_attribute": "Display Name Attribute",
|
||||||
|
"display_name": "Display Name",
|
||||||
|
"configure_application_images": "Configure Application Images",
|
||||||
|
"ui_config_disabled_info_title": "UI Configuration Disabled",
|
||||||
|
"ui_config_disabled_info_description": "The UI configuration is disabled because the application configuration settings are managed through environment variables. Some settings may not be editable.",
|
||||||
|
"logo_from_url_description": "Paste a direct image URL (svg, png, webp). Find icons at <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> or <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
|
||||||
|
"invalid_url": "Invalid URL",
|
||||||
|
"require_user_email": "Require Email Address",
|
||||||
|
"require_user_email_description": "Requires users to have an email address. If disabled, the users without an email address won't be able to use features that require an email address.",
|
||||||
|
"view": "View",
|
||||||
|
"toggle_columns": "Toggle columns",
|
||||||
|
"locale": "Locale",
|
||||||
|
"ldap_id": "LDAP ID",
|
||||||
|
"reauthentication": "Re-authentication",
|
||||||
|
"clear_filters": "Clear Filters",
|
||||||
|
"default_profile_picture": "Default Profile Picture",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark",
|
||||||
|
"system": "System",
|
||||||
|
"signup_token_user_groups_description": "Automatically assign these groups to users who sign up using this token.",
|
||||||
|
"allowed_oidc_clients": "Allowed OIDC Clients",
|
||||||
|
"allowed_oidc_clients_description": "Select the OIDC clients that members of this user group are allowed to sign in to.",
|
||||||
|
"unrestrict_oidc_client": "Unrestrict {clientName}",
|
||||||
|
"confirm_unrestrict_oidc_client_description": "Are you sure you want to unrestrict the OIDC client <b>{clientName}</b>? This will remove all group assignments for this client and any user will be able to sign in.",
|
||||||
|
"allowed_oidc_clients_updated_successfully": "Allowed OIDC clients updated successfully",
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
|
"restricted": "Restricted",
|
||||||
|
"scim_provisioning": "SCIM Provisioning",
|
||||||
|
"scim_provisioning_description": "SCIM provisioning allows you to automatically provision and deprovision users and groups from your OIDC client. Learn more in the <link href='https://pocket-id.org/docs/configuration/scim'>docs</link>.",
|
||||||
|
"scim_endpoint": "SCIM Endpoint",
|
||||||
|
"scim_token": "SCIM Token",
|
||||||
|
"last_successful_sync_at": "Last successful sync: {time}",
|
||||||
|
"scim_configuration_updated_successfully": "SCIM configuration updated successfully.",
|
||||||
|
"scim_enabled_successfully": "SCIM enabled successfully.",
|
||||||
|
"scim_disabled_successfully": "SCIM disabled successfully.",
|
||||||
|
"disable_scim_provisioning": "Disable SCIM Provisioning",
|
||||||
|
"disable_scim_provisioning_confirm_description": "Are you sure you want to disable SCIM provisioning for <b>{clientName}</b>? This will stop all automatic user and group provisioning and deprovisioning.",
|
||||||
|
"scim_sync_failed": "SCIM sync failed. Check the server logs for more information.",
|
||||||
|
"scim_sync_successful": "The SCIM sync has been completed successfully.",
|
||||||
|
"save_and_sync": "Save and Sync",
|
||||||
|
"scim_save_changes_description": "You have to save the changes before starting a SCIM sync. Do you want to save now?",
|
||||||
|
"scopes": "Scopes",
|
||||||
|
"issuer_url": "Issuer URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Required when any SMTP setting is provided",
|
||||||
|
"smtp_field_required_when_email_enabled": "Required when email notifications are enabled",
|
||||||
|
"renew": "Renew",
|
||||||
|
"renew_api_key": "Renew API Key",
|
||||||
|
"renew_api_key_description": "Renewing the API key will generate a new key. Make sure to update any integrations using this key.",
|
||||||
|
"api_key_renewed": "API key renewed",
|
||||||
|
"app_config_home_page": "Home Page",
|
||||||
|
"app_config_home_page_description": "The page users are redirected to after signing in.",
|
||||||
|
"email_verification_warning": "Verify your email address",
|
||||||
|
"email_verification_warning_description": "Your email address is not verified yet. Please verify it as soon as possible.",
|
||||||
|
"email_verification": "Email Verification",
|
||||||
|
"email_verification_description": "Send a verification email to users when they sign up or change their email address.",
|
||||||
|
"email_verification_success_title": "Email Verified Successfully",
|
||||||
|
"email_verification_success_description": "Your email address has been verified successfully.",
|
||||||
|
"email_verification_error_title": "Email Verification Failed",
|
||||||
|
"mark_as_unverified": "Mark as unverified",
|
||||||
|
"mark_as_verified": "Mark as verified",
|
||||||
|
"email_verification_sent": "Verification email sent successfully.",
|
||||||
|
"emails_verified_by_default": "Emails verified by default",
|
||||||
|
"emails_verified_by_default_description": "When enabled, users' email addresses will be marked as verified by default upon signup or when their email address is changed."
|
||||||
|
}
|
||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Todentaja ei tue laiteavaimia",
|
"authenticator_does_not_support_resident_keys": "Todentaja ei tue laiteavaimia",
|
||||||
"passkey_was_previously_registered": "Tämä pääsyavain on aiemmin rekisteröity",
|
"passkey_was_previously_registered": "Tämä pääsyavain on aiemmin rekisteröity",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Todentaja ei tue mitään pyydetyistä algoritmeista",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Todentaja ei tue mitään pyydetyistä algoritmeista",
|
||||||
"authenticator_timed_out": "Todentaja aikakatkaistiin",
|
"webauthn_error_invalid_rp_id": "Määritetty luottavan osapuolen tunnus on virheellinen.",
|
||||||
|
"webauthn_error_invalid_domain": "Määritetty verkkotunnus ei ole kelvollinen.",
|
||||||
|
"contact_administrator_to_fix": "Ota yhteyttä järjestelmänvalvojaan tämän ongelman korjaamiseksi.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Toimintoa ei sallittu tai sen aikakatkaisu umpeutui.",
|
||||||
|
"webauthn_not_supported_by_browser": "Tämä selain ei tue salasanan sijaan käytettäviä tunnuksia. Käytä vaihtoehtoista kirjautumistapaa.",
|
||||||
"critical_error_occurred_contact_administrator": "Kriittinen virhe tapahtui. Ota yhteyttä järjestelmänvalvojaan.",
|
"critical_error_occurred_contact_administrator": "Kriittinen virhe tapahtui. Ota yhteyttä järjestelmänvalvojaan.",
|
||||||
"sign_in_to": "Kirjaudu palveluun {name}",
|
"sign_in_to": "Kirjaudu palveluun {name}",
|
||||||
"client_not_found": "Asiakasta ei löydy",
|
"client_not_found": "Asiakasta ei löydy",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Istunnon kesto minuutteina ennen kuin käyttäjän on kirjauduttava uudelleen.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Istunnon kesto minuutteina ennen kuin käyttäjän on kirjauduttava uudelleen.",
|
||||||
"enable_self_account_editing": "Ota käyttöön tilin itsemuokkaus",
|
"enable_self_account_editing": "Ota käyttöön tilin itsemuokkaus",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Määrittää voiko käyttäjät itse muokata oman tilinsä tietoja.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Määrittää voiko käyttäjät itse muokata oman tilinsä tietoja.",
|
||||||
"emails_verified": "Sähköpostiosoitteet vahvistettu",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Merkitäänkö käyttäjän sähköpostiosoite vahvistetuksi OIDC-asiakkaille.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP-määritykset päivitetty onnistuneesti",
|
"ldap_configuration_updated_successfully": "LDAP-määritykset päivitetty onnistuneesti",
|
||||||
"ldap_disabled_successfully": "LDAP poistettu käytöstä onnistuneesti",
|
"ldap_disabled_successfully": "LDAP poistettu käytöstä onnistuneesti",
|
||||||
"ldap_sync_finished": "LDAP-synkronointi valmis",
|
"ldap_sync_finished": "LDAP-synkronointi valmis",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Tallenna ja synkronoi",
|
"save_and_sync": "Tallenna ja synkronoi",
|
||||||
"scim_save_changes_description": "Sinun on tallennettava muutokset ennen SCIM-synkronoinnin aloittamista. Haluatko tallentaa nyt?",
|
"scim_save_changes_description": "Sinun on tallennettava muutokset ennen SCIM-synkronoinnin aloittamista. Haluatko tallentaa nyt?",
|
||||||
"scopes": "Käyttöalueet",
|
"scopes": "Käyttöalueet",
|
||||||
"issuer_url": "Julkaisijan URL-osoite"
|
"issuer_url": "Julkaisijan URL-osoite",
|
||||||
|
"smtp_field_required_when_other_provided": "Vaaditaan, kun SMTP-asetukset on määritetty",
|
||||||
|
"smtp_field_required_when_email_enabled": "Vaaditaan, kun sähköpostimuistutukset ovat käytössä",
|
||||||
|
"renew": "Uudista",
|
||||||
|
"renew_api_key": "Uudista API-avain",
|
||||||
|
"renew_api_key_description": "API-avaimen uusiminen luo uuden avaimen. Muista päivittää kaikki integraatiot, joissa tätä avainta käytetään.",
|
||||||
|
"api_key_renewed": "API-avain uusittu",
|
||||||
|
"app_config_home_page": "Kotisivu",
|
||||||
|
"app_config_home_page_description": "Sivu, jolle käyttäjät ohjataan kirjautumisen jälkeen.",
|
||||||
|
"email_verification_warning": "Vahvista sähköpostiosoitteesi",
|
||||||
|
"email_verification_warning_description": "Sähköpostiosoitteesi ei ole vielä vahvistettu. Vahvista se mahdollisimman pian.",
|
||||||
|
"email_verification": "Sähköpostin vahvistus",
|
||||||
|
"email_verification_description": "Lähetä vahvistussähköposti käyttäjille, kun he rekisteröityvät tai muuttavat sähköpostiosoitteensa.",
|
||||||
|
"email_verification_success_title": "Sähköposti vahvistettu onnistuneesti",
|
||||||
|
"email_verification_success_description": "Sähköpostiosoitteesi on vahvistettu onnistuneesti.",
|
||||||
|
"email_verification_error_title": "Sähköpostin vahvistus epäonnistui",
|
||||||
|
"mark_as_unverified": "Merkitse vahvistamattomaksi",
|
||||||
|
"mark_as_verified": "Merkitse vahvistetuksi",
|
||||||
|
"email_verification_sent": "Vahvistussähköposti lähetetty onnistuneesti.",
|
||||||
|
"emails_verified_by_default": "Sähköpostit vahvistettu oletuksena",
|
||||||
|
"emails_verified_by_default_description": "Kun tämä toiminto on käytössä, käyttäjien sähköpostiosoitteet merkitään oletusarvoisesti vahvistetuiksi rekisteröitymisen yhteydessä tai kun heidän sähköpostiosoitteensa muuttuu."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "L'authentificateur ne prend pas en charge les clés résidentes",
|
"authenticator_does_not_support_resident_keys": "L'authentificateur ne prend pas en charge les clés résidentes",
|
||||||
"passkey_was_previously_registered": "Cette clé d'accès a déjà été enregistrée",
|
"passkey_was_previously_registered": "Cette clé d'accès a déjà été enregistrée",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "L'authentificateur ne supporte aucun des algorithmes requis",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "L'authentificateur ne supporte aucun des algorithmes requis",
|
||||||
"authenticator_timed_out": "L'authentification a expiré",
|
"webauthn_error_invalid_rp_id": "L'ID de la partie de confiance configurée n'est pas valide.",
|
||||||
|
"webauthn_error_invalid_domain": "Le domaine configuré n'est pas valide.",
|
||||||
|
"contact_administrator_to_fix": "Contacte ton administrateur pour régler ce problème.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "L'opération n'a pas été autorisée ou a expiré.",
|
||||||
|
"webauthn_not_supported_by_browser": "Les clés d'accès ne sont pas prises en charge par ce navigateur. Essaie une autre méthode de connexion.",
|
||||||
"critical_error_occurred_contact_administrator": "Une erreur critique s'est produite. Veuillez contacter votre administrateur.",
|
"critical_error_occurred_contact_administrator": "Une erreur critique s'est produite. Veuillez contacter votre administrateur.",
|
||||||
"sign_in_to": "Connexion à {name}",
|
"sign_in_to": "Connexion à {name}",
|
||||||
"client_not_found": "Client introuvable",
|
"client_not_found": "Client introuvable",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La durée d'une session en minutes avant que l'utilisateur ne doive se reconnecter.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La durée d'une session en minutes avant que l'utilisateur ne doive se reconnecter.",
|
||||||
"enable_self_account_editing": "Activer l'édition de compte par l'utilisateur",
|
"enable_self_account_editing": "Activer l'édition de compte par l'utilisateur",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Cela permet aux utilisateurs de modifier les détails de leur compte.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Cela permet aux utilisateurs de modifier les détails de leur compte.",
|
||||||
"emails_verified": "Email vérifié",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Indique si l'adresse e-mail de l'utilisateur doit être marquée comme vérifiée pour les clients OIDC.",
|
|
||||||
"ldap_configuration_updated_successfully": "Configuration LDAP mise à jour avec succès",
|
"ldap_configuration_updated_successfully": "Configuration LDAP mise à jour avec succès",
|
||||||
"ldap_disabled_successfully": "LDAP désactivé avec succès",
|
"ldap_disabled_successfully": "LDAP désactivé avec succès",
|
||||||
"ldap_sync_finished": "Synchronisation LDAP terminée",
|
"ldap_sync_finished": "Synchronisation LDAP terminée",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Enregistrer et synchroniser",
|
"save_and_sync": "Enregistrer et synchroniser",
|
||||||
"scim_save_changes_description": "Tu dois enregistrer les changements avant de lancer une synchronisation SCIM. Tu veux enregistrer maintenant ?",
|
"scim_save_changes_description": "Tu dois enregistrer les changements avant de lancer une synchronisation SCIM. Tu veux enregistrer maintenant ?",
|
||||||
"scopes": "Portées",
|
"scopes": "Portées",
|
||||||
"issuer_url": "URL de l'émetteur"
|
"issuer_url": "URL de l'émetteur",
|
||||||
|
"smtp_field_required_when_other_provided": "Nécessaire quand un paramètre SMTP est fourni",
|
||||||
|
"smtp_field_required_when_email_enabled": "C'est nécessaire quand les notifications par e-mail sont activées.",
|
||||||
|
"renew": "Renouveler",
|
||||||
|
"renew_api_key": "Renouveler la clé API",
|
||||||
|
"renew_api_key_description": "Quand tu renouvelles la clé API, une nouvelle clé est créée. N'oublie pas de mettre à jour toutes les intégrations qui utilisent cette clé.",
|
||||||
|
"api_key_renewed": "Clé API renouvelée",
|
||||||
|
"app_config_home_page": "Page d'accueil",
|
||||||
|
"app_config_home_page_description": "La page où les utilisateurs sont redirigés après s'être connectés.",
|
||||||
|
"email_verification_warning": "Vérifie ton adresse e-mail",
|
||||||
|
"email_verification_warning_description": "Ton adresse e-mail n'est pas encore validée. Valide-la dès que possible.",
|
||||||
|
"email_verification": "Vérification de l'adresse e-mail",
|
||||||
|
"email_verification_description": "Envoie un e-mail de vérification aux utilisateurs quand ils s'inscrivent ou changent leur adresse e-mail.",
|
||||||
|
"email_verification_success_title": "Adresse e-mail validée avec succès",
|
||||||
|
"email_verification_success_description": "Ton adresse e-mail a été validée avec succès.",
|
||||||
|
"email_verification_error_title": "Échec de la vérification de l'adresse e-mail",
|
||||||
|
"mark_as_unverified": "Marquer comme non vérifié",
|
||||||
|
"mark_as_verified": "Marquer comme vérifié",
|
||||||
|
"email_verification_sent": "L'e-mail de vérification a été envoyé sans problème.",
|
||||||
|
"emails_verified_by_default": "E-mails vérifiés par défaut",
|
||||||
|
"emails_verified_by_default_description": "Quand cette option est activée, les adresses e-mail des utilisateurs seront marquées comme vérifiées par défaut lors de leur inscription ou quand ils changent d'adresse e-mail."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "L'autenticatore non supporta le chiavi residenti",
|
"authenticator_does_not_support_resident_keys": "L'autenticatore non supporta le chiavi residenti",
|
||||||
"passkey_was_previously_registered": "Questa passkey è stata registrata in precedenza",
|
"passkey_was_previously_registered": "Questa passkey è stata registrata in precedenza",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "L'autenticatore non supporta nessuno degli algoritmi richiesti",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "L'autenticatore non supporta nessuno degli algoritmi richiesti",
|
||||||
"authenticator_timed_out": "L'autenticatore ha superato il tempo limite",
|
"webauthn_error_invalid_rp_id": "L'ID della parte affidabile che hai impostato non va bene.",
|
||||||
|
"webauthn_error_invalid_domain": "Il dominio che hai impostato non va bene.",
|
||||||
|
"contact_administrator_to_fix": "Chiedi al tuo amministratore di risolvere questo problema.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "L'operazione non è stata autorizzata o è scaduta.",
|
||||||
|
"webauthn_not_supported_by_browser": "Questo browser non supporta le passkey. Prova a usare un altro modo per accedere.",
|
||||||
"critical_error_occurred_contact_administrator": "Si è verificato un errore critico. Contatta il tuo amministratore.",
|
"critical_error_occurred_contact_administrator": "Si è verificato un errore critico. Contatta il tuo amministratore.",
|
||||||
"sign_in_to": "Accedi a {name}",
|
"sign_in_to": "Accedi a {name}",
|
||||||
"client_not_found": "Client non trovato",
|
"client_not_found": "Client non trovato",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La durata di una sessione in minuti prima che l'utente debba accedere nuovamente.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "La durata di una sessione in minuti prima che l'utente debba accedere nuovamente.",
|
||||||
"enable_self_account_editing": "Abilita modifica del proprio account",
|
"enable_self_account_editing": "Abilita modifica del proprio account",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Se gli utenti dovrebbero essere in grado di modificare i dettagli del proprio account.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Se gli utenti dovrebbero essere in grado di modificare i dettagli del proprio account.",
|
||||||
"emails_verified": "Email verificate",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Se l'email dell'utente deve essere contrassegnata come verificata per i client OIDC.",
|
|
||||||
"ldap_configuration_updated_successfully": "Configurazione LDAP aggiornata con successo",
|
"ldap_configuration_updated_successfully": "Configurazione LDAP aggiornata con successo",
|
||||||
"ldap_disabled_successfully": "LDAP disabilitato con successo",
|
"ldap_disabled_successfully": "LDAP disabilitato con successo",
|
||||||
"ldap_sync_finished": "Sincronizzazione LDAP completata",
|
"ldap_sync_finished": "Sincronizzazione LDAP completata",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Salva e sincronizza",
|
"save_and_sync": "Salva e sincronizza",
|
||||||
"scim_save_changes_description": "Devi salvare le modifiche prima di iniziare una sincronizzazione SCIM. Vuoi salvare adesso?",
|
"scim_save_changes_description": "Devi salvare le modifiche prima di iniziare una sincronizzazione SCIM. Vuoi salvare adesso?",
|
||||||
"scopes": "Scopi",
|
"scopes": "Scopi",
|
||||||
"issuer_url": "URL dell'emittente"
|
"issuer_url": "URL dell'emittente",
|
||||||
|
"smtp_field_required_when_other_provided": "Richiesto quando c'è un'impostazione SMTP",
|
||||||
|
"smtp_field_required_when_email_enabled": "Richiesto quando le notifiche via e-mail sono attivate",
|
||||||
|
"renew": "Rinnovare",
|
||||||
|
"renew_api_key": "Rinnova chiave API",
|
||||||
|
"renew_api_key_description": "Rinnovando la chiave API ne verrà generata una nuova. Assicurati di aggiornare tutte le integrazioni che usano questa chiave.",
|
||||||
|
"api_key_renewed": "Chiave API rinnovata",
|
||||||
|
"app_config_home_page": "Pagina iniziale",
|
||||||
|
"app_config_home_page_description": "La pagina a cui gli utenti vengono reindirizzati dopo aver effettuato l'accesso.",
|
||||||
|
"email_verification_warning": "Conferma il tuo indirizzo email",
|
||||||
|
"email_verification_warning_description": "Il tuo indirizzo email non è ancora stato verificato. Ti chiediamo di farlo il prima possibile.",
|
||||||
|
"email_verification": "Verifica dell'indirizzo e-mail",
|
||||||
|
"email_verification_description": "Manda un'email di verifica agli utenti quando si registrano o cambiano il loro indirizzo email.",
|
||||||
|
"email_verification_success_title": "Email verificata con successo",
|
||||||
|
"email_verification_success_description": "Il tuo indirizzo email è stato verificato senza problemi.",
|
||||||
|
"email_verification_error_title": "Verifica e-mail non riuscita",
|
||||||
|
"mark_as_unverified": "Contrassegna come non verificato",
|
||||||
|
"mark_as_verified": "Contrassegna come verificato",
|
||||||
|
"email_verification_sent": "Email di conferma inviata con successo.",
|
||||||
|
"emails_verified_by_default": "Email verificate di default",
|
||||||
|
"emails_verified_by_default_description": "Quando questa opzione è attiva, gli indirizzi email degli utenti saranno automaticamente contrassegnati come verificati al momento della registrazione o quando cambiano il loro indirizzo email."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "認証ツールは resident key をサポートしていません",
|
"authenticator_does_not_support_resident_keys": "認証ツールは resident key をサポートしていません",
|
||||||
"passkey_was_previously_registered": "このパスキーは既に登録されています",
|
"passkey_was_previously_registered": "このパスキーは既に登録されています",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "認証ツールは要求されたアルゴリズムのいずれをもサポートしていません",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "認証ツールは要求されたアルゴリズムのいずれをもサポートしていません",
|
||||||
"authenticator_timed_out": "認証ツールがタイムアウトしました",
|
"webauthn_error_invalid_rp_id": "設定された信頼当事者IDは無効です。",
|
||||||
|
"webauthn_error_invalid_domain": "設定されたドメインは無効です。",
|
||||||
|
"contact_administrator_to_fix": "この問題を修正するには、管理者にお問い合わせください。",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "操作は許可されませんでした、またはタイムアウトしました",
|
||||||
|
"webauthn_not_supported_by_browser": "このブラウザではパスキーはサポートされていません。別のサインイン方法をご利用ください。",
|
||||||
"critical_error_occurred_contact_administrator": "重大なエラーが発生しました。管理者にお問い合わせください。",
|
"critical_error_occurred_contact_administrator": "重大なエラーが発生しました。管理者にお問い合わせください。",
|
||||||
"sign_in_to": "{name} にサインイン",
|
"sign_in_to": "{name} にサインイン",
|
||||||
"client_not_found": "クライアントが見つかりません",
|
"client_not_found": "クライアントが見つかりません",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"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": "ユーザーが自身のアカウントの詳細を編集できるかどうか。",
|
||||||
"emails_verified": "メールアドレス確認済み",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "ユーザのEメールをOIDCクライアントで検証済みとしてマークするかどうか。",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP 設定が正常に更新されました",
|
"ldap_configuration_updated_successfully": "LDAP 設定が正常に更新されました",
|
||||||
"ldap_disabled_successfully": "LDAPは正常に無効化されました",
|
"ldap_disabled_successfully": "LDAPは正常に無効化されました",
|
||||||
"ldap_sync_finished": "LDAP同期が完了しました",
|
"ldap_sync_finished": "LDAP同期が完了しました",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"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_email_enabled": "メール通知が有効な場合に必須",
|
||||||
|
"renew": "更新",
|
||||||
|
"renew_api_key": "APIキーを更新する",
|
||||||
|
"renew_api_key_description": "APIキーを更新すると新しいキーが生成されます。このキーを使用しているすべての連携を更新してください。",
|
||||||
|
"api_key_renewed": "APIキーを更新しました",
|
||||||
|
"app_config_home_page": "ホームページ",
|
||||||
|
"app_config_home_page_description": "ユーザーがサインイン後にリダイレクトされるページ。",
|
||||||
|
"email_verification_warning": "メールアドレスを確認してください",
|
||||||
|
"email_verification_warning_description": "メールアドレスはまだ確認されていません。できるだけ早く確認してください。",
|
||||||
|
"email_verification": "メール認証",
|
||||||
|
"email_verification_description": "ユーザーが登録時またはメールアドレスを変更した際に、確認メールを送信する。",
|
||||||
|
"email_verification_success_title": "メールアドレスの確認が完了しました",
|
||||||
|
"email_verification_success_description": "メールアドレスの確認が完了しました。",
|
||||||
|
"email_verification_error_title": "メール認証に失敗しました",
|
||||||
|
"mark_as_unverified": "未確認としてマークする",
|
||||||
|
"mark_as_verified": "確認済みとしてマークする",
|
||||||
|
"email_verification_sent": "確認メールが正常に送信されました。",
|
||||||
|
"emails_verified_by_default": "メールはデフォルトで検証済み",
|
||||||
|
"emails_verified_by_default_description": "有効化すると、ユーザーが登録時またはメールアドレスを変更した際に、デフォルトでメールアドレスが確認済みとしてマークされます。"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "인증기가 레지던트 키를 지원하지 않습니다",
|
"authenticator_does_not_support_resident_keys": "인증기가 레지던트 키를 지원하지 않습니다",
|
||||||
"passkey_was_previously_registered": "이 패스키는 이미 등록되었습니다",
|
"passkey_was_previously_registered": "이 패스키는 이미 등록되었습니다",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "인증기가 요청된 알고리즘 중 어느 것도 지원하지 않습니다",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "인증기가 요청된 알고리즘 중 어느 것도 지원하지 않습니다",
|
||||||
"authenticator_timed_out": "인증기가 시간 초과되었습니다",
|
"webauthn_error_invalid_rp_id": "구성된 신뢰 당사자 ID가 유효하지 않습니다.",
|
||||||
|
"webauthn_error_invalid_domain": "구성된 도메인이 유효하지 않습니다.",
|
||||||
|
"contact_administrator_to_fix": "이 문제를 해결하려면 관리자에게 문의하십시오.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "작업이 허용되지 않았거나 시간 초과되었습니다.",
|
||||||
|
"webauthn_not_supported_by_browser": "이 브라우저에서는 패스키를 지원하지 않습니다. 다른 로그인 방법을 사용해 주세요.",
|
||||||
"critical_error_occurred_contact_administrator": "치명적인 오류가 발생했습니다. 관리자에게 연락해주세요.",
|
"critical_error_occurred_contact_administrator": "치명적인 오류가 발생했습니다. 관리자에게 연락해주세요.",
|
||||||
"sign_in_to": "{name}에 로그인",
|
"sign_in_to": "{name}에 로그인",
|
||||||
"client_not_found": "클라이언트를 찾을 수 없습니다",
|
"client_not_found": "클라이언트를 찾을 수 없습니다",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"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": "사용자가 자신의 계정 정보를 편집할 수 있습니다.",
|
||||||
"emails_verified": "이메일 인증됨",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "OIDC 클라이언트에게 사용자의 이메일이 인증된 것으로 표시합니다.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP 구성이 성공적으로 변경되었습니다",
|
"ldap_configuration_updated_successfully": "LDAP 구성이 성공적으로 변경되었습니다",
|
||||||
"ldap_disabled_successfully": "LDAP가 성공적으로 비활성화되었습니다",
|
"ldap_disabled_successfully": "LDAP가 성공적으로 비활성화되었습니다",
|
||||||
"ldap_sync_finished": "LDAP 동기화 완료",
|
"ldap_sync_finished": "LDAP 동기화 완료",
|
||||||
@@ -309,7 +311,7 @@
|
|||||||
"allowed_user_groups_description": "이 클라이언트에 로그인할 수 있는 사용자 그룹을 선택하십시오.",
|
"allowed_user_groups_description": "이 클라이언트에 로그인할 수 있는 사용자 그룹을 선택하십시오.",
|
||||||
"allowed_user_groups_status_unrestricted_description": "사용자 그룹 제한이 적용되지 않습니다. 모든 사용자가 이 클라이언트에 로그인할 수 있습니다.",
|
"allowed_user_groups_status_unrestricted_description": "사용자 그룹 제한이 적용되지 않습니다. 모든 사용자가 이 클라이언트에 로그인할 수 있습니다.",
|
||||||
"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": "파비콘",
|
||||||
@@ -354,8 +356,8 @@
|
|||||||
"login_code_email_success": "로그인 코드가 사용자에게 전송되었습니다.",
|
"login_code_email_success": "로그인 코드가 사용자에게 전송되었습니다.",
|
||||||
"send_email": "이메일 전송",
|
"send_email": "이메일 전송",
|
||||||
"show_code": "코드 표시",
|
"show_code": "코드 표시",
|
||||||
"callback_url_description": "고객이 제공한 URL. 비워두면 자동으로 추가됩니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드가</link> 지원됩니다.",
|
"callback_url_description": "클라이언트에서 제공된 URL입니다. 비워두면 자동으로 추가됩니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link>가 지원됩니다.",
|
||||||
"logout_callback_url_description": "로그아웃을 위해 클라이언트가 제공하는 URL(들). <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드가</link> 지원됩니다.",
|
"logout_callback_url_description": "클라이언트에서 제공된 로그아웃 URL입니다. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>와일드카드</link>가 지원됩니다.",
|
||||||
"api_key_expiration": "API 키 만료",
|
"api_key_expiration": "API 키 만료",
|
||||||
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "API 키가 만료되기 전에 사용자에게 이메일을 전송합니다.",
|
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "API 키가 만료되기 전에 사용자에게 이메일을 전송합니다.",
|
||||||
"authorize_device": "기기 승인",
|
"authorize_device": "기기 승인",
|
||||||
@@ -478,11 +480,11 @@
|
|||||||
"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> 참조하세요.",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"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_email_enabled": "이메일 알림이 활성화된 경우 필수",
|
||||||
|
"renew": "갱신",
|
||||||
|
"renew_api_key": "API 키 갱신",
|
||||||
|
"renew_api_key_description": "API 키를 갱신하면 새 키가 생성됩니다. 이 키를 사용하는 모든 통합 기능을 반드시 업데이트하십시오.",
|
||||||
|
"api_key_renewed": "API 키 갱신됨",
|
||||||
|
"app_config_home_page": "홈페이지",
|
||||||
|
"app_config_home_page_description": "사용자가 로그인 후 이동하는 페이지.",
|
||||||
|
"email_verification_warning": "이메일 주소를 확인하세요",
|
||||||
|
"email_verification_warning_description": "귀하의 이메일 주소는 아직 확인되지 않았습니다. 가능한 한 빨리 확인해 주시기 바랍니다.",
|
||||||
|
"email_verification": "이메일 인증",
|
||||||
|
"email_verification_description": "사용자가 가입하거나 이메일 주소를 변경할 때 인증 이메일을 발송합니다.",
|
||||||
|
"email_verification_success_title": "이메일 확인이 성공적으로 완료되었습니다",
|
||||||
|
"email_verification_success_description": "귀하의 이메일 주소가 성공적으로 확인되었습니다.",
|
||||||
|
"email_verification_error_title": "이메일 확인 실패",
|
||||||
|
"mark_as_unverified": "확인되지 않음으로 표시",
|
||||||
|
"mark_as_verified": "검증됨으로 표시",
|
||||||
|
"email_verification_sent": "확인 이메일이 성공적으로 발송되었습니다.",
|
||||||
|
"emails_verified_by_default": "이메일은 기본적으로 확인됨",
|
||||||
|
"emails_verified_by_default_description": "이 기능이 활성화되면, 사용자의 이메일 주소는 가입 시 또는 이메일 주소 변경 시 기본적으로 확인된 상태로 표시됩니다."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "De authenticator ondersteunt geen vaste sleutels",
|
"authenticator_does_not_support_resident_keys": "De authenticator ondersteunt geen vaste sleutels",
|
||||||
"passkey_was_previously_registered": "Deze passkey is eerder geregistreerd",
|
"passkey_was_previously_registered": "Deze passkey is eerder geregistreerd",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "De authenticator ondersteunt geen van de gevraagde algoritmen",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "De authenticator ondersteunt geen van de gevraagde algoritmen",
|
||||||
"authenticator_timed_out": "De authenticator is verlopen",
|
"webauthn_error_invalid_rp_id": "De ID van de vertrouwende partij die je hebt ingesteld, klopt niet.",
|
||||||
|
"webauthn_error_invalid_domain": "Het domein dat je hebt ingesteld, klopt niet.",
|
||||||
|
"contact_administrator_to_fix": "Neem contact op met je beheerder om dit probleem op te lossen.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "De bewerking is niet toegestaan of de tijd is verstreken.",
|
||||||
|
"webauthn_not_supported_by_browser": "Passkeys worden niet ondersteund door deze browser. Probeer een andere manier om in te loggen.",
|
||||||
"critical_error_occurred_contact_administrator": "Er is een kritieke fout opgetreden. Neem contact op met de beheerder.",
|
"critical_error_occurred_contact_administrator": "Er is een kritieke fout opgetreden. Neem contact op met de beheerder.",
|
||||||
"sign_in_to": "Meld je aan bij {name}",
|
"sign_in_to": "Meld je aan bij {name}",
|
||||||
"client_not_found": "Client niet gevonden",
|
"client_not_found": "Client niet gevonden",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "De duur van een sessie in minuten voordat de gebruiker zich opnieuw moet aanmelden.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "De duur van een sessie in minuten voordat de gebruiker zich opnieuw moet aanmelden.",
|
||||||
"enable_self_account_editing": "Bewerken van eigen account mogelijk maken",
|
"enable_self_account_editing": "Bewerken van eigen account mogelijk maken",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Of gebruikers hun eigen accountgegevens moeten kunnen bewerken.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Of gebruikers hun eigen accountgegevens moeten kunnen bewerken.",
|
||||||
"emails_verified": "E-mails geverifieerd",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Of het e-mailadres van de gebruiker als geverifieerd moet worden gemarkeerd voor de OIDC-clients.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP-configuratie succesvol bijgewerkt",
|
"ldap_configuration_updated_successfully": "LDAP-configuratie succesvol bijgewerkt",
|
||||||
"ldap_disabled_successfully": "LDAP succesvol uitgeschakeld",
|
"ldap_disabled_successfully": "LDAP succesvol uitgeschakeld",
|
||||||
"ldap_sync_finished": "LDAP-synchronisatie voltooid",
|
"ldap_sync_finished": "LDAP-synchronisatie voltooid",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Opslaan en synchroniseren",
|
"save_and_sync": "Opslaan en synchroniseren",
|
||||||
"scim_save_changes_description": "Je moet de wijzigingen opslaan voordat je een SCIM-synchronisatie start. Wil je nu opslaan?",
|
"scim_save_changes_description": "Je moet de wijzigingen opslaan voordat je een SCIM-synchronisatie start. Wil je nu opslaan?",
|
||||||
"scopes": "Scopes",
|
"scopes": "Scopes",
|
||||||
"issuer_url": "URL van de uitgever"
|
"issuer_url": "URL van de uitgever",
|
||||||
|
"smtp_field_required_when_other_provided": "Moet je invullen als er SMTP-instellingen zijn",
|
||||||
|
"smtp_field_required_when_email_enabled": "Moet je invullen als je e-mailmeldingen hebt ingeschakeld.",
|
||||||
|
"renew": "Vernieuwen",
|
||||||
|
"renew_api_key": "API-sleutel vernieuwen",
|
||||||
|
"renew_api_key_description": "Als je de API-sleutel vernieuwt, krijg je een nieuwe sleutel. Zorg ervoor dat je alle integraties die deze sleutel gebruiken, bijwerkt.",
|
||||||
|
"api_key_renewed": "API-sleutel vernieuwd",
|
||||||
|
"app_config_home_page": "Startpagina",
|
||||||
|
"app_config_home_page_description": "De pagina waar gebruikers naartoe gaan nadat ze zijn ingelogd.",
|
||||||
|
"email_verification_warning": "Check je e-mailadres",
|
||||||
|
"email_verification_warning_description": "Je e-mailadres is nog niet geverifieerd. Doe dat alsjeblieft zo snel mogelijk.",
|
||||||
|
"email_verification": "E-mailverificatie",
|
||||||
|
"email_verification_description": "Stuur een bevestigingsmail naar mensen als ze zich aanmelden of hun e-mailadres veranderen.",
|
||||||
|
"email_verification_success_title": "E-mailadres succesvol geverifieerd",
|
||||||
|
"email_verification_success_description": "Je e-mailadres is goed geverifieerd.",
|
||||||
|
"email_verification_error_title": "E-mailverificatie mislukt",
|
||||||
|
"mark_as_unverified": "Markeer als niet geverifieerd",
|
||||||
|
"mark_as_verified": "Markeer als geverifieerd",
|
||||||
|
"email_verification_sent": "Verificatiemail is goed verstuurd.",
|
||||||
|
"emails_verified_by_default": "E-mails standaard geverifieerd",
|
||||||
|
"emails_verified_by_default_description": "Als je dit aan zet, worden de e-mailadressen van gebruikers standaard gemarkeerd als geverifieerd bij het aanmelden of als hun e-mailadres verandert."
|
||||||
}
|
}
|
||||||
|
|||||||
525
frontend/messages/no.json
Normal file
525
frontend/messages/no.json
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||||
|
"my_account": "My Account",
|
||||||
|
"logout": "Logg ut",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"docs": "Docs",
|
||||||
|
"key": "Nøkkel",
|
||||||
|
"value": "Verdi",
|
||||||
|
"remove_custom_claim": "Remove custom claim",
|
||||||
|
"add_custom_claim": "Add custom claim",
|
||||||
|
"add_another": "Add another",
|
||||||
|
"select_a_date": "Velg dato",
|
||||||
|
"select_file": "Velg fil",
|
||||||
|
"profile_picture": "Profilbilde",
|
||||||
|
"profile_picture_is_managed_by_ldap_server": "Profilbildet administreres av LDAP serveren og kan ikke endres her.",
|
||||||
|
"click_profile_picture_to_upload_custom": "Klikk på profilbildet for å laste opp et bilde fra filene dine.",
|
||||||
|
"image_should_be_in_format": "Bildet kan være i PNG, JPEG eller WEBP format.",
|
||||||
|
"items_per_page": "Items per page",
|
||||||
|
"no_items_found": "No items found",
|
||||||
|
"select_items": "Select items...",
|
||||||
|
"search": "Søk...",
|
||||||
|
"expand_card": "Utvid kort",
|
||||||
|
"copied": "Kopiert",
|
||||||
|
"click_to_copy": "Klikk for å kopiere",
|
||||||
|
"something_went_wrong": "Noe gikk galt",
|
||||||
|
"go_back_to_home": "Go back to home",
|
||||||
|
"alternative_sign_in_methods": "Alternative innloggingingsmetoder",
|
||||||
|
"login_background": "Login background",
|
||||||
|
"logo": "Logo",
|
||||||
|
"login_code": "Innloggingskode",
|
||||||
|
"create_a_login_code_to_sign_in_without_a_passkey_once": "Lag en innloggingskode som brukeren kan bruke for å logge inn uten en passnøkkel.",
|
||||||
|
"one_hour": "1 time",
|
||||||
|
"twelve_hours": "12 timer",
|
||||||
|
"one_day": "1 dag",
|
||||||
|
"one_week": "1 uke",
|
||||||
|
"one_month": "1 måned",
|
||||||
|
"expiration": "Expiration",
|
||||||
|
"generate_code": "Generer kode",
|
||||||
|
"name": "Navn",
|
||||||
|
"browser_unsupported": "Nettleser ikke støttet",
|
||||||
|
"this_browser_does_not_support_passkeys": "Denne nettleseren støtter ikke passnøkler. Vennligst bruk en annen metode for å logge inn.",
|
||||||
|
"an_unknown_error_occurred": "En ukjent feil oppstod",
|
||||||
|
"authentication_process_was_aborted": "Autentiseringsprosessen ble avbrutt",
|
||||||
|
"error_occurred_with_authenticator": "An error occurred with the authenticator",
|
||||||
|
"authenticator_does_not_support_discoverable_credentials": "The authenticator does not support discoverable credentials",
|
||||||
|
"authenticator_does_not_support_resident_keys": "The authenticator does not support resident keys",
|
||||||
|
"passkey_was_previously_registered": "Denne passnøkkelen er allerede registrert",
|
||||||
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "The authenticator does not support any of the requested algorithms",
|
||||||
|
"webauthn_error_invalid_rp_id": "The configured relying party ID is invalid.",
|
||||||
|
"webauthn_error_invalid_domain": "Det konfigurerte domenet er ugyldig.",
|
||||||
|
"contact_administrator_to_fix": "Kontakt administratoren for å fikse feilen.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "The operation was not allowed or timed out",
|
||||||
|
"webauthn_not_supported_by_browser": "Passkeys are not supported by this browser. Please use an alternative sign in method.",
|
||||||
|
"critical_error_occurred_contact_administrator": "A critical error occurred. Please contact your administrator.",
|
||||||
|
"sign_in_to": "Logg inn til {name}",
|
||||||
|
"client_not_found": "Fant ikke klient",
|
||||||
|
"client_wants_to_access_the_following_information": "<b>{client}</b> ønsker tilgang til følgende informasjon:",
|
||||||
|
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Do you want to sign in to <b>{client}</b> with your {appName} account?",
|
||||||
|
"email": "E-post",
|
||||||
|
"view_your_email_address": "Vis E-post adressen din",
|
||||||
|
"profile": "Profil",
|
||||||
|
"view_your_profile_information": "Vis brukerinformasjonen din",
|
||||||
|
"groups": "Grupper",
|
||||||
|
"view_the_groups_you_are_a_member_of": "Vis grupper du er medlem i",
|
||||||
|
"cancel": "Avbryt",
|
||||||
|
"sign_in": "Logg inn",
|
||||||
|
"try_again": "Prøv på nytt",
|
||||||
|
"client_logo": "Klient logo",
|
||||||
|
"sign_out": "Logg ut",
|
||||||
|
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Do you want to sign out of {appName} with the account <b>{username}</b>?",
|
||||||
|
"sign_in_to_appname": "Sign in to {appName}",
|
||||||
|
"please_try_to_sign_in_again": "Vennligst prøv å logge inn på nytt.",
|
||||||
|
"authenticate_with_passkey_to_access_account": "Authenticate yourself with your passkey to access your account.",
|
||||||
|
"authenticate": "Autentiser",
|
||||||
|
"please_try_again": "Vennligst prøv på nytt.",
|
||||||
|
"continue": "Fortsett",
|
||||||
|
"alternative_sign_in": "Alternativ innloggingsmetode",
|
||||||
|
"if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "Om du ikke har tilgang til passnøkkelen din, så kan du bruke en av følgende innloggingsmetoder.",
|
||||||
|
"use_your_passkey_instead": "Bruk passnøkkelen din i stedet for?",
|
||||||
|
"email_login": "E-post innlogging",
|
||||||
|
"enter_a_login_code_to_sign_in": "Enter a login code to sign in.",
|
||||||
|
"sign_in_with_login_code": "Sign in with login code",
|
||||||
|
"request_a_login_code_via_email": "Request a login code via email.",
|
||||||
|
"go_back": "Go back",
|
||||||
|
"an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system": "An email has been sent to the provided email, if it exists in the system.",
|
||||||
|
"enter_code": "Enter code",
|
||||||
|
"enter_your_email_address_to_receive_an_email_with_a_login_code": "Enter your email address to receive an email with a login code.",
|
||||||
|
"your_email": "Your email",
|
||||||
|
"submit": "Submit",
|
||||||
|
"enter_the_code_you_received_to_sign_in": "Enter the code you received to sign in.",
|
||||||
|
"code": "Code",
|
||||||
|
"invalid_redirect_url": "Invalid redirect URL",
|
||||||
|
"audit_log": "Audit Log",
|
||||||
|
"users": "Users",
|
||||||
|
"user_groups": "User Groups",
|
||||||
|
"oidc_clients": "OIDC Clients",
|
||||||
|
"api_keys": "API Keys",
|
||||||
|
"application_configuration": "Application Configuration",
|
||||||
|
"settings": "Settings",
|
||||||
|
"update_pocket_id": "Update Pocket ID",
|
||||||
|
"powered_by": "Powered by",
|
||||||
|
"see_your_recent_account_activities": "See your account activities within the configured retention period.",
|
||||||
|
"time": "Time",
|
||||||
|
"event": "Event",
|
||||||
|
"approximate_location": "Approximate Location",
|
||||||
|
"ip_address": "IP adresse",
|
||||||
|
"device": "Enhet",
|
||||||
|
"client": "Klient",
|
||||||
|
"unknown": "Ukjent",
|
||||||
|
"account_details_updated_successfully": "Brukerdetaljer oppdatert",
|
||||||
|
"profile_picture_updated_successfully": "Profilbildet er oppdatert. Det kan ta noen minutter før det vises overalt.",
|
||||||
|
"account_settings": "Kontoinnstillinger",
|
||||||
|
"passkey_missing": "Finner ingen passnøkkel",
|
||||||
|
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Please add a passkey to prevent losing access to your account.",
|
||||||
|
"single_passkey_configured": "Revoker API nøkkel",
|
||||||
|
"it_is_recommended_to_add_more_than_one_passkey": "Det er anbefalt å legge til mer enn én passnøkkel for å forhindre at du mister tilgang til kontoen din.",
|
||||||
|
"account_details": "Kontodetaljer",
|
||||||
|
"passkeys": "Passnøkler",
|
||||||
|
"manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Manage your passkeys that you can use to authenticate yourself.",
|
||||||
|
"add_passkey": "Legg til passnøkkel",
|
||||||
|
"create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Create a one-time login code to sign in from a different device without a passkey.",
|
||||||
|
"create": "Opprett",
|
||||||
|
"first_name": "Fornavn",
|
||||||
|
"last_name": "Etternavn",
|
||||||
|
"username": "Brukernavn",
|
||||||
|
"save": "Lagre",
|
||||||
|
"username_can_only_contain": "Username can only contain lowercase letters, numbers, underscores, dots, hyphens, and '@' symbols",
|
||||||
|
"username_must_start_with": "Username must start with an alphanumeric character",
|
||||||
|
"username_must_end_with": "Username must end with an alphanumeric character",
|
||||||
|
"sign_in_using_the_following_code_the_code_will_expire_in_minutes": "Sign in using the following code. The code will expire in 15 minutes.",
|
||||||
|
"or_visit": "or visit",
|
||||||
|
"added_on": "Lagt til på",
|
||||||
|
"rename": "Endre navn",
|
||||||
|
"delete": "Slett",
|
||||||
|
"are_you_sure_you_want_to_delete_this_passkey": "Er du sikker på at du vil slette denne passnøkkelen?",
|
||||||
|
"passkey_deleted_successfully": "Passnøkkelen er slettet",
|
||||||
|
"delete_passkey_name": "Slett {passkeyName}",
|
||||||
|
"passkey_name_updated_successfully": "Kallenavnet til passnøkkelen er oppdatert",
|
||||||
|
"name_passkey": "Navngi passnøkkel",
|
||||||
|
"name_your_passkey_to_easily_identify_it_later": "Gi et navn til passnøkkelen så den blir lettere å identifisere senere.",
|
||||||
|
"create_api_key": "Opprett en API nøkkel",
|
||||||
|
"add_a_new_api_key_for_programmatic_access": "Add a new API key for programmatic access to the <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
|
||||||
|
"add_api_key": "Legg til API nøkkel",
|
||||||
|
"manage_api_keys": "Administrer API nøkler",
|
||||||
|
"api_key_created": "API Key Created",
|
||||||
|
"for_security_reasons_this_key_will_only_be_shown_once": "For security reasons, this key will only be shown once. Please store it securely.",
|
||||||
|
"description": "Beskrivelse",
|
||||||
|
"api_key": "API nøkkel",
|
||||||
|
"close": "Lukk",
|
||||||
|
"name_to_identify_this_api_key": "Name to identify this API key.",
|
||||||
|
"expires_at": "Expires At",
|
||||||
|
"when_this_api_key_will_expire": "When this API key will expire.",
|
||||||
|
"optional_description_to_help_identify_this_keys_purpose": "Optional description to help identify this key's purpose.",
|
||||||
|
"expiration_date_must_be_in_the_future": "Expiration date must be in the future",
|
||||||
|
"revoke_api_key": "Revoker API nøkkel",
|
||||||
|
"never": "Never",
|
||||||
|
"revoke": "Revoke",
|
||||||
|
"api_key_revoked_successfully": "API key revoked successfully",
|
||||||
|
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Are you sure you want to revoke the API key \"{apiKeyName}\"? This will break any integrations using this key.",
|
||||||
|
"last_used": "Last Used",
|
||||||
|
"actions": "Actions",
|
||||||
|
"images_updated_successfully": "Images updated successfully. It may take a few minutes to update.",
|
||||||
|
"general": "General",
|
||||||
|
"configure_smtp_to_send_emails": "Enable email notifications to alert users when a login is detected from a new device or location.",
|
||||||
|
"ldap": "LDAP",
|
||||||
|
"configure_ldap_settings_to_sync_users_and_groups_from_an_ldap_server": "Configure LDAP settings to sync users and groups from an LDAP server.",
|
||||||
|
"images": "Images",
|
||||||
|
"update": "Update",
|
||||||
|
"email_configuration_updated_successfully": "Email configuration updated successfully",
|
||||||
|
"save_changes_question": "Save changes?",
|
||||||
|
"you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "You have to save the changes before sending a test email. Do you want to save now?",
|
||||||
|
"save_and_send": "Save and send",
|
||||||
|
"test_email_sent_successfully": "Test email sent successfully to your email address.",
|
||||||
|
"failed_to_send_test_email": "Failed to send test email. Check the server logs for more information.",
|
||||||
|
"smtp_configuration": "SMTP Configuration",
|
||||||
|
"smtp_host": "SMTP Host",
|
||||||
|
"smtp_port": "SMTP Port",
|
||||||
|
"smtp_user": "SMTP User",
|
||||||
|
"smtp_password": "SMTP Password",
|
||||||
|
"smtp_from": "SMTP From",
|
||||||
|
"smtp_tls_option": "SMTP TLS Option",
|
||||||
|
"email_tls_option": "Email TLS Option",
|
||||||
|
"skip_certificate_verification": "Skip Certificate Verification",
|
||||||
|
"this_can_be_useful_for_selfsigned_certificates": "This can be useful for self-signed certificates.",
|
||||||
|
"enabled_emails": "Enabled Emails",
|
||||||
|
"email_login_notification": "Email Login Notification",
|
||||||
|
"send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Send an email to the user when they log in from a new device.",
|
||||||
|
"emai_login_code_requested_by_user": "Email Login Code Requested by User",
|
||||||
|
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Allows users to bypass passkeys by requesting a login code sent to their email. This significantly reduces security as anyone with access to the user's email can gain entry.",
|
||||||
|
"email_login_code_from_admin": "Email Login Code from Admin",
|
||||||
|
"allows_an_admin_to_send_a_login_code_to_the_user": "Allows an admin to send a login code to the user via email.",
|
||||||
|
"send_test_email": "Send test E-post",
|
||||||
|
"application_configuration_updated_successfully": "Application configuration updated successfully",
|
||||||
|
"application_name": "Applikasjonsnavn",
|
||||||
|
"session_duration": "Varighet på sesjon",
|
||||||
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Varighet på sesjon i minutter før brukeren må logge inn på nytt.",
|
||||||
|
"enable_self_account_editing": "Enable Self-Account Editing",
|
||||||
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Whether the users should be able to edit their own account details.",
|
||||||
|
"ldap_configuration_updated_successfully": "LDAP konfigurasjon oppdatert",
|
||||||
|
"ldap_disabled_successfully": "LDAP er slått av",
|
||||||
|
"ldap_sync_finished": "LDAP synkronisert",
|
||||||
|
"client_configuration": "Klient konfigurasjon",
|
||||||
|
"ldap_url": "LDAP URL",
|
||||||
|
"ldap_bind_dn": "LDAP Bind DN",
|
||||||
|
"ldap_bind_password": "LDAP Bind Password",
|
||||||
|
"ldap_base_dn": "LDAP Base DN",
|
||||||
|
"user_search_filter": "User Search Filter",
|
||||||
|
"the_search_filter_to_use_to_search_or_sync_users": "The Search filter to use to search/sync users.",
|
||||||
|
"groups_search_filter": "Groups Search Filter",
|
||||||
|
"the_search_filter_to_use_to_search_or_sync_groups": "The Search filter to use to search/sync groups.",
|
||||||
|
"attribute_mapping": "Attribute Mapping",
|
||||||
|
"user_unique_identifier_attribute": "User Unique Identifier Attribute",
|
||||||
|
"the_value_of_this_attribute_should_never_change": "The value of this attribute should never change.",
|
||||||
|
"username_attribute": "Username Attribute",
|
||||||
|
"user_mail_attribute": "User Mail Attribute",
|
||||||
|
"user_first_name_attribute": "User First Name Attribute",
|
||||||
|
"user_last_name_attribute": "User Last Name Attribute",
|
||||||
|
"user_profile_picture_attribute": "User Profile Picture Attribute",
|
||||||
|
"the_value_of_this_attribute_can_either_be_a_url_binary_or_base64_encoded_image": "The value of this attribute can either be a URL, a binary or a base64 encoded image.",
|
||||||
|
"group_members_attribute": "Group Members Attribute",
|
||||||
|
"the_attribute_to_use_for_querying_members_of_a_group": "The attribute to use for querying members of a group.",
|
||||||
|
"group_unique_identifier_attribute": "Group Unique Identifier Attribute",
|
||||||
|
"group_rdn_attribute": "Group RDN Attribute (in DN)",
|
||||||
|
"admin_group_name": "Admin Group Name",
|
||||||
|
"members_of_this_group_will_have_admin_privileges_in_pocketid": "Members of this group will have Admin Privileges in Pocket ID.",
|
||||||
|
"disable": "Slå av",
|
||||||
|
"sync_now": "Synkroniser nå",
|
||||||
|
"enable": "Slå på",
|
||||||
|
"user_created_successfully": "Bruker er opprettet",
|
||||||
|
"create_user": "Opprett bruker",
|
||||||
|
"add_a_new_user_to_appname": "Legg til bruker i {appName}",
|
||||||
|
"add_user": "Legg til bruker",
|
||||||
|
"manage_users": "Administrer brukere",
|
||||||
|
"admin_privileges": "Admin Privileges",
|
||||||
|
"admins_have_full_access_to_the_admin_panel": "Administratorene har full tilgang til administratorpanelet.",
|
||||||
|
"delete_firstname_lastname": "Slett {firstName} {lastName}",
|
||||||
|
"are_you_sure_you_want_to_delete_this_user": "Er du sikker på at du vil slette denne brukeren?",
|
||||||
|
"user_deleted_successfully": "Bruker slettet",
|
||||||
|
"role": "Rolle",
|
||||||
|
"source": "Source",
|
||||||
|
"admin": "Admin",
|
||||||
|
"user": "User",
|
||||||
|
"local": "Local",
|
||||||
|
"toggle_menu": "Toggle menu",
|
||||||
|
"edit": "Edit",
|
||||||
|
"user_groups_updated_successfully": "User groups updated successfully",
|
||||||
|
"user_updated_successfully": "User updated successfully",
|
||||||
|
"custom_claims_updated_successfully": "Custom claims updated successfully",
|
||||||
|
"back": "Back",
|
||||||
|
"user_details_firstname_lastname": "User Details {firstName} {lastName}",
|
||||||
|
"manage_which_groups_this_user_belongs_to": "Manage which groups this user belongs to.",
|
||||||
|
"custom_claims": "Custom Claims",
|
||||||
|
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested.",
|
||||||
|
"user_group_created_successfully": "User group created successfully",
|
||||||
|
"create_user_group": "Create User Group",
|
||||||
|
"create_a_new_group_that_can_be_assigned_to_users": "Create a new group that can be assigned to users.",
|
||||||
|
"add_group": "Add Group",
|
||||||
|
"manage_user_groups": "Manage User Groups",
|
||||||
|
"friendly_name": "Friendly Name",
|
||||||
|
"name_that_will_be_displayed_in_the_ui": "Name that will be displayed in the UI",
|
||||||
|
"name_that_will_be_in_the_groups_claim": "Name that will be in the \"groups\" claim",
|
||||||
|
"delete_name": "Slett {name}",
|
||||||
|
"are_you_sure_you_want_to_delete_this_user_group": "Er du sikker på at du vil slette denne brukergruppen?",
|
||||||
|
"user_group_deleted_successfully": "User group deleted successfully",
|
||||||
|
"user_count": "Antall brukere",
|
||||||
|
"user_group_updated_successfully": "User group updated successfully",
|
||||||
|
"users_updated_successfully": "Brukere er oppdatert",
|
||||||
|
"user_group_details_name": "User Group Details {name}",
|
||||||
|
"assign_users_to_this_group": "Legg brukerne til i denne gruppen.",
|
||||||
|
"custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user_prioritized": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested. Custom claims defined on the user will be prioritized if there are conflicts.",
|
||||||
|
"oidc_client_created_successfully": "OIDC klient er opprettet",
|
||||||
|
"create_oidc_client": "Opprett OIDC klient",
|
||||||
|
"add_a_new_oidc_client_to_appname": "Add a new OIDC client to {appName}.",
|
||||||
|
"add_oidc_client": "Add OIDC Client",
|
||||||
|
"manage_oidc_clients": "Manage OIDC Clients",
|
||||||
|
"one_time_link": "Engangslenke",
|
||||||
|
"use_this_link_to_sign_in_once": "Use this link to sign in once. This is needed for users who haven't added a passkey yet or have lost it.",
|
||||||
|
"add": "Legg til",
|
||||||
|
"callback_urls": "Callback URLs",
|
||||||
|
"logout_callback_urls": "Logout Callback URLs",
|
||||||
|
"public_client": "Public Client",
|
||||||
|
"public_clients_description": "Public clients do not have a client secret. They are designed for mobile, web, and native applications where secrets cannot be securely stored.",
|
||||||
|
"pkce": "PKCE",
|
||||||
|
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange is a security feature to prevent CSRF and authorization code interception attacks.",
|
||||||
|
"requires_reauthentication": "Requires Re-Authentication",
|
||||||
|
"requires_users_to_authenticate_again_on_each_authorization": "Requires users to authenticate again on each authorization, even if already signed in",
|
||||||
|
"name_logo": "{name} logo",
|
||||||
|
"change_logo": "Bytt logo",
|
||||||
|
"upload_logo": "Last opp logo",
|
||||||
|
"remove_logo": "Fjern logo",
|
||||||
|
"are_you_sure_you_want_to_delete_this_oidc_client": "Are you sure you want to delete this OIDC client?",
|
||||||
|
"oidc_client_deleted_successfully": "OIDC client deleted successfully",
|
||||||
|
"authorization_url": "Authorization URL",
|
||||||
|
"oidc_discovery_url": "OIDC Discovery URL",
|
||||||
|
"token_url": "Token URL",
|
||||||
|
"userinfo_url": "Userinfo URL",
|
||||||
|
"logout_url": "Logout URL",
|
||||||
|
"certificate_url": "Certificate URL",
|
||||||
|
"enabled": "Aktivert",
|
||||||
|
"disabled": "Deaktivert",
|
||||||
|
"oidc_client_updated_successfully": "OIDC client updated successfully",
|
||||||
|
"create_new_client_secret": "Create new client secret",
|
||||||
|
"are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.",
|
||||||
|
"generate": "Generer",
|
||||||
|
"new_client_secret_created_successfully": "New client secret created successfully",
|
||||||
|
"oidc_client_name": "OIDC klient {name}",
|
||||||
|
"client_id": "Client ID",
|
||||||
|
"client_secret": "Client secret",
|
||||||
|
"show_more_details": "Vis mer",
|
||||||
|
"allowed_user_groups": "Tillatte brukergrupper",
|
||||||
|
"allowed_user_groups_description": "Velg brukergruppene som skal kunne logge inn med denne klienten.",
|
||||||
|
"allowed_user_groups_status_unrestricted_description": "No user group restrictions are applied. Any user can sign in to this client.",
|
||||||
|
"unrestrict": "Unrestrict",
|
||||||
|
"restrict": "Restrict",
|
||||||
|
"user_groups_restriction_updated_successfully": "User groups restriction updated successfully",
|
||||||
|
"allowed_user_groups_updated_successfully": "Allowed user groups updated successfully",
|
||||||
|
"favicon": "Favicon",
|
||||||
|
"light_mode_logo": "Light Mode Logo",
|
||||||
|
"dark_mode_logo": "Dark Mode Logo",
|
||||||
|
"email_logo": "Email Logo",
|
||||||
|
"background_image": "Background Image",
|
||||||
|
"language": "Language",
|
||||||
|
"reset_profile_picture_question": "Reset profile picture?",
|
||||||
|
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "This will remove the uploaded image and reset the profile picture to default. Do you want to continue?",
|
||||||
|
"reset": "Reset",
|
||||||
|
"reset_to_default": "Reset to default",
|
||||||
|
"profile_picture_has_been_reset": "Profile picture has been reset. It may take a few minutes to update.",
|
||||||
|
"select_the_language_you_want_to_use": "Select the language you want to use. Please note that some text may be automatically translated and could be inaccurate.",
|
||||||
|
"contribute_to_translation": "If you find an issue you're welcome to contribute to the translation on <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
|
||||||
|
"personal": "Personal",
|
||||||
|
"global": "Global",
|
||||||
|
"all_users": "All Users",
|
||||||
|
"all_events": "All Events",
|
||||||
|
"all_clients": "All Clients",
|
||||||
|
"all_locations": "All Locations",
|
||||||
|
"global_audit_log": "Global Audit Log",
|
||||||
|
"see_all_recent_account_activities": "View the account activities of all users during the set retention period.",
|
||||||
|
"token_sign_in": "Token Sign In",
|
||||||
|
"client_authorization": "Client Authorization",
|
||||||
|
"new_client_authorization": "New Client Authorization",
|
||||||
|
"device_code_authorization": "Device Code Authorization",
|
||||||
|
"new_device_code_authorization": "New Device Code Authorization",
|
||||||
|
"passkey_added": "Passnøkkel lagt til",
|
||||||
|
"passkey_removed": "Passnøkkel fjernet",
|
||||||
|
"disable_animations": "Deaktiver animasjoner",
|
||||||
|
"turn_off_ui_animations": "Slå av animasjoner i brukergrensesnittet.",
|
||||||
|
"user_disabled": "Konto deaktivert",
|
||||||
|
"disabled_users_cannot_log_in_or_use_services": "Deaktiverte brukere kan ikke logge inn eller bruke tjenester.",
|
||||||
|
"user_disabled_successfully": "Bruker har blitt deaktivert.",
|
||||||
|
"user_enabled_successfully": "Bruker har blitt aktivert.",
|
||||||
|
"status": "Status",
|
||||||
|
"disable_firstname_lastname": "Deaktiver {firstName} {lastName}",
|
||||||
|
"are_you_sure_you_want_to_disable_this_user": "Are you sure you want to disable this user? They will not be able to log in or access any services.",
|
||||||
|
"ldap_soft_delete_users": "Keep disabled users from LDAP.",
|
||||||
|
"ldap_soft_delete_users_description": "When enabled, users removed from LDAP will be disabled rather than deleted from the system.",
|
||||||
|
"login_code_email_success": "The login code has been sent to the user.",
|
||||||
|
"send_email": "Send E-post",
|
||||||
|
"show_code": "Vis kode",
|
||||||
|
"callback_url_description": "URL(s) provided by your client. Will be automatically added if left blank. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
|
||||||
|
"logout_callback_url_description": "URL(s) provided by your client for logout. <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>Wildcards</link> are supported.",
|
||||||
|
"api_key_expiration": "API Key Expiration",
|
||||||
|
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Send an email to the user when their API key is about to expire.",
|
||||||
|
"authorize_device": "Authorize Device",
|
||||||
|
"the_device_has_been_authorized": "The device has been authorized.",
|
||||||
|
"enter_code_displayed_in_previous_step": "Enter the code that was displayed in the previous step.",
|
||||||
|
"authorize": "Authorize",
|
||||||
|
"federated_client_credentials": "Federated Client Credentials",
|
||||||
|
"federated_client_credentials_description": "Using federated client credentials, you can authenticate OIDC clients using JWT tokens issued by third-party authorities.",
|
||||||
|
"add_federated_client_credential": "Add Federated Client Credential",
|
||||||
|
"add_another_federated_client_credential": "Add another federated client credential",
|
||||||
|
"oidc_allowed_group_count": "Allowed Group Count",
|
||||||
|
"unrestricted": "Unrestricted",
|
||||||
|
"show_advanced_options": "Show Advanced Options",
|
||||||
|
"hide_advanced_options": "Hide Advanced Options",
|
||||||
|
"oidc_data_preview": "OIDC Data Preview",
|
||||||
|
"preview_the_oidc_data_that_would_be_sent_for_different_users": "Preview the OIDC data that would be sent for different users",
|
||||||
|
"id_token": "ID Token",
|
||||||
|
"access_token": "Access Token",
|
||||||
|
"userinfo": "Brukerinformasjon",
|
||||||
|
"id_token_payload": "ID Token Payload",
|
||||||
|
"access_token_payload": "Access Token Payload",
|
||||||
|
"userinfo_endpoint_response": "Userinfo Endpoint Response",
|
||||||
|
"copy": "Copy",
|
||||||
|
"no_preview_data_available": "No preview data available",
|
||||||
|
"copy_all": "Copy All",
|
||||||
|
"preview": "Preview",
|
||||||
|
"preview_for_user": "Preview for {name}",
|
||||||
|
"preview_the_oidc_data_that_would_be_sent_for_this_user": "Preview the OIDC data that would be sent for this user",
|
||||||
|
"show": "Show",
|
||||||
|
"select_an_option": "Select an option",
|
||||||
|
"select_user": "Select User",
|
||||||
|
"error": "Error",
|
||||||
|
"select_an_accent_color_to_customize_the_appearance_of_pocket_id": "Select an accent color to customize the appearance of Pocket ID.",
|
||||||
|
"accent_color": "Accent Color",
|
||||||
|
"custom_accent_color": "Custom Accent Color",
|
||||||
|
"custom_accent_color_description": "Enter a custom color using valid CSS color formats (e.g., hex, rgb, hsl).",
|
||||||
|
"color_value": "Color Value",
|
||||||
|
"apply": "Apply",
|
||||||
|
"signup_token": "Signup Token",
|
||||||
|
"create_a_signup_token_to_allow_new_user_registration": "Create a signup token to allow new user registration.",
|
||||||
|
"usage_limit": "Bruksgrense",
|
||||||
|
"number_of_times_token_can_be_used": "Number of times the signup token can be used.",
|
||||||
|
"expires": "Expires",
|
||||||
|
"signup": "Registrer",
|
||||||
|
"user_creation": "User Creation",
|
||||||
|
"configure_user_creation": "Manage user creation settings, including signup methods and default permissions for new users.",
|
||||||
|
"user_creation_groups_description": "Assign these groups automatically to new users upon signup.",
|
||||||
|
"user_creation_claims_description": "Assign these custom claims automatically to new users upon signup.",
|
||||||
|
"user_creation_updated_successfully": "User creation settings updated successfully.",
|
||||||
|
"signup_disabled_description": "User signups are completely disabled. Only administrators can create new user accounts.",
|
||||||
|
"signup_requires_valid_token": "A valid signup token is required to create an account",
|
||||||
|
"validating_signup_token": "Validating signup token",
|
||||||
|
"go_to_login": "Gå til innlogging",
|
||||||
|
"signup_to_appname": "Registrer for {appName}",
|
||||||
|
"create_your_account_to_get_started": "Opprett kontoen din for å komme i gang.",
|
||||||
|
"initial_account_creation_description": "Please create your account to get started. You will be able to set up a passkey later.",
|
||||||
|
"setup_your_passkey": "Opprett din passnøkkel",
|
||||||
|
"create_a_passkey_to_securely_access_your_account": "Create a passkey to securely access your account. This will be your primary way to sign in.",
|
||||||
|
"skip_for_now": "Hopp over for denne gang",
|
||||||
|
"account_created": "Konto opprettet",
|
||||||
|
"enable_user_signups": "Enable User Signups",
|
||||||
|
"enable_user_signups_description": "Decide how users can sign up for new accounts in Pocket ID.",
|
||||||
|
"user_signups_are_disabled": "User signups are currently disabled",
|
||||||
|
"create_signup_token": "Create Signup Token",
|
||||||
|
"view_active_signup_tokens": "View Active Signup Tokens",
|
||||||
|
"manage_signup_tokens": "Manage Signup Tokens",
|
||||||
|
"view_and_manage_active_signup_tokens": "View and manage active signup tokens.",
|
||||||
|
"signup_token_deleted_successfully": "Signup token deleted successfully.",
|
||||||
|
"expired": "Expired",
|
||||||
|
"used_up": "Used Up",
|
||||||
|
"active": "Active",
|
||||||
|
"usage": "Usage",
|
||||||
|
"created": "Created",
|
||||||
|
"token": "Token",
|
||||||
|
"loading": "Loading",
|
||||||
|
"delete_signup_token": "Delete Signup Token",
|
||||||
|
"are_you_sure_you_want_to_delete_this_signup_token": "Are you sure you want to delete this signup token? This action cannot be undone.",
|
||||||
|
"signup_with_token": "Signup with token",
|
||||||
|
"signup_with_token_description": "Users can only sign up using a valid signup token created by an administrator.",
|
||||||
|
"signup_open": "Open Signup",
|
||||||
|
"signup_open_description": "Anyone can create a new account without restrictions.",
|
||||||
|
"of": "of",
|
||||||
|
"skip_passkey_setup": "Skip Passkey Setup",
|
||||||
|
"skip_passkey_setup_description": "It's highly recommended to set up a passkey because without one, you will be locked out of your account as soon as the session expires.",
|
||||||
|
"my_apps": "My Apps",
|
||||||
|
"no_apps_available": "No apps available",
|
||||||
|
"contact_your_administrator_for_app_access": "Contact your administrator to get access to applications.",
|
||||||
|
"launch": "Launch",
|
||||||
|
"client_launch_url": "Client Launch URL",
|
||||||
|
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
|
||||||
|
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
|
||||||
|
"revoke_access": "Revoke Access",
|
||||||
|
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
|
||||||
|
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
|
||||||
|
"last_signed_in_ago": "Last signed in {time} ago",
|
||||||
|
"invalid_client_id": "Client ID can only contain letters, numbers, underscores, and hyphens",
|
||||||
|
"custom_client_id_description": "Set a custom client ID if this is required by your application. Otherwise, leave it blank to generate a random one.",
|
||||||
|
"generated": "Generated",
|
||||||
|
"administration": "Administration",
|
||||||
|
"group_rdn_attribute_description": "The attribute used in the groups distinguished name (DN).",
|
||||||
|
"display_name_attribute": "Display Name Attribute",
|
||||||
|
"display_name": "Display Name",
|
||||||
|
"configure_application_images": "Configure Application Images",
|
||||||
|
"ui_config_disabled_info_title": "UI Configuration Disabled",
|
||||||
|
"ui_config_disabled_info_description": "The UI configuration is disabled because the application configuration settings are managed through environment variables. Some settings may not be editable.",
|
||||||
|
"logo_from_url_description": "Paste a direct image URL (svg, png, webp). Find icons at <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> or <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
|
||||||
|
"invalid_url": "Invalid URL",
|
||||||
|
"require_user_email": "Require Email Address",
|
||||||
|
"require_user_email_description": "Requires users to have an email address. If disabled, the users without an email address won't be able to use features that require an email address.",
|
||||||
|
"view": "View",
|
||||||
|
"toggle_columns": "Toggle columns",
|
||||||
|
"locale": "Locale",
|
||||||
|
"ldap_id": "LDAP ID",
|
||||||
|
"reauthentication": "Re-authentication",
|
||||||
|
"clear_filters": "Clear Filters",
|
||||||
|
"default_profile_picture": "Default Profile Picture",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark",
|
||||||
|
"system": "System",
|
||||||
|
"signup_token_user_groups_description": "Automatically assign these groups to users who sign up using this token.",
|
||||||
|
"allowed_oidc_clients": "Allowed OIDC Clients",
|
||||||
|
"allowed_oidc_clients_description": "Select the OIDC clients that members of this user group are allowed to sign in to.",
|
||||||
|
"unrestrict_oidc_client": "Unrestrict {clientName}",
|
||||||
|
"confirm_unrestrict_oidc_client_description": "Are you sure you want to unrestrict the OIDC client <b>{clientName}</b>? This will remove all group assignments for this client and any user will be able to sign in.",
|
||||||
|
"allowed_oidc_clients_updated_successfully": "Allowed OIDC clients updated successfully",
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
|
"restricted": "Restricted",
|
||||||
|
"scim_provisioning": "SCIM Provisioning",
|
||||||
|
"scim_provisioning_description": "SCIM provisioning allows you to automatically provision and deprovision users and groups from your OIDC client. Learn more in the <link href='https://pocket-id.org/docs/configuration/scim'>docs</link>.",
|
||||||
|
"scim_endpoint": "SCIM Endpoint",
|
||||||
|
"scim_token": "SCIM Token",
|
||||||
|
"last_successful_sync_at": "Last successful sync: {time}",
|
||||||
|
"scim_configuration_updated_successfully": "SCIM configuration updated successfully.",
|
||||||
|
"scim_enabled_successfully": "SCIM enabled successfully.",
|
||||||
|
"scim_disabled_successfully": "SCIM disabled successfully.",
|
||||||
|
"disable_scim_provisioning": "Disable SCIM Provisioning",
|
||||||
|
"disable_scim_provisioning_confirm_description": "Are you sure you want to disable SCIM provisioning for <b>{clientName}</b>? This will stop all automatic user and group provisioning and deprovisioning.",
|
||||||
|
"scim_sync_failed": "SCIM sync failed. Check the server logs for more information.",
|
||||||
|
"scim_sync_successful": "The SCIM sync has been completed successfully.",
|
||||||
|
"save_and_sync": "Save and Sync",
|
||||||
|
"scim_save_changes_description": "You have to save the changes before starting a SCIM sync. Do you want to save now?",
|
||||||
|
"scopes": "Scopes",
|
||||||
|
"issuer_url": "Issuer URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Required when any SMTP setting is provided",
|
||||||
|
"smtp_field_required_when_email_enabled": "Required when email notifications are enabled",
|
||||||
|
"renew": "Renew",
|
||||||
|
"renew_api_key": "Renew API Key",
|
||||||
|
"renew_api_key_description": "Renewing the API key will generate a new key. Make sure to update any integrations using this key.",
|
||||||
|
"api_key_renewed": "API key renewed",
|
||||||
|
"app_config_home_page": "Home Page",
|
||||||
|
"app_config_home_page_description": "The page users are redirected to after signing in.",
|
||||||
|
"email_verification_warning": "Verify your email address",
|
||||||
|
"email_verification_warning_description": "Your email address is not verified yet. Please verify it as soon as possible.",
|
||||||
|
"email_verification": "Email Verification",
|
||||||
|
"email_verification_description": "Send a verification email to users when they sign up or change their email address.",
|
||||||
|
"email_verification_success_title": "Email Verified Successfully",
|
||||||
|
"email_verification_success_description": "Your email address has been verified successfully.",
|
||||||
|
"email_verification_error_title": "Email Verification Failed",
|
||||||
|
"mark_as_unverified": "Mark as unverified",
|
||||||
|
"mark_as_verified": "Mark as verified",
|
||||||
|
"email_verification_sent": "Verification email sent successfully.",
|
||||||
|
"emails_verified_by_default": "Emails verified by default",
|
||||||
|
"emails_verified_by_default_description": "When enabled, users' email addresses will be marked as verified by default upon signup or when their email address is changed."
|
||||||
|
}
|
||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Autoryzator nie obsługuje kluczy rezydentnych",
|
"authenticator_does_not_support_resident_keys": "Autoryzator nie obsługuje kluczy rezydentnych",
|
||||||
"passkey_was_previously_registered": "Ten klucz był już wcześniej zarejestrowany",
|
"passkey_was_previously_registered": "Ten klucz był już wcześniej zarejestrowany",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autoryzator nie obsługuje żadnego z żądanych algorytmów",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autoryzator nie obsługuje żadnego z żądanych algorytmów",
|
||||||
"authenticator_timed_out": "Czas autoryzatora upłynął",
|
"webauthn_error_invalid_rp_id": "Skonfigurowany identyfikator strony ufającej jest nieprawidłowy.",
|
||||||
|
"webauthn_error_invalid_domain": "Skonfigurowana domena jest nieprawidłowa.",
|
||||||
|
"contact_administrator_to_fix": "Skontaktuj się z administratorem, aby rozwiązać ten problem.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Operacja nie została dozwolona lub przekroczono limit czasu",
|
||||||
|
"webauthn_not_supported_by_browser": "Ta przeglądarka nie obsługuje kluczy dostępu. Proszę skorzystać z alternatywnej metody logowania.",
|
||||||
"critical_error_occurred_contact_administrator": "Wystąpił krytyczny błąd. Skontaktuj się z administratorem.",
|
"critical_error_occurred_contact_administrator": "Wystąpił krytyczny błąd. Skontaktuj się z administratorem.",
|
||||||
"sign_in_to": "Zaloguj się do {name}",
|
"sign_in_to": "Zaloguj się do {name}",
|
||||||
"client_not_found": "Nie znaleziono klienta",
|
"client_not_found": "Nie znaleziono klienta",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Czas trwania sesji w minutach, zanim użytkownik będzie musiał ponownie się zalogować.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Czas trwania sesji w minutach, zanim użytkownik będzie musiał ponownie się zalogować.",
|
||||||
"enable_self_account_editing": "Włącz edytowanie konta przez użytkownika",
|
"enable_self_account_editing": "Włącz edytowanie konta przez użytkownika",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Czy użytkownicy powinni mieć możliwość edytowania szczegółów swojego konta.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Czy użytkownicy powinni mieć możliwość edytowania szczegółów swojego konta.",
|
||||||
"emails_verified": "E-maile zweryfikowane",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Czy adres e-mail użytkownika powinien być oznaczony jako zweryfikowany dla klientów OIDC.",
|
|
||||||
"ldap_configuration_updated_successfully": "Sukces! Konfiguracja LDAP została zaktualizowana.",
|
"ldap_configuration_updated_successfully": "Sukces! Konfiguracja LDAP została zaktualizowana.",
|
||||||
"ldap_disabled_successfully": "Sukces! LDAP został wyłączony.",
|
"ldap_disabled_successfully": "Sukces! LDAP został wyłączony.",
|
||||||
"ldap_sync_finished": "Synchronizacja LDAP zakończona",
|
"ldap_sync_finished": "Synchronizacja LDAP zakończona",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Zapisz i zsynchronizuj",
|
"save_and_sync": "Zapisz i zsynchronizuj",
|
||||||
"scim_save_changes_description": "Przed rozpoczęciem synchronizacji SCIM należy zapisać zmiany. Czy chcesz zapisać teraz?",
|
"scim_save_changes_description": "Przed rozpoczęciem synchronizacji SCIM należy zapisać zmiany. Czy chcesz zapisać teraz?",
|
||||||
"scopes": "Zakresy",
|
"scopes": "Zakresy",
|
||||||
"issuer_url": "Adres URL wystawcy"
|
"issuer_url": "Adres URL wystawcy",
|
||||||
|
"smtp_field_required_when_other_provided": "Wymagane, gdy podano dowolne ustawienie SMTP",
|
||||||
|
"smtp_field_required_when_email_enabled": "Wymagane, gdy włączone są powiadomienia e-mailowe",
|
||||||
|
"renew": "Odnowić",
|
||||||
|
"renew_api_key": "Odnów klucz API",
|
||||||
|
"renew_api_key_description": "Odnowienie klucza API spowoduje wygenerowanie nowego klucza. Pamiętaj o aktualizacji wszystkich integracji korzystających z tego klucza.",
|
||||||
|
"api_key_renewed": "Klucz API odnowiony",
|
||||||
|
"app_config_home_page": "Strona główna",
|
||||||
|
"app_config_home_page_description": "Strona, do której użytkownicy są przekierowywani po zalogowaniu.",
|
||||||
|
"email_verification_warning": "Zweryfikuj swój adres e-mail",
|
||||||
|
"email_verification_warning_description": "Twój adres e-mail nie został jeszcze zweryfikowany. Prosimy o jak najszybszą weryfikację.",
|
||||||
|
"email_verification": "Weryfikacja adresu e-mail",
|
||||||
|
"email_verification_description": "Wyślijcie użytkownikom wiadomość e-mail z linkiem weryfikacyjnym po zarejestrowaniu się lub zmianie adresu e-mail.",
|
||||||
|
"email_verification_success_title": "Adres e-mail został pomyślnie zweryfikowany",
|
||||||
|
"email_verification_success_description": "Twój adres e-mail został pomyślnie zweryfikowany.",
|
||||||
|
"email_verification_error_title": "Weryfikacja adresu e-mail nie powiodła się",
|
||||||
|
"mark_as_unverified": "Oznacz jako niezweryfikowane",
|
||||||
|
"mark_as_verified": "Oznacz jako zweryfikowane",
|
||||||
|
"email_verification_sent": "Wiadomość e-mail z linkiem weryfikacyjnym została wysłana.",
|
||||||
|
"emails_verified_by_default": "E-maile weryfikowane domyślnie",
|
||||||
|
"emails_verified_by_default_description": "Po włączeniu tej opcji adresy e-mail użytkowników będą domyślnie oznaczane jako zweryfikowane podczas rejestracji lub zmiany adresu e-mail."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "O autenticador não aceita chaves residentes",
|
"authenticator_does_not_support_resident_keys": "O autenticador não aceita chaves residentes",
|
||||||
"passkey_was_previously_registered": "Esta chave de acesso já está registrada",
|
"passkey_was_previously_registered": "Esta chave de acesso já está registrada",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "O autenticador não suporta nenhum dos algoritmos solicitados",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "O autenticador não suporta nenhum dos algoritmos solicitados",
|
||||||
"authenticator_timed_out": "Tempo limite do autenticador atingido",
|
"webauthn_error_invalid_rp_id": "A identificação da parte confiável configurada não está válida.",
|
||||||
|
"webauthn_error_invalid_domain": "O domínio configurado não está certo.",
|
||||||
|
"contact_administrator_to_fix": "Fala com o administrador pra resolver esse problema.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "A operação não foi permitida ou expirou.",
|
||||||
|
"webauthn_not_supported_by_browser": "As chaves de acesso não são suportadas por este navegador. Por favor, use um método alternativo de login.",
|
||||||
"critical_error_occurred_contact_administrator": "Ocorreu um erro grave. Por favor, entre em contato com o administrador.",
|
"critical_error_occurred_contact_administrator": "Ocorreu um erro grave. Por favor, entre em contato com o administrador.",
|
||||||
"sign_in_to": "Entrar em {name}",
|
"sign_in_to": "Entrar em {name}",
|
||||||
"client_not_found": "Cliente não encontrado",
|
"client_not_found": "Cliente não encontrado",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "O tempo que dura uma sessão, em minutos, antes que o usuário precise fazer login de novo.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "O tempo que dura uma sessão, em minutos, antes que o usuário precise fazer login de novo.",
|
||||||
"enable_self_account_editing": "Ativar edição da conta pessoal",
|
"enable_self_account_editing": "Ativar edição da conta pessoal",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Se os usuários podem editar os detalhes de suas contas.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Se os usuários podem editar os detalhes de suas contas.",
|
||||||
"emails_verified": "E-mails verificados",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Se o e-mail do usuário deve ser marcado como verificado para os clientes OIDC.",
|
|
||||||
"ldap_configuration_updated_successfully": "Configuração LDAP atualizada com sucesso",
|
"ldap_configuration_updated_successfully": "Configuração LDAP atualizada com sucesso",
|
||||||
"ldap_disabled_successfully": "LDAP desativado com sucesso",
|
"ldap_disabled_successfully": "LDAP desativado com sucesso",
|
||||||
"ldap_sync_finished": "Sincronização LDAP concluída",
|
"ldap_sync_finished": "Sincronização LDAP concluída",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Salvar e sincronizar",
|
"save_and_sync": "Salvar e sincronizar",
|
||||||
"scim_save_changes_description": "Você precisa salvar as alterações antes de iniciar uma sincronização SCIM. Quer salvar agora?",
|
"scim_save_changes_description": "Você precisa salvar as alterações antes de iniciar uma sincronização SCIM. Quer salvar agora?",
|
||||||
"scopes": "Âmbitos",
|
"scopes": "Âmbitos",
|
||||||
"issuer_url": "URL do emissor"
|
"issuer_url": "URL do emissor",
|
||||||
|
"smtp_field_required_when_other_provided": "É necessário quando qualquer configuração SMTP é fornecida.",
|
||||||
|
"smtp_field_required_when_email_enabled": "É necessário quando as notificações por e-mail estão ativadas.",
|
||||||
|
"renew": "Renovar",
|
||||||
|
"renew_api_key": "Renovar chave API",
|
||||||
|
"renew_api_key_description": "Renovar a chave API vai gerar uma nova chave. Não esqueça de atualizar todas as integrações que usam essa chave.",
|
||||||
|
"api_key_renewed": "Chave API renovada",
|
||||||
|
"app_config_home_page": "Página inicial",
|
||||||
|
"app_config_home_page_description": "A página para a qual os usuários são redirecionados após fazerem login.",
|
||||||
|
"email_verification_warning": "Confirme seu endereço de e-mail",
|
||||||
|
"email_verification_warning_description": "Seu endereço de e-mail ainda não foi verificado. Por favor, verifique-o assim que possível.",
|
||||||
|
"email_verification": "Verificação de e-mail",
|
||||||
|
"email_verification_description": "Manda um e-mail de verificação pros usuários quando eles se cadastrarem ou mudarem o endereço de e-mail.",
|
||||||
|
"email_verification_success_title": "E-mail verificado com sucesso",
|
||||||
|
"email_verification_success_description": "Seu endereço de e-mail foi verificado com sucesso.",
|
||||||
|
"email_verification_error_title": "Falha na verificação do e-mail",
|
||||||
|
"mark_as_unverified": "Marcar como não verificado",
|
||||||
|
"mark_as_verified": "Marcar como verificado",
|
||||||
|
"email_verification_sent": "E-mail de verificação enviado com sucesso.",
|
||||||
|
"emails_verified_by_default": "E-mails verificados por padrão",
|
||||||
|
"emails_verified_by_default_description": "Quando ativado, os endereços de e-mail dos usuários serão marcados como verificados por padrão no momento da inscrição ou quando o endereço de e-mail for alterado."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"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_to_sign_in_without_a_passkey_once": "Создайте код входа, с которым пользователь сможет войти без ключа доступа один раз.",
|
||||||
"one_hour": "1 час",
|
"one_hour": "1 час",
|
||||||
"twelve_hours": "12 часов",
|
"twelve_hours": "12 часов",
|
||||||
"one_day": "1 день",
|
"one_day": "1 день",
|
||||||
@@ -38,15 +38,19 @@
|
|||||||
"generate_code": "Сгенерировать код",
|
"generate_code": "Сгенерировать код",
|
||||||
"name": "Имя",
|
"name": "Имя",
|
||||||
"browser_unsupported": "Браузер не поддерживается",
|
"browser_unsupported": "Браузер не поддерживается",
|
||||||
"this_browser_does_not_support_passkeys": "Этот браузер не поддерживает пасскеи. Пожалуйста, воспользуйтесь альтернативным способом входа.",
|
"this_browser_does_not_support_passkeys": "Этот браузер не поддерживает ключи доступа. Пожалуйста, воспользуйтесь альтернативным способом входа.",
|
||||||
"an_unknown_error_occurred": "Произошла неизвестная ошибка",
|
"an_unknown_error_occurred": "Произошла неизвестная ошибка",
|
||||||
"authentication_process_was_aborted": "Процесс аутентификации был прерван",
|
"authentication_process_was_aborted": "Процесс аутентификации был прерван",
|
||||||
"error_occurred_with_authenticator": "Произошла ошибка аутентификатора",
|
"error_occurred_with_authenticator": "Произошла ошибка аутентификатора",
|
||||||
"authenticator_does_not_support_discoverable_credentials": "Аутентификатор не поддерживает обнаруживаемые учетные данные",
|
"authenticator_does_not_support_discoverable_credentials": "Аутентификатор не поддерживает обнаруживаемые учетные данные",
|
||||||
"authenticator_does_not_support_resident_keys": "Аутентификатор не поддерживает резидентные ключи",
|
"authenticator_does_not_support_resident_keys": "Аутентификатор не поддерживает резидентные ключи",
|
||||||
"passkey_was_previously_registered": "Этот пасскей был ранее зарегистрирован",
|
"passkey_was_previously_registered": "Этот ключ доступа был ранее зарегистрирован",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Аутентификатор не поддерживает ни один из запрошенных алгоритмов",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Аутентификатор не поддерживает ни один из запрошенных алгоритмов",
|
||||||
"authenticator_timed_out": "Время ожидания аутентификатора истекло",
|
"webauthn_error_invalid_rp_id": "Настроенный идентификатор доверяющей стороны является недопустимым.",
|
||||||
|
"webauthn_error_invalid_domain": "Настроенный домен является недопустимым.",
|
||||||
|
"contact_administrator_to_fix": "Обратись к своему администратору, чтобы решить эту проблему.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Операция не разрешена или истекло время ожидания",
|
||||||
|
"webauthn_not_supported_by_browser": "Этот браузер не поддерживает ключи доступа. Попробуйте войти другим способом.",
|
||||||
"critical_error_occurred_contact_administrator": "Произошла критическая ошибка. Обратитесь к администратору.",
|
"critical_error_occurred_contact_administrator": "Произошла критическая ошибка. Обратитесь к администратору.",
|
||||||
"sign_in_to": "Войти в {name}",
|
"sign_in_to": "Войти в {name}",
|
||||||
"client_not_found": "Клиент не найден",
|
"client_not_found": "Клиент не найден",
|
||||||
@@ -66,13 +70,13 @@
|
|||||||
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Вы хотите выйти из {appName} с учетной записью <b>{username}</b>?",
|
"do_you_want_to_sign_out_of_pocketid_with_the_account": "Вы хотите выйти из {appName} с учетной записью <b>{username}</b>?",
|
||||||
"sign_in_to_appname": "Войти в {appName}",
|
"sign_in_to_appname": "Войти в {appName}",
|
||||||
"please_try_to_sign_in_again": "Пожалуйста, попробуйте войти снова.",
|
"please_try_to_sign_in_again": "Пожалуйста, попробуйте войти снова.",
|
||||||
"authenticate_with_passkey_to_access_account": "Авторизуйтесь с использованием пасскея для доступа к вашей учетной записи.",
|
"authenticate_with_passkey_to_access_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_do_not_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": "Войти с помощью кода входа",
|
||||||
@@ -95,7 +99,7 @@
|
|||||||
"settings": "Настройки",
|
"settings": "Настройки",
|
||||||
"update_pocket_id": "Обновите Pocket ID",
|
"update_pocket_id": "Обновите Pocket ID",
|
||||||
"powered_by": "Работает на",
|
"powered_by": "Работает на",
|
||||||
"see_your_recent_account_activities": "Проверь, что происходит с твоей учетной записью в течение того времени, которое ты установил.",
|
"see_your_recent_account_activities": "Смотрите действия вашей учетной записи в установленный период хранения.",
|
||||||
"time": "Время",
|
"time": "Время",
|
||||||
"event": "Событие",
|
"event": "Событие",
|
||||||
"approximate_location": "Примерное местоположение",
|
"approximate_location": "Примерное местоположение",
|
||||||
@@ -106,15 +110,15 @@
|
|||||||
"account_details_updated_successfully": "Данные учетной записи успешно обновлены",
|
"account_details_updated_successfully": "Данные учетной записи успешно обновлены",
|
||||||
"profile_picture_updated_successfully": "Изображение профиля успешно обновлено. Обновление может занять несколько минут.",
|
"profile_picture_updated_successfully": "Изображение профиля успешно обновлено. Обновление может занять несколько минут.",
|
||||||
"account_settings": "Настройки учетной записи",
|
"account_settings": "Настройки учетной записи",
|
||||||
"passkey_missing": "Пасскей отсутствует",
|
"passkey_missing": "Ключ доступа отсутствует",
|
||||||
"please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Пожалуйста, добавьте пасскей, чтобы избежать утери доступа к вашей учетной записи.",
|
"please_provide_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": "Рекомендуется добавить более одного ключа доступа, чтобы не потерять доступ к вашей учетной записи.",
|
||||||
"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": "Фамилия",
|
||||||
@@ -128,12 +132,12 @@
|
|||||||
"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": "Удалить {passkeyName}",
|
"delete_passkey_name": "Удалить {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": "Создать ключ API",
|
"create_api_key": "Создать ключ API",
|
||||||
"add_a_new_api_key_for_programmatic_access": "Добавить новый ключ API для программного доступа к <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
|
"add_a_new_api_key_for_programmatic_access": "Добавить новый ключ API для программного доступа к <link href='https://pocket-id.org/docs/api'>Pocket ID API</link>.",
|
||||||
"add_api_key": "Добавить ключ API",
|
"add_api_key": "Добавить ключ API",
|
||||||
@@ -182,7 +186,7 @@
|
|||||||
"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": "Код входа по электронной почте, запрошенный пользователем",
|
"emai_login_code_requested_by_user": "Код входа по электронной почте, запрошенный пользователем",
|
||||||
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Позволяет пользователям обходить вход через пасскей, запросив код входа, отправляемый на их электронную почту. Это значительно снижает безопасность так как любой человек, имеющий доступ к электронной почте пользователя, может получить доступ.",
|
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Позволяет пользователям обойти ключи доступа, запросив код входа, отправляемый на их электронную почту. Это значительно снижает безопасность так как любой человек, имеющий доступ к электронной почте пользователя, сможет получить доступ.",
|
||||||
"email_login_code_from_admin": "Код входа по электронной почте от администратора",
|
"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": "Позволяет администратору отправлять код входа пользователю по электронной почте.",
|
||||||
"send_test_email": "Отправить тестовое письмо",
|
"send_test_email": "Отправить тестовое письмо",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"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": "Должны ли пользователи иметь возможность редактировать данные своей учетной записи.",
|
||||||
"emails_verified": "Адреса электронной почты подтверждены",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Должен ли адрес электронной почты пользователя быть отмечен как проверенный для OIDC клиентов.",
|
|
||||||
"ldap_configuration_updated_successfully": "Конфигурация LDAP успешно обновлена",
|
"ldap_configuration_updated_successfully": "Конфигурация LDAP успешно обновлена",
|
||||||
"ldap_disabled_successfully": "LDAP успешно отключен",
|
"ldap_disabled_successfully": "LDAP успешно отключен",
|
||||||
"ldap_sync_finished": "Синхронизация с LDAP завершена",
|
"ldap_sync_finished": "Синхронизация с LDAP завершена",
|
||||||
@@ -272,7 +274,7 @@
|
|||||||
"add_oidc_client": "Добавить OIDC клиент",
|
"add_oidc_client": "Добавить OIDC клиент",
|
||||||
"manage_oidc_clients": "Управление OIDC клиентами",
|
"manage_oidc_clients": "Управление OIDC клиентами",
|
||||||
"one_time_link": "Одноразовая ссылка",
|
"one_time_link": "Одноразовая ссылка",
|
||||||
"use_this_link_to_sign_in_once": "Используйте эту ссылку, чтобы войти единожды. Это необходимо для пользователей, которые ещё не добавили пасскей или потеряли его.",
|
"use_this_link_to_sign_in_once": "Используйте эту ссылку, чтобы войти один раз. Это необходимо для пользователей, которые ещё не добавили ключ доступа или потеряли его.",
|
||||||
"add": "Добавить",
|
"add": "Добавить",
|
||||||
"callback_urls": "URL-адреса обратного вызова",
|
"callback_urls": "URL-адреса обратного вызова",
|
||||||
"logout_callback_urls": "URL-адреса обратного вызова при выходе",
|
"logout_callback_urls": "URL-адреса обратного вызова при выходе",
|
||||||
@@ -306,16 +308,16 @@
|
|||||||
"client_secret": "Секрет клиента",
|
"client_secret": "Секрет клиента",
|
||||||
"show_more_details": "Показать больше деталей",
|
"show_more_details": "Показать больше деталей",
|
||||||
"allowed_user_groups": "Разрешенные группы пользователей",
|
"allowed_user_groups": "Разрешенные группы пользователей",
|
||||||
"allowed_user_groups_description": "Выбери группы пользователей, члены которых могут входить в этот клиент.",
|
"allowed_user_groups_description": "Выберите группы пользователей, члены которых могут входить в этот клиент.",
|
||||||
"allowed_user_groups_status_unrestricted_description": "Никаких ограничений по группам пользователей нет. Любой может зайти в этот клиент.",
|
"allowed_user_groups_status_unrestricted_description": "Никаких ограничений по группам пользователей нет. Любой может зайти в этот клиент.",
|
||||||
"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": "Логотип E-Mail",
|
||||||
"background_image": "Фоновое изображение",
|
"background_image": "Фоновое изображение",
|
||||||
"language": "Язык",
|
"language": "Язык",
|
||||||
"reset_profile_picture_question": "Сбросить изображение профиля?",
|
"reset_profile_picture_question": "Сбросить изображение профиля?",
|
||||||
@@ -332,14 +334,14 @@
|
|||||||
"all_clients": "Все клиенты",
|
"all_clients": "Все клиенты",
|
||||||
"all_locations": "Все местоположения",
|
"all_locations": "Все местоположения",
|
||||||
"global_audit_log": "Глобальный журнал аудита",
|
"global_audit_log": "Глобальный журнал аудита",
|
||||||
"see_all_recent_account_activities": "Просмотри, что делали все пользователи на аккаунтах за период, который ты выбрал.",
|
"see_all_recent_account_activities": "Просмотр активности всех пользователей в установленный период хранения.",
|
||||||
"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_ui_animations": "Отключить все анимации в интерфейсе.",
|
||||||
"user_disabled": "Учетная запись отключена",
|
"user_disabled": "Учетная запись отключена",
|
||||||
@@ -354,8 +356,8 @@
|
|||||||
"login_code_email_success": "Код входа был отправлен пользователю.",
|
"login_code_email_success": "Код входа был отправлен пользователю.",
|
||||||
"send_email": "Отправить письмо",
|
"send_email": "Отправить письмо",
|
||||||
"show_code": "Показать код",
|
"show_code": "Показать код",
|
||||||
"callback_url_description": "URL-адреса, которые дал твой клиент. Если поле оставить пустым, они добавятся автоматически. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>подстановочные знаки</link>.",
|
"callback_url_description": "URL-адрес(а), предоставленный вашим клиентом. Будет добавлен автоматически, если оставить поле пустым. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>шаблоны</link>.",
|
||||||
"logout_callback_url_description": "URL-адреса, которые твой клиент дает для выхода из системы. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>подстановочные знаки</link>.",
|
"logout_callback_url_description": "URL-адрес(а) для выхода из системы, указанный(-е) в вашем клиенте. Поддерживаются <link href='https://pocket-id.org/docs/advanced/callback-url-wildcards'>шаблоны</link>.",
|
||||||
"api_key_expiration": "Истечение срока действия ключа API",
|
"api_key_expiration": "Истечение срока действия ключа API",
|
||||||
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Отправлять пользователю письмо, когда срок действия его ключа API истекает.",
|
"send_an_email_to_the_user_when_their_api_key_is_about_to_expire": "Отправлять пользователю письмо, когда срок действия его ключа API истекает.",
|
||||||
"authorize_device": "Авторизовать устройство",
|
"authorize_device": "Авторизовать устройство",
|
||||||
@@ -411,9 +413,9 @@
|
|||||||
"go_to_login": "Перейти ко входу",
|
"go_to_login": "Перейти ко входу",
|
||||||
"signup_to_appname": "Зарегистрироваться в {appName}",
|
"signup_to_appname": "Зарегистрироваться в {appName}",
|
||||||
"create_your_account_to_get_started": "Создайте свою учетную запись, чтобы начать.",
|
"create_your_account_to_get_started": "Создайте свою учетную запись, чтобы начать.",
|
||||||
"initial_account_creation_description": "Пожалуйста, создайте свою учетную запись, чтобы начать. Вы сможете настроить пасскей позже.",
|
"initial_account_creation_description": "Пожалуйста, создайте свою учетную запись, чтобы начать. Вы сможете настроить ключ доступа позже.",
|
||||||
"setup_your_passkey": "Настройте ваш пасскей",
|
"setup_your_passkey": "Настройте ваш ключ доступа",
|
||||||
"create_a_passkey_to_securely_access_your_account": "Создайте пасскей для безопасного доступа к учетной записи. Это будет ваш основной способ входа.",
|
"create_a_passkey_to_securely_access_your_account": "Создайте ключ доступа для безопасного доступа к учетной записи. Это будет ваш основной способ входа.",
|
||||||
"skip_for_now": "Пока пропустить",
|
"skip_for_now": "Пока пропустить",
|
||||||
"account_created": "Учетная запись создана",
|
"account_created": "Учетная запись создана",
|
||||||
"enable_user_signups": "Включить регистрацию пользователей",
|
"enable_user_signups": "Включить регистрацию пользователей",
|
||||||
@@ -438,8 +440,8 @@
|
|||||||
"signup_open": "Открытая регистрация",
|
"signup_open": "Открытая регистрация",
|
||||||
"signup_open_description": "Любой может создать новую учетную запись без ограничений.",
|
"signup_open_description": "Любой может создать новую учетную запись без ограничений.",
|
||||||
"of": "из",
|
"of": "из",
|
||||||
"skip_passkey_setup": "Пропустить настройку пасскея",
|
"skip_passkey_setup": "Пропустить настройку ключа доступа",
|
||||||
"skip_passkey_setup_description": "Настоятельно рекомендуется настроить пасскей, так как без него вы более не сможете войти в учетную запись после истечения сессии.",
|
"skip_passkey_setup_description": "Настоятельно рекомендуется настроить ключ доступа, так как без него вы не сможете войти в свою учетную запись по истечении сессии.",
|
||||||
"my_apps": "Мои приложения",
|
"my_apps": "Мои приложения",
|
||||||
"no_apps_available": "Нет доступных приложений",
|
"no_apps_available": "Нет доступных приложений",
|
||||||
"contact_your_administrator_for_app_access": "Свяжись с администратором, чтобы получить доступ к приложениям.",
|
"contact_your_administrator_for_app_access": "Свяжись с администратором, чтобы получить доступ к приложениям.",
|
||||||
@@ -475,29 +477,49 @@
|
|||||||
"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_email_enabled": "Требуется, если включены уведомления по электронной почте",
|
||||||
|
"renew": "Обновить",
|
||||||
|
"renew_api_key": "Обновить ключ API",
|
||||||
|
"renew_api_key_description": "При обновлении ключа API будет сгенерирован новый ключ. Не забудь обновить все интеграции, которые используют этот ключ.",
|
||||||
|
"api_key_renewed": "Ключ API обновлен",
|
||||||
|
"app_config_home_page": "Главная страница",
|
||||||
|
"app_config_home_page_description": "Страница, на которую пользователи перенаправляются после входа.",
|
||||||
|
"email_verification_warning": "Подтвердите ваш адрес электронной почты",
|
||||||
|
"email_verification_warning_description": "Ваш адрес электронной почты ещё не подтверждён. Пожалуйста, подтвердите его как можно скорее.",
|
||||||
|
"email_verification": "Подтверждение электронной почты",
|
||||||
|
"email_verification_description": "Отправлять пользователям письмо с подтверждением при регистрации или изменении их адреса электронной почты.",
|
||||||
|
"email_verification_success_title": "Электронная почта успешно подтверждена",
|
||||||
|
"email_verification_success_description": "Ваш адрес электронной почты успешно подтвержден.",
|
||||||
|
"email_verification_error_title": "Не удалось подтвердить электронную почту",
|
||||||
|
"mark_as_unverified": "Пометить как неподтвержденную",
|
||||||
|
"mark_as_verified": "Пометить как подтвержденную",
|
||||||
|
"email_verification_sent": "Письмо с подтверждением успешно отправлено.",
|
||||||
|
"emails_verified_by_default": "Электронные почты подтверждены по умолчанию",
|
||||||
|
"emails_verified_by_default_description": "Если эта функция включена, адреса электронной почты пользователей будут по умолчанию помечаться как подтверждённые при регистрации или при смене адреса."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Autentiseraren stöder inte lagrade nycklar",
|
"authenticator_does_not_support_resident_keys": "Autentiseraren stöder inte lagrade nycklar",
|
||||||
"passkey_was_previously_registered": "Denna passkey har redan registrerats",
|
"passkey_was_previously_registered": "Denna passkey har redan registrerats",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autentiseraren stöder inte någon av de begärda algoritmerna",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Autentiseraren stöder inte någon av de begärda algoritmerna",
|
||||||
"authenticator_timed_out": "Autentiseraren överskred tidsgränsen",
|
"webauthn_error_invalid_rp_id": "Det konfigurerade ID:t för den förlitande parten är ogiltigt.",
|
||||||
|
"webauthn_error_invalid_domain": "Den konfigurerade domänen är ogiltig.",
|
||||||
|
"contact_administrator_to_fix": "Kontakta din administratör för att åtgärda detta problem.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Operationen var inte tillåten eller tidsgränsen överskreds",
|
||||||
|
"webauthn_not_supported_by_browser": "Passkeys stöds inte av denna webbläsare. Använd en alternativ inloggningsmetod.",
|
||||||
"critical_error_occurred_contact_administrator": "Ett kritiskt fel har inträffat. Kontakta din administratör.",
|
"critical_error_occurred_contact_administrator": "Ett kritiskt fel har inträffat. Kontakta din administratör.",
|
||||||
"sign_in_to": "Logga in på {name}",
|
"sign_in_to": "Logga in på {name}",
|
||||||
"client_not_found": "Klienten hittades inte",
|
"client_not_found": "Klienten hittades inte",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Hur länge en session varar i minuter innan användaren måste logga in igen.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Hur länge en session varar i minuter innan användaren måste logga in igen.",
|
||||||
"enable_self_account_editing": "Aktivera redigering av eget konto",
|
"enable_self_account_editing": "Aktivera redigering av eget konto",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Om användarna ska kunna redigera sina egna kontouppgifter.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Om användarna ska kunna redigera sina egna kontouppgifter.",
|
||||||
"emails_verified": "E-postadresser verifierade",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Om användarens e-postadress ska markeras som verifierad för OIDC-klienterna.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP-konfigurationen har uppdaterats",
|
"ldap_configuration_updated_successfully": "LDAP-konfigurationen har uppdaterats",
|
||||||
"ldap_disabled_successfully": "LDAP har inaktiverats",
|
"ldap_disabled_successfully": "LDAP har inaktiverats",
|
||||||
"ldap_sync_finished": "LDAP-synkronisering slutförd",
|
"ldap_sync_finished": "LDAP-synkronisering slutförd",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Spara och synkronisera",
|
"save_and_sync": "Spara och synkronisera",
|
||||||
"scim_save_changes_description": "Du måste spara ändringarna innan du startar en SCIM-synkronisering. Vill du spara nu?",
|
"scim_save_changes_description": "Du måste spara ändringarna innan du startar en SCIM-synkronisering. Vill du spara nu?",
|
||||||
"scopes": "Omfattning",
|
"scopes": "Omfattning",
|
||||||
"issuer_url": "Utfärdarens URL"
|
"issuer_url": "Utfärdarens URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Krävs när någon SMTP-inställning anges",
|
||||||
|
"smtp_field_required_when_email_enabled": "Krävs när e-postaviseringar är aktiverade",
|
||||||
|
"renew": "Förnya",
|
||||||
|
"renew_api_key": "Förnya API-nyckel",
|
||||||
|
"renew_api_key_description": "När API-nyckeln förnyas genereras en ny nyckel. Se till att uppdatera alla integrationer som använder denna nyckel.",
|
||||||
|
"api_key_renewed": "API-nyckel förnyad",
|
||||||
|
"app_config_home_page": "Hemsida",
|
||||||
|
"app_config_home_page_description": "Den sida som användarna omdirigeras till efter inloggningen.",
|
||||||
|
"email_verification_warning": "Verifiera din e-postadress",
|
||||||
|
"email_verification_warning_description": "Din e-postadress är ännu inte verifierad. Verifiera den så snart som möjligt.",
|
||||||
|
"email_verification": "E-postverifiering",
|
||||||
|
"email_verification_description": "Skicka ett verifieringsmeddelande till användarna när de registrerar sig eller ändrar sin e-postadress.",
|
||||||
|
"email_verification_success_title": "E-postadress verifierad",
|
||||||
|
"email_verification_success_description": "Din e-postadress har verifierats.",
|
||||||
|
"email_verification_error_title": "E-postverifiering misslyckades",
|
||||||
|
"mark_as_unverified": "Markera som obekräftat",
|
||||||
|
"mark_as_verified": "Markera som verifierad",
|
||||||
|
"email_verification_sent": "Verifieringsmeddelandet har skickats.",
|
||||||
|
"emails_verified_by_default": "E-postmeddelanden verifierade som standard",
|
||||||
|
"emails_verified_by_default_description": "När funktionen är aktiverad kommer användarnas e-postadresser att markeras som verifierade som standard vid registrering eller när deras e-postadress ändras."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Kimlik doğrulayıcı yerleşik anahtarları desteklemiyor",
|
"authenticator_does_not_support_resident_keys": "Kimlik doğrulayıcı yerleşik anahtarları desteklemiyor",
|
||||||
"passkey_was_previously_registered": "Bu geçiş anahtarı daha önce kaydedilmiştir",
|
"passkey_was_previously_registered": "Bu geçiş anahtarı daha önce kaydedilmiştir",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Kimlik doğrulayıcı, talep edilen algoritmalardan hiçbirini desteklemiyor",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Kimlik doğrulayıcı, talep edilen algoritmalardan hiçbirini desteklemiyor",
|
||||||
"authenticator_timed_out": "Kimlik doğrulayıcı zaman aşımına uğradı",
|
"webauthn_error_invalid_rp_id": "Yapılandırılan güvenen taraf kimliği geçersiz.",
|
||||||
|
"webauthn_error_invalid_domain": "Yapılandırılan etki alanı geçersiz.",
|
||||||
|
"contact_administrator_to_fix": "Bu sorunu gidermek için yöneticinize başvurun.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "İşlem izin verilmedi veya zaman aşımına uğradı",
|
||||||
|
"webauthn_not_supported_by_browser": "Bu tarayıcıda geçiş anahtarları desteklenmemektedir. Lütfen alternatif bir oturum açma yöntemi kullanın.",
|
||||||
"critical_error_occurred_contact_administrator": "Kritik bir hata oluştu. Lütfen sistem yöneticinizle iletişime geçin.",
|
"critical_error_occurred_contact_administrator": "Kritik bir hata oluştu. Lütfen sistem yöneticinizle iletişime geçin.",
|
||||||
"sign_in_to": "{name} hesabına giriş yap",
|
"sign_in_to": "{name} hesabına giriş yap",
|
||||||
"client_not_found": "İstemci bulunamadı",
|
"client_not_found": "İstemci bulunamadı",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Kullanıcının tekrar oturum açması gereken süre, dakika cinsinden.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Kullanıcının tekrar oturum açması gereken süre, dakika cinsinden.",
|
||||||
"enable_self_account_editing": "Kullanıcının kendi hesabını düzenlemesini etkinleştir",
|
"enable_self_account_editing": "Kullanıcının kendi hesabını düzenlemesini etkinleştir",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Kullanıcıların kendi hesap bilgilerini düzenlemesine izin verilsin mi.",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Kullanıcıların kendi hesap bilgilerini düzenlemesine izin verilsin mi.",
|
||||||
"emails_verified": "E-postalar doğrulandı",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Kullanıcının e-postasının OIDC istemcileri için doğrulanmış olarak işaretlenip işaretlenmeyeceği.",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP yapılandırması başarıyla güncellendi",
|
"ldap_configuration_updated_successfully": "LDAP yapılandırması başarıyla güncellendi",
|
||||||
"ldap_disabled_successfully": "LDAP başarıyla devre dışı bırakıldı",
|
"ldap_disabled_successfully": "LDAP başarıyla devre dışı bırakıldı",
|
||||||
"ldap_sync_finished": "LDAP senkronizasyonu tamamlandı",
|
"ldap_sync_finished": "LDAP senkronizasyonu tamamlandı",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Kaydet ve Senkronize Et",
|
"save_and_sync": "Kaydet ve Senkronize Et",
|
||||||
"scim_save_changes_description": "SCIM senkronizasyonunu başlatmadan önce değişiklikleri kaydetmeniz gerekir. Şimdi kaydetmek ister misiniz?",
|
"scim_save_changes_description": "SCIM senkronizasyonunu başlatmadan önce değişiklikleri kaydetmeniz gerekir. Şimdi kaydetmek ister misiniz?",
|
||||||
"scopes": "Kapsamlar",
|
"scopes": "Kapsamlar",
|
||||||
"issuer_url": "İhraççı URL"
|
"issuer_url": "İhraççı URL",
|
||||||
|
"smtp_field_required_when_other_provided": "Herhangi bir SMTP ayarı sağlandığında gereklidir",
|
||||||
|
"smtp_field_required_when_email_enabled": "E-posta bildirimleri etkinleştirildiğinde gereklidir",
|
||||||
|
"renew": "Yenile",
|
||||||
|
"renew_api_key": "API Anahtarını Yenile",
|
||||||
|
"renew_api_key_description": "API anahtarını yenilemek yeni bir anahtar oluşturacaktır. Bu anahtarı kullanarak tüm entegrasyonları güncellediğinizden emin olun.",
|
||||||
|
"api_key_renewed": "API anahtarı yenilendi",
|
||||||
|
"app_config_home_page": "Ana Sayfa",
|
||||||
|
"app_config_home_page_description": "Kullanıcıların oturum açtıktan sonra yönlendirildikleri sayfa.",
|
||||||
|
"email_verification_warning": "E-posta adresinizi doğrulayın",
|
||||||
|
"email_verification_warning_description": "E-posta adresiniz henüz doğrulanmadı. Lütfen en kısa sürede doğrulayın.",
|
||||||
|
"email_verification": "E-posta Doğrulama",
|
||||||
|
"email_verification_description": "Kullanıcılar kaydolduğunda veya e-posta adreslerini değiştirdiğinde onlara doğrulama e-postası gönderin.",
|
||||||
|
"email_verification_success_title": "E-posta Doğrulaması Başarılı Oldu",
|
||||||
|
"email_verification_success_description": "E-posta adresiniz başarıyla doğrulandı.",
|
||||||
|
"email_verification_error_title": "E-posta Doğrulama Başarısız",
|
||||||
|
"mark_as_unverified": "Doğrulanmamış olarak işaretle",
|
||||||
|
"mark_as_verified": "Doğrulanmış olarak işaretle",
|
||||||
|
"email_verification_sent": "Doğrulama e-postası başarıyla gönderildi.",
|
||||||
|
"emails_verified_by_default": "Varsayılan olarak doğrulanmış e-postalar",
|
||||||
|
"emails_verified_by_default_description": "Etkinleştirildiğinde, kullanıcıların e-posta adresleri kayıt sırasında veya e-posta adresleri değiştirildiğinde varsayılan olarak doğrulanmış olarak işaretlenecektir."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
"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": "Фотографія профілю управляється сервером LDAP і не може бути змінена тут.",
|
"profile_picture_is_managed_by_ldap_server": "Зображення профілю керується сервером LDAP і не може бути змінене тут.",
|
||||||
"click_profile_picture_to_upload_custom": "Натисніть на зображення профілю, щоб завантажити власне зображення.",
|
"click_profile_picture_to_upload_custom": "Натисніть на зображення профілю, щоб завантажити власне зображення.",
|
||||||
"image_should_be_in_format": "Зображення повинно бути у форматі PNG, JPEG або WEBP.",
|
"image_should_be_in_format": "Зображення повинно бути у форматі PNG, JPEG або WEBP.",
|
||||||
"items_per_page": "Елементів на сторінці",
|
"items_per_page": "Елементів на сторінці",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"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_to_sign_in_without_a_passkey_once": "Створіть код входу, який користувач може одноразово використати для входу без ключа доступу.",
|
||||||
"one_hour": "1 година",
|
"one_hour": "1 година",
|
||||||
"twelve_hours": "12 годин",
|
"twelve_hours": "12 годин",
|
||||||
"one_day": "1 день",
|
"one_day": "1 день",
|
||||||
@@ -46,10 +46,14 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Автентифікатор не підтримує локальні ключі",
|
"authenticator_does_not_support_resident_keys": "Автентифікатор не підтримує локальні ключі",
|
||||||
"passkey_was_previously_registered": "Цей ключ доступу був раніше зареєстрований",
|
"passkey_was_previously_registered": "Цей ключ доступу був раніше зареєстрований",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Автентифікатор не підтримує жоден із запитаних алгоритмів",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Автентифікатор не підтримує жоден із запитаних алгоритмів",
|
||||||
"authenticator_timed_out": "Час очікування автентифікатора вичерпано",
|
"webauthn_error_invalid_rp_id": "Налаштований ідентифікатор сторони, що покладається, є недійсним.",
|
||||||
|
"webauthn_error_invalid_domain": "Налаштований домен є недійсним.",
|
||||||
|
"contact_administrator_to_fix": "Зверніться до адміністратора, щоб вирішити цю проблему.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Операція не була дозволена або закінчився час очікування",
|
||||||
|
"webauthn_not_supported_by_browser": "Цей браузер не підтримує ключі доступу. Будь ласка, скористайтеся альтернативним методом входу.",
|
||||||
"critical_error_occurred_contact_administrator": "Виникла критична помилка. Будь ласка, зверніться до адміністратора.",
|
"critical_error_occurred_contact_administrator": "Виникла критична помилка. Будь ласка, зверніться до адміністратора.",
|
||||||
"sign_in_to": "Увійти в {name}",
|
"sign_in_to": "Увійти в {name}",
|
||||||
"client_not_found": "Клієнта не знайдено",
|
"client_not_found": "Клієнт не знайдений",
|
||||||
"client_wants_to_access_the_following_information": "<b>{client}</b> хоче отримати доступ до наступної інформації:",
|
"client_wants_to_access_the_following_information": "<b>{client}</b> хоче отримати доступ до наступної інформації:",
|
||||||
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Бажаєте увійти до <b>{client}</b> за допомогою облікового запису {appName}?",
|
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Бажаєте увійти до <b>{client}</b> за допомогою облікового запису {appName}?",
|
||||||
"email": "Електронна пошта",
|
"email": "Електронна пошта",
|
||||||
@@ -86,7 +90,7 @@
|
|||||||
"enter_the_code_you_received_to_sign_in": "Введіть отриманий код, щоб увійти.",
|
"enter_the_code_you_received_to_sign_in": "Введіть отриманий код, щоб увійти.",
|
||||||
"code": "Код",
|
"code": "Код",
|
||||||
"invalid_redirect_url": "Неправильна URL-адреса перенаправлення",
|
"invalid_redirect_url": "Неправильна URL-адреса перенаправлення",
|
||||||
"audit_log": "Журнал авдиту",
|
"audit_log": "Журнал аудиту",
|
||||||
"users": "Користувачі",
|
"users": "Користувачі",
|
||||||
"user_groups": "Групи користувачів",
|
"user_groups": "Групи користувачів",
|
||||||
"oidc_clients": "Клієнти OIDC",
|
"oidc_clients": "Клієнти OIDC",
|
||||||
@@ -131,14 +135,14 @@
|
|||||||
"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": "Видалити {passkeyName}",
|
"delete_passkey_name": "Видалити {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": "Створити API-ключ",
|
"create_api_key": "Створити API-ключ",
|
||||||
"add_a_new_api_key_for_programmatic_access": "Додайте новий ключ API для програмного доступу до <link href='https://pocket-id.org/docs/api'>API Pocket ID</link>.",
|
"add_a_new_api_key_for_programmatic_access": "Додайте новий API-ключ для програмного доступу до <link href='https://pocket-id.org/docs/api'>API Pocket ID</link>.",
|
||||||
"add_api_key": "Додати API-ключ",
|
"add_api_key": "Додати API-ключ",
|
||||||
"manage_api_keys": "Керувати ключами API",
|
"manage_api_keys": "Керувати API-ключами",
|
||||||
"api_key_created": "Створено API-ключ",
|
"api_key_created": "API-ключ створено",
|
||||||
"for_security_reasons_this_key_will_only_be_shown_once": "З міркувань безпеки цей ключ буде показано лише один раз. Будь ласка, збережіть його в безпечному місці.",
|
"for_security_reasons_this_key_will_only_be_shown_once": "З міркувань безпеки цей ключ буде показано лише один раз. Будь ласка, збережіть його в безпечному місці.",
|
||||||
"description": "Опис",
|
"description": "Опис",
|
||||||
"api_key": "API-ключ",
|
"api_key": "API-ключ",
|
||||||
@@ -148,11 +152,11 @@
|
|||||||
"when_this_api_key_will_expire": "Коли спливе термін дії цього API-ключа.",
|
"when_this_api_key_will_expire": "Коли спливе термін дії цього API-ключа.",
|
||||||
"optional_description_to_help_identify_this_keys_purpose": "Додатковий опис для допомоги в ідентифікації призначення цього ключа (необов’язково).",
|
"optional_description_to_help_identify_this_keys_purpose": "Додатковий опис для допомоги в ідентифікації призначення цього ключа (необов’язково).",
|
||||||
"expiration_date_must_be_in_the_future": "Дата закінчення терміну дії повинна бути в майбутньому",
|
"expiration_date_must_be_in_the_future": "Дата закінчення терміну дії повинна бути в майбутньому",
|
||||||
"revoke_api_key": "Анулювати API-ключ",
|
"revoke_api_key": "Відкликати API-ключ",
|
||||||
"never": "Ніколи",
|
"never": "Ніколи",
|
||||||
"revoke": "Анулювати",
|
"revoke": "Відкликати",
|
||||||
"api_key_revoked_successfully": "API-ключ успішно анульовано",
|
"api_key_revoked_successfully": "API-ключ успішно відкликано",
|
||||||
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Ви впевнені, що хочете анулювати API-ключ «{apiKeyName}»? Це призведе до зупинки всіх інтеграцій, які використовують цей ключ.",
|
"are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Ви впевнені, що хочете відкликати API-ключ «{apiKeyName}»? Це призведе до зупинки всіх інтеграцій, які використовують цей ключ.",
|
||||||
"last_used": "Останнє використання",
|
"last_used": "Останнє використання",
|
||||||
"actions": "Дії",
|
"actions": "Дії",
|
||||||
"images_updated_successfully": "Зображення успішно оновлено. Оновлення може зайняти кілька хвилин.",
|
"images_updated_successfully": "Зображення успішно оновлено. Оновлення може зайняти кілька хвилин.",
|
||||||
@@ -166,7 +170,7 @@
|
|||||||
"save_changes_question": "Зберегти зміни?",
|
"save_changes_question": "Зберегти зміни?",
|
||||||
"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": "Тестовий лист успішно надіслано на вашу електронну адресу.",
|
||||||
"failed_to_send_test_email": "Не вдалося надіслати тестовий лист. Перевірте журнали сервера для отримання додаткової інформації.",
|
"failed_to_send_test_email": "Не вдалося надіслати тестовий лист. Перевірте журнали сервера для отримання додаткової інформації.",
|
||||||
"smtp_configuration": "Налаштування SMTP",
|
"smtp_configuration": "Налаштування SMTP",
|
||||||
"smtp_host": "SMTP хост",
|
"smtp_host": "SMTP хост",
|
||||||
@@ -181,19 +185,17 @@
|
|||||||
"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": "Надіслати коду входу, згенерований користувачем, електронною поштою",
|
"emai_login_code_requested_by_user": "Надіслати код входу, згенерований користувачем, електронною поштою",
|
||||||
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Дозволяє користувачам обходити ключі доступу шляхом запиту коду для входу, який був відправлений на їх електронну пошту. Це суттєво зменшує безпеку, оскільки будь-хто, хто має доступ до електронної пошти користувача, може отримати доступ.",
|
"allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Дозволяє користувачам обходити ключі доступу шляхом запиту коду для входу, який був відправлений на їх електронну пошту. Це суттєво зменшує безпеку, оскільки будь-хто, хто має доступ до електронної пошти користувача, може отримати доступ.",
|
||||||
"email_login_code_from_admin": "Надіслати коду входу, згенерований адміністратором, електронною поштою",
|
"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": "Дозволяє адміністратору надсилати код для входу користувачеві електронною поштою.",
|
||||||
"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": "Чи повинні користувачі мати можливість редагувати дані свого облікового запису.",
|
||||||
"emails_verified": "Підтверджена електронна пошта",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Чи слід позначати електронну пошту користувача як підтверджену для OIDC клієнтів.",
|
|
||||||
"ldap_configuration_updated_successfully": "Налаштування LDAP успішно оновлено",
|
"ldap_configuration_updated_successfully": "Налаштування LDAP успішно оновлено",
|
||||||
"ldap_disabled_successfully": "LDAP успішно вимкнено",
|
"ldap_disabled_successfully": "LDAP успішно вимкнено",
|
||||||
"ldap_sync_finished": "Синхронізація LDAP завершена",
|
"ldap_sync_finished": "Синхронізація LDAP завершена",
|
||||||
@@ -277,7 +279,7 @@
|
|||||||
"callback_urls": "URL-адреси зворотного виклику",
|
"callback_urls": "URL-адреси зворотного виклику",
|
||||||
"logout_callback_urls": "URL-адреси зворотного виклику для виходу",
|
"logout_callback_urls": "URL-адреси зворотного виклику для виходу",
|
||||||
"public_client": "Публічний клієнт",
|
"public_client": "Публічний клієнт",
|
||||||
"public_clients_description": "Публічні клієнти не мають секретного ключа. Вони призначені для мобільних, веб та нативних додатків, де секретний ключ не може надійно зберігатись.",
|
"public_clients_description": "Публічні клієнти не мають секретного ключа. Вони призначені для мобільних, веб та нативних застосунків, де секретний ключ не може надійно зберігатись.",
|
||||||
"pkce": "PKCE",
|
"pkce": "PKCE",
|
||||||
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange — це функція безпеки, що запобігає атакам типу CSRF та перехопленню коду авторизації.",
|
"public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange — це функція безпеки, що запобігає атакам типу CSRF та перехопленню коду авторизації.",
|
||||||
"requires_reauthentication": "Потрібна повторна автентифікація",
|
"requires_reauthentication": "Потрібна повторна автентифікація",
|
||||||
@@ -319,10 +321,10 @@
|
|||||||
"background_image": "Фонове зображення",
|
"background_image": "Фонове зображення",
|
||||||
"language": "Мова",
|
"language": "Мова",
|
||||||
"reset_profile_picture_question": "Скинути зображення профілю?",
|
"reset_profile_picture_question": "Скинути зображення профілю?",
|
||||||
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "Це видалить завантажене зображення та скине фото профілю на стандартне. Продовжити?",
|
"this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "Це видалить завантажене зображення та скине зображення профілю на стандартне. Продовжити?",
|
||||||
"reset": "Скинути",
|
"reset": "Скинути",
|
||||||
"reset_to_default": "Відновити налаштування за замовчуванням",
|
"reset_to_default": "Відновити налаштування за замовчуванням",
|
||||||
"profile_picture_has_been_reset": "Фотографію профілю скинуто. Оновлення може зайняти кілька хвилин.",
|
"profile_picture_has_been_reset": "Зображення профілю скинуто. Оновлення може зайняти кілька хвилин.",
|
||||||
"select_the_language_you_want_to_use": "Виберіть мову, яку бажаєте використовувати. Зверніть увагу, що деякий текст може бути автоматично перекладений і може містити неточності.",
|
"select_the_language_you_want_to_use": "Виберіть мову, яку бажаєте використовувати. Зверніть увагу, що деякий текст може бути автоматично перекладений і може містити неточності.",
|
||||||
"contribute_to_translation": "Якщо ви знайдете помилку, ви можете долучитися до перекладу на <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
|
"contribute_to_translation": "Якщо ви знайдете помилку, ви можете долучитися до перекладу на <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
|
||||||
"personal": "Особисте",
|
"personal": "Особисте",
|
||||||
@@ -331,26 +333,26 @@
|
|||||||
"all_events": "Усі події",
|
"all_events": "Усі події",
|
||||||
"all_clients": "Усі клієнти",
|
"all_clients": "Усі клієнти",
|
||||||
"all_locations": "Усі місця розташування",
|
"all_locations": "Усі місця розташування",
|
||||||
"global_audit_log": "Глобальний журнал авдиту",
|
"global_audit_log": "Глобальний журнал аудиту",
|
||||||
"see_all_recent_account_activities": "Перегляньте активність облікових записів усіх користувачів протягом встановленого періоду зберігання.",
|
"see_all_recent_account_activities": "Перегляньте активність облікових записів усіх користувачів протягом встановленого періоду зберігання.",
|
||||||
"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_ui_animations": "Вимкнути анімації у всьому інтерфейсі.",
|
||||||
"user_disabled": "Обліковий запис вимкнено",
|
"user_disabled": "Обліковий запис деактивовано",
|
||||||
"disabled_users_cannot_log_in_or_use_services": "Вимкнені користувачі не можуть увійти в систему або користуватися послугами.",
|
"disabled_users_cannot_log_in_or_use_services": "Деактивовані користувачі не можуть увійти в систему або користуватися сервісами.",
|
||||||
"user_disabled_successfully": "Користувача успішно деактивовано.",
|
"user_disabled_successfully": "Користувача успішно деактивовано.",
|
||||||
"user_enabled_successfully": "Користувача успішно активовано.",
|
"user_enabled_successfully": "Користувача успішно активовано.",
|
||||||
"status": "Статус",
|
"status": "Статус",
|
||||||
"disable_firstname_lastname": "Деактивувати {firstName} {lastName}",
|
"disable_firstname_lastname": "Деактивувати {firstName} {lastName}",
|
||||||
"are_you_sure_you_want_to_disable_this_user": "Ви впевнені, що хочете вимкнути цього користувача? Він не зможе увійти в систему або користуватися будь-якими послугами.",
|
"are_you_sure_you_want_to_disable_this_user": "Ви впевнені, що хочете деактивувати цього користувача? Він не зможе увійти в систему або отримати доступ до будь-яких сервісів.",
|
||||||
"ldap_soft_delete_users": "Зберігати вимкнених користувачів із LDAP.",
|
"ldap_soft_delete_users": "Зберігати вимкнених користувачів із LDAP.",
|
||||||
"ldap_soft_delete_users_description": "Якщо увімкнено, користувачів, видалених з LDAP, буде вимкнено, а не видалено з системи.",
|
"ldap_soft_delete_users_description": "Якщо увімкнено, користувачів, видалених з LDAP, буде деактивовано, а не видалено з системи.",
|
||||||
"login_code_email_success": "Код для входу було надіслано користувачеві.",
|
"login_code_email_success": "Код для входу було надіслано користувачеві.",
|
||||||
"send_email": "Надіслати електронного листа",
|
"send_email": "Надіслати електронного листа",
|
||||||
"show_code": "Показати код",
|
"show_code": "Показати код",
|
||||||
@@ -377,7 +379,7 @@
|
|||||||
"userinfo": "Userinfo",
|
"userinfo": "Userinfo",
|
||||||
"id_token_payload": "Вміст ID-токена",
|
"id_token_payload": "Вміст ID-токена",
|
||||||
"access_token_payload": "Вміст токена доступу",
|
"access_token_payload": "Вміст токена доступу",
|
||||||
"userinfo_endpoint_response": "Відповідь сервісу Userinfo",
|
"userinfo_endpoint_response": "Відповідь кінцевої точки Userinfo",
|
||||||
"copy": "Копіювати",
|
"copy": "Копіювати",
|
||||||
"no_preview_data_available": "Попередній перегляд даних недоступний",
|
"no_preview_data_available": "Попередній перегляд даних недоступний",
|
||||||
"copy_all": "Скопіювати все",
|
"copy_all": "Скопіювати все",
|
||||||
@@ -402,8 +404,8 @@
|
|||||||
"signup": "Зареєструватися",
|
"signup": "Зареєструватися",
|
||||||
"user_creation": "Створення користувача",
|
"user_creation": "Створення користувача",
|
||||||
"configure_user_creation": "Керуйте налаштуваннями створення користувачів, включаючи методи реєстрації та права доступу за замовчуванням для нових користувачів.",
|
"configure_user_creation": "Керуйте налаштуваннями створення користувачів, включаючи методи реєстрації та права доступу за замовчуванням для нових користувачів.",
|
||||||
"user_creation_groups_description": "Призначте ці групи автоматично новим користувачам під час реєстрації.",
|
"user_creation_groups_description": "Призначати ці групи автоматично новим користувачам під час реєстрації.",
|
||||||
"user_creation_claims_description": "Призначте ці власні вимоги автоматично новим користувачам під час реєстрації.",
|
"user_creation_claims_description": "Призначати ці власні атрибути автоматично новим користувачам під час реєстрації.",
|
||||||
"user_creation_updated_successfully": "Налаштування створення користувача успішно оновлено.",
|
"user_creation_updated_successfully": "Налаштування створення користувача успішно оновлено.",
|
||||||
"signup_disabled_description": "Реєстрація користувачів повністю вимкнена. Нові облікові записи можуть створювати лише адміністратори.",
|
"signup_disabled_description": "Реєстрація користувачів повністю вимкнена. Нові облікові записи можуть створювати лише адміністратори.",
|
||||||
"signup_requires_valid_token": "Для створення облікового запису потрібен дійсний токен реєстрації",
|
"signup_requires_valid_token": "Для створення облікового запису потрібен дійсний токен реєстрації",
|
||||||
@@ -411,10 +413,10 @@
|
|||||||
"go_to_login": "Перейти до входу",
|
"go_to_login": "Перейти до входу",
|
||||||
"signup_to_appname": "Зареєструватися в {appName}",
|
"signup_to_appname": "Зареєструватися в {appName}",
|
||||||
"create_your_account_to_get_started": "Створіть свій обліковий запис, щоб розпочати.",
|
"create_your_account_to_get_started": "Створіть свій обліковий запис, щоб розпочати.",
|
||||||
"initial_account_creation_description": "Будь ласка, створіть свій обліковий запис, щоб почати. Ви зможете налаштувати ключ доступу пізніше.",
|
"initial_account_creation_description": "Будь ласка, створіть свій обліковий запис, щоб розпочати. Ви зможете налаштувати ключ доступу пізніше.",
|
||||||
"setup_your_passkey": "Налаштуйте свій ключ доступу",
|
"setup_your_passkey": "Налаштуйте свій ключ доступу",
|
||||||
"create_a_passkey_to_securely_access_your_account": "Створіть ключ доступу для безпечного входу до свого облікового запису. Це буде ваш основний спосіб увійти.",
|
"create_a_passkey_to_securely_access_your_account": "Створіть ключ доступу для безпечного входу до свого облікового запису. Це буде ваш основний спосіб увійти.",
|
||||||
"skip_for_now": "Пропустити наразі",
|
"skip_for_now": "Поки що пропустити",
|
||||||
"account_created": "Обліковий запис створено",
|
"account_created": "Обліковий запис створено",
|
||||||
"enable_user_signups": "Дозволити реєстрацію користувачів",
|
"enable_user_signups": "Дозволити реєстрацію користувачів",
|
||||||
"enable_user_signups_description": "Визначте, як користувачі можуть реєструвати нові облікові записи в Pocket ID.",
|
"enable_user_signups_description": "Визначте, як користувачі можуть реєструвати нові облікові записи в Pocket ID.",
|
||||||
@@ -440,64 +442,84 @@
|
|||||||
"of": "з",
|
"of": "з",
|
||||||
"skip_passkey_setup": "Пропустити налаштування ключа доступу",
|
"skip_passkey_setup": "Пропустити налаштування ключа доступу",
|
||||||
"skip_passkey_setup_description": "Рекомендується налаштувати ключ доступу, оскільки без нього ви не зможете увійти у свій обліковий запис після закінчення сеансу.",
|
"skip_passkey_setup_description": "Рекомендується налаштувати ключ доступу, оскільки без нього ви не зможете увійти у свій обліковий запис після закінчення сеансу.",
|
||||||
"my_apps": "Мої додатки",
|
"my_apps": "Мої застосунки",
|
||||||
"no_apps_available": "Немає доступних додатків",
|
"no_apps_available": "Немає доступних застосунків",
|
||||||
"contact_your_administrator_for_app_access": "Зверніться до адміністратора, щоб отримати доступ до додатків.",
|
"contact_your_administrator_for_app_access": "Зверніться до адміністратора, щоб отримати доступ до застосунків.",
|
||||||
"launch": "Запуск",
|
"launch": "Запустити",
|
||||||
"client_launch_url": "URL-адреса для запуску клієнта",
|
"client_launch_url": "URL-адреса для запуску клієнта",
|
||||||
"client_launch_url_description": "URL-адреса, яка відкриється, коли користувач запустить програму зі сторінки «Мої програми».",
|
"client_launch_url_description": "URL-адреса, яка відкриється, коли користувач запустить програму зі сторінки «Мої програми».",
|
||||||
"client_name_description": "Назва клієнта, яке відображається в інтерфейсі Pocket ID.",
|
"client_name_description": "Назва клієнта, яка відображається в інтерфейсі Pocket ID.",
|
||||||
"revoke_access": "Скасувати доступ",
|
"revoke_access": "Відкликати доступ",
|
||||||
"revoke_access_description": "Скасувати доступ для <b>{clientName}</b>. <b>{clientName}</b> більше не зможе отримати доступ до інформації вашого облікового запису.",
|
"revoke_access_description": "Відкликати доступ для <b>{clientName}</b>. <b>{clientName}</b> більше не зможе отримати доступ до інформації вашого облікового запису.",
|
||||||
"revoke_access_successful": "Доступ для {clientName} було успішно скасовано.",
|
"revoke_access_successful": "Доступ для {clientName} був успішно відкликаний.",
|
||||||
"last_signed_in_ago": "Останній вхід {time} тому",
|
"last_signed_in_ago": "Останній вхід {time} тому",
|
||||||
"invalid_client_id": "Ідентифікатор клієнта може містити тільки літери, цифри, підкреслення та дефіси.",
|
"invalid_client_id": "Ідентифікатор клієнта може містити тільки літери, цифри, підкреслення та дефіси",
|
||||||
"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_email_enabled": "Обов'язково, якщо увімкнено сповіщення електронною поштою",
|
||||||
|
"renew": "Оновити",
|
||||||
|
"renew_api_key": "Оновити API-ключ",
|
||||||
|
"renew_api_key_description": "Оновлення API-ключа призведе до створення нового ключа. Обов'язково оновіть усі інтеграції, що використовують цей ключ.",
|
||||||
|
"api_key_renewed": "API-ключ оновлено",
|
||||||
|
"app_config_home_page": "Головна сторінка",
|
||||||
|
"app_config_home_page_description": "Сторінка, на яку користувачі перенаправляються після входу.",
|
||||||
|
"email_verification_warning": "Підтвердьте свою адресу електронної пошти",
|
||||||
|
"email_verification_warning_description": "Ваша електронна адреса ще не підтверджена. Будь ласка, підтвердьте її якомога швидше.",
|
||||||
|
"email_verification": "Перевірка електронної адреси",
|
||||||
|
"email_verification_description": "Надсилайте користувачам підтверджувальний лист електронною поштою, коли вони реєструються або змінюють свою адресу електронної пошти.",
|
||||||
|
"email_verification_success_title": "Електронна адреса успішно підтверджена",
|
||||||
|
"email_verification_success_description": "Ваша електронна адреса була успішно підтверджена.",
|
||||||
|
"email_verification_error_title": "Перевірка електронної адреси не вдалася",
|
||||||
|
"mark_as_unverified": "Позначити як неперевірене",
|
||||||
|
"mark_as_verified": "Позначити як перевірене",
|
||||||
|
"email_verification_sent": "Електронний лист для підтвердження надіслано успішно.",
|
||||||
|
"emails_verified_by_default": "Електронні листи перевіряються за замовчуванням",
|
||||||
|
"emails_verified_by_default_description": "Якщо ця опція увімкнена, адреси електронної пошти користувачів будуть позначатися як підтверджені за замовчуванням під час реєстрації або при зміні адреси електронної пошти."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "Thiết bị xác thực không hỗ trợ khóa lưu trữ",
|
"authenticator_does_not_support_resident_keys": "Thiết bị xác thực không hỗ trợ khóa lưu trữ",
|
||||||
"passkey_was_previously_registered": "Passkey này đã được đăng ký trước đó",
|
"passkey_was_previously_registered": "Passkey này đã được đăng ký trước đó",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "Thiết bị xác thực không hỗ trợ bất kỳ thuật toán nào trong số các thuật toán được yêu cầu",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "Thiết bị xác thực không hỗ trợ bất kỳ thuật toán nào trong số các thuật toán được yêu cầu",
|
||||||
"authenticator_timed_out": "Thời gian chờ của trình xác thực đã hết hạn",
|
"webauthn_error_invalid_rp_id": "ID của bên tin cậy đã cấu hình là không hợp lệ.",
|
||||||
|
"webauthn_error_invalid_domain": "Domain đã cấu hình không hợp lệ.",
|
||||||
|
"contact_administrator_to_fix": "Liên hệ với quản trị viên của bạn để khắc phục sự cố này.",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "Hoạt động này không được phép hoặc đã hết thời gian chờ.",
|
||||||
|
"webauthn_not_supported_by_browser": "Chìa khóa truy cập không được hỗ trợ bởi trình duyệt này. Vui lòng sử dụng phương thức đăng nhập thay thế.",
|
||||||
"critical_error_occurred_contact_administrator": "Đã xảy ra lỗi nghiêm trọng. Vui lòng liên hệ với quản trị viên.",
|
"critical_error_occurred_contact_administrator": "Đã xảy ra lỗi nghiêm trọng. Vui lòng liên hệ với quản trị viên.",
|
||||||
"sign_in_to": "Đăng nhập {name}",
|
"sign_in_to": "Đăng nhập {name}",
|
||||||
"client_not_found": "Không tìm thấy client.",
|
"client_not_found": "Không tìm thấy client.",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Thời gian của một phiên (tính bằng phút) trước khi người dùng phải đăng nhập lại.",
|
"the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "Thời gian của một phiên (tính bằng phút) trước khi người dùng phải đăng nhập lại.",
|
||||||
"enable_self_account_editing": "Cho Phép Chỉnh Sửa Tài Khoản Cá Nhân",
|
"enable_self_account_editing": "Cho Phép Chỉnh Sửa Tài Khoản Cá Nhân",
|
||||||
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Người dùng có nên được phép chỉnh sửa thông tin tài khoản của mình không?",
|
"whether_the_users_should_be_able_to_edit_their_own_account_details": "Người dùng có nên được phép chỉnh sửa thông tin tài khoản của mình không?",
|
||||||
"emails_verified": "Xác Minh Email",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Có nên đánh dấu email của người dùng là đã xác minh cho các OIDC clients hay không.",
|
|
||||||
"ldap_configuration_updated_successfully": "Cấu hình LDAP đã được cập nhật thành công",
|
"ldap_configuration_updated_successfully": "Cấu hình LDAP đã được cập nhật thành công",
|
||||||
"ldap_disabled_successfully": "Tắt LDAP thành công",
|
"ldap_disabled_successfully": "Tắt LDAP thành công",
|
||||||
"ldap_sync_finished": "Quá trình đồng bộ hóa LDAP đã hoàn tất",
|
"ldap_sync_finished": "Quá trình đồng bộ hóa LDAP đã hoàn tất",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "Lưu và Đồng bộ hóa",
|
"save_and_sync": "Lưu và Đồng bộ hóa",
|
||||||
"scim_save_changes_description": "Bạn phải lưu các thay đổi trước khi bắt đầu đồng bộ hóa SCIM. Bạn có muốn lưu ngay bây giờ không?",
|
"scim_save_changes_description": "Bạn phải lưu các thay đổi trước khi bắt đầu đồng bộ hóa SCIM. Bạn có muốn lưu ngay bây giờ không?",
|
||||||
"scopes": "Phạm vi",
|
"scopes": "Phạm vi",
|
||||||
"issuer_url": "Địa chỉ URL của tổ chức phát hành"
|
"issuer_url": "Địa chỉ URL của tổ chức phát hành",
|
||||||
|
"smtp_field_required_when_other_provided": "Yêu cầu khi cung cấp bất kỳ cài đặt SMTP nào.",
|
||||||
|
"smtp_field_required_when_email_enabled": "Yêu cầu khi bật thông báo qua email",
|
||||||
|
"renew": "Cập nhật",
|
||||||
|
"renew_api_key": "Cập nhật khóa API",
|
||||||
|
"renew_api_key_description": "Việc gia hạn khóa API sẽ tạo ra một khóa mới. Hãy đảm bảo cập nhật các tích hợp sử dụng khóa này.",
|
||||||
|
"api_key_renewed": "Khóa API đã được gia hạn",
|
||||||
|
"app_config_home_page": "Trang chủ",
|
||||||
|
"app_config_home_page_description": "Trang mà người dùng được chuyển hướng đến sau khi đăng nhập.",
|
||||||
|
"email_verification_warning": "Xác minh địa chỉ email của bạn",
|
||||||
|
"email_verification_warning_description": "Địa chỉ email của bạn chưa được xác minh. Vui lòng xác minh ngay lập tức.",
|
||||||
|
"email_verification": "Xác minh email",
|
||||||
|
"email_verification_description": "Gửi email xác minh cho người dùng khi họ đăng ký hoặc thay đổi địa chỉ email.",
|
||||||
|
"email_verification_success_title": "Email đã được xác minh thành công.",
|
||||||
|
"email_verification_success_description": "Địa chỉ email của bạn đã được xác minh thành công.",
|
||||||
|
"email_verification_error_title": "Xác minh email không thành công",
|
||||||
|
"mark_as_unverified": "Đánh dấu là chưa xác minh",
|
||||||
|
"mark_as_verified": "Đánh dấu là đã xác minh",
|
||||||
|
"email_verification_sent": "Email xác minh đã được gửi thành công.",
|
||||||
|
"emails_verified_by_default": "Email được xác minh theo mặc định",
|
||||||
|
"emails_verified_by_default_description": "Khi tính năng này được kích hoạt, địa chỉ email của người dùng sẽ được đánh dấu là đã xác minh theo mặc định khi đăng ký hoặc khi địa chỉ email của họ được thay đổi."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "认证器不支持常驻密钥",
|
"authenticator_does_not_support_resident_keys": "认证器不支持常驻密钥",
|
||||||
"passkey_was_previously_registered": "此通行密钥曾被注册",
|
"passkey_was_previously_registered": "此通行密钥曾被注册",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "认证器不支持任何请求的算法",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "认证器不支持任何请求的算法",
|
||||||
"authenticator_timed_out": "认证器超时",
|
"webauthn_error_invalid_rp_id": "配置的依赖方ID无效。",
|
||||||
|
"webauthn_error_invalid_domain": "配置的域名无效。",
|
||||||
|
"contact_administrator_to_fix": "请联系您的管理员以解决此问题。",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "该操作未被允许或超时",
|
||||||
|
"webauthn_not_supported_by_browser": "此浏览器不支持密钥登录。请使用其他登录方式。",
|
||||||
"critical_error_occurred_contact_administrator": "发生严重错误。请联系您的管理员。",
|
"critical_error_occurred_contact_administrator": "发生严重错误。请联系您的管理员。",
|
||||||
"sign_in_to": "登录到 {name}",
|
"sign_in_to": "登录到 {name}",
|
||||||
"client_not_found": "客户端未找到",
|
"client_not_found": "客户端未找到",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"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": "用户是否能够编辑自己的账户详细信息。",
|
||||||
"emails_verified": "已验证的邮箱地址",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "用户的电子邮件是否应标记为已验证,适用于 OIDC 客户端。",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP 配置更新成功",
|
"ldap_configuration_updated_successfully": "LDAP 配置更新成功",
|
||||||
"ldap_disabled_successfully": "LDAP 已成功禁用",
|
"ldap_disabled_successfully": "LDAP 已成功禁用",
|
||||||
"ldap_sync_finished": "LDAP 同步完成",
|
"ldap_sync_finished": "LDAP 同步完成",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "保存并同步",
|
"save_and_sync": "保存并同步",
|
||||||
"scim_save_changes_description": "在开始 SCIM 同步之前,您必须先保存更改。是否现在保存?",
|
"scim_save_changes_description": "在开始 SCIM 同步之前,您必须先保存更改。是否现在保存?",
|
||||||
"scopes": "Scopes",
|
"scopes": "Scopes",
|
||||||
"issuer_url": "发行者网址"
|
"issuer_url": "发行者网址",
|
||||||
|
"smtp_field_required_when_other_provided": "当提供任何SMTP设置时需要",
|
||||||
|
"smtp_field_required_when_email_enabled": "启用电子邮件通知时需要",
|
||||||
|
"renew": "更新",
|
||||||
|
"renew_api_key": "更新 API 密钥",
|
||||||
|
"renew_api_key_description": "更新API密钥将生成新密钥。请确保更新所有使用此密钥的集成。",
|
||||||
|
"api_key_renewed": "API密钥已更新",
|
||||||
|
"app_config_home_page": "主页",
|
||||||
|
"app_config_home_page_description": "用户登录后被重定向到的页面。",
|
||||||
|
"email_verification_warning": "请验证您的电子邮件地址",
|
||||||
|
"email_verification_warning_description": "您的电子邮箱尚未完成验证。请尽快完成验证。",
|
||||||
|
"email_verification": "电子邮件验证",
|
||||||
|
"email_verification_description": "在用户注册或更改电子邮件地址时向其发送验证邮件。",
|
||||||
|
"email_verification_success_title": "电子邮件验证成功",
|
||||||
|
"email_verification_success_description": "您的电子邮件地址已成功验证。",
|
||||||
|
"email_verification_error_title": "电子邮件验证失败",
|
||||||
|
"mark_as_unverified": "标记为未验证",
|
||||||
|
"mark_as_verified": "标记为已验证",
|
||||||
|
"email_verification_sent": "验证邮件已成功发送。",
|
||||||
|
"emails_verified_by_default": "电子邮件默认已验证",
|
||||||
|
"emails_verified_by_default_description": "启用后,用户的电子邮件地址将在注册时或更改电子邮件地址时默认标记为已验证。"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
"authenticator_does_not_support_resident_keys": "此驗證器不支援常駐金鑰",
|
"authenticator_does_not_support_resident_keys": "此驗證器不支援常駐金鑰",
|
||||||
"passkey_was_previously_registered": "這個密碼金鑰先前已註冊",
|
"passkey_was_previously_registered": "這個密碼金鑰先前已註冊",
|
||||||
"authenticator_does_not_support_any_of_the_requested_algorithms": "驗證器不支援任何一種所要求的演算法",
|
"authenticator_does_not_support_any_of_the_requested_algorithms": "驗證器不支援任何一種所要求的演算法",
|
||||||
"authenticator_timed_out": "驗證器逾時",
|
"webauthn_error_invalid_rp_id": "已設定的信賴方識別碼無效。",
|
||||||
|
"webauthn_error_invalid_domain": "設定的網域無效。",
|
||||||
|
"contact_administrator_to_fix": "請聯絡您的管理員以解決此問題。",
|
||||||
|
"webauthn_operation_not_allowed_or_timed_out": "此操作未獲許可或已超時",
|
||||||
|
"webauthn_not_supported_by_browser": "此瀏覽器不支援通行密鑰。請使用其他登入方式。",
|
||||||
"critical_error_occurred_contact_administrator": "發生嚴重錯誤,請聯絡您的管理員。",
|
"critical_error_occurred_contact_administrator": "發生嚴重錯誤,請聯絡您的管理員。",
|
||||||
"sign_in_to": "登入 {name}",
|
"sign_in_to": "登入 {name}",
|
||||||
"client_not_found": "找不到客戶端",
|
"client_not_found": "找不到客戶端",
|
||||||
@@ -192,8 +196,6 @@
|
|||||||
"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": "是否允許使用者編輯自己的帳號資料。",
|
||||||
"emails_verified": "已驗證的電子郵件",
|
|
||||||
"whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "是否應將使用者的電子郵件標記為已驗證,以供 OIDC 客戶端使用。",
|
|
||||||
"ldap_configuration_updated_successfully": "LDAP 設定更新成功",
|
"ldap_configuration_updated_successfully": "LDAP 設定更新成功",
|
||||||
"ldap_disabled_successfully": "LDAP 已成功停用",
|
"ldap_disabled_successfully": "LDAP 已成功停用",
|
||||||
"ldap_sync_finished": "LDAP 同步完成",
|
"ldap_sync_finished": "LDAP 同步完成",
|
||||||
@@ -472,8 +474,8 @@
|
|||||||
"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 客戶端",
|
||||||
@@ -499,5 +501,25 @@
|
|||||||
"save_and_sync": "儲存與同步",
|
"save_and_sync": "儲存與同步",
|
||||||
"scim_save_changes_description": "您必須在開始 SCIM 同步前儲存變更。現在要儲存嗎?",
|
"scim_save_changes_description": "您必須在開始 SCIM 同步前儲存變更。現在要儲存嗎?",
|
||||||
"scopes": "範圍",
|
"scopes": "範圍",
|
||||||
"issuer_url": "發行者網址"
|
"issuer_url": "發行者網址",
|
||||||
|
"smtp_field_required_when_other_provided": "當提供任何 SMTP 設定時即為必要",
|
||||||
|
"smtp_field_required_when_email_enabled": "當電子郵件通知功能啟用時,此項目為必填項目",
|
||||||
|
"renew": "更新",
|
||||||
|
"renew_api_key": "重新生成 API 金鑰",
|
||||||
|
"renew_api_key_description": "重新生成 API 金鑰將產生新的金鑰。請務必更新所有使用此金鑰的整合服務。",
|
||||||
|
"api_key_renewed": "API 金鑰已更新",
|
||||||
|
"app_config_home_page": "首頁",
|
||||||
|
"app_config_home_page_description": "用戶登入後被重定向至的頁面。",
|
||||||
|
"email_verification_warning": "請驗證您的電子郵件地址",
|
||||||
|
"email_verification_warning_description": "您的電子郵件地址尚未完成驗證。請盡快完成驗證程序。",
|
||||||
|
"email_verification": "電子郵件驗證",
|
||||||
|
"email_verification_description": "當用戶註冊或變更電子郵件地址時,向其發送驗證郵件。",
|
||||||
|
"email_verification_success_title": "電子郵件驗證成功",
|
||||||
|
"email_verification_success_description": "您的電子郵件地址已成功驗證。",
|
||||||
|
"email_verification_error_title": "電子郵件驗證失敗",
|
||||||
|
"mark_as_unverified": "標記為未驗證",
|
||||||
|
"mark_as_verified": "標記為已驗證",
|
||||||
|
"email_verification_sent": "驗證電子郵件已成功寄出。",
|
||||||
|
"emails_verified_by_default": "電子郵件預設為已驗證",
|
||||||
|
"emails_verified_by_default_description": "啟用此功能後,用戶的電子郵件地址將在註冊時或變更電子郵件地址時,預設標記為已驗證狀態。"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pocket-id-frontend",
|
"name": "pocket-id-frontend",
|
||||||
"version": "2.1.0",
|
"version": "2.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -15,49 +15,49 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@simplewebauthn/browser": "^13.2.2",
|
"@simplewebauthn/browser": "^13.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.2.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.5",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"jose": "^6.1.3",
|
"jose": "^6.1.3",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"runed": "^0.37.1",
|
"runed": "^0.37.1",
|
||||||
"sveltekit-superforms": "^2.29.1",
|
"sveltekit-superforms": "^2.30.0",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"zod": "^4.3.4"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@inlang/paraglide-js": "^2.7.1",
|
"@inlang/paraglide-js": "^2.12.0",
|
||||||
"@inlang/plugin-m-function-matcher": "^2.1.0",
|
"@inlang/plugin-m-function-matcher": "^2.2.1",
|
||||||
"@inlang/plugin-message-format": "^4.0.0",
|
"@inlang/plugin-message-format": "^4.3.0",
|
||||||
"@internationalized/date": "^3.10.1",
|
"@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.49.2",
|
"@sveltejs/kit": "^2.53.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||||
"@types/eslint": "^9.6.1",
|
"@types/eslint": "^9.6.1",
|
||||||
"@types/node": "^24.10.4",
|
"@types/node": "^24.10.13",
|
||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"bits-ui": "^2.14.4",
|
"bits-ui": "^2.16.2",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.3",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-svelte": "^3.13.1",
|
"eslint-plugin-svelte": "^3.15.0",
|
||||||
"formsnap": "^2.0.1",
|
"formsnap": "^2.0.1",
|
||||||
"globals": "^16.5.0",
|
"globals": "^16.5.0",
|
||||||
"mode-watcher": "^1.1.0",
|
"mode-watcher": "^1.1.0",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-svelte": "^3.4.1",
|
"prettier-plugin-svelte": "^3.5.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||||
"rollup": "^4.54.0",
|
"rollup": "^4.59.0",
|
||||||
"svelte": "^5.46.1",
|
"svelte": "^5.53.2",
|
||||||
"svelte-check": "^4.3.5",
|
"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",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.2.0",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.51.0",
|
"typescript-eslint": "^8.56.0",
|
||||||
"vite": "^7.3.0"
|
"vite": "^7.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
frontend/project.inlang/.gitignore
vendored
1
frontend/project.inlang/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
cache
|
|
||||||
@@ -7,12 +7,14 @@
|
|||||||
"de",
|
"de",
|
||||||
"en",
|
"en",
|
||||||
"es",
|
"es",
|
||||||
|
"et",
|
||||||
"fi",
|
"fi",
|
||||||
"fr",
|
"fr",
|
||||||
"it",
|
"it",
|
||||||
"ja",
|
"ja",
|
||||||
"ko",
|
"ko",
|
||||||
"nl",
|
"nl",
|
||||||
|
"no",
|
||||||
"pl",
|
"pl",
|
||||||
"pt-BR",
|
"pt-BR",
|
||||||
"ru",
|
"ru",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
inputClass?: string;
|
inputClass?: string;
|
||||||
type?: 'text' | 'password' | 'email' | 'number' | 'checkbox' | 'date';
|
type?: 'text' | 'password' | 'email' | 'number' | 'checkbox' | 'date' | 'url';
|
||||||
onInput?: (e: FormInputEvent) => void;
|
onInput?: (e: FormInputEvent) => void;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@@ -86,6 +86,6 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if input?.error}
|
{#if input?.error}
|
||||||
<Field.Error>{input.error}</Field.Error>
|
<Field.Error class="text-start">{input.error}</Field.Error>
|
||||||
{/if}
|
{/if}
|
||||||
</Field.Field>
|
</Field.Field>
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
oninput={(e) => (url = e.currentTarget.value)}
|
oninput={(e) => (url = e.currentTarget.value)}
|
||||||
onfocusout={handleUrlChange}
|
onfocusout={handleUrlChange}
|
||||||
aria-invalid={hasError}
|
aria-invalid={hasError}
|
||||||
|
type="url"
|
||||||
/>
|
/>
|
||||||
{#if hasError}
|
{#if hasError}
|
||||||
<p class="text-destructive mt-1 text-start text-xs">{m.invalid_url()}</p>
|
<p class="text-destructive mt-1 text-start text-xs">{m.invalid_url()}</p>
|
||||||
|
|||||||
@@ -27,10 +27,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex h-16 items-center">
|
<div class="flex h-16 items-center">
|
||||||
{#if !isAuthPage}
|
{#if !isAuthPage}
|
||||||
<a
|
<a href="/" class="flex items-center gap-3 transition-opacity hover:opacity-80">
|
||||||
href="/"
|
|
||||||
class="flex items-center gap-3 transition-opacity hover:opacity-80"
|
|
||||||
>
|
|
||||||
<Logo class="size-8" />
|
<Logo class="size-8" />
|
||||||
<h1 class="text-lg font-semibold tracking-tight" data-testid="application-name">
|
<h1 class="text-lg font-semibold tracking-tight" data-testid="application-name">
|
||||||
{$appConfigStore.appName}
|
{$appConfigStore.appName}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import Root from "./toggle.svelte";
|
import Root from './toggle.svelte';
|
||||||
export {
|
export {
|
||||||
toggleVariants,
|
toggleVariants,
|
||||||
type ToggleSize,
|
type ToggleSize,
|
||||||
type ToggleVariant,
|
type ToggleVariant,
|
||||||
type ToggleVariants,
|
type ToggleVariants
|
||||||
} from "./toggle.svelte";
|
} from './toggle.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Toggle,
|
Root as Toggle
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
<script lang="ts" module>
|
<script lang="ts" module>
|
||||||
import { type VariantProps, tv } from "tailwind-variants";
|
import { type VariantProps, tv } from 'tailwind-variants';
|
||||||
|
|
||||||
export const toggleVariants = tv({
|
export const toggleVariants = tv({
|
||||||
base: "hover:bg-muted hover:text-muted-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
base: "hover:bg-muted hover:text-muted-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-transparent",
|
default: 'bg-transparent',
|
||||||
outline:
|
outline:
|
||||||
"border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs",
|
'border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-9 min-w-9 px-2",
|
default: 'h-9 min-w-9 px-2',
|
||||||
sm: "h-8 min-w-8 px-1.5",
|
sm: 'h-8 min-w-8 px-1.5',
|
||||||
lg: "h-10 min-w-10 px-2.5",
|
lg: 'h-10 min-w-10 px-2.5'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: 'default',
|
||||||
size: "default",
|
size: 'default'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ToggleVariant = VariantProps<typeof toggleVariants>["variant"];
|
export type ToggleVariant = VariantProps<typeof toggleVariants>['variant'];
|
||||||
export type ToggleSize = VariantProps<typeof toggleVariants>["size"];
|
export type ToggleSize = VariantProps<typeof toggleVariants>['size'];
|
||||||
export type ToggleVariants = VariantProps<typeof toggleVariants>;
|
export type ToggleVariants = VariantProps<typeof toggleVariants>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Toggle as TogglePrimitive } from "bits-ui";
|
import { Toggle as TogglePrimitive } from 'bits-ui';
|
||||||
import { cn } from "$lib/utils/style.js";
|
import { cn } from '$lib/utils/style.js';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
pressed = $bindable(false),
|
pressed = $bindable(false),
|
||||||
class: className,
|
class: className,
|
||||||
size = "default",
|
size = 'default',
|
||||||
variant = "default",
|
variant = 'default',
|
||||||
...restProps
|
...restProps
|
||||||
}: TogglePrimitive.RootProps & {
|
}: TogglePrimitive.RootProps & {
|
||||||
variant?: ToggleVariant;
|
variant?: ToggleVariant;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export type User = {
|
|||||||
|
|
||||||
export type UserCreate = Omit<User, 'id' | 'customClaims' | 'ldapId' | 'userGroups'>;
|
export type UserCreate = Omit<User, 'id' | 'customClaims' | 'ldapId' | 'userGroups'>;
|
||||||
|
|
||||||
export type AccountUpdate = Omit<UserCreate, 'isAdmin' | 'disabled' | 'emailVerified'>
|
export type AccountUpdate = Omit<UserCreate, 'isAdmin' | 'disabled' | 'emailVerified'>;
|
||||||
|
|
||||||
export type UserSignUp = Omit<
|
export type UserSignUp = Omit<
|
||||||
UserCreate,
|
UserCreate,
|
||||||
|
|||||||
@@ -9,14 +9,17 @@ export function getAuthRedirectPath(url: URL, user: User | null) {
|
|||||||
|
|
||||||
const isUnauthenticatedOnlyPath =
|
const isUnauthenticatedOnlyPath =
|
||||||
path == '/login' ||
|
path == '/login' ||
|
||||||
path.startsWith('/login/') ||
|
(path.startsWith('/login/') && path != '/login/alternative/code') ||
|
||||||
path == '/lc' ||
|
path == '/lc' ||
|
||||||
path.startsWith('/lc/') ||
|
|
||||||
path == '/signup' ||
|
path == '/signup' ||
|
||||||
path == '/signup/setup' ||
|
path == '/signup/setup' ||
|
||||||
path == '/setup' ||
|
path == '/setup' ||
|
||||||
path.startsWith('/st/');
|
path.startsWith('/st/');
|
||||||
const isPublicPath = ['/authorize', '/device', '/health', '/healthz'].includes(path);
|
|
||||||
|
const isPublicPath =
|
||||||
|
path.startsWith('/lc/') ||
|
||||||
|
['/authorize', '/login/alternative/code', '/device', '/health', '/healthz'].includes(path);
|
||||||
|
|
||||||
const isAdminPath = path == '/settings/admin' || path.startsWith('/settings/admin/');
|
const isAdminPath = path == '/settings/admin' || path.startsWith('/settings/admin/');
|
||||||
|
|
||||||
if (!isUnauthenticatedOnlyPath && !isPublicPath && !isSignedIn) {
|
if (!isUnauthenticatedOnlyPath && !isPublicPath && !isSignedIn) {
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ export const load: LayoutLoad = async () => {
|
|||||||
let isUpToDate = true;
|
let isUpToDate = true;
|
||||||
try {
|
try {
|
||||||
newestVersion = await versionService.getNewestVersion();
|
newestVersion = await versionService.getNewestVersion();
|
||||||
isUpToDate = newestVersion === currentVersion;
|
// If newestVersion is empty, it means the check is disabled or failed.
|
||||||
} catch {}
|
// In this case, we assume the version is up to date.
|
||||||
|
isUpToDate = newestVersion === '' || newestVersion === currentVersion;
|
||||||
|
} catch {
|
||||||
|
// If the request fails, assume up-to-date to avoid showing a warning.
|
||||||
|
isUpToDate = true;
|
||||||
|
}
|
||||||
|
|
||||||
const versionInformation: AppVersionInformation = {
|
const versionInformation: AppVersionInformation = {
|
||||||
currentVersion: versionService.getCurrentVersion(),
|
currentVersion: versionService.getCurrentVersion(),
|
||||||
|
|||||||
@@ -14,12 +14,14 @@
|
|||||||
de: 'Deutsch',
|
de: 'Deutsch',
|
||||||
en: 'English',
|
en: 'English',
|
||||||
es: 'Español',
|
es: 'Español',
|
||||||
|
et: 'Eesti',
|
||||||
fi: 'Suomi',
|
fi: 'Suomi',
|
||||||
fr: 'Français',
|
fr: 'Français',
|
||||||
it: 'Italiano',
|
it: 'Italiano',
|
||||||
ja: '日本語',
|
ja: '日本語',
|
||||||
ko: '한국어',
|
ko: '한국어',
|
||||||
nl: 'Nederlands',
|
nl: 'Nederlands',
|
||||||
|
no: 'Norsk',
|
||||||
pl: 'Polski',
|
pl: 'Polski',
|
||||||
'pt-BR': 'Português brasileiro',
|
'pt-BR': 'Português brasileiro',
|
||||||
ru: 'Русский',
|
ru: 'Русский',
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<Input
|
<Input
|
||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
data-testid={`callback-url-${i + 1}`}
|
data-testid={`callback-url-${i + 1}`}
|
||||||
|
type="url"
|
||||||
bind:value={callbackURLs[i]}
|
bind:value={callbackURLs[i]}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -181,6 +181,7 @@
|
|||||||
label={m.client_launch_url()}
|
label={m.client_launch_url()}
|
||||||
description={m.client_launch_url_description()}
|
description={m.client_launch_url_description()}
|
||||||
class="w-full"
|
class="w-full"
|
||||||
|
type="url"
|
||||||
bind:input={$inputs.launchURL}
|
bind:input={$inputs.launchURL}
|
||||||
/>
|
/>
|
||||||
<OidcCallbackUrlInput
|
<OidcCallbackUrlInput
|
||||||
|
|||||||
@@ -48,10 +48,10 @@
|
|||||||
try {
|
try {
|
||||||
await userService.remove(user.id);
|
await userService.remove(user.id);
|
||||||
await refresh();
|
await refresh();
|
||||||
|
toast.success(m.user_deleted_successfully());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
axiosErrorToast(e);
|
axiosErrorToast(e);
|
||||||
}
|
}
|
||||||
toast.success(m.user_deleted_successfully());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,5 +12,5 @@
|
|||||||
"test": "pnpm --filter pocket-id-tests test",
|
"test": "pnpm --filter pocket-id-tests test",
|
||||||
"format": "pnpm --filter pocket-id-frontend format"
|
"format": "pnpm --filter pocket-id-frontend format"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|
"packageManager": "pnpm@10.30.1+sha512.3590e550d5384caa39bd5c7c739f72270234b2f6059e13018f975c313b1eb9fefcc09714048765d4d9efe961382c312e624572c0420762bdc5d5940cdf9be73a"
|
||||||
}
|
}
|
||||||
|
|||||||
1670
pnpm-lock.yaml
generated
1670
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,11 @@ packages:
|
|||||||
- email-templates
|
- email-templates
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
cookie@<0.7.0: '>=0.7.0'
|
cookie@<0.7.0: ">=0.7.0"
|
||||||
devalue: ^5.3.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'
|
valibot@>=0.31.0 <1.2.0: ">=1.2.0"
|
||||||
validator@<13.15.20: '>=13.15.20'
|
validator@<13.15.20: ">=13.15.20"
|
||||||
|
"@isaacs/brace-expansion": ">=5.0.1"
|
||||||
|
next: ">=16.1.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user