mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
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:
@@ -3,6 +3,7 @@ import {
|
||||
createAlbumLinkSchema,
|
||||
immichSearchSchema,
|
||||
immichSettingsSchema,
|
||||
immichTestSchema,
|
||||
setTripPhotoSharingSchema,
|
||||
synologySearchSchema,
|
||||
synologySettingsSchema,
|
||||
@@ -29,6 +30,32 @@ describe('immich contracts', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts the self-signed switch as a boolean, on save and on test (#2475)', () => {
|
||||
for (const allow_insecure_tls of [true, false]) {
|
||||
expect(immichSettingsSchema.safeParse({ allow_insecure_tls }).success).toBe(true);
|
||||
expect(
|
||||
immichTestSchema.safeParse({
|
||||
immich_url: 'https://immich.example.org',
|
||||
immich_api_key: 'k',
|
||||
allow_insecure_tls,
|
||||
}).success,
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('leaves the switch optional, since an older client never sends it', () => {
|
||||
const parsed = immichSettingsSchema.safeParse({ immich_url: 'https://immich.example.org', immich_api_key: 'k' });
|
||||
expect(parsed.success).toBe(true);
|
||||
expect(parsed.success && parsed.data.allow_insecure_tls).toBeUndefined();
|
||||
});
|
||||
|
||||
it('refuses a switch value that is not a boolean, its string included', () => {
|
||||
for (const allow_insecure_tls of ['true', 'yes', 1, null]) {
|
||||
expect(immichSettingsSchema.safeParse({ allow_insecure_tls }).success).toBe(false);
|
||||
expect(immichTestSchema.safeParse({ allow_insecure_tls }).success).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts search paging as numbers OR strings (the controller does Number(x) || fallback)', () => {
|
||||
expect(immichSearchSchema.safeParse({ page: 2, size: 50 }).success).toBe(true);
|
||||
expect(immichSearchSchema.safeParse({ page: '2', size: '50' }).success).toBe(true);
|
||||
|
||||
@@ -40,17 +40,28 @@ const utcOffsetMinutes = looseNumber;
|
||||
|
||||
// ── Immich ────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Trust a self-signed certificate on the Immich server (#2475). Absent means
|
||||
* "leave the stored choice as it is", so a client that predates the switch
|
||||
* cannot turn it off by saving. A plain boolean: the field is new, and the
|
||||
* settings form has always sent its checkboxes as booleans, so none of the
|
||||
* string leniency `synology_skip_ssl` carries is owed here.
|
||||
*/
|
||||
const immichAllowInsecureTls = z.boolean().optional();
|
||||
|
||||
export const immichSettingsSchema = z.looseObject({
|
||||
immich_url: optionalText,
|
||||
immich_api_key: optionalText,
|
||||
// Applied only when it is a real boolean (`typeof auto_upload === 'boolean'`),
|
||||
// so anything else is accepted and ignored, exactly as before.
|
||||
auto_upload: z.unknown().optional(),
|
||||
allow_insecure_tls: immichAllowInsecureTls,
|
||||
});
|
||||
|
||||
export const immichTestSchema = z.looseObject({
|
||||
immich_url: optionalText,
|
||||
immich_api_key: optionalText,
|
||||
allow_insecure_tls: immichAllowInsecureTls,
|
||||
});
|
||||
|
||||
export const immichSearchSchema = z.looseObject({
|
||||
|
||||
Reference in New Issue
Block a user