diff --git a/src/main/index.ts b/src/main/index.ts index c5fcba6..faa1604 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1065,6 +1065,35 @@ if (!gotTheLock) { log.info('Running with GPU sandbox disabled (marker file present)') } + // ─── Self-Signed / Untrusted Certificate Support ─ + // Allow connections to Open WebUI instances that use self-signed or + // otherwise untrusted SSL certificates (issue #108). The user + // explicitly configures the server URL, so trusting all certs is + // acceptable — this matches the behaviour of VS Code, Postman, and + // other Electron apps used in enterprise/self-hosted environments. + app.on('certificate-error', (event, _webContents, url, error, certificate, callback) => { + log.warn( + `Certificate error: ${error} for ${url} ` + + `(subject: ${certificate.subjectName}, issuer: ${certificate.issuerName})` + ) + event.preventDefault() + callback(true) + }) + + // Trust all certs on the default session (used by net.fetch() in + // validateRemoteUrl / checkUrlAndOpen). + session.defaultSession.setCertificateVerifyProc((_request, callback) => { + callback(0) // 0 = verified/trusted + }) + + // Webviews use partitioned sessions (persist:connection-*). Each + // new partition's session also needs to trust all certs. + app.on('session-created', (newSession) => { + newSession.setCertificateVerifyProc((_request, callback) => { + callback(0) + }) + }) + app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) diff --git a/src/main/utils/index.ts b/src/main/utils/index.ts index 86fd436..4d1153b 100644 --- a/src/main/utils/index.ts +++ b/src/main/utils/index.ts @@ -8,7 +8,7 @@ import crypto from 'crypto' import * as tar from 'tar' -import { app, shell, Notification } from 'electron' +import { app, shell, Notification, net as electronNet } from 'electron' import { execFileSync, exec, spawn, execSync, execFile } from 'child_process' import log from 'electron-log' @@ -755,7 +755,7 @@ export const checkUrlAndOpen = async (url: string, callback: Function = async () const checkUrl = async (): Promise => { try { - const response = await fetch(url, { method: 'HEAD' }) + const response = await electronNet.fetch(url, { method: 'HEAD' }) return response.ok } catch { return false @@ -783,7 +783,7 @@ export const checkUrlAndOpen = async (url: string, callback: Function = async () export const validateRemoteUrl = async (url: string): Promise => { try { - const response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) }) + const response = await electronNet.fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) }) return response.ok } catch { return false