Merge remote-tracking branch 'origin/develop' into TestImprovements

This commit is contained in:
Keith Martin 2025-12-10 20:48:47 +10:00
commit 6fd45a0940
787 changed files with 20740 additions and 15486 deletions

View file

@ -59,7 +59,7 @@ compose.*.yaml
__pycache__
venv
.venv
.env
.env*
.tmp
.nv
.eslintcache

20
.editorconfig Normal file
View file

@ -0,0 +1,20 @@
# Top-most EditorConfig file, https://editorconfig.org
root = true
# Use Unix-style newlines with a newline ending every file.
[*]
end_of_line = lf
insert_final_newline = false
# Set rules by file type.
[*.json]
indent_style = space
indent_size = 2
[*.{js,yaml,yml,md,txt}]
charset = utf-8
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab

2
.gitignore vendored
View file

@ -27,7 +27,7 @@
__pycache__
venv
.venv
.env
.env*
.tmp
.nv
.eslintcache

View file

@ -6,16 +6,9 @@ build/
dist/
bin/
tests/upload-files/
.tmp
.gocache
.var
*.html
*.md
.*
.idea
.codex
.local
.config
.github
.tmp
.local
.cache
.gocache
.var

103
AGENTS.md
View file

@ -1,11 +1,10 @@
# PhotoPrism® Repository Guidelines
# PhotoPrism® Repository Guidelines
**Last Updated:** November 21, 2025
**Last Updated:** December 8, 2025
## Purpose
This file tells automated coding agents (and humans) where to find the single sources of truth for building, testing, and contributing to PhotoPrism.
Learn more: https://agents.md/
This file tells automated coding agents (and humans) where to find the single sources of truth for building, testing, and contributing to this repository. Visit https://agents.md/ to learn more.
## Sources of Truth
@ -16,32 +15,44 @@ Learn more: https://agents.md/
- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
- REST API: https://docs.photoprism.dev/ (Swagger), https://docs.photoprism.app/developer-guide/api/ (Docs)
- Code Maps: [`CODEMAP.md`](CODEMAP.md) (Backend/Go), [`frontend/CODEMAP.md`](frontend/CODEMAP.md) (Frontend/JS)
- Face Detection & Embeddings Notes: [`internal/ai/face/README.md`](internal/ai/face/README.md)
- Vision Engine Guides: [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md), [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md)
- Packages: `README.md` files under `internal/`, `pkg/`, and `frontend/src/`, e.g. [`internal/photoprism/README.md`](internal/photoprism/README.md), [`internal/photoprism/batch/README.md`](internal/photoprism/batch/README.md), [`internal/config/README.md`](internal/config/README.md), [`internal/server/README.md`](internal/server/README.md), [`internal/api/README.md`](internal/api/README.md), [`internal/thumb/README.md`](internal/thumb/README.md), [`internal/ffmpeg/README.md`](internal/ffmpeg/README.md), and [`frontend/src/common/README.md`](frontend/src/common/README.md).
- Face Detection & Embeddings: [`internal/ai/face/README.md`](internal/ai/face/README.md)
- Vision Config & Engines: [`internal/ai/vision/README.md`](internal/ai/vision/README.md), [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md), [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md)
> Quick Tip: to inspect GitHub issue details without leaving the terminal, run `curl -s https://api.github.com/repos/photoprism/photoprism/issues/<id>`.
### Specifications (Versioning & Usage)
### Specifications, Versioning, & Writing Style
- In the main repo, `specs/` appears ignored because it is managed as a nested Git repository; change into `specs/` before staging or committing spec updates.
- Availability: The `specs/` repository is private and is not guaranteed to be present in every clone or environment. Do not add `Makefile` targets in the main project that depend on `specs/` paths. When `specs/` is available, run its tools directly (e.g., `bash specs/scripts/lint-status.sh`).
- If available, always use the latest spec version for a topic (highest `-vN`), as linked from `specs/README.md`.
- Testing Guides: `specs/dev/backend-testing.md` (Backend/Go), `specs/dev/frontend-testing.md` (Frontend/JS)
- Whenever the Change Management instructions for a document require it, publish changes as a new file with an incremented version suffix (e.g., `*-v3.md`) rather than overwriting the original file.
- Older spec versions remain in the repo for historical reference but are not linked from the main TOC. Do not base new work on superseded files (e.g., `*-v1.md` when `*-v2.md` exists).
- Auto-generated configuration and command references live under `specs/generated/`. Agents MUST NOT read, analyse, or modify anything in this directory; refer humans to `specs/generated/README.md` if regeneration is required.
- Regenerate NOTICE files with `make notice` when dependencies change. Do not edit `NOTICE` or `frontend/NOTICE` manually.
- In the main repo, `specs/` and other directories may appear to be ignored because they are nested Git repositories; if so, change directories before staging or committing updates.
- Availability: The `specs/` repository is private and is not guaranteed to be present in every clone or environment. Do not add `Makefile` targets in the main project that depend on `specs/` paths. When `specs/` is available, you MAY run its tools manually (e.g., `bash specs/scripts/lint-status.sh`), but the main repo must remain buildable without `specs/`.
- If available, always use the latest spec version for a topic (highest `-vN`), as linked from `specs/README.md`.
- Testing Guides: `specs/dev/backend-testing.md` (Backend/Go), `specs/dev/frontend-testing.md` (Frontend/JS)
- Whenever the Change Management instructions for a document require it, publish changes as a new file with an incremented version suffix (e.g., `*-v3.md`) rather than overwriting the original file.
- Older spec versions remain in the repo for historical reference but are not linked from the main TOC. Do not base new work on superseded files (e.g., `*-v1.md` when `*-v2.md` exists).
- Auto-generated configuration and command references live under `specs/generated/`. Agents MUST NOT read, analyse, or modify anything in this directory; refer humans to `specs/generated/README.md` if regeneration is required.
- Regenerate `NOTICE` files with `make notice` when dependencies change (e.g., updates to `go.mod`, `go.sum`, `package-lock.json`, or other lockfiles). Do not edit `NOTICE` or `frontend/NOTICE` manually.
- When writing CLI examples or scripts, place option flags before positional arguments unless the command requires a different order.
**Style note:** Document headings must use Title Case (capitalize words ≥4 letters in AP-style) across Markdown files to keep generated navigation and changelogs consistent.
> Document headings must use **Title Case** (in APA or AP style) across Markdown files to keep generated navigation and changelogs consistent. Always spell the product name as `PhotoPrism`; this proper noun is an exception to generic naming rules.
**CLI note:** When writing CLI examples or scripts, place option flags before positional arguments unless the command requires a different order.
## Safety & Data
- If `git status` shows unexpected changes, assume a human might be editing; if you think you caused them, ask for permission before using reset commands like `git checkout` or `git reset`.
- Do not run `git config` (global or repo-level); changing Git configuration is prohibited for agents.
- Do not run destructive commands against production data. Prefer ephemeral volumes and test fixtures for acceptance tests.
- Never commit secrets, local configurations, or cache files. Use environment variables or a local `.env`.
- Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are ignored in `.gitignore` and `.dockerignore`.
- Prefer using existing caches, workers, and batching strategies referenced in code and `Makefile`.
- Consider memory/CPU impact of changes; only suggest benchmarks or profiling when justified.
> If anything in this file conflicts with the `Makefile` or Sources of Truth, **ask** for clarification before proceeding.
## Project Structure & Languages
- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
- Package boundaries: Code in `pkg/*` MUST NOT import from `internal/*`.
- If you need access to config/entity/DB, put new code in a package under `internal/` instead of `pkg/`.
- GORM field naming: When adding struct fields that include uppercase abbreviations (e.g., `LabelNSFW`), set an explicit `gorm:"column:<name>"` tag so column names stay consistent (`label_nsfw` instead of `label_n_s_f_w`).
- GORM field naming: When adding struct fields that include uppercase abbreviations (e.g., `LabelNSFW`, `UserID`, `URLHash`), set an explicit `gorm:"column:<name>"` tag so column names stay consistent (`label_nsfw`, `user_id`, `url_hash` instead of split-letter variants).
- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
- Docker/compose for dev/CI; Traefik is used for local TLS (`*.localssl.dev`)
@ -64,16 +75,15 @@ Agents MAY run either:
Agents SHOULD detect the runtime and choose commands accordingly:
- **Inside container if** one of the following is true:
- File exists: `/.dockerenv`
- Project path equals (or is a direct child of): `/go/src/github.com/photoprism/photoprism`
- **Inside container if** `/.dockerenv` exists (authoritative signal).
- Path hint: when the project path is `/go/src/github.com/photoprism/photoprism` *and* `/.dockerenv` is absent, assume you are on the host with a bind mount; treat it as host mode and prefer host-side Docker commands.
#### Examples
Bash:
```bash
if [ -f "/.dockerenv" ] || [ -d "/go/src/github.com/photoprism/photoprism/.git" ]; then
if [ -f "/.dockerenv" ]; then
echo "container"
else
echo "host"
@ -85,8 +95,7 @@ Node.js:
```js
const fs = require("fs");
const inContainer = fs.existsSync("/.dockerenv");
const inDevPath = fs.existsSync("/go/src/github.com/photoprism/photoprism/.git");
console.log(inContainer || inDevPath ? "container" : "host");
console.log(inContainer ? "container" : "host");
```
### Agent installation and invocation
@ -132,10 +141,29 @@ console.log(inContainer || inDevPath ? "container" : "host");
- Only if Traefik is running and the dev compose labels are active
- Labels for `*.localssl.dev` are defined in the dev compose files, e.g. https://github.com/photoprism/photoprism/blob/develop/compose.yaml
- Admin Login: Local compose files set `PHOTOPRISM_ADMIN_USER=admin` and `PHOTOPRISM_ADMIN_PASSWORD=photoprism`; if the credentials differ, inspect `compose.yaml` (or the active environment) for these variables before logging in.
- Do not use the Docker CLI inside the container; starting/stopping services requires host Docker access.
- Do not use the Docker CLI inside the container; starting/stopping services requires host Docker access. If you need to manage compose while inside the dev container, switch to host mode (or ask a human) instead of running `docker compose` there.
Note: Across our public documentation, official images, and in production, the command-line interface (CLI) name is `photoprism`. Other PhotoPrism binary names are only used in development builds for side-by-side comparisons of the Community Edition (CE) with PhotoPrism Plus (`photoprism-plus`) and PhotoPrism Pro (`photoprism-pro`).
### Operating Systems & Architectures
- Our guides and command examples generally assume the use of a Linux/Unix shell on a 64-bit AMD64 or ARM64 system.
- For Windows-specifics, see the Developer Guide FAQ: https://docs.photoprism.app/developer-guide/faq/#can-your-development-environment-be-used-under-windows
## Code Style & Lint
- Go: run `make fmt-go swag-fmt` to reformat the backend code + Swagger annotations (see `Makefile` for additional targets)
- Run `make lint-go` (golangci-lint) after Go changes; prefer `golangci-lint run ./internal/<pkg>/...` for focused edits.
- Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period.
- All newly added functions, including unexported helpers, must have a concise doc comment that explains their behavior.
- For short examples inside comments, indent code rather than using backticks; godoc treats indented blocks as preformatted.
- Branding: Always spell the product name as `PhotoPrism`; this proper noun is an exception to generic naming rules.
- Every Go package must contain a `<package>.go` file in its root (for example, `internal/auth/jwt/jwt.go`) with the standard license header and a short package description comment explaining its purpose.
- JS/Vue: use the lint/format scripts in `frontend/package.json` (ESLint + Prettier)
- All added code and tests **must** be formatted according to our standards.
> Remember to update the `**Last Updated:**` line at the top whenever you edit these guidelines or other files containing a timestamp.
## Tests
- From within the Development Environment:
@ -209,19 +237,6 @@ Note: Across our public documentation, official images, and in production, the c
- `config.NewTestConfig("<pkg>")` defaults to SQLite with a persuite DSN like `.<pkg>.db`. Dont assert an empty DSN for SQLite.
- Clean up any persuite SQLite files in tests with `t.Cleanup(func(){ _ = os.Remove(dsn) })` if you capture the DSN.
## Code Style & Lint
- Go: run `make fmt-go swag-fmt` to reformat the backend code + Swagger annotations (see `Makefile` for additional targets)
- Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period.
- All newly added functions, including unexported helpers, must have a concise doc comment that explains their behavior.
- For short examples inside comments, indent code rather than using backticks; godoc treats indented blocks as preformatted.
- Branding: Always spell the product name as `PhotoPrism`; this proper noun is an exception to generic naming rules.
- Every Go package must contain a `<package>.go` file in its root (for example, `internal/auth/jwt/jwt.go`) with the standard license header and a short package description comment explaining its purpose.
- JS/Vue: use the lint/format scripts in `frontend/package.json` (ESLint + Prettier)
- All added code and tests **must** be formatted according to our standards.
> Remember to update the `**Last Updated:**` line at the top whenever you edit these guidelines or other files containing a timestamp.
### Frontend Focus Management
- Dialogs must follow the shared focus pattern documented in `frontend/src/common/README.md`.
@ -230,15 +245,6 @@ Note: Across our public documentation, official images, and in production, the c
- Global shortcuts run through `onShortCut(ev)` in `common/view.js`; it only forwards Escape and `ctrl`/`meta` combinations, so do not rely on it for arbitrary keys.
- When a dialog opens nested menus (for example, combobox suggestion lists), ensure they work with the global trap; see the README for troubleshooting tips.
## Safety & Data
- Never commit secrets, local configurations, or cache files. Use environment variables or a local `.env`.
- Ensure `.env` and `.local` are ignored in `.gitignore` and `.dockerignore`.
- Prefer using existing caches, workers, and batching strategies referenced in code and `Makefile`. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
- Do not run destructive commands against production data. Prefer ephemeral volumes and test fixtures when running acceptance tests.
> If anything in this file conflicts with the `Makefile` or the Developer Guide, the `Makefile` and the documentation win. When unsure, **ask** for clarification before proceeding.
### Filesystem Permissions & io/fs Aliasing (Go)
- Always use our shared permission variables from `pkg/fs` when creating files/directories:
@ -278,9 +284,6 @@ Note: Across our public documentation, official images, and in production, the c
- `..` traversal skipped; `__MACOSX` skipped.
- Per-file and total size limits enforced; directory entries created; nested paths extracted safely.
- Examples assume a Linux/Unix shell. For Windows specifics, see the Developer Guide FAQ:
https://docs.photoprism.app/developer-guide/faq/#can-your-development-environment-be-used-under-windows
### HTTP Download — Security Checklist
- Use the shared safe HTTP helper instead of adhoc `net/http` code:

View file

@ -1,6 +1,6 @@
PhotoPrism — Backend CODEMAP
**Last Updated:** November 21, 2025
**Last Updated:** November 22, 2025
Purpose
- Give agents and contributors a fast, reliable map of where things live and how they fit together, so you can add features, fix bugs, and write tests without spelunking.
@ -40,8 +40,8 @@ High-Level Package Map (Go)
- `internal/workers` — background schedulers (index, vision, sync, meta, backup)
- `internal/auth` — ACL, sessions, OIDC
- `internal/service` — cluster/portal, maps, hub, webdav
- `internal/event` — logging, pub/sub, audit; canonical outcome tokens live in `pkg/log/status` (use helpers like `status.Error(err)` when the sanitized message should be the outcome)
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination
- `internal/event` — logging, pub/sub, audit; canonical outcome tokens live in `pkg/log/status` (use helpers like `status.Error(err)` when the sanitized message should be the outcome). Docs: `internal/event/README.md`.
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination. Docs: `internal/ffmpeg/README.md`, `internal/meta/README.md`.
- `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/clean`, `pkg/enum`, `pkg/fs`, `pkg/txt`, `pkg/http/header`
Templates & Static Assets
@ -81,6 +81,10 @@ Configuration & Flags
- ACL/mode aware: Values are filtered by user/session and may differ for public vs. authenticated users.
- Dont expose secrets: Treat it as client-visible; avoid sensitive data. To add fields, extend client values via `config.Register` rather than exposing Options directly.
- Refresh cadence: The web UI (nonmobile) also polls for updates every 10 minutes via `$config.update()` in `frontend/src/app.js`, complementing the websocket push.
- OIDC Groups (Pro-Only)
- Config options (tagged `pro`, flags hidden in CE): `oidc-group-claim` (default `groups`), `oidc-group` (required membership list), `oidc-group-role` (mapping `GROUP=ROLE`).
- Parsing/helpers: `internal/auth/oidc/groups.go` normalizes IDs, detects Entra `_claim_names` overage, maps groups→roles, and enforces required membership in `internal/api/oidc_redirect.go`.
- Overage: if `_claim_names.groups` is present and no groups are returned, login fails when required groups are configured; Graph fetch is not implemented yet.
Database & Migrations
- Driver: GORM v1 (`github.com/jinzhu/gorm`). No `WithContext`. Use `db.Raw(stmt).Scan(&nop)` for raw SQL.

View file

@ -1,5 +1,5 @@
# Ubuntu 25.10 (Questing Quokka)
FROM photoprism/develop:251121-questing
FROM photoprism/develop:251208-questing
# Harden npm usage by default (applies to npm ci / install in dev container)
ENV NPM_CONFIG_IGNORE_SCRIPTS=true

View file

@ -99,7 +99,7 @@ show-rev:
show-build:
@echo "$(BUILD_TAG)"
test-all: test acceptance-run-chromium
fmt: fmt-js fmt-go swag-fmt
fmt: fmt-js fmt-go fmt-swag
clean-local: clean-local-config clean-local-cache
upgrade: dep-upgrade-js dep-upgrade
devtools: install-go dep-npm
@ -670,18 +670,18 @@ docker-preview-oracular:
docker pull --platform=arm64 photoprism/develop:oracular
docker pull --platform=arm64 photoprism/develop:oracular-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /oracular
docker-preview-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /questing "-t photoprism/photoprism:preview -t photoprism/photoprism:ubuntu"
docker-preview-plucky:
docker pull --platform=amd64 photoprism/develop:plucky
docker pull --platform=amd64 photoprism/develop:plucky-slim
docker pull --platform=arm64 photoprism/develop:plucky
docker pull --platform=arm64 photoprism/develop:plucky-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /plucky
docker-preview-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /questing
release: docker-release
docker-release: docker-release-latest
docker-release-all: docker-release-latest docker-release-other
@ -752,18 +752,18 @@ docker-release-oracular:
docker pull --platform=arm64 photoprism/develop:oracular
docker pull --platform=arm64 photoprism/develop:oracular-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /oracular
docker-release-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /questing "-t photoprism/photoprism:latest -t photoprism/photoprism:ubuntu"
docker-release-plucky:
docker pull --platform=amd64 photoprism/develop:plucky
docker pull --platform=amd64 photoprism/develop:plucky-slim
docker pull --platform=arm64 photoprism/develop:plucky
docker pull --platform=arm64 photoprism/develop:plucky-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /plucky
docker-release-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /questing
start-traefik:
$(DOCKER_COMPOSE) up -d --wait traefik
stop-traefik:
@ -949,6 +949,7 @@ fmt-go:
go fmt ./pkg/... ./internal/... ./cmd/... ./.../internal/...
gofmt -w -s pkg internal cmd
goimports -w -local "github.com/photoprism" pkg internal cmd
fmt-swag: swag-fmt
tidy:
go mod tidy
users:

62
NOTICE
View file

@ -9,7 +9,7 @@ The following 3rd-party software packages may be used by or distributed with
PhotoPrism. Any information relevant to third-party vendors listed below are
collected using common, reasonable means.
Date generated: 2025-11-12
Date generated: 2025-12-10
================================================================================
@ -581,7 +581,7 @@ SOFTWARE.
Package: github.com/dsoprea/go-exif/v3
Version: v3.0.1
License: MIT (https://github.com/dsoprea/go-exif/blob/v3.0.1/v3/LICENSE)
License: MIT (https://github.com/dsoprea/go-exif/blob/v3.0.1/LICENSE)
MIT LICENSE
@ -641,7 +641,7 @@ SOFTWARE.
Package: github.com/dsoprea/go-jpeg-image-structure/v2
Version: v2.0.0-20221012074422-4f3f7e934102
License: MIT (https://github.com/dsoprea/go-jpeg-image-structure/blob/4f3f7e934102/v2/LICENSE)
License: MIT (https://github.com/dsoprea/go-jpeg-image-structure/blob/4f3f7e934102/LICENSE)
MIT LICENSE
@ -717,7 +717,7 @@ SOFTWARE.
Package: github.com/dsoprea/go-png-image-structure/v2
Version: v2.0.0-20210512210324-29b889a6093d
License: MIT (https://github.com/dsoprea/go-png-image-structure/blob/29b889a6093d/v2/LICENSE)
License: MIT (https://github.com/dsoprea/go-png-image-structure/blob/29b889a6093d/LICENSE)
MIT LICENSE
@ -733,7 +733,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
Package: github.com/dsoprea/go-tiff-image-structure/v2
Version: v2.0.0-20221003165014-8ecc4f52edca
License: MIT (https://github.com/dsoprea/go-tiff-image-structure/blob/8ecc4f52edca/v2/LICENSE)
License: MIT (https://github.com/dsoprea/go-tiff-image-structure/blob/8ecc4f52edca/LICENSE)
MIT License
@ -1206,8 +1206,8 @@ THE SOFTWARE.
--------------------------------------------------------------------------------
Package: github.com/go-co-op/gocron/v2
Version: v2.18.0
License: MIT (https://github.com/go-co-op/gocron/blob/v2.18.0/LICENSE)
Version: v2.18.2
License: MIT (https://github.com/go-co-op/gocron/blob/v2.18.2/LICENSE)
MIT License
@ -2443,8 +2443,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
--------------------------------------------------------------------------------
Package: github.com/golang/geo
Version: v0.0.0-20251111181513-e7f3a1a58fb3
License: Apache-2.0 (https://github.com/golang/geo/blob/e7f3a1a58fb3/LICENSE)
Version: v0.0.0-20251209161508-25c597310d4b
License: Apache-2.0 (https://github.com/golang/geo/blob/25c597310d4b/LICENSE)
Apache License
@ -5325,8 +5325,8 @@ License: Apache-2.0 (https://github.com/prometheus/client_model/blob/v0.6.2/LICE
--------------------------------------------------------------------------------
Package: github.com/prometheus/common
Version: v0.67.2
License: Apache-2.0 (https://github.com/prometheus/common/blob/v0.67.2/LICENSE)
Version: v0.67.4
License: Apache-2.0 (https://github.com/prometheus/common/blob/v0.67.4/LICENSE)
Apache License
Version 2.0, January 2004
@ -6376,8 +6376,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
Package: github.com/yalue/onnxruntime_go
Version: v1.22.0
License: MIT (https://github.com/yalue/onnxruntime_go/blob/v1.22.0/LICENSE)
Version: v1.24.0
License: MIT (https://github.com/yalue/onnxruntime_go/blob/v1.24.0/LICENSE)
Copyright (c) 2023 Nathan Otterness
@ -6610,8 +6610,8 @@ License: Apache-2.0 (https://github.com/zitadel/logging/blob/v0.6.2/LICENSE)
--------------------------------------------------------------------------------
Package: github.com/zitadel/oidc/v3
Version: v3.45.0
License: Apache-2.0 (https://github.com/zitadel/oidc/blob/v3.45.0/LICENSE)
Version: v3.45.1
License: Apache-2.0 (https://github.com/zitadel/oidc/blob/v3.45.1/LICENSE)
Apache License
Version 2.0, January 2004
@ -8188,8 +8188,8 @@ License: Apache-2.0 (https://github.com/go4org/go4/blob/214862532bf5/LICENSE)
--------------------------------------------------------------------------------
Package: golang.org/x/crypto
Version: v0.44.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/crypto/+/v0.44.0:LICENSE)
Version: v0.46.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/crypto/+/v0.46.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8222,8 +8222,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/image
Version: v0.33.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/image/+/v0.33.0:LICENSE)
Version: v0.34.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/image/+/v0.34.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8256,8 +8256,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/mod/semver
Version: v0.30.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/mod/+/v0.30.0:LICENSE)
Version: v0.31.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/mod/+/v0.31.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8290,8 +8290,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/net
Version: v0.47.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/net/+/v0.47.0:LICENSE)
Version: v0.48.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/net/+/v0.48.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8324,8 +8324,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/oauth2
Version: v0.32.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/oauth2/+/v0.32.0:LICENSE)
Version: v0.33.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/oauth2/+/v0.33.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8358,8 +8358,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/sync/errgroup
Version: v0.18.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sync/+/v0.18.0:LICENSE)
Version: v0.19.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8392,8 +8392,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/sys
Version: v0.38.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sys/+/v0.38.0:LICENSE)
Version: v0.39.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sys/+/v0.39.0:LICENSE)
Copyright 2009 The Go Authors.
@ -8426,8 +8426,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/text
Version: v0.31.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/text/+/v0.31.0:LICENSE)
Version: v0.32.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/text/+/v0.32.0:LICENSE)
Copyright 2009 The Go Authors.

122
assets/profiles/icc/NOTICE Normal file
View file

@ -0,0 +1,122 @@
================================================================================
================================================================================
Third-Party ICC Profiles for PhotoPrism
--------------------------------------------------------------------------------
The following 3rd-party ICC profiles may be used by or distributed with
PhotoPrism. Any information relevant to third-party vendors listed below are
collected using common, reasonable means.
Date generated: 2025-11-23
--------------------------------------------------------------------------------
Files: a98.icc (compatibleWithAdobeRGB1998.icc)
Source: OpenICC "compatibleWithAdobeRGB1998.icc" via Debian icc-profiles-free
URL: https://salsa.debian.org/debian/icc-profiles-free/-/blob/a7a3c11b8a6d3bc2937447183b87dc89de9d2388/icc-profiles-openicc/default_profiles/base/compatibleWithAdobeRGB1998.icc
License: zlib/libpng
Checksum (md5): 826a1e13374e3dc34f9872f31ec028c8
The zlib/libpng License
Copyright (c) Graeme Gill <graeme@argyllcms.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
The provided ICC Profiles in the package are called DATA in the following
statement:
NO WARRANTY
BECAUSE THE DATA IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE DATA, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE DATA "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE DATA IS WITH YOU. SHOULD THE
DATA PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE DATA AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE DATA (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE DATA TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
--------------------------------------------------------------------------------
Files: adobecompat-v2.icc, adobecompat-v4.icc, applecompat-v2.icc, applecompat-v4.icc, cgats001compat-v2-micro.icc, colormatchcompat-v2.icc, colormatchcompat-v4.icc, dci-p3-v4.icc, displayp3-v2-magic.icc, displayp3-v2-micro.icc, displayp3-v4.icc, displayp3compat-v2-magic.icc, displayp3compat-v2-micro.icc, displayp3compat-v4.icc, prophoto-v2-magic.icc, prophoto-v2-micro.icc, prophoto-v4.icc, rec2020-g24-v4.icc, rec2020-v2-magic.icc, rec2020-v2-micro.icc, rec2020-v4.icc, rec2020compat-v2-magic.icc, rec2020compat-v2-micro.icc, rec2020compat-v4.icc, rec601ntsc-v2-magic.icc, rec601ntsc-v2-micro.icc, rec601ntsc-v4.icc, rec601pal-v2-magic.icc, rec601pal-v2-micro.icc, rec601pal-v4.icc, rec709-v2-magic.icc, rec709-v2-micro.icc, rec709-v4.icc, scrgb-v2.icc, sgrey-v2-magic.icc, sgrey-v2-micro.icc, sgrey-v2-nano.icc, sgrey-v4.icc, srgb-v2-magic.icc, srgb-v2-micro.icc, srgb-v2-nano.icc, srgb-v4.icc, widegamutcompat-v2.icc, widegamutcompat-v4.icc
Source: Compact-ICC-Profiles via Debian icc-profiles-free
URL: https://salsa.debian.org/debian/icc-profiles-free/-/tree/a7a3c11b8a6d3bc2937447183b87dc89de9d2388/Compact-ICC-Profiles/profiles
License: CC0-1.0 (Public Domain Dedication)
Checksums (md5):
adobecompat-v2.icc 08220aa4b4e4259ec3c446a35197d89b
adobecompat-v4.icc fbf912760a8d14e496ff389c29c3132d
applecompat-v2.icc 21453c734d9364abceacc7ab837019ec
applecompat-v4.icc fc399558e27a0d53748820cff2a98a2b
cgats001compat-v2-micro.icc 56a85233ee08fa7527875be36cf426d6
colormatchcompat-v2.icc 9f2a755b4b3069f46f4eaef11e24926d
colormatchcompat-v4.icc 9e119efb0abaa31e955f8a30eeabc58c
dci-p3-v4.icc bdedf9e7ad0b93ed8f85f8c3ebdc4223
displayp3-v2-magic.icc 6748fcfd56d38770a02c023bbd6d0529
displayp3-v2-micro.icc 2615293123ddc4366af3da39455c3d7a
displayp3-v4.icc 32dc35d6a113b86cbc31bd1281e3baed
displayp3compat-v2-magic.icc 05fb82a702e27438ecec47a2f120cdcd
displayp3compat-v2-micro.icc 2ef6c295ac5d05760c1a4cf1668951a3
displayp3compat-v4.icc c34c90451326b183916f05b3ae41d920
prophoto-v2-magic.icc 15a31d407cf35662fbe4513f6204bfdf
prophoto-v2-micro.icc 445c1a3f3f1a20aab68e76838d3ed334
prophoto-v4.icc 8f4523255234753cd2d3111d8f09b184
rec2020-g24-v4.icc 3c7afbfff612d10a10775c167d36b51e
rec2020-v2-magic.icc 3b5846fb69faa53ebdfd29061f17b0e3
rec2020-v2-micro.icc 13d1e96875c35f7d5ebaf0f6a3d16357
rec2020-v4.icc 297c644758a979abe62349ca1ff416d5
rec2020compat-v2-magic.icc 9aa85534e81c275bc0627badf157580a
rec2020compat-v2-micro.icc fa39fc95daece7dcaff18e7265082368
rec2020compat-v4.icc 66839229639bb55bc443b490fe302364
rec601ntsc-v2-magic.icc 53ee12707ac87a8e3b3452af4a325e29
rec601ntsc-v2-micro.icc af05afec2146917a67445ac6cb5ca61d
rec601ntsc-v4.icc cc57dd6fa3d6f08e43e0f70b5376c00a
rec601pal-v2-magic.icc f706fd528cedcd1c88dac50073112f94
rec601pal-v2-micro.icc d193e01949eb5347b0d16d2b3ccdabcf
rec601pal-v4.icc dd7cd61d6ee14a521c9fb5afa2803e8e
rec709-v2-magic.icc 47f09046656a2f0d66117a9c1b15e137
rec709-v2-micro.icc f91edc9f3ff1390c842bd9e8759688b0
rec709-v4.icc 0339e2a70940aefd9237311889d065e6
scrgb-v2.icc a841263101bdf48fb9b81486f5451f2d
sgrey-v2-magic.icc ef6221686b517e4665480639202dacd5
sgrey-v2-micro.icc ca08451dba57ca1e910330cda37515ad
sgrey-v2-nano.icc 57d72e3f6437d65c618ebcdb1f6fa1bd
sgrey-v4.icc b93b1e31e75243ea08fbdab9e82f7cbe
srgb-v2-magic.icc 5967f401f9a54913a283942710cef93c
srgb-v2-micro.icc e8de3a5b44d70610306b0a20225701d1
srgb-v2-nano.icc e060a57b7a057f7f0bdb859b68db60e9
srgb-v4.icc 3c6a277ddee033ad090ba22b8323dcaf
widegamutcompat-v2.icc 63c0165987ee94c8c7f2c68749e0418d
widegamutcompat-v4.icc 4ccb168ae2f7daa51d3cef7df6fa6f16
--------------------------------------------------------------------------------

BIN
assets/profiles/icc/a98.icc Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -121,7 +121,7 @@ services:
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
PHOTOPRISM_INIT: "https tensorflow-gpu"
## Computer Vision API (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
## Computer Vision (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)

View file

@ -68,6 +68,12 @@ services:
PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000)
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
PHOTOPRISM_INIT: "https"
## Computer Vision (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
OLLAMA_BASE_URL: "http://ollama:11434" # use "https://ollama.com" for Ollama Cloud
OLLAMA_API_KEY: "" # API key required to access Ollama (optional)
## External dependencies and tools:
TF_CPP_MIN_LOG_LEVEL: 1
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
@ -85,7 +91,7 @@ services:
## Dummy WebDAV Server
dummy-webdav:
image: photoprism/dummy-webdav:231015
image: photoprism/dummy-webdav:251210
environment:
WEBDAV_USERNAME: admin
WEBDAV_PASSWORD: photoprism

View file

@ -131,10 +131,12 @@ services:
# PHOTOPRISM_FFMPEG_BITRATE: "64" # video bitrate limit in Mbps (default: 60)
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
PHOTOPRISM_INIT: "https"
## Computer Vision API (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
## Computer Vision (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
OLLAMA_BASE_URL: "http://ollama:11434" # use "https://ollama.com" for Ollama Cloud
OLLAMA_API_KEY: "" # API key required to access Ollama (optional)
## External dependencies and tools:
TF_CPP_MIN_LOG_LEVEL: 1
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
@ -154,7 +156,7 @@ services:
## Release Notes: https://mariadb.com/kb/en/changes-improvements-in-mariadb-1011/
mariadb:
image: mariadb:11
stop_grace_period: 15s
stop_grace_period: 10s
security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239
- seccomp:unconfined
- apparmor:unconfined
@ -181,7 +183,7 @@ services:
qdrant:
image: qdrant/qdrant:latest
profiles: [ "all", "qdrant" ]
stop_grace_period: 15s
stop_grace_period: 10s
links:
- "traefik:localssl.dev"
- "traefik:app.localssl.dev"
@ -335,8 +337,8 @@ services:
## Dummy WebDAV Server
dummy-webdav:
image: photoprism/dummy-webdav:240627
stop_grace_period: 30s
image: photoprism/dummy-webdav:251210
stop_grace_period: 10s
environment:
WEBDAV_USERNAME: admin
WEBDAV_PASSWORD: photoprism
@ -352,8 +354,8 @@ services:
## Dummy OIDC Identity Provider
dummy-oidc:
image: photoprism/dummy-oidc:240627
stop_grace_period: 30s
image: photoprism/dummy-oidc:251210
stop_grace_period: 5s
labels:
- "traefik.enable=true"
- "traefik.http.services.dummy-oidc.loadbalancer.server.port=9998"
@ -368,7 +370,7 @@ services:
## Docs: https://glauth.github.io/docs/
dummy-ldap:
image: glauth/glauth-plugins:latest
stop_grace_period: 15s
stop_grace_period: 5s
ports:
- "127.0.0.1:389:389"
labels:
@ -388,7 +390,7 @@ services:
## Login with "user / photoprism" and "admin / photoprism".
keycloak:
image: quay.io/keycloak/keycloak:25.0
stop_grace_period: 20s
stop_grace_period: 10s
profiles: [ "all", "auth", "keycloak" ]
command: "start-dev" # development mode, do not use this in production!
links:
@ -421,7 +423,7 @@ services:
## ./photoprism client add --id=cs5cpu17n6gj2qo5 --secret=xcCbOrw6I0vcoXzhnOmXhjpVSyFq0l0e -s metrics -n Prometheus -e 60 -t 1
prometheus:
image: prom/prometheus:latest
stop_grace_period: 15s
stop_grace_period: 10s
profiles: [ "all", "auth", "prometheus" ]
labels:
- "traefik.enable=true"

View file

@ -5,4 +5,4 @@ FROM golang:1.22-alpine
RUN go install github.com/skibish/ddns@latest
CMD ["ddns", "-conf-file", "/config/ddns.yml"]
CMD ["ddns", "-conf-file", "/config/ddns.yml"]

View file

@ -79,4 +79,4 @@ WORKDIR /photoprism
EXPOSE 2342 2442 2443
# Keep container running.
CMD ["tail", "-f", "/dev/null"]
CMD ["tail", "-f", "/dev/null"]

View file

@ -99,4 +99,4 @@ WORKDIR /photoprism
EXPOSE 2342 2443
# keep container running
CMD ["tail", "-f", "/dev/null"]
CMD ["tail", "-f", "/dev/null"]

View file

@ -32,7 +32,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
TF_CPP_MIN_LOG_LEVEL=4 \
TF_ENABLE_ONEDNN_OPTS=1 \
MALLOC_ARENA_MAX=2 \
PROG="photoprism" \
PROG="photoprism"
S6_KEEP_ENV=0 \
S6_VERBOSITY=0 \
S6_LOGGING=0

View file

@ -37,7 +37,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
GOBIN="/usr/local/bin" \
GO111MODULE="on" \
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
PROG="photoprism" \
PROG="photoprism"
S6_KEEP_ENV=1 \
S6_VERBOSITY=0 \
S6_LOGGING=0

View file

@ -1,26 +1,23 @@
module caos-test-op
go 1.17
go 1.24.0
require (
github.com/caos/oidc v0.15.10
github.com/gorilla/mux v1.8.1
github.com/zitadel/oidc v1.13.5
gopkg.in/square/go-jose.v2 v2.6.0
)
require (
github.com/caos/logging v0.3.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/schema v1.2.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/gorilla/schema v1.4.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.32.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/zitadel/logging v0.6.2 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
)

View file

@ -1,476 +1,46 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
github.com/caos/logging v0.3.1 h1:892AMeHs09D0e3ZcGB+QDRsZ5+2xtPAsAhOy8eKfztc=
github.com/caos/logging v0.3.1/go.mod h1:B8QNS0WDmR2Keac52Fw+XN4ZJkzLDGrcRIPB2Ux4uRo=
github.com/caos/oidc v0.15.10 h1:dSzkIvsZR2PSZgvBFFkLJt8A/MujsyLac1yNvBShXuw=
github.com/caos/oidc v0.15.10/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU=
github.com/caos/oidc v1.3.0 h1:6I4S5XPjFQZx/GZVZaRvemFWYTlO27UvZILrWYL+P60=
github.com/caos/oidc v1.3.0/go.mod h1:/EWr+09pcXQbSpCgGna6D+d726NtFAR4KRdG9D0x3OE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/schema v1.2.1 h1:tjDxcmdb+siIqkTNoV+qRH2mjYdr2hHe5MKXbp61ziM=
github.com/gorilla/schema v1.2.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/zitadel/logging v0.6.2 h1:MW2kDDR0ieQynPZ0KIZPrh9ote2WkxfBif5QoARDQcU=
github.com/zitadel/logging v0.6.2/go.mod h1:z6VWLWUkJpnNVDSLzrPSQSQyttysKZ6bCRongw0ROK4=
github.com/zitadel/oidc v1.13.5 h1:7jhh68NGZitLqwLiVU9Dtwa4IraJPFF1vS+4UupO93U=
github.com/zitadel/oidc v1.13.5/go.mod h1:rHs1DhU3Sv3tnI6bQRVlFa3u0lCwtR7S21WHY+yXgPA=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -0,0 +1,104 @@
package mock
// revive:disable
// Dummy storage implementation for the test OIDC provider; lint strictness is relaxed intentionally.
import (
"time"
"github.com/zitadel/oidc/pkg/oidc"
"github.com/zitadel/oidc/pkg/op"
)
// ConfClient represents a fixed client configuration used by the dummy provider.
type ConfClient struct {
applicationType op.ApplicationType
authMethod oidc.AuthMethod
responseTypes []oidc.ResponseType
grantTypes []oidc.GrantType
ID string
accessTokenType op.AccessTokenType
devMode bool
}
func (c *ConfClient) GetID() string {
return c.ID
}
func (c *ConfClient) RedirectURIs() []string {
return []string{
"https://registered.com/callback",
"http://localhost:9999/callback",
"http://localhost:5556/auth/callback",
"custom://callback",
"https://localhost:8443/test/a/instructions-example/callback",
"https://op.certification.openid.net:62064/authz_cb",
"https://op.certification.openid.net:62064/authz_post",
"http://localhost:2342/api/v1/oidc/redirect",
"https://app.localssl.dev/api/v1/oidc/redirect",
}
}
func (c *ConfClient) PostLogoutRedirectURIs() []string {
return []string{}
}
func (c *ConfClient) LoginURL(id string) string {
// return "authorize/callback?id=" + id
return "login?id=" + id
}
func (c *ConfClient) ApplicationType() op.ApplicationType {
return c.applicationType
}
func (c *ConfClient) AuthMethod() oidc.AuthMethod {
return c.authMethod
}
func (c *ConfClient) IDTokenLifetime() time.Duration {
return 60 * time.Minute
}
func (c *ConfClient) AccessTokenType() op.AccessTokenType {
return c.accessTokenType
}
func (c *ConfClient) ResponseTypes() []oidc.ResponseType {
return c.responseTypes
}
func (c *ConfClient) GrantTypes() []oidc.GrantType {
return c.grantTypes
}
func (c *ConfClient) DevMode() bool {
return c.devMode
}
func (c *ConfClient) AllowedScopes() []string {
return nil
}
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
return scopes
}
}
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
return scopes
}
}
func (c *ConfClient) IsScopeAllowed(scope string) bool {
return false
}
func (c *ConfClient) IDTokenUserinfoClaimsAssertion() bool {
return false
}
func (c *ConfClient) ClockSkew() time.Duration {
return 0
}

View file

@ -1,5 +1,9 @@
// Package mock provides an in-memory OIDC storage used by the dummy provider in development.
package mock
// revive:disable
// Dummy storage implementation for the test OIDC provider; lint strictness is relaxed intentionally.
import (
"context"
"crypto/rand"
@ -10,23 +14,36 @@ import (
"gopkg.in/square/go-jose.v2"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op"
"github.com/zitadel/oidc/pkg/oidc"
"github.com/zitadel/oidc/pkg/op"
)
var (
a = &AuthRequest{}
t bool
c string
state string
)
// AuthStorage keeps ephemeral keys and auth state for the dummy provider.
type AuthStorage struct {
key *rsa.PrivateKey
kid string
}
// NewAuthStorage constructs the dummy storage with a fresh RSA key.
func NewAuthStorage() op.Storage {
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
b := make([]byte, 16)
rand.Read(b)
if _, err = rand.Read(b); err != nil {
panic(err)
}
return &AuthStorage{
key: key,
@ -34,9 +51,11 @@ func NewAuthStorage() op.Storage {
}
}
// AuthRequest is a lightweight auth request implementation for tests.
type AuthRequest struct {
ID string
ResponseType oidc.ResponseType
ResponseMode oidc.ResponseMode
RedirectURI string
Nonce string
ClientID string
@ -86,6 +105,13 @@ func (a *AuthRequest) GetResponseType() oidc.ResponseType {
return a.ResponseType
}
func (a *AuthRequest) GetResponseMode() oidc.ResponseMode {
if a.ResponseMode != "" {
return a.ResponseMode
}
return oidc.ResponseModeQuery
}
func (a *AuthRequest) GetScopes() []string {
return []string{
"openid",
@ -108,20 +134,13 @@ func (a *AuthRequest) Done() bool {
return true
}
var (
a = &AuthRequest{}
t bool
c string
state string
)
func (s *AuthStorage) Health(ctx context.Context) error {
return nil
}
// CreateAuthRequest stores the incoming request in memory and returns a stub AuthRequest.
func (s *AuthStorage) CreateAuthRequest(_ context.Context, authReq *oidc.AuthRequest, userId string) (op.AuthRequest, error) {
fmt.Println("Userid: ", userId)
fmt.Println("CreateAuthRequest ID: ", authReq.ID)
fmt.Println("CreateAuthRequest CodeChallenge: ", authReq.CodeChallenge)
fmt.Println("CreateAuthRequest CodeChallengeMethod: ", authReq.CodeChallengeMethod)
fmt.Println("CreateAuthRequest State: ", authReq.State)
@ -132,7 +151,14 @@ func (s *AuthStorage) CreateAuthRequest(_ context.Context, authReq *oidc.AuthReq
fmt.Println("CreateAuthRequest Display: ", authReq.Display)
fmt.Println("CreateAuthRequest LoginHint: ", authReq.LoginHint)
fmt.Println("CreateAuthRequest IDTokenHint: ", authReq.IDTokenHint)
a = &AuthRequest{ID: "authReqUserAgentId", ClientID: authReq.ClientID, ResponseType: authReq.ResponseType, Nonce: authReq.Nonce, RedirectURI: authReq.RedirectURI}
a = &AuthRequest{
ID: "authReqUserAgentId",
ClientID: authReq.ClientID,
ResponseType: authReq.ResponseType,
ResponseMode: authReq.ResponseMode,
Nonce: authReq.Nonce,
RedirectURI: authReq.RedirectURI,
}
if authReq.CodeChallenge != "" {
a.CodeChallenge = &oidc.CodeChallenge{
Challenge: authReq.CodeChallenge,
@ -143,12 +169,14 @@ func (s *AuthStorage) CreateAuthRequest(_ context.Context, authReq *oidc.AuthReq
t = false
return a, nil
}
func (s *AuthStorage) AuthRequestByCode(_ context.Context, code string) (op.AuthRequest, error) {
if code != c {
return nil, errors.New("invalid code")
}
return a, nil
}
func (s *AuthStorage) SaveAuthCode(_ context.Context, id, code string) error {
if a.ID != id {
return errors.New("SaveAuthCode: not found")
@ -156,10 +184,12 @@ func (s *AuthStorage) SaveAuthCode(_ context.Context, id, code string) error {
c = code
return nil
}
func (s *AuthStorage) DeleteAuthRequest(context.Context, string) error {
t = true
return nil
}
func (s *AuthStorage) AuthRequestByID(_ context.Context, id string) (op.AuthRequest, error) {
fmt.Println("AuthRequestByID: ", id)
if id != "authReqUserAgentId:usertoken" || t {
@ -167,12 +197,15 @@ func (s *AuthStorage) AuthRequestByID(_ context.Context, id string) (op.AuthRequ
}
return a, nil
}
func (s *AuthStorage) CreateAccessToken(ctx context.Context, request op.TokenRequest) (string, time.Time, error) {
return "loginId", time.Now().UTC().Add(5 * time.Minute), nil
}
func (s *AuthStorage) CreateAccessAndRefreshTokens(ctx context.Context, request op.TokenRequest, currentRefreshToken string) (accessTokenID string, newRefreshToken string, expiration time.Time, err error) {
return "loginId", "refreshToken", time.Now().UTC().Add(5 * time.Minute), nil
}
func (s *AuthStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (op.RefreshTokenRequest, error) {
if refreshToken != c {
return nil, errors.New("invalid token")
@ -183,13 +216,21 @@ func (s *AuthStorage) TokenRequestByRefreshToken(ctx context.Context, refreshTok
func (s *AuthStorage) TerminateSession(_ context.Context, userID, clientID string) error {
return nil
}
// RevokeToken is a no-op for the dummy implementation.
func (s *AuthStorage) RevokeToken(_ context.Context, tokenOrTokenID string, userID string, clientID string) *oidc.Error {
return nil
}
func (s *AuthStorage) GetSigningKey(_ context.Context, keyCh chan<- jose.SigningKey) {
//keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: s.key}
// keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: s.key}
keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: &jose.JSONWebKey{Key: s.key, KeyID: s.kid}}
}
func (s *AuthStorage) GetKey(_ context.Context) (*rsa.PrivateKey, error) {
return s.key, nil
}
func (s *AuthStorage) GetKeySet(_ context.Context) (*jose.JSONWebKeySet, error) {
pubkey := s.key.Public()
@ -214,6 +255,7 @@ func (s *AuthStorage) GetKeySet(_ context.Context) (*jose.JSONWebKeySet, error)
},
}, nil
}
func (s *AuthStorage) GetKeyByIDAndUserID(_ context.Context, _, _ string) (*jose.JSONWebKey, error) {
pubkey := s.key.Public()
@ -229,6 +271,7 @@ func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Clie
if id == "none" {
return nil, errors.New("GetClientByClientID: not found")
}
var appType op.ApplicationType
var authMethod oidc.AuthMethod
var accessTokenType op.AccessTokenType
@ -236,22 +279,25 @@ func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Clie
var grantTypes = []oidc.GrantType{
oidc.GrantTypeCode,
}
if id == "web" {
switch id {
case "web":
appType = op.ApplicationTypeWeb
authMethod = oidc.AuthMethodBasic
accessTokenType = op.AccessTokenTypeBearer
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
} else if id == "native" {
case "native":
appType = op.ApplicationTypeNative
authMethod = oidc.AuthMethodBasic
accessTokenType = op.AccessTokenTypeBearer
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode, oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
} else {
default:
appType = op.ApplicationTypeUserAgent
authMethod = oidc.AuthMethodNone
accessTokenType = op.AccessTokenTypeJWT
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
}
return &ConfClient{ID: id, applicationType: appType, authMethod: authMethod, accessTokenType: accessTokenType, responseTypes: responseTypes, grantTypes: grantTypes, devMode: true}, nil
}
@ -262,9 +308,10 @@ func (s *AuthStorage) AuthorizeClientIDSecret(_ context.Context, id string, _ st
func (s *AuthStorage) SetUserinfoFromToken(ctx context.Context, userinfo oidc.UserInfoSetter, _, _, _ string) error {
return s.SetUserinfoFromScopes(ctx, userinfo, "", "", []string{})
}
func (s *AuthStorage) SetUserinfoFromScopes(ctx context.Context, userinfo oidc.UserInfoSetter, _, _ string, _ []string) error {
userinfo.SetSubject(a.GetSubject())
//userinfo.SetAddress(oidc.NewUserInfoAddress("Test 789\nPostfach 2", "", "", "", "", ""))
// userinfo.SetAddress(oidc.NewUserInfoAddress("Test 789\nPostfach 2", "", "", "", "", ""))
userinfo.SetEmail("test@example.com", true)
userinfo.SetPhone("0791234567", true)
userinfo.SetName("Test")
@ -273,6 +320,7 @@ func (s *AuthStorage) SetUserinfoFromScopes(ctx context.Context, userinfo oidc.U
userinfo.SetPreferredUsername("prefname")
return nil
}
func (s *AuthStorage) GetPrivateClaimsFromScopes(_ context.Context, _, _ string, _ []string) (map[string]interface{}, error) {
return map[string]interface{}{"private_claim": "test"}, nil
}
@ -281,98 +329,12 @@ func (s *AuthStorage) SetIntrospectionFromToken(ctx context.Context, introspect
if err := s.SetUserinfoFromScopes(ctx, introspect, "", "", []string{}); err != nil {
return err
}
introspect.SetClientID(a.ClientID)
return nil
}
func (s *AuthStorage) ValidateJWTProfileScopes(ctx context.Context, userID string, scope []string) ([]string, error) {
return scope, nil
}
type ConfClient struct {
applicationType op.ApplicationType
authMethod oidc.AuthMethod
responseTypes []oidc.ResponseType
grantTypes []oidc.GrantType
ID string
accessTokenType op.AccessTokenType
devMode bool
}
func (c *ConfClient) GetID() string {
return c.ID
}
func (c *ConfClient) RedirectURIs() []string {
return []string{
"https://registered.com/callback",
"http://localhost:9999/callback",
"http://localhost:5556/auth/callback",
"custom://callback",
"https://localhost:8443/test/a/instructions-example/callback",
"https://op.certification.openid.net:62064/authz_cb",
"https://op.certification.openid.net:62064/authz_post",
"http://localhost:2342/api/v1/oidc/redirect",
"https://app.localssl.dev/api/v1/oidc/redirect",
}
}
func (c *ConfClient) PostLogoutRedirectURIs() []string {
return []string{}
}
func (c *ConfClient) LoginURL(id string) string {
//return "authorize/callback?id=" + id
return "login?id=" + id
}
func (c *ConfClient) ApplicationType() op.ApplicationType {
return c.applicationType
}
func (c *ConfClient) AuthMethod() oidc.AuthMethod {
return c.authMethod
}
func (c *ConfClient) IDTokenLifetime() time.Duration {
return 60 * time.Minute
}
func (c *ConfClient) AccessTokenType() op.AccessTokenType {
return c.accessTokenType
}
func (c *ConfClient) ResponseTypes() []oidc.ResponseType {
return c.responseTypes
}
func (c *ConfClient) GrantTypes() []oidc.GrantType {
return c.grantTypes
}
func (c *ConfClient) DevMode() bool {
return c.devMode
}
func (c *ConfClient) AllowedScopes() []string {
return nil
}
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
return scopes
}
}
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
return scopes
}
}
func (c *ConfClient) IsScopeAllowed(scope string) bool {
return false
}
func (c *ConfClient) IDTokenUserinfoClaimsAssertion() bool {
return false
}
func (c *ConfClient) ClockSkew() time.Duration {
return 0
}

View file

@ -0,0 +1,27 @@
package mock
import (
"context"
"testing"
"github.com/zitadel/oidc/pkg/oidc"
)
func TestAuthRequestResponseModeDefault(t *testing.T) {
req := &AuthRequest{}
if got := req.GetResponseMode(); got != oidc.ResponseModeQuery {
t.Fatalf("expected default response mode %q, got %q", oidc.ResponseModeQuery, got)
}
}
func TestRevokeTokenNoError(t *testing.T) {
s := &AuthStorage{}
if err := s.RevokeToken(
context.TODO(),
"token",
"user",
"client",
); err != nil {
t.Fatalf("expected nil error from RevokeToken, got %v", err)
}
}

View file

@ -1,23 +1,33 @@
// Command dummy-oidc starts a minimal OIDC provider used by docker-compose for local development.
package main
import (
"context"
"crypto/rand"
"crypto/sha256"
"errors"
"log"
"net/http"
"os/signal"
"syscall"
"time"
"github.com/gorilla/mux"
"github.com/zitadel/oidc/pkg/op"
"caos-test-op/mock"
"github.com/caos/oidc/pkg/op"
)
func main() {
ctx := context.Background()
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
b := make([]byte, 32)
rand.Read(b)
_, _ = rand.Read(b)
if _, err := rand.Read(b); err != nil {
log.Printf("failed to seed crypto key: %v", err)
return
}
port := "9998"
config := &op.Config{
@ -29,26 +39,39 @@ func main() {
handler, err := op.NewOpenIDProvider(ctx, config, storage)
if err != nil {
log.Fatal(err)
log.Printf("failed to create OIDC provider: %v", err)
return
}
router := handler.HttpHandler().(*mux.Router)
router.Methods("GET").Path("/login").HandlerFunc(HandleLogin)
server := &http.Server{
Addr: ":" + port,
Handler: router,
Addr: ":" + port,
Handler: router,
ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second,
}
err = server.ListenAndServe()
if err != nil {
log.Fatal(err)
go func() {
<-ctx.Done()
_ = server.Shutdown(context.Background())
}()
if err = server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Printf("OIDC server stopped with error: %v", err)
}
<-ctx.Done()
}
func HandleLogin(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
// HandleLogin mocks a login page and immediately redirects with a user token.
if err := r.ParseForm(); err != nil {
http.Error(w, "invalid login request", http.StatusBadRequest)
return
}
requestId := r.Form.Get("id")
// simulate user login and retrieve a token that indicates a successfully logged-in user
usertoken := requestId + ":usertoken"
userToken := requestId + ":usertoken"
http.Redirect(w, r, "/authorize/callback?id="+usertoken, http.StatusFound)
http.Redirect(w, r, "/authorize/callback?id="+userToken, http.StatusFound)
}

View file

@ -0,0 +1,36 @@
package main
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestHandleLoginRedirects(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/login?id=abc123", nil)
w := httptest.NewRecorder()
HandleLogin(w, req)
resp := w.Result()
if resp.StatusCode != http.StatusFound {
t.Fatalf("expected status %d, got %d", http.StatusFound, resp.StatusCode)
}
location := resp.Header.Get("Location")
if location != "/authorize/callback?id=abc123:usertoken" {
t.Fatalf("unexpected redirect location: %s", location)
}
}
func TestHandleLoginBadRequest(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/login", strings.NewReader("%zz"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
HandleLogin(w, req)
if w.Result().StatusCode != http.StatusBadRequest {
t.Fatalf("expected bad request, got %d", w.Result().StatusCode)
}
}

View file

@ -16,4 +16,4 @@ EXPOSE 80
COPY /docker/dummy/webdav/config.yml /webdav/config.yml
COPY /docker/dummy/webdav/files /webdav/files
CMD webdav -c /webdav/config.yml
CMD ["webdav", "-c", "/webdav/config.yml"]

View file

@ -23,4 +23,4 @@ VOLUME "/go"
EXPOSE 8888
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/goproxy", "-listen", "0.0.0.0:8888"]
CMD ["/goproxy", "-listen", "0.0.0.0:8888"]

View file

@ -49,7 +49,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
TF_VERSION=1.15.2 \
TF_CPP_MIN_LOG_LEVEL=4 \
MALLOC_ARENA_MAX=2 \
PROG="photoprism" \
PROG="photoprism"
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \

View file

@ -3,16 +3,9 @@ node_modules/
tests/screenshots/
tests/acceptance/screenshots/
tests/upload-files/
*.html
*.md
.*
.idea
.codex
.local
.config
.github
.tmp
.local
.cache
.gocache
.var
*.html
*.md
.*

View file

@ -1,5 +1,5 @@
{
"printWidth": 120,
"printWidth": 160,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",

View file

@ -128,7 +128,7 @@ export default defineConfig([
"prettier/prettier": [
"warn",
{
printWidth: 120,
printWidth: 160,
semi: true,
singleQuote: false,
bracketSpacing: true,

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@
"security:scan": "npm run -s security:scan-installs && npm run -s security:scan-xss",
"security:scan-installs": "sh -lc 'set -e; MATCHES=\"$(rg -n --hidden --glob !**/.git/** -S \"npm (ci|install|update)\" ./Makefile ./package.json 2>/dev/null || true)\"; if [ -z \"$MATCHES\" ]; then echo \"No npm install/update/ci commands found in frontend/\"; exit 0; fi; VIOLATIONS=\"$(printf %s \"$MATCHES\" | rg -v -e \"ignore-scripts\" -e \"install .* -g npm\" -e \"update .* -g npm\" -e \":[0-9]+:\\s*#\" -e \"install-npm\" || true)\"; if [ -n \"$VIOLATIONS\" ]; then echo \"ERROR: npm install/update/ci without --ignore-scripts (exceptions excluded)\"; printf %s\\n \"$VIOLATIONS\"; exit 1; fi; echo \"OK: All frontend installs/updates use --ignore-scripts or are allowed exceptions.\"'",
"security:scan-xss": "sh -lc 'set -e; if rg -n --glob \"src/**\" -S \"v-html=\\\"\" src >/dev/null; then echo \"ERROR: v-html usage detected; prefer v-sanitize or $util.sanitizeHtml()\"; rg -n --glob \"src/**\" -S \"v-html=\\\"\" src; exit 1; else echo \"OK: No v-html usage detected.\"; fi'",
"watch": "webpack --watch"
"watch": "cross-env BUILD_ENV=development NODE_ENV=production webpack --watch"
},
"browserslist": [
">0.25% and last 2 years"
@ -39,26 +39,26 @@
"@babel/preset-env": "^7.28.5",
"@babel/register": "^7.28.3",
"@babel/runtime": "^7.28.4",
"@eslint/eslintrc": "^3.3.1",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.33.0",
"@mdi/font": "^7.4.47",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@vitejs/plugin-react": "^5.1.1",
"@vitejs/plugin-react": "^5.1.2",
"@vitejs/plugin-vue": "^6.0.2",
"@vitest/browser": "^3.2.4",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.2.4",
"@vue/compiler-sfc": "^3.5.18",
"@vue/language-server": "^3.1.4",
"@vue/language-server": "^3.1.8",
"@vue/test-utils": "^2.4.6",
"@vvo/tzdb": "^6.196.0",
"@vvo/tzdb": "^6.198.0",
"axios": "^1.13.2",
"axios-mock-adapter": "^2.1.0",
"babel-loader": "^10.0.0",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-polyfill-corejs3": "^0.13.0",
"browserslist": "^4.28.0",
"browserslist": "^4.28.1",
"cheerio": "1.0.0-rc.12",
"core-js": "^3.47.0",
"cross-env": "^7.0.3",
@ -72,7 +72,7 @@
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-vue": "^10.5.1",
"eslint-plugin-vue": "^10.6.2",
"eslint-plugin-vuetify": "^2.5.3",
"eslint-webpack-plugin": "^5.0.2",
"eventsource-polyfill": "^0.9.6",
@ -84,26 +84,26 @@
"i": "^0.3.7",
"jsdom": "^26.1.0",
"luxon": "^3.7.2",
"maplibre-gl": "^5.13.0",
"maplibre-gl": "^5.14.0",
"memoize-one": "^6.0.0",
"mini-css-extract-plugin": "^2.9.4",
"minimist": "^1.2.8",
"node-storage-shim": "^2.0.1",
"passive-events-support": "^1.1.0",
"photoswipe": "^5.4.4",
"playwright": "^1.56.1",
"playwright": "^1.57.0",
"postcss": "^8.5.6",
"postcss-import": "^16.1.1",
"postcss-loader": "^8.2.0",
"postcss-preset-env": "^10.4.0",
"postcss-preset-env": "^10.5.0",
"postcss-reporter": "^7.1.0",
"postcss-url": "^10.1.3",
"prettier": "^3.6.2",
"prettier": "^3.7.4",
"pubsub-js": "^1.9.5",
"regenerator-runtime": "^0.14.1",
"resolve-url-loader": "^5.0.0",
"sanitize-html": "^2.17.0",
"sass": "^1.94.2",
"sass": "^1.95.1",
"sass-loader": "^16.0.6",
"sockette": "^2.0.6",
"style-loader": "^4.0.0",
@ -122,7 +122,7 @@
"vue-sanitize-directive": "^0.2.1",
"vue-style-loader": "^4.1.3",
"vue3-gettext": "^2.4.0",
"vuetify": "^3.10.11",
"vuetify": "^3.11.3",
"webpack": "^5.103.0",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-cli": "^6.0.1",

View file

@ -12,9 +12,7 @@ export function processAlbumSelection(selectedAlbums, availableAlbums) {
selectedAlbums.forEach((item) => {
// If it's a string, try to match it with existing albums
if (typeof item === "string" && item.trim().length > 0) {
const matchedAlbum = availableAlbums.find(
(album) => album.Title && album.Title.toLowerCase() === item.trim().toLowerCase()
);
const matchedAlbum = availableAlbums.find((album) => album.Title && album.Title.toLowerCase() === item.trim().toLowerCase());
if (matchedAlbum && !seenUids.has(matchedAlbum.UID)) {
// Replace string with actual album object

View file

@ -125,13 +125,12 @@ export class Clipboard {
const id = model.getId();
this.addId(id);
return this.addId(id);
}
addId(id) {
this.updateDom(id, true);
if (this.hasId(id)) {
this.lastId = id;
return true;
}
@ -145,6 +144,7 @@ export class Clipboard {
this.lastId = id;
this.saveToStorage();
this.updateDom(id, true);
return true;
}
@ -170,12 +170,19 @@ export class Clipboard {
rangeEnd = newEnd;
}
let added = 0;
for (let i = rangeStart; i <= rangeEnd; i++) {
this.add(models[i], false);
this.updateDom(models[i].getId(), true);
const result = this.add(models[i]);
if (!result) {
break;
}
added++;
}
return rangeEnd - rangeStart + 1;
return added;
}
has(model) {

View file

@ -241,12 +241,7 @@ export default class Config {
.filter((m) => m.UID === values.UID)
.forEach((m) => {
for (let key in values) {
if (
key !== "UID" &&
values.hasOwnProperty(key) &&
values[key] != null &&
typeof values[key] !== "object"
) {
if (key !== "UID" && values.hasOwnProperty(key) && values[key] != null && typeof values[key] !== "object") {
m[key] = values[key];
}
}

View file

@ -102,11 +102,7 @@ export class Form {
// getOptions resolves the options array for select-style fields.
getOptions(fieldName) {
if (
this.definition &&
this.definition.hasOwnProperty(fieldName) &&
this.definition[fieldName].hasOwnProperty("options")
) {
if (this.definition && this.definition.hasOwnProperty(fieldName) && this.definition[fieldName].hasOwnProperty("options")) {
return this.definition[fieldName].options;
}
@ -209,9 +205,7 @@ export class rules {
return false;
}
return /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/.test(
v
);
return /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/.test(v);
}
// isUrl validates strings by length and URL parsing.
@ -260,10 +254,7 @@ export class rules {
// email returns Vuetify rule callbacks for email validation.
static email(required) {
if (required) {
return [
(v) => !!v || $gettext("This field is required"),
(v) => !v || this.isEmail(v) || $gettext("Invalid address"),
];
return [(v) => !!v || $gettext("This field is required"), (v) => !v || this.isEmail(v) || $gettext("Invalid address")];
} else {
return [(v) => !v || this.isEmail(v) || $gettext("Invalid address")];
}
@ -352,20 +343,14 @@ export class rules {
(v) => this.maxLen(v, 2) || $gettext("Invalid country"),
];
} else {
return [
(v) => this.minLen(v, 2) || $gettext("Invalid country"),
(v) => this.maxLen(v, 2) || $gettext("Invalid country"),
];
return [(v) => this.minLen(v, 2) || $gettext("Invalid country"), (v) => this.maxLen(v, 2) || $gettext("Invalid country")];
}
}
// day validates day-of-month values between 1 and 31.
static day(required) {
if (required) {
return [
(v) => !!v || Number(v) < -1 || $gettext("This field is required"),
(v) => this.isNumberRange(v, 1, 31) || $gettext("Invalid"),
];
return [(v) => !!v || Number(v) < -1 || $gettext("This field is required"), (v) => this.isNumberRange(v, 1, 31) || $gettext("Invalid")];
} else {
return [(v) => this.isNumberRange(v, 1, 31) || $gettext("Invalid")];
}
@ -374,10 +359,7 @@ export class rules {
// month validates month values between 1 and 12.
static month(required) {
if (required) {
return [
(v) => !!v || Number(v) < -1 || $gettext("This field is required"),
(v) => this.isNumberRange(v, 1, 12) || $gettext("Invalid"),
];
return [(v) => !!v || Number(v) < -1 || $gettext("This field is required"), (v) => this.isNumberRange(v, 1, 12) || $gettext("Invalid")];
} else {
return [(v) => this.isNumberRange(v, 1, 12) || $gettext("Invalid")];
}
@ -394,10 +376,7 @@ export class rules {
}
if (required) {
return [
(v) => !!v || Number(v) < -1 || $gettext("This field is required"),
(v) => this.isNumberRange(v, min, max) || $gettext("Invalid"),
];
return [(v) => !!v || Number(v) < -1 || $gettext("This field is required"), (v) => this.isNumberRange(v, min, max) || $gettext("Invalid")];
} else {
return [(v) => this.isNumberRange(v, min, max) || $gettext("Invalid")];
}

View file

@ -75,10 +75,7 @@ export class Input {
return InputInvalid;
}
if (
Math.abs(this.touches[0].screenX - ev.changedTouches[0].screenX) > 4 ||
Math.abs(this.touches[0].screenY - ev.changedTouches[0].screenY) > 4
) {
if (Math.abs(this.touches[0].screenX - ev.changedTouches[0].screenX) > 4 || Math.abs(this.touches[0].screenY - ev.changedTouches[0].screenY) > 4) {
return InputInvalid;
}
}

View file

@ -15,13 +15,7 @@ const langFallbackDecorate = function (style, cfg) {
for (let i = layers.length - 1; i >= 0; i--) {
let layer = layers[i];
if (
!(
lf[0] === "in" &&
lfProp === "layout.text-field" &&
layer.layout &&
layer.layout["text-field"] &&
lfValues.indexOf(layer.layout["text-field"]) >= 0
)
!(lf[0] === "in" && lfProp === "layout.text-field" && layer.layout && layer.layout["text-field"] && lfValues.indexOf(layer.layout["text-field"]) >= 0)
) {
continue;
}
@ -95,27 +89,7 @@ maplibregl.Map.prototype.setLanguage = function (language, noAlt) {
return;
}
let isNonlatin =
[
"ar",
"hy",
"be",
"bg",
"zh",
"ka",
"el",
"he",
"ja",
"ja_kana",
"kn",
"kk",
"ko",
"mk",
"ru",
"sr",
"th",
"uk",
].indexOf(language) >= 0;
let isNonlatin = ["ar", "hy", "be", "bg", "zh", "ka", "el", "he", "ja", "ja_kana", "kn", "kk", "ko", "mk", "ru", "sr", "th", "uk"].indexOf(language) >= 0;
let style = JSON.parse(JSON.stringify(this.styleUndecorated));
let langCfg = {
@ -131,15 +105,12 @@ maplibregl.Map.prototype.setLanguage = function (language, noAlt) {
],
"decorators": [
{
"layout.text-field": isNonlatin
? "{name:nonlatin}" + (noAlt ? "" : "\n{name:latin}")
: "{name:latin}" + (noAlt ? "" : "\n{name:nonlatin}"),
"layout.text-field": isNonlatin ? "{name:nonlatin}" + (noAlt ? "" : "\n{name:latin}") : "{name:latin}" + (noAlt ? "" : "\n{name:nonlatin}"),
"filter-all-part": ["!has", "name:" + language],
},
{
"layer-name-postfix": language,
"layout.text-field":
"{name:" + language + "}" + (noAlt ? "" : "\n{name:" + (isNonlatin ? "latin" : "nonlatin") + "}"),
"layout.text-field": "{name:" + language + "}" + (noAlt ? "" : "\n{name:" + (isNonlatin ? "latin" : "nonlatin") + "}"),
"filter-all-part": ["has", "name:" + language],
},
],

View file

@ -89,10 +89,7 @@ export default class Session {
}
// Restore authentication from session storage.
if (
this.applyAuthToken(this.storage.getItem(this.storageKey + ".token")) &&
this.applyId(this.storage.getItem(this.storageKey + ".id"))
) {
if (this.applyAuthToken(this.storage.getItem(this.storageKey + ".token")) && this.applyId(this.storage.getItem(this.storageKey + ".id"))) {
const dataJson = this.storage.getItem(this.storageKey + ".data");
if (dataJson && dataJson !== "undefined") {
this.data = JSON.parse(dataJson);

View file

@ -353,12 +353,7 @@ export default class $util {
}
// Escape HTML control characters.
text = text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
text = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
// Make URLs clickable.
text = text.replace(linkRegex, linkFunc);

View file

@ -521,10 +521,7 @@ export class View {
const scope = this.scopes.map((s) => `${s?.$options?.name} #${s?.$?.uid.toString()}`).join(" ");
// To make them easy to recognize, the collapsed view logs are displayed
// in the browser console with bold white text on a purple background.
console.groupCollapsed(
`%c${scope}`,
"background: #502A85; color: white; padding: 3px 5px; border-radius: 8px; font-weight: bold;"
);
console.groupCollapsed(`%c${scope}`, "background: #502A85; color: white; padding: 3px 5px; border-radius: 8px; font-weight: bold;");
console.log("data:", toRaw(c?.$data));
}
@ -744,11 +741,7 @@ export class View {
ev.preventDefault();
const target =
(fallback && fallback.isConnected && root.contains(fallback) && fallback) ||
resolveFocusTarget(root) ||
findFocusElement(component) ||
root;
const target = (fallback && fallback.isConnected && root.contains(fallback) && fallback) || resolveFocusTarget(root) || findFocusElement(component) || root;
if (!target) {
return;
@ -1019,10 +1012,7 @@ export class View {
const current = typeof this.navigation.currentPosition === "number" ? this.navigation.currentPosition : nextPos;
if (
this.navigation.direction !== NavigationDirection.Back &&
this.navigation.direction !== NavigationDirection.Forward
) {
if (this.navigation.direction !== NavigationDirection.Back && this.navigation.direction !== NavigationDirection.Forward) {
if (nextPos < current) {
this.navigation.direction = NavigationDirection.Back;
} else if (nextPos > current) {

View file

@ -6,26 +6,14 @@
</strong>
<span :title="version" class="body-link text-selectable">
<span class="cursor-copy" @click.stop.prevent="$util.copyText(about, version)">Build</span>
<a
href="https://docs.photoprism.app/release-notes/"
target="_blank"
rel="noopener"
class="body-link text-truncate"
>{{ build }}</a
>
<a href="https://docs.photoprism.app/release-notes/" target="_blank" rel="noopener" class="body-link text-truncate">{{ build }}</a>
</span>
</div>
<div class="hidden-xs text-sm-end">
<a
href="https://raw.githubusercontent.com/photoprism/photoprism/develop/NOTICE"
target="_blank"
rel="noopener"
class="text-link"
<a href="https://raw.githubusercontent.com/photoprism/photoprism/develop/NOTICE" target="_blank" rel="noopener" class="text-link"
>3rd-party software packages</a
>
<a href="https://www.photoprism.app/about/team/" target="_blank" rel="noopener" class="body-link"
>© 2018-2025 PhotoPrism UG</a
>
<a href="https://www.photoprism.app/about/team/" target="_blank" rel="noopener" class="body-link">© 2018-2025 PhotoPrism UG</a>
</div>
</footer>
</template>

View file

@ -1,20 +1,8 @@
<template>
<div class="p-action-menu">
<v-menu
:model-value="visible"
:open-on-hover="openOnHover"
class="action-menu action-menu--default"
@update:model-value="onMenu"
>
<v-menu :model-value="visible" :open-on-hover="openOnHover" class="action-menu action-menu--default" @update:model-value="onMenu">
<template #activator="{ props }">
<v-btn
v-bind="props"
density="comfortable"
:icon="buttonIcon"
:tabindex="tabindex"
class="action-menu__btn"
:class="buttonClass"
></v-btn>
<v-btn v-bind="props" density="comfortable" :icon="buttonIcon" :tabindex="tabindex" class="action-menu__btn" :class="buttonClass"></v-btn>
</template>
<v-list slim nav density="compact" bg-color="navigation" class="action-menu__list" :class="listClass">

View file

@ -13,15 +13,7 @@
offset="12"
>
<template #activator="{ props }">
<v-btn
v-bind="props"
icon
size="52"
color="highlight"
variant="elevated"
density="comfortable"
class="action-menu opacity-95 ma-5"
>
<v-btn v-bind="props" icon size="52" color="highlight" variant="elevated" density="comfortable" class="action-menu opacity-95 ma-5">
<span class="count-clipboard">{{ selection.length }}</span>
</v-btn>
</template>
@ -81,26 +73,11 @@
class="action-delete"
@click.stop="dialog.delete = true"
></v-btn>
<v-btn
key="action-close"
icon="mdi-close"
color="grey-darken-2"
density="comfortable"
class="action-clear"
@click.stop="clearClipboard()"
></v-btn>
<v-btn key="action-close" icon="mdi-close" color="grey-darken-2" density="comfortable" class="action-clear" @click.stop="clearClipboard()"></v-btn>
</v-speed-dial>
</div>
<p-photo-album-dialog
:visible="dialog.album"
@close="dialog.album = false"
@confirm="cloneAlbums"
></p-photo-album-dialog>
<p-album-delete-dialog
:visible="dialog.delete"
@close="dialog.delete = false"
@confirm="batchDelete"
></p-album-delete-dialog>
<p-photo-album-dialog :visible="dialog.album" @close="dialog.album = false" @confirm="cloneAlbums"></p-photo-album-dialog>
<p-album-delete-dialog :visible="dialog.delete" @close="dialog.delete = false" @confirm="batchDelete"></p-album-delete-dialog>
</div>
</template>
<script>
@ -143,8 +120,7 @@ export default {
return {
canDelete: this.$config.allow("albums", "delete"),
canDownload:
this.$config.allow("albums", "download") && features.download && !settings?.albums?.download?.disabled,
canDownload: this.$config.allow("albums", "download") && features.download && !settings?.albums?.download?.disabled,
canShare: this.$config.allow("albums", "share") && features.share,
canManage: this.$config.allow("albums", "manage"),
deletable: ["album", "moment", "state"],

View file

@ -10,13 +10,7 @@
@after-enter="afterEnter"
@after-leave="afterLeave"
>
<v-form
ref="form"
validate-on="invalid-input"
class="form-album-edit"
accept-charset="UTF-8"
@submit.prevent="confirm"
>
<v-form ref="form" validate-on="invalid-input" class="form-album-edit" accept-charset="UTF-8" @submit.prevent="confirm">
<v-card>
<v-card-title class="d-flex justify-start align-center ga-3">
<v-icon size="28" color="primary">mdi-bookmark</v-icon>
@ -40,13 +34,7 @@
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
v-model="model.Location"
hide-details
:label="$gettext('Location')"
:disabled="disabled"
class="input-location"
></v-text-field>
<v-text-field v-model="model.Location" hide-details :label="$gettext('Location')" :disabled="disabled" class="input-location"></v-text-field>
</v-col>
<v-col cols="12">
<v-textarea
@ -85,22 +73,10 @@
></v-select>
</v-col>
<v-col sm="3">
<v-checkbox
v-model="model.Favorite"
:disabled="disabled"
:label="$gettext('Favorite')"
density="comfortable"
hide-details
></v-checkbox>
<v-checkbox v-model="model.Favorite" :disabled="disabled" :label="$gettext('Favorite')" density="comfortable" hide-details></v-checkbox>
</v-col>
<v-col v-if="experimental && featPrivate" sm="3">
<v-checkbox
v-model="model.Private"
:disabled="disabled"
:label="$gettext('Private')"
density="comfortable"
hide-details
></v-checkbox>
<v-checkbox v-model="model.Private" :disabled="disabled" :label="$gettext('Private')" density="comfortable" hide-details></v-checkbox>
</v-col>
</v-row>
</v-card-text>

View file

@ -7,12 +7,7 @@
accept-charset="UTF-8"
@submit.prevent="updateQuery()"
>
<v-toolbar
flat
:density="$vuetify.display.smAndDown ? 'compact' : 'default'"
class="page-toolbar"
color="secondary"
>
<v-toolbar flat :density="$vuetify.display.smAndDown ? 'compact' : 'default'" class="page-toolbar" color="secondary">
<v-toolbar-title :title="album.Title" class="page__title">
<router-link :to="{ name: collectionRoute }" class="hidden-xs">
{{ T(collectionTitle) }}
@ -36,13 +31,7 @@
class="ms-1"
>
<v-btn value="cards" icon="mdi-view-column" class="ps-1 action-view-cards" @click="setView('cards')"></v-btn>
<v-btn
v-if="listView"
value="list"
icon="mdi-view-list"
class="action-view-list"
@click="setView('list')"
></v-btn>
<v-btn v-if="listView" value="list" icon="mdi-view-list" class="action-view-list" @click="setView('list')"></v-btn>
<v-btn value="mosaic" icon="mdi-view-comfy" class="pe-1 action-view-mosaic" @click="setView('mosaic')"></v-btn>
</v-btn-toggle>
@ -53,12 +42,7 @@
{{ album.Description }}
</div>
<p-share-dialog
:visible="dialog.share"
:model="album"
@upload="webdavUpload"
@close="dialog.share = false"
></p-share-dialog>
<p-share-dialog :visible="dialog.share" :model="album" @upload="webdavUpload" @close="dialog.share = false"></p-share-dialog>
<p-service-upload
:visible="dialog.upload"
:items="{ albums: album.getId() }"
@ -124,8 +108,7 @@ export default {
return {
expanded: false,
canUpload: this.$config.allow("files", "upload") && features.upload,
canDownload:
this.$config.allow("albums", "download") && features.download && !settings?.albums?.download?.disabled,
canDownload: this.$config.allow("albums", "download") && features.download && !settings?.albums?.download?.disabled,
canShare: this.$config.allow("albums", "share") && features.share,
canManage: this.$config.allow("albums", "manage"),
canDelete: this.$config.allow("albums", "delete"),

View file

@ -15,9 +15,7 @@
<h6 class="text-h6">{{ $gettext(`Support Our Mission`) }}</h6>
</v-card-title>
<v-card-text class="text-subtitle-2">{{
$gettext(
`Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy.`
)
$gettext(`Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy.`)
}}</v-card-text>
<v-card-text class="text-body-2">{{
$gettext(

View file

@ -156,7 +156,6 @@ export default {
color: "on-surface",
bgColor: "secondary",
baseColor: "secondary",
sliderColor: "surface-variant",
},
VTable: {
density: "comfortable",

View file

@ -8,17 +8,8 @@
:tab="edit.tab"
@close="closeEditDialog"
></p-photo-edit-dialog>
<p-photo-batch-edit
:visible="batchEdit.visible"
:selection="batchEdit.selection"
@close="closeBatchEdit"
></p-photo-batch-edit>
<p-upload-dialog
:visible="upload.visible"
:data="upload.data"
@close="closeUploadDialog"
@confirm="closeUploadDialog"
></p-upload-dialog>
<p-photo-batch-edit :visible="batchEdit.visible" :selection="batchEdit.selection" @close="closeBatchEdit"></p-photo-batch-edit>
<p-upload-dialog :visible="upload.visible" :data="upload.data" @close="closeUploadDialog" @confirm="closeUploadDialog"></p-upload-dialog>
<p-update :visible="update.visible" @close="closeUpdateDialog"></p-update>
<p-lightbox @enter="onLightboxEnter" @leave="onLightboxLeave"></p-lightbox>
</div>

View file

@ -13,15 +13,7 @@
offset="12"
>
<template #activator="{ props }">
<v-btn
v-bind="props"
icon
size="52"
color="highlight"
variant="elevated"
density="comfortable"
class="action-menu opacity-95 ma-5"
>
<v-btn v-bind="props" icon size="52" color="highlight" variant="elevated" density="comfortable" class="action-menu opacity-95 ma-5">
<span class="count-clipboard">{{ selection.length }}</span>
</v-btn>
</template>
@ -61,11 +53,7 @@
></v-btn>
</v-speed-dial>
</div>
<p-photo-album-dialog
:visible="dialog.album"
@close="dialog.album = false"
@confirm="addToAlbum"
></p-photo-album-dialog>
<p-photo-album-dialog :visible="dialog.album" @close="dialog.album = false" @confirm="addToAlbum"></p-photo-album-dialog>
</div>
</template>
<script>

View file

@ -1,12 +1,5 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="currentColor"
>
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor">
<rect fill="none" height="24" width="24" />
<path
d="M9.68,13.69L12,11.93l2.31,1.76l-0.88-2.85L15.75,9h-2.84L12,6.19L11.09,9H8.25l2.31,1.84L9.68,13.69z M20,10 c0-4.42-3.58-8-8-8s-8,3.58-8,8c0,2.03,0.76,3.87,2,5.28V23l6-2l6,2v-7.72C19.24,13.87,20,12.03,20,10z M12,4c3.31,0,6,2.69,6,6 s-2.69,6-6,6s-6-2.69-6-6S8.69,4,12,4z"

View file

@ -49,6 +49,7 @@
hide-no-data
return-object
class="chip-selector__input"
@click:control="focusInput"
@keydown.enter.prevent="onEnter"
@blur="addNewItem"
@update:model-value="onComboboxChange"
@ -220,17 +221,13 @@ export default {
updateItemAction(itemToUpdate, action) {
// Special case: remove new items completely
if (itemToUpdate.isNew && action === "remove") {
const updatedItems = this.items.filter(
(item) => (item.value || item.title) !== (itemToUpdate.value || itemToUpdate.title)
);
const updatedItems = this.items.filter((item) => (item.value || item.title) !== (itemToUpdate.value || itemToUpdate.title));
this.$emit("update:items", updatedItems);
return;
}
// Update action for existing item
const updatedItems = this.items.map((item) =>
(item.value || item.title) === (itemToUpdate.value || itemToUpdate.title) ? { ...item, action } : item
);
const updatedItems = this.items.map((item) => ((item.value || item.title) === (itemToUpdate.value || itemToUpdate.title) ? { ...item, action } : item));
this.$emit("update:items", updatedItems);
},
@ -238,19 +235,8 @@ export default {
onComboboxChange(value) {
if (value && typeof value === "object" && value.title) {
this.newItemTitle = value;
this.temporarilyCloseMenu();
this.addNewItem();
this.menuOpen = false;
// Immediately clear the input, remove focus and restore placeholder
this.$nextTick(() => {
this.newItemTitle = "";
if (this.$refs.inputField) {
this.$refs.inputField.blur();
// Force the combobox to reset completely
setTimeout(() => {
this.newItemTitle = null;
}, 10);
}
});
} else {
this.newItemTitle = value;
}
@ -283,15 +269,12 @@ export default {
}
const normalizedTitle = this.normalizeTitle(title);
const existingItem = this.items.find(
(item) => (item.value && value && item.value === value) || this.normalizeTitle(item.title) === normalizedTitle
);
const existingItem = this.items.find((item) => (item.value && value && item.value === value) || this.normalizeTitle(item.title) === normalizedTitle);
if (existingItem) {
let changed = false;
const updatedItems = this.items.map((item) => {
const isSame =
(item.value && value && item.value === value) || this.normalizeTitle(item.title) === normalizedTitle;
const isSame = (item.value && value && item.value === value) || this.normalizeTitle(item.title) === normalizedTitle;
if (!isSame) {
return item;
}
@ -341,24 +324,13 @@ export default {
};
this.$emit("update:items", [...this.items, newItem]);
this.newItemTitle = null;
this.menuOpen = false;
// Refocus input field
this.$nextTick(() => {
if (this.$refs.inputField) {
this.$refs.inputField.focus();
}
});
this.temporarilyCloseMenu();
this.clearAndOptionallyRefocus(true);
},
onEnter() {
this.suppressMenuOpen = true;
this.menuOpen = false;
this.temporarilyCloseMenu();
this.addNewItem();
window.setTimeout(() => {
this.suppressMenuOpen = false;
}, 250);
},
onMenuUpdate(val) {
@ -368,20 +340,42 @@ export default {
}
this.menuOpen = val;
},
resetInputField() {
focusInput() {
if (this.$refs.inputField && typeof this.$refs.inputField.focus === "function") {
this.$refs.inputField.focus();
}
},
temporarilyCloseMenu() {
this.menuOpen = false;
this.suppressMenuOpen = true;
window.setTimeout(() => {
this.suppressMenuOpen = false;
}, 200);
},
clearAndOptionallyRefocus(shouldRefocus = false) {
this.$nextTick(() => {
this.newItemTitle = "";
if (this.$refs.inputField) {
this.$refs.inputField.blur();
setTimeout(() => {
this.newItemTitle = null;
if (shouldRefocus) {
this.focusInput();
}
}, 10);
} else {
this.newItemTitle = null;
}
});
},
resetInputField() {
this.temporarilyCloseMenu();
this.clearAndOptionallyRefocus(false);
},
},
};
</script>

View file

@ -13,15 +13,7 @@
offset="12"
>
<template #activator="{ props }">
<v-btn
v-bind="props"
icon
size="52"
color="highlight"
variant="elevated"
density="comfortable"
class="action-menu opacity-95 ma-5"
>
<v-btn v-bind="props" icon size="52" color="highlight" variant="elevated" density="comfortable" class="action-menu opacity-95 ma-5">
<span class="count-clipboard">{{ selection.length }}</span>
</v-btn>
</template>
@ -47,26 +39,11 @@
class="action-delete"
@click.stop="dialog.delete = true"
></v-btn>
<v-btn
key="action-close"
icon="mdi-close"
color="grey-darken-2"
density="comfortable"
class="action-clear"
@click.stop="clearClipboard()"
></v-btn>
<v-btn key="action-close" icon="mdi-close" color="grey-darken-2" density="comfortable" class="action-clear" @click.stop="clearClipboard()"></v-btn>
</v-speed-dial>
</div>
<p-photo-album-dialog
:visible="dialog.album"
@close="dialog.album = false"
@confirm="addToAlbum"
></p-photo-album-dialog>
<p-label-delete-dialog
:visible="dialog.delete"
@close="dialog.delete = false"
@confirm="batchDelete"
></p-label-delete-dialog>
<p-photo-album-dialog :visible="dialog.album" @close="dialog.album = false" @confirm="addToAlbum"></p-photo-album-dialog>
<p-label-delete-dialog :visible="dialog.delete" @close="dialog.delete = false" @confirm="batchDelete"></p-label-delete-dialog>
</div>
</template>
<script>

View file

@ -11,14 +11,7 @@
@after-enter="afterEnter"
@after-leave="afterLeave"
>
<v-form
ref="form"
validate-on="invalid-input"
class="form-label-edit"
accept-charset="UTF-8"
tabindex="-1"
@submit.prevent="confirm"
>
<v-form ref="form" validate-on="invalid-input" class="form-label-edit" accept-charset="UTF-8" tabindex="-1" @submit.prevent="confirm">
<v-card>
<v-card-title class="d-flex justify-start align-center ga-3">
<v-icon size="28" color="primary">mdi-label</v-icon>
@ -38,14 +31,7 @@
></v-text-field>
</v-col>
<v-col sm="4">
<v-checkbox
v-model="model.Favorite"
:disabled="disabled"
:label="$gettext('Favorite')"
density="comfortable"
hide-details
>
</v-checkbox>
<v-checkbox v-model="model.Favorite" :disabled="disabled" :label="$gettext('Favorite')" density="comfortable" hide-details> </v-checkbox>
</v-col>
</v-row>
</v-card-text>

Some files were not shown because too many files have changed in this diff Show more