Commit graph

384 commits

Author SHA1 Message Date
Keith Martin
b6687b6c29
Tests: Improve isolation and add fixes #5263
* Tests: fix random selection of deleted record causing test failure
* Tests: fix test folders being left after test
* Tests: ensure that required records are available
* Tests: make each package execute against it's own testdata folder to ensure no interpackage test failures
* Tests: add unit tests of CleanupTestFolder
* Tests:  Allow defer in TestMain
* Tests: rename testMain to runTestMain
2026-07-12 05:47:21 +02:00
Michael Mayer
c9f21cd965 Server: Derive WebDAV proxy test paths from proxy.PathPrefix
TestIsWebDAVPath hardcoded the "/i/" proxy prefix, so it failed when
proxy.DefaultPathPrefix changed. Build the proxy cases from proxy.PathPrefix,
the same value IsWebDAVPath uses, so they track the configured prefix.
2026-07-07 23:47:57 +00:00
Michael Mayer
a693df1eaa WebDAV: Route favorite-flag sidecar errors to the system log #5715
WebDAVSetFavoriteFlag logged sidecar mkdir/write failures at error level on
the UI log stream with the raw error, leaking the absolute sidecar path.
Route them through event.SystemError with clean.Error, matching the request
error handling in the WebDAV logger.
2026-07-07 23:47:57 +00:00
Michael Mayer
7bea2dccfe WebDAV: Route request errors to the system log, not the UI #5715
All WebDAV write-method errors (PUT/DELETE/MOVE/COPY/MKCOL/...) now go to
the console-only system log instead of the in-app errors table and browser
log viewer, because golang.org/x/net/webdav embeds absolute server paths in
its messages. Operators still see full detail in the container/service logs.

A MKCOL against an already-existing collection is a benign probe used by
sync clients such as PhotoSync to test for a directory before creating it;
it returns 405 and is logged at debug rather than as an error.
2026-07-07 23:27:52 +00:00
Ömer Duran
4b33d3bd1a
PWA: Add maskable icons, lang/dir, and install screenshots #5696 2026-06-30 19:53:52 +02:00
Michael Mayer
50976f427e Auth: Add RP-initiated OIDC logout via PHOTOPRISM_OIDC_LOGOUT #5684 #5433
Sign-out of an OIDC session redirects the browser to the provider's
discovered end_session_endpoint (id_token_hint + absolute
post_logout_redirect_uri) when PHOTOPRISM_OIDC_LOGOUT is enabled, so the
provider SSO session ends and the next login re-prompts. Opt-in (default
off); local/LDAP logout and providers without an end-session endpoint fall
back to local logout.

Adds the shared CE /api/v1/oauth/logout route and OAuthLogoutHandler hook
plus the Portal OP end_session_endpoint advertised in the Portal discovery
document, for Portal builds to serve via the override hook.
2026-06-24 17:21:00 +02:00
Cathie Integra
3f096a592b Links: Use canonical trailing-slash form for website URLs 2026-06-24 17:20:30 +02:00
Michael Mayer
c45ee6e54f Auth: Revoke derived sessions & gate app passwords by login state #5647
- Add scoped session revocation (RevokeSessions / RevokeDerivedSessions)
  shared by the user-update API and the CLI: a privilege-level change now
  revokes logins and app-password-derived sessions while keeping the app
  passwords themselves, so configured devices keep working.
- Identify app-password-derived sessions by auth_method "session".
- Deny app passwords on the REST API when the account cannot log in
  (DenyLogIn); WebDAV access stays governed by CanUseWebDAV.
- Reduce the WebDAV auth cache expiration to one minute.
- Add IsSystemOrInvalid; allow deleting the initial admin account and skip
  re-initializing a deactivated or deleted admin in InitAccount.
- Move session-revocation scopes to pkg/authn and extend tests.
2026-06-15 23:41:01 +00:00
Michael Mayer
bc327016ad Metadata: Add Camera Make and Model updates via CLI & API #5663 #5656
Mirror the lens make/model editing surface for cameras: entity UpdateMakeModel/SaveForm, form validation, query, search, the GET/PUT /api/v1/cameras endpoints, and the cameras CLI command, plus a cameras ACL resource and scope.

Also tidy the lens surface for parity: self-validating SaveForm, empty make/model guard, X-Count search header, service-role grant, the empty-id/slug docs, and order cameras before lenses everywhere.
2026-06-15 09:25:44 +00:00
Keith Martin
c3eda657fd
Metadata: Add Lens Make and Model updates via CLI & API #5644 #5656
Adds the ability to override a lens's Make/Model (e.g. fixing Pentax lenses that ExifTool decodes as `4 38`) via a new photoprism lenses update CLI command and a `PUT /api/v1/lenses/:id endpoint`, plus a `GET /api/v1/lenses` search endpoint, a new lenses ACL resource, and an lenses ls list command.
2026-06-15 09:37:32 +02:00
Michael Mayer
b6e8ad2d60 WebDAV: Limit PUT upload size to the configured originals limit
Cap the WebDAV PUT request body at OriginalsLimitBytes when an originals limit is configured, so a single upload cannot stream an unbounded body to disk past the per-file ceiling; no-op when unlimited. Adds a load-bearing regression test.
2026-06-10 20:40:28 +00:00
Michael Mayer
22c1789c14 WebDAV: Harden joinUnderBase against drive-letter and backslash paths
Normalize separators, reject drive-letter prefixes, and verify
containment with filepath.Rel instead of a string prefix, matching the
pkg/fs ZIP safe-join. Extend TestJoinUnderBase to mirror TestSafeJoin
coverage and lock the handler surface via WebDAVFileName.
2026-06-10 17:44:13 +00:00
Michael Mayer
cb48c209b6 Auth: Gate app passwords behind a settings feature flag #5647
Adds an AppPasswords feature flag (default on) so app passwords can be disabled, closing the bypass where an app password minted by an OIDC-provisioned user keeps working after the account expires. When off, minting (oauth/token and auth add) is rejected and existing app passwords are no longer accepted on the REST API (403) or WebDAV (401). App passwords are identified by their session auth provider (IsApplication), covering every grant type. The Apps and Devices affordance is hidden for sessions that may not change a password; operators can force it off via PHOTOPRISM_DISABLE_FEATURES.
2026-06-09 17:36:24 +00:00
Ömer Duran
8e73783ddd
Tests: Drop blank lines between Portal OpenID config subtests 2026-06-05 21:03:38 +02:00
Michael Mayer
51c4eed71e Auth: Serve Portal OIDC OP endpoints under /api/v1/oauth/* #4368 #4369
Move the Portal OIDC OP authorize/token/userinfo onto the shared CE
/api/v1/oauth/* routes (the reserved #4368/#4369 stubs) and drop the parallel
root /oauth/* set.

- Add overridable handler hooks (oauth_handlers.go) mirroring
  server.WebDAVHandler; OAuthToken delegates only the authorization_code grant
  (gated on a form content type) and keeps client_credentials/password/session
  unchanged; userinfo now serves GET and POST.
- Scope the OP session cookie to /api/v1/oauth (base-path aware) so the browser
  still sends it to the moved authorize endpoint instead of looping.
- Stop the proxy re-scoping instance->Portal authorize redirects
  (portalRootPathPrefixes -> /api/v1/oauth/).
- Point discovery at issuer + /api/v1/oauth/*; fix the JWKS URL base-path
  doubling for sub-path deployments (also in CE openid.go).
2026-06-03 15:28:05 +00:00
Michael Mayer
b04233f2f4 Backend: Use strings.SplitSeq for split-and-iterate loops #5599
Replace strings.Split with the lazy strings.SplitSeq iterator (Go 1.23+)
in loops that only range over the tokens, avoiding the intermediate
slice allocation. The yielded substrings are identical to Split, so
behavior is unchanged. Applies the suggestion from #5599 to its three
sites (CIDR parsing, WebDAV hidden-path, overlay path checks) and
extends it to two more split-and-iterate loops in the server compression
negotiator and MCP config-options builder for consistency. The slice
returning splitPath helper is intentionally left on strings.Split.
2026-05-30 09:49:47 +00:00
Michael Mayer
fb6166b490 Storage: Extend insufficient-storage gates to imports and writes #5613 2026-05-25 23:56:21 +00:00
Michael Mayer
570a563748 Docs: Bump copyright year to 2026 in Go package headers 2026-05-25 14:39:38 +00:00
Michael Mayer
825c8c6a2d Backend: Compact code comments and drop duplicate package headers 2026-05-25 11:47:44 +00:00
Michael Mayer
e3cd90bc43 Cluster: Add Portal OIDC discovery doc at /.well-known/openid-configuration 2026-05-24 06:43:11 +00:00
Michael Mayer
ea05645668 Cleanup: Use US English spelling in code comments 2026-05-17 13:46:24 +00:00
Michael Mayer
2e93a02195 Server: Compact verbose comments in compress and static helpers 2026-05-15 17:50:08 +00:00
Michael Mayer
3012786d82 Docs: Drop private subrepo references from public files
Sweeps top-level CODEMAP/GLOSSARY, package READMEs under internal/,
and a handful of source-comment references that linked to the private
specs/ subrepo. AGENTS.md hints stay (agent-instruction document) and
the agent-skill linking targets in Makefile are guarded with
directory checks.
2026-05-05 09:40:18 +00:00
Michael Mayer
38a20d2552 Server: Align README validator wording with code & spec #5552
internal/server/README.md still listed both `If-Modified-Since` and
`If-None-Match` as active validators for `PrecompressedStatic`. The
handler does not set an `ETag`, so the active validator pair on
`/static/*` and `/c/static/*` is `Last-Modified` + `If-Modified-Since`
only — matching the doc comment in `static_precompressed.go` and the
"Conditional requests" subsection of `specs/platform/http-compression.md`.
2026-05-03 13:51:14 +00:00
Michael Mayer
9bbe7e27a0 Server: Serve precompressed static asset siblings #5552
Adds PrecompressedStatic handler in internal/server/static_precompressed.go,
wired by routes_static.go for /static/*filepath (bundled) and
/c/static/*filepath (custom). When a .zst or .gz sibling is on disk and
the client's Accept-Encoding allows it, the handler streams the
sibling via http.ServeContent — preserving Last-Modified and
If-Modified-Since revalidation, deriving Content-Type from the identity
filename so service-worker registration and SRI continue to work, and
setting an explicit Content-Length that http.ServeContent omits when
Content-Encoding is in effect.

Range requests always serve identity (the byte offsets in Content-Range
correspond to identity bytes), and PHOTOPRISM_HTTP_COMPRESSION=none
disables encoded-sibling selection so the operator switch stays
consistent with the runtime middleware. Vary: Accept-Encoding is
emitted only when the response could realistically vary by encoding.

Both /static/* and /c/static/* are added to NewShouldCompressFn's
exclusion list so the runtime middleware never re-encodes an
already-encoded body.
2026-05-03 13:43:59 +00:00
Michael Mayer
083d437ec4 Server: Add zstd compression support #5550
Negotiates zstd alongside gzip via PHOTOPRISM_HTTP_COMPRESSION as a
comma-separated preference list (e.g. "zstd,gzip"); legacy "gzip",
"none", and the empty string keep behaving as before. Bypasses
Connection: Upgrade, predicate-excluded paths, HEAD (with Vary kept),
4xx/5xx, 206, 204, and 304. Weakens strong ETags on the encoding path
so caches don't reuse a compressed body for a different coding.
2026-05-03 10:10:33 +00:00
Michael Mayer
da224d309e MCP: Add "DisableMCP" option to disable /api/v1/mcp #5024 #5536
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 11:08:58 +02:00
Michael Mayer
7db82af193 API: Document "GET /api/v1/photos/view" in swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 14:01:19 +02:00
Michael Mayer
4f14ed90c0 MCP: Remove "prototype" wording for production-readiness #5024 #5519
- Rewrite package doc, struct comments, log line, and route-registration
  comment so they describe the MCP server as a first-class feature
  rather than a pre-release prototype. The "Usage" strings on
  MCPCommands / MCPServeCommand were updated separately and stay
  unchanged.
- Drop "in this prototype" from the edition-advisory warning emitted by
  list_config_keys; the message now reads "edition filtering is
  advisory; results come from the current <edition> build metadata".
- Rewrite internal/mcp/README.md: new "Scope" section with
  in-scope/out-of-scope invariants, corrected authorization summary
  (admin + API client roles + manager in Pro/Portal, anonymous in
  public mode for the registered read-only tools), and a clearer
  "Current Capabilities" block.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 08:46:07 +02:00
Ömer Duran
e2f8474309
MCP: Add read-only Model Context Protocol prototype #5024 #5519
* MCP: Add internal read-only prototype #5024

* MCP: Fix edition detection, section assignment, and input validation #5024

* MCP: Add authenticated HTTP endpoint with ACL and experimental gate #5024

* MCP: Document client compatibility and config examples #502

* MCP: Refine ACL grants and finalize prototype polish #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

* MCP: Update go.sum #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

* MCP: Update license NOTICE files #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

---------

Signed-off-by: Michael Mayer <michael@photoprism.app>
Co-authored-by: Michael Mayer <michael@photoprism.app>
2026-04-10 12:51:11 +02:00
Michael Mayer
d32e9d754e Backend: Update Go deps in go.mod/go.sum, align server gzip 404 test
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 12:19:12 +01:00
Michael Mayer
5b8868b656 Security: Canonicalize HTTPS redirects
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 14:45:59 +01:00
Michael Mayer
e2ff8cd15d Server: Use canonical host for AutoTLS HTTP redirects
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 14:31:03 +01:00
Michael Mayer
0ae82d3683 Server: Export WebDAV response helper for PROPFIND content type #5472
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 16:03:33 +01:00
Michael Mayer
7b96a768d5 WebDAV: Harden response headers for interoperability #5472
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 15:23:10 +01:00
Michael Mayer
ecdc49ad33 Server: Add HTTP security hardening config options #5471
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 10:12:57 +01:00
Michael Mayer
fcb8bc60c4 Proxy: Rename portal-proxy-prefix to portal-proxy-uri
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 19:20:41 +01:00
Michael Mayer
2ee5f1337e PWA: Use scope-relative manifest URLs for iOS path-based installs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 23:33:44 +01:00
Michael Mayer
349cea2d2b PWA: Use scope-relative start_url for path-based installs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 22:48:13 +01:00
Michael Mayer
a570da6335 Feedback: Remove UI route and disable API endpoint
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 23:30:43 +01:00
Michael Mayer
7476231235 Server: Fix remaining gosec/revive issues in internal/server
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 16:01:47 +01:00
Michael Mayer
c91726d969 Server: Disable implicit proxy trust and add spoof tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 15:57:40 +01:00
Michael Mayer
038d38d552 Security: Extend denylist coverage for names, paths and extensions #5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 11:01:15 +01:00
Michael Mayer
31515f9524 Security: Harden web overlay serving via shared security checks
https://github.com/photoprism/photoprism/issues/5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 17:01:39 +01:00
Michael Mayer
18061fb536 Config: Refactor frontend URI handling for configurable base paths
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 00:55:16 +01:00
Michael Mayer
bcb6d39332 Server: Add web overlay handler for unmatched routes #5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 20:02:58 +01:00
Michael Mayer
d5ecab8827 Proxy: Define /i/ as DefaultPathPrefix for shared-domain deployments
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 01:15:23 +01:00
Michael Mayer
a2b7615c93 Go: Apply go fix modernizations across backend packages
Run `go fix ./...` and keep mechanical modernization updates.

- Replace `interface{}` with `any` in signatures and local types
- Apply formatter/style cleanups from go1.26 tooling
- Keep `omitempty` behavior-preserving simplifications suggested by fix
- No functional feature changes intended

Validation:
- go test ./... -run '^$' -count=1 (Go 1.26.0)
- GOTOOLCHAIN=go1.24.10 go test ./... -run '^$' -count=1

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 03:54:33 +01:00
Michael Mayer
89f4cb4e34 Config: Add portal-proxy-prefix option for multi-tenant setups #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 10:26:12 +01:00
Michael Mayer
6867626c9a Docs: Shorten "Context & Constraints" to "Constraints"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 08:23:27 +01:00