fix(immich): a server with a self-signed certificate can be connected, as the other providers can

Synology Photos, AirTrail and Dawarich each have a switch to trust a
self-signed certificate; Immich had none, so every request to such a
server failed with a bare "fetch failed" (#2475).

Immich gets the same switch, per user and off by default:

- users.immich_allow_insecure_tls (migration 243, column guarded) and a
  settings row labelled with the existing skipSSLVerification string, so
  no new translations. The settings card on desktop and phone draws it
  from that row.
- Every request to the user's Immich (status, browse, search, asset info
  and proxy, albums, upload) passes rejectUnauthorized from the switch.
  Only 1 counts as on. A shared photo follows its owner's switch, since
  it goes to the owner's server with the owner's key.
- Settings PUT and the connection test take allow_insecure_tls as a
  boolean. Absent on a save keeps the stored choice, so an older client
  cannot clear it; disconnecting turns it off again.
- A failed request names its cause, e.g. "fetch failed (self-signed
  certificate)", instead of only the undici message.
- The upload mirror gets a timeout: the journey upload waits on it.

Fresh installs also never showed "Mirror journey photos to Immich on
upload": migration 112 added that row only where the Immich provider
already existed, and on a new database the seeds create it after the
migrations. The row is now in the seeds, and migration 243 adds it where
the provider exists without it.

Wiki: Photo-Providers.md documents the switch.
This commit is contained in:
Maurice
2026-09-23 16:12:18 +02:00
parent 41b14ebc2a
commit ae80ad266d
17 changed files with 704 additions and 53 deletions
@@ -120,8 +120,8 @@ describe('MemoriesService (delegation wrapper over services/memories/*)', () =>
svc.immichGetConnectionSettings(7);
expect(immich.getConnectionSettings).toHaveBeenCalledWith(7);
await svc.immichSaveSettings(7, 'u', 'k', '1.2.3.4');
expect(immich.saveImmichSettings).toHaveBeenCalledWith(7, 'u', 'k', '1.2.3.4');
await svc.immichSaveSettings(7, 'u', 'k', '1.2.3.4', true);
expect(immich.saveImmichSettings).toHaveBeenCalledWith(7, 'u', 'k', '1.2.3.4', true);
svc.immichSetAutoUpload(7, true);
expect(immich.setImmichAutoUpload).toHaveBeenCalledWith(7, true);
@@ -129,8 +129,8 @@ describe('MemoriesService (delegation wrapper over services/memories/*)', () =>
await svc.immichGetConnectionStatus(7);
expect(immich.getConnectionStatus).toHaveBeenCalledWith(7);
await svc.immichTestConnection('u', 'k');
expect(immich.testConnection).toHaveBeenCalledWith('u', 'k');
await svc.immichTestConnection('u', 'k', true);
expect(immich.testConnection).toHaveBeenCalledWith('u', 'k', true);
await svc.immichBrowseTimeline(7);
expect(immich.browseTimeline).toHaveBeenCalledWith(7);