Docs: Update /pkg/service/http/... -> /pkg/http/...

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2025-10-19 21:35:16 +02:00
parent a921f82a17
commit 72f88be5fe
4 changed files with 10 additions and 10 deletions

View File

@@ -274,7 +274,7 @@ Note: Across our public documentation, official images, and in production, the c
### HTTP Download — Security Checklist ### HTTP Download — Security Checklist
- Use the shared safe HTTP helper instead of adhoc `net/http` code: - Use the shared safe HTTP helper instead of adhoc `net/http` code:
- Package: `pkg/service/http/safe` → `safe.Download(destPath, url, *safe.Options)`. - Package: `pkg/http/safe` → `safe.Download(destPath, url, *safe.Options)`.
- Default policy in this repo: allow only `http/https`, enforce timeouts and max size, write to a `0600` temp file then rename. - Default policy in this repo: allow only `http/https`, enforce timeouts and max size, write to a `0600` temp file then rename.
- SSRF protection (mandatory unless explicitly needed for tests): - SSRF protection (mandatory unless explicitly needed for tests):
- Set `AllowPrivate=false` to block private/loopback/multicast/linklocal ranges. - Set `AllowPrivate=false` to block private/loopback/multicast/linklocal ranges.
@@ -419,7 +419,7 @@ Note: Across our public documentation, official images, and in production, the c
- Keep bootstrap code decoupled: avoid importing `internal/service/cluster/node/*` from `internal/config` or the cluster root, let nodes talk to the Portal over HTTP(S), and rely on constants from `internal/service/cluster/const.go`. - Keep bootstrap code decoupled: avoid importing `internal/service/cluster/node/*` from `internal/config` or the cluster root, let nodes talk to the Portal over HTTP(S), and rely on constants from `internal/service/cluster/const.go`.
- Config init order: load `options.yml` (`c.initSettings()`), run `EarlyExt().InitEarly(c)`, connect/register the DB, then invoke `Ext().Init(c)`. - Config init order: load `options.yml` (`c.initSettings()`), run `EarlyExt().InitEarly(c)`, connect/register the DB, then invoke `Ext().Init(c)`.
- Theme endpoint: `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`; only reinstall when `app.js` is missing and always use the header helpers in `pkg/service/http/header`. - Theme endpoint: `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`; only reinstall when `app.js` is missing and always use the header helpers in `pkg/http/header`.
- Registration flow: send `rotate=true` only for MySQL/MariaDB nodes without credentials, treat 401/403/404 as terminal, include `ClientID` + `ClientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings. - Registration flow: send `rotate=true` only for MySQL/MariaDB nodes without credentials, treat 401/403/404 as terminal, include `ClientID` + `ClientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings.
- Registry & DTOs: use the client-backed registry (`NewClientRegistryWithConfig`)—the file-backed version is legacy—and treat migration as complete only after swapping callsites, building, and running focused API/CLI tests. Nodes are keyed by UUID v7 (`/api/v1/cluster/nodes/{uuid}`), the registry interface stays UUID-first (`Get`, `FindByNodeUUID`, `FindByClientID`, `RotateSecret`, `DeleteAllByUUID`), CLI lookups resolve `uuid → ClientID → name`, and DTOs normalize `Database.{Name,User,Driver,RotatedAt}` while exposing `ClientSecret` only during creation/rotation. `nodes rm --all-ids` cleans duplicate client rows, admin responses may include `AdvertiseUrl`/`Database`, client/user sessions stay redacted, registry files live under `conf.PortalConfigPath()/nodes/` (mode 0600), and `ClientData` no longer stores `NodeUUID`. - Registry & DTOs: use the client-backed registry (`NewClientRegistryWithConfig`)—the file-backed version is legacy—and treat migration as complete only after swapping callsites, building, and running focused API/CLI tests. Nodes are keyed by UUID v7 (`/api/v1/cluster/nodes/{uuid}`), the registry interface stays UUID-first (`Get`, `FindByNodeUUID`, `FindByClientID`, `RotateSecret`, `DeleteAllByUUID`), CLI lookups resolve `uuid → ClientID → name`, and DTOs normalize `Database.{Name,User,Driver,RotatedAt}` while exposing `ClientSecret` only during creation/rotation. `nodes rm --all-ids` cleans duplicate client rows, admin responses may include `AdvertiseUrl`/`Database`, client/user sessions stay redacted, registry files live under `conf.PortalConfigPath()/nodes/` (mode 0600), and `ClientData` no longer stores `NodeUUID`.
- Provisioner & DSN: database/user names use UUID-based HMACs (`photoprism_d<hmac11>`, `photoprism_u<hmac11>`); `BuildDSN` accepts a `driver` but falls back to MySQL format with a warning when unsupported. - Provisioner & DSN: database/user names use UUID-based HMACs (`photoprism_d<hmac11>`, `photoprism_u<hmac11>`); `BuildDSN` accepts a `driver` but falls back to MySQL format with a warning when unsupported.

View File

@@ -40,7 +40,7 @@ High-Level Package Map (Go)
- `internal/service` — cluster/portal, maps, hub, webdav - `internal/service` — cluster/portal, maps, hub, webdav
- `internal/event` — logging, pub/sub, audit - `internal/event` — logging, pub/sub, audit
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination - `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination
- `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/clean`, `pkg/enum`, `pkg/fs`, `pkg/txt`, `pkg/service/http/header` - `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/clean`, `pkg/enum`, `pkg/fs`, `pkg/txt`, `pkg/http/header`
Templates & Static Assets Templates & Static Assets
- Entry HTML lives in `assets/templates/index.gohtml`, which includes the splash markup from `app.gohtml` and the SPA loader from `app.js.gohtml`. - Entry HTML lives in `assets/templates/index.gohtml`, which includes the splash markup from `app.gohtml` and the SPA loader from `app.js.gohtml`.
@@ -109,7 +109,7 @@ Cluster / Portal
Logging & Events Logging & Events
- Logger and event hub: `internal/event/*`; `event.Log` is the shared logger. - Logger and event hub: `internal/event/*`; `event.Log` is the shared logger.
- HTTP headers/constants: `pkg/service/http/header/*` always prefer these in handlers and tests. - HTTP headers/constants: `pkg/http/header/*` always prefer these in handlers and tests.
Server Startup Flow (happy path) Server Startup Flow (happy path)
1) `photoprism start` (CLI) `internal/commands/start.go` 1) `photoprism start` (CLI) `internal/commands/start.go`
@@ -170,7 +170,7 @@ Security & Hot Spots (Where to Look)
- Sizes & names: `internal/thumb/sizes.go`, `internal/thumb/names.go`, `internal/thumb/filter.go`; face/marker crop helpers live in `internal/thumb/crop` (e.g., `ParseThumb`, `IsCroppedThumb`). - Sizes & names: `internal/thumb/sizes.go`, `internal/thumb/names.go`, `internal/thumb/filter.go`; face/marker crop helpers live in `internal/thumb/crop` (e.g., `ParseThumb`, `IsCroppedThumb`).
- Safe HTTP downloader: - Safe HTTP downloader:
- Shared utility: `pkg/service/http/safe` (`Download`, `Options`). - Shared utility: `pkg/http/safe` (`Download`, `Options`).
- Protections: scheme allowlist (http/https), preDNS + perredirect hostname/IP validation, final peer IP check, size and timeout enforcement, temp file `0600` + rename. - Protections: scheme allowlist (http/https), preDNS + perredirect hostname/IP validation, final peer IP check, size and timeout enforcement, temp file `0600` + rename.
- Avatars: wrapper `internal/thumb/avatar.SafeDownload` applies stricter defaults (15s, 10MiB, `AllowPrivate=false`, imagefocused `Accept`). - Avatars: wrapper `internal/thumb/avatar.SafeDownload` applies stricter defaults (15s, 10MiB, `AllowPrivate=false`, imagefocused `Accept`).
- Tests: `go test ./pkg/http/safe -count=1` (includes redirect SSRF cases); avatars: `go test ./internal/thumb/avatar -count=1`. - Tests: `go test ./pkg/http/safe -count=1` (includes redirect SSRF cases); avatars: `go test ./internal/thumb/avatar -count=1`.
@@ -181,7 +181,7 @@ Performance & Limits
Conventions & Rules of Thumb Conventions & Rules of Thumb
- Respect package boundaries: code in `pkg/*` must not import `internal/*`. - Respect package boundaries: code in `pkg/*` must not import `internal/*`.
- Prefer constants/helpers from `pkg/service/http/header` over string literals. - Prefer constants/helpers from `pkg/http/header` over string literals.
- Never log secrets; compare tokens constanttime. - Never log secrets; compare tokens constanttime.
- Dont import Portal internals from cluster instance/service bootstraps; use HTTP. - Dont import Portal internals from cluster instance/service bootstraps; use HTTP.
- Prefer small, hermetic unit tests; isolate filesystem paths with `t.TempDir()` and env like `PHOTOPRISM_STORAGE_PATH`. - Prefer small, hermetic unit tests; isolate filesystem paths with `t.TempDir()` and env like `PHOTOPRISM_STORAGE_PATH`.
@@ -222,7 +222,7 @@ Frequently Touched Files (by topic)
- Cluster: `internal/service/cluster/*` - Cluster: `internal/service/cluster/*`
- Theme support: `internal/service/cluster/theme/version.go` exposes `DetectVersion`, used by bootstrap, CLI, and API handlers to compare portal vs node theme revisions (prefers `fs.VersionTxtFile`, falls back to `app.js` mtime). - Theme support: `internal/service/cluster/theme/version.go` exposes `DetectVersion`, used by bootstrap, CLI, and API handlers to compare portal vs node theme revisions (prefers `fs.VersionTxtFile`, falls back to `app.js` mtime).
- Registration sanitizes `AppName`, `AppVersion`, and `Theme` with `clean.TypeUnicode`; defaults for app metadata come from `config.About()` / `config.Version()`. `cluster.RegisterResponse` now includes a `Theme` hint when the portal has a newer bundle so nodes can decide whether to download immediately. - Registration sanitizes `AppName`, `AppVersion`, and `Theme` with `clean.TypeUnicode`; defaults for app metadata come from `config.About()` / `config.Version()`. `cluster.RegisterResponse` now includes a `Theme` hint when the portal has a newer bundle so nodes can decide whether to download immediately.
- Headers: `pkg/service/http/header/*` - Headers: `pkg/http/header/*`
Downloads (CLI) & yt-dlp helpers Downloads (CLI) & yt-dlp helpers
- CLI command & core: - CLI command & core:

View File

@@ -39,7 +39,7 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
## Testing Strategy ## Testing Strategy
- Build tests around the API harness (`NewApiTest`) to obtain a configured Gin router, config, and dependencies. This isolates filesystem paths and avoids polluting global state. - Build tests around the API harness (`NewApiTest`) to obtain a configured Gin router, config, and dependencies. This isolates filesystem paths and avoids polluting global state.
- Wrap requests with helper functions (for example, `PerformRequestJSON`, `PerformAuthenticatedRequest`) to capture status codes, headers, and payloads. Assert headers using constants from `pkg/service/http/header`. - Wrap requests with helper functions (for example, `PerformRequestJSON`, `PerformAuthenticatedRequest`) to capture status codes, headers, and payloads. Assert headers using constants from `pkg/http/header`.
- When handlers interact with the database, initialize fixtures through config helpers such as `config.NewTestConfig("api")` or `config.NewMinimalTestConfigWithDb("api", t.TempDir())` depending on fixture needs. - When handlers interact with the database, initialize fixtures through config helpers such as `config.NewTestConfig("api")` or `config.NewMinimalTestConfigWithDb("api", t.TempDir())` depending on fixture needs.
- Stub external dependencies (`httptest.Server`) for remote calls and set `AllowPrivate=true` explicitly when the test server binds to loopback addresses. - Stub external dependencies (`httptest.Server`) for remote calls and set `AllowPrivate=true` explicitly when the test server binds to loopback addresses.
- Structure tests with table-driven subtests (`t.Run("CaseName", ...)`) and use PascalCase names. Provide cleanup functions (`t.Cleanup`) to remove temporary files or databases created during tests. - Structure tests with table-driven subtests (`t.Run("CaseName", ...)`) and use PascalCase names. Provide cleanup functions (`t.Cleanup`) to remove temporary files or databases created during tests.

View File

@@ -18,7 +18,7 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- Follow the overwrite policy used by media helpers: require explicit confirmation (`force` flags) before replacing non-empty files. Where replacements are expected, open destinations with `O_WRONLY|O_CREATE|O_TRUNC`. - Follow the overwrite policy used by media helpers: require explicit confirmation (`force` flags) before replacing non-empty files. Where replacements are expected, open destinations with `O_WRONLY|O_CREATE|O_TRUNC`.
- Use shared logging through `event.Log` rather than direct `fmt` printing. Sensitive information such as secrets or tokens must never be logged. - Use shared logging through `event.Log` rather than direct `fmt` printing. Sensitive information such as secrets or tokens must never be logged.
- When integrating configuration options, call the accessors on `*config.Config` (for example, `conf.ClusterUUID()`) rather than mutating option structs directly. - When integrating configuration options, call the accessors on `*config.Config` (for example, `conf.ClusterUUID()`) rather than mutating option structs directly.
- For HTTP interactions, depend on the safe download helpers in `pkg/service/http/safe` or the specialized wrappers in `internal/thumb/avatar` to inherit timeout, size, and SSRF protection defaults. - For HTTP interactions, depend on the safe download helpers in `pkg/http/safe` or the specialized wrappers in `internal/thumb/avatar` to inherit timeout, size, and SSRF protection defaults.
## Configuration & Flags Integration ## Configuration & Flags Integration
@@ -48,7 +48,7 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- Stub external binaries such as `yt-dlp` with lightweight shell scripts that honor `--dump-single-json` and `--print` requests. Support environment variables like `YTDLP_ARGS_LOG`, `YTDLP_OUTPUT_FILE`, and `YTDLP_DUMMY_CONTENT` to capture arguments, create deterministic artifacts, and avoid duplicate detection in importer flows. - Stub external binaries such as `yt-dlp` with lightweight shell scripts that honor `--dump-single-json` and `--print` requests. Support environment variables like `YTDLP_ARGS_LOG`, `YTDLP_OUTPUT_FILE`, and `YTDLP_DUMMY_CONTENT` to capture arguments, create deterministic artifacts, and avoid duplicate detection in importer flows.
- Disable FFmpeg during tests that focus on command construction by setting `conf.Options().FFmpegBin = "/bin/false"` and `conf.Settings().Index.Convert = false`. - Disable FFmpeg during tests that focus on command construction by setting `conf.Options().FFmpegBin = "/bin/false"` and `conf.Settings().Index.Convert = false`.
- When asserting HTTP responses, rely on header constants from `pkg/service/http/header` (for example, `header.ContentTypeZip`) to keep expectations aligned with middleware. - When asserting HTTP responses, rely on header constants from `pkg/http/header` (for example, `header.ContentTypeZip`) to keep expectations aligned with middleware.
- For role and scope checks, reuse helpers in `internal/auth/acl` such as `acl.ParseRole`, `acl.ScopePermits`, and `acl.ScopeAttrPermits` instead of duplicating logic inside commands. - For role and scope checks, reuse helpers in `internal/auth/acl` such as `acl.ParseRole`, `acl.ScopePermits`, and `acl.ScopeAttrPermits` instead of duplicating logic inside commands.
## Preflight Checklist ## Preflight Checklist