diff --git a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/HttpClientFactory.jvm.kt b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/HttpClientFactory.jvm.kt index aaa4ef266..942f10aa8 100644 --- a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/HttpClientFactory.jvm.kt +++ b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/HttpClientFactory.jvm.kt @@ -14,6 +14,16 @@ actual fun createPlatformHttpClient(proxyConfig: ProxyConfig): HttpClient = HttpClient(OkHttp) { engine { config { + // Trust OS-installed root certificates in addition to the + // JVM cacerts bundle. Lets users behind TLS-intercepting + // tools (Watt Toolkit, Fiddler, corporate MITM) keep using + // the app without manually injecting certs into the JDK. + // Silently skipped on platforms where no OS keystore is + // available — default trust still applies. + buildOsTrustChainOrNull()?.let { chain -> + sslSocketFactory(chain.socketFactory, chain.trustManager) + } + // Reset any inherited global SOCKS authenticator before // deciding what this client needs — prevents a stale // Authenticator from a previous [ProxyConfig.Socks] client diff --git a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/OsTrustManager.kt b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/OsTrustManager.kt new file mode 100644 index 000000000..76eafface --- /dev/null +++ b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/network/OsTrustManager.kt @@ -0,0 +1,89 @@ +package zed.rainxch.core.data.network + +import java.security.KeyStore +import java.security.cert.X509Certificate +import javax.net.ssl.SSLContext +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509TrustManager + +internal data class OsTrustChain( + val socketFactory: SSLSocketFactory, + val trustManager: X509TrustManager, +) + +internal fun buildOsTrustChainOrNull(): OsTrustChain? { + val managers = buildList { + defaultTrustManagerOrNull()?.let { add(it) } + osTrustManagerOrNull()?.let { add(it) } + } + if (managers.size < 2) return null + val composite = CompositeX509TrustManager(managers) + return try { + val ctx = SSLContext.getInstance("TLS").apply { + init(null, arrayOf(composite), null) + } + OsTrustChain(ctx.socketFactory, composite) + } catch (_: Throwable) { + null + } +} + +private fun defaultTrustManagerOrNull(): X509TrustManager? = trustManagerFromKeyStore(null) + +private fun osTrustManagerOrNull(): X509TrustManager? { + val osName = System.getProperty("os.name").orEmpty().lowercase() + val keyStore = when { + osName.contains("windows") -> loadKeyStore("Windows-ROOT") + osName.contains("mac") || osName.contains("darwin") -> loadKeyStore("KeychainStore") + else -> null + } ?: return null + return trustManagerFromKeyStore(keyStore) +} + +private fun loadKeyStore(type: String): KeyStore? = try { + KeyStore.getInstance(type).apply { load(null, null) } +} catch (_: Throwable) { + null +} + +private fun trustManagerFromKeyStore(keyStore: KeyStore?): X509TrustManager? = try { + val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + tmf.init(keyStore) + tmf.trustManagers.filterIsInstance().firstOrNull() +} catch (_: Throwable) { + null +} + +private class CompositeX509TrustManager( + private val delegates: List, +) : X509TrustManager { + override fun checkClientTrusted(chain: Array, authType: String) { + var lastError: Throwable? = null + for (tm in delegates) { + try { + tm.checkClientTrusted(chain, authType) + return + } catch (t: Throwable) { + lastError = t + } + } + throw lastError ?: java.security.cert.CertificateException("No trust manager accepted the chain") + } + + override fun checkServerTrusted(chain: Array, authType: String) { + var lastError: Throwable? = null + for (tm in delegates) { + try { + tm.checkServerTrusted(chain, authType) + return + } catch (t: Throwable) { + lastError = t + } + } + throw lastError ?: java.security.cert.CertificateException("No trust manager accepted the chain") + } + + override fun getAcceptedIssuers(): Array = + delegates.flatMap { it.acceptedIssuers.toList() }.toTypedArray() +} diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json index 911ad71c0..73407366b 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json @@ -31,7 +31,8 @@ "bullets": [ "Multi-source downloads no longer clobber each other's APK file.", "Shizuku-fallback installs no longer flip rows to \"installed\" prematurely.", - "Self-update no longer leaves apps stuck on \"Preparing to install\"." + "Self-update no longer leaves apps stuck on \"Preparing to install\".", + "Desktop now trusts OS-installed root certificates — Watt Toolkit, FastGithub, Fiddler, and corporate MITM proxies just work without keytool gymnastics." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json index 83857c6bf..07bebbcc0 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json @@ -31,7 +31,8 @@ "bullets": [ "تنزيلات المصادر المتعددة لم تعد تطمس ملفات APK الخاصة ببعضها.", "تثبيتات Shizuku الاحتياطية لم تعد تُعلّم التطبيقات بأنها «مثبّتة» قبل الأوان.", - "التحديث الذاتي لم يعد يترك التطبيقات معلّقة على «التحضير للتثبيت»." + "التحديث الذاتي لم يعد يترك التطبيقات معلّقة على «التحضير للتثبيت».", + "تطبيق سطح المكتب يثق الآن بشهادات الجذر المثبَّتة في النظام — Watt Toolkit و FastGithub و Fiddler ووكلاء MITM للشركات تعمل دون الحاجة إلى استخدام keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json index 94514310e..d3fe88b03 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json @@ -31,7 +31,8 @@ "bullets": [ "মাল্টি-সোর্স ডাউনলোড আর একে অপরের APK ফাইল ওভাররাইট করে না।", "Shizuku-ফলব্যাক ইনস্টল আর অ্যাপগুলোকে আগেভাগে 'ইনস্টল হয়েছে' হিসেবে চিহ্নিত করে না।", - "সেলফ-আপডেট আর অ্যাপগুলোকে 'ইনস্টলের জন্য প্রস্তুত হচ্ছে' অবস্থায় আটকে রাখে না।" + "সেলফ-আপডেট আর অ্যাপগুলোকে 'ইনস্টলের জন্য প্রস্তুত হচ্ছে' অবস্থায় আটকে রাখে না।", + "ডেস্কটপ এখন OS-এ ইনস্টল করা রুট সার্টিফিকেটগুলোকে বিশ্বাস করে — Watt Toolkit, FastGithub, Fiddler আর কর্পোরেট MITM প্রক্সি keytool ছাড়াই কাজ করে।" ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json index 920817655..a33ca0e68 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json @@ -31,7 +31,8 @@ "bullets": [ "Las descargas multi-origen ya no se sobrescriben entre sí.", "Las instalaciones con respaldo Shizuku ya no marcan apps como «instaladas» antes de tiempo.", - "La auto-actualización ya no deja apps atascadas en «Preparando para instalar»." + "La auto-actualización ya no deja apps atascadas en «Preparando para instalar».", + "El escritorio ahora confía en los certificados raíz instalados en el sistema — Watt Toolkit, FastGithub, Fiddler y proxies MITM corporativos funcionan sin tener que usar keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json index ec6e2922d..8703973b1 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json @@ -31,7 +31,8 @@ "bullets": [ "Les téléchargements multi-source ne s’écrasent plus entre eux.", "Les installations en repli Shizuku ne marquent plus les apps comme « installées » trop tôt.", - "L’auto-mise à jour ne laisse plus d’apps bloquées sur « Préparation de l’installation »." + "L’auto-mise à jour ne laisse plus d’apps bloquées sur « Préparation de l’installation ».", + "Le bureau fait désormais confiance aux certificats racine installés par l’OS — Watt Toolkit, FastGithub, Fiddler et les proxys MITM d’entreprise fonctionnent sans manip keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json index e5ce2f506..a87d7088f 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json @@ -31,7 +31,8 @@ "bullets": [ "मल्टी-सोर्स डाउनलोड अब एक-दूसरे की APK फ़ाइल को ओवरराइट नहीं करते।", "Shizuku-फ़ॉलबैक इंस्टॉल अब समय से पहले ऐप को 'इंस्टॉल' के रूप में चिह्नित नहीं करते।", - "सेल्फ़-अपडेट अब ऐप्स को 'इंस्टॉल के लिए तैयार किया जा रहा है' पर अटका नहीं छोड़ता।" + "सेल्फ़-अपडेट अब ऐप्स को 'इंस्टॉल के लिए तैयार किया जा रहा है' पर अटका नहीं छोड़ता।", + "डेस्कटॉप अब OS में इंस्टॉल किए गए रूट सर्टिफिकेट पर भरोसा करता है — Watt Toolkit, FastGithub, Fiddler और कॉर्पोरेट MITM प्रॉक्सी keytool के बिना भी काम करते हैं।" ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json index 50bbdfc5e..68629a944 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json @@ -31,7 +31,8 @@ "bullets": [ "I download multi-sorgente non si sovrascrivono più a vicenda.", "Le installazioni con fallback Shizuku non segnano più le app come «installate» troppo presto.", - "L’aggiornamento automatico non lascia più app bloccate su «Preparazione all’installazione»." + "L’aggiornamento automatico non lascia più app bloccate su «Preparazione all’installazione».", + "Il desktop ora si fida dei certificati radice installati dal sistema — Watt Toolkit, FastGithub, Fiddler e i proxy MITM aziendali funzionano senza manovre con keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json index f4bff0d77..e566e0f75 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json @@ -31,7 +31,8 @@ "bullets": [ "複数ソースのダウンロードが互いの APK を上書きしてしまう問題を修正。", "Shizuku フォールバック時に「インストール済み」と早まって表示されることがなくなりました。", - "セルフアップデート後にアプリが「インストールの準備中」のまま固まる問題を修正。" + "セルフアップデート後にアプリが「インストールの準備中」のまま固まる問題を修正。", + "デスクトップが OS にインストール済みのルート証明書を信頼するようになりました。Watt Toolkit、FastGithub、Fiddler、社内 MITM プロキシも keytool 不要で動作します。" ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json index 3747fe9de..161e10cdf 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json @@ -31,7 +31,8 @@ "bullets": [ "다중 소스 다운로드가 서로의 APK 파일을 덮어쓰던 문제를 수정했습니다.", "Shizuku 폴백 설치가 시스템 확정 전에 ‘설치됨’으로 표시되던 문제를 수정했습니다.", - "셀프 업데이트 후 앱이 ‘설치 준비 중’ 상태로 멈춰 있던 문제를 수정했습니다." + "셀프 업데이트 후 앱이 ‘설치 준비 중’ 상태로 멈춰 있던 문제를 수정했습니다.", + "데스크톱이 OS에 설치된 루트 인증서를 신뢰합니다 — Watt Toolkit, FastGithub, Fiddler, 사내 MITM 프록시가 keytool 작업 없이 그대로 동작합니다." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json index 6b7eeb00e..c6a60bf2a 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json @@ -31,7 +31,8 @@ "bullets": [ "Pobierania z wielu źródeł nie nadpisują już swoich plików APK.", "Instalacje z trybem awaryjnym Shizuku nie oznaczają już aplikacji jako „zainstalowanych” przedwcześnie.", - "Auto-aktualizacja nie zostawia już aplikacji w stanie „Przygotowywanie instalacji”." + "Auto-aktualizacja nie zostawia już aplikacji w stanie „Przygotowywanie instalacji”.", + "Wersja desktopowa ufa teraz certyfikatom głównym zainstalowanym w systemie — Watt Toolkit, FastGithub, Fiddler i firmowe proxy MITM działają bez kombinowania z keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json index b4a41ad98..39d6c25d4 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json @@ -31,7 +31,8 @@ "bullets": [ "Загрузки из нескольких источников больше не затирают APK друг друга.", "Установка через Shizuku-fallback больше не помечает приложения как «установленные» раньше времени.", - "Самообновление больше не оставляет приложения зависшими на статусе «Подготовка к установке»." + "Самообновление больше не оставляет приложения зависшими на статусе «Подготовка к установке».", + "Десктоп теперь доверяет корневым сертификатам, установленным в ОС — Watt Toolkit, FastGithub, Fiddler и корпоративные MITM-прокси работают без шаманства с keytool." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json index 33deac8de..a6a728445 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json @@ -31,7 +31,8 @@ "bullets": [ "Çoklu kaynaklı indirmeler artık birbirinin APK dosyasını ezmez.", "Shizuku yedekli kurulumlar uygulamaları artık erkenden “kuruldu” olarak işaretlemez.", - "Otomatik güncelleme uygulamaları artık “Yüklemeye hazırlanıyor” durumunda asılı bırakmaz." + "Otomatik güncelleme uygulamaları artık “Yüklemeye hazırlanıyor” durumunda asılı bırakmaz.", + "Masaüstü artık işletim sistemine yüklü kök sertifikalara güveniyor — Watt Toolkit, FastGithub, Fiddler ve kurumsal MITM proxy'leri keytool uğraşı olmadan çalışıyor." ] } ] diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json index 5bd975615..07db4b9c5 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json @@ -31,7 +31,8 @@ "bullets": [ "修复多源下载相互覆盖 APK 文件的问题。", "修复 Shizuku 回退安装时,应用提前被标记为「已安装」的问题。", - "修复自动更新后应用卡在「准备安装」状态的问题。" + "修复自动更新后应用卡在「准备安装」状态的问题。", + "桌面端现在信任系统已安装的根证书 — Watt Toolkit、FastGithub、Fiddler 以及企业 MITM 代理无需折腾 keytool 即可使用。" ] } ]