From 915f0143f7bc1bcecfd2df4a1cbe93ae9e0741be Mon Sep 17 00:00:00 2001 From: Psychotoxical Date: Tue, 14 Apr 2026 18:15:58 +0200 Subject: [PATCH] fix(ssl): strip trailing slash in getBaseUrl + trust OS certificate store for HTTPS streaming Fixes two bugs reported in #178: - getBaseUrl() now strips trailing slashes from server URLs, consistent with restBaseFromUrl(). A trailing slash caused double-slash stream URLs (//rest/stream.view) which Caddy rejects. Trailing slash also caused browsing to return 0 results. Fix manually ported from PR #179 by kveld9. - reqwest now loads the OS native certificate store in addition to Mozilla's webpki roots (rustls-tls-native-roots feature). Fixes HTTPS streaming failures where the server certificate is signed by a local CA (e.g. Caddy internal CA) that is trusted in the system keychain but not in Mozilla's root store. Co-Authored-By: Claude Sonnet 4.6 --- src-tauri/Cargo.lock | 52 ++++++++++++++++++++++++++++++++++++++++++ src-tauri/Cargo.toml | 2 +- src/store/authStore.ts | 3 ++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index fd05ac86..bb1be099 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1991,6 +1991,7 @@ dependencies = [ "hyper", "hyper-util", "rustls", + "rustls-native-certs", "tokio", "tokio-rustls", "tower-service", @@ -3065,6 +3066,12 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "option-ext" version = "0.2.0" @@ -3890,6 +3897,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -4070,6 +4078,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.14.0" @@ -4112,6 +4132,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -4169,6 +4198,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b7a5424f..c0f0787f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -32,7 +32,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" rodio = { version = "0.19", default-features = false, features = ["symphonia-all"] } symphonia = { version = "0.5", default-features = false, features = ["flac", "mp3", "pcm", "aac", "alac", "isomp4", "vorbis", "ogg", "wav", "adpcm"] } -reqwest = { version = "0.12", default-features = false, features = ["stream", "json", "multipart", "rustls-tls", "blocking"] } +reqwest = { version = "0.12", default-features = false, features = ["stream", "json", "multipart", "rustls-tls", "rustls-tls-native-roots", "blocking"] } futures-util = "0.3" md5 = "0.7" tokio = { version = "1", features = ["rt", "time", "sync"] } diff --git a/src/store/authStore.ts b/src/store/authStore.ts index 65d6d72c..1c1c0546 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -546,7 +546,8 @@ export const useAuthStore = create()( const s = get(); const server = s.servers.find(srv => srv.id === s.activeServerId); if (!server?.url) return ''; - return server.url.startsWith('http') ? server.url : `http://${server.url}`; + const base = server.url.startsWith('http') ? server.url : `http://${server.url}`; + return base.replace(/\/$/, ''); }, getActiveServer: () => {