Repository navigation
fix: trust user-installed CAs - #141
Conversation
…sted ZenNotes#141 trusts the user certificate store app-wide so a self-hosted server behind a private CA connects (ZenNotes#140). That store also holds any CA a device manager pushes or a user is talked into installing, and with the base policy alone such a CA could vouch for zennotes.org as well. On an emulator with a throwaway CA in the user store and a proxy presenting a zennotes.org certificate signed by it, the ZenNotes#141 build completed the handshake and handed its Cloud API request to the proxy. Cloud's hosts (zennotes.org and the legacy zennotes.laravel.cloud, subdomains included) now get a domain-config that trusts the system store alone and refuses plain HTTP: the trust Cloud had before ZenNotes#141. Every other host keeps the PR's policy, system and user CAs with plain HTTP allowed for LAN servers. The same interception now fails the handshake ("Trust anchor for certification path not found"), while a self-hosted server behind the private CA still connects and syncs, in a debug build and in a release-signed build. The debug-only manifest that pointed at the old debug resource is gone too: the main manifest declares the one policy for every build type. It does not cover the object-storage hosts of presigned uploads and downloads. The service names them at run time, and they never receive the account token (DirectUploadPlugin refuses an Authorization header on a signed upload). network-security-config.test.ts checks the policy against the Cloud URLs in mobile-cloud-auth.ts, so a future host move (2.28 made one) cannot leave Cloud on user trust unnoticed.
|
Thanks @lewxdev, this is exactly the right fix for #140, and it ships in Android 1.1.50. I tested it on an emulator against a self-hosted ZenNotes server behind a throwaway private CA, installed in the user certificate store. Before the change the app failed with "Trust anchor for certification path not found." With it, the app connects with the token and syncs both ways. It still rejects the server once the CA is removed, a certificate for the wrong host, and an expired certificate, and plain-HTTP servers on the LAN and public HTTPS keep working, in debug and in a release-signed build.
One follow-up commit sits on top of yours. Trusting the user store everywhere also let a user-installed CA vouch for zennotes.org: a proxy presenting such a certificate intercepted the app's Cloud requests. ZenNotes Cloud's hosts now trust only the system store and refuse plain HTTP, as before, while every other host keeps your policy, so private CAs work for self-hosted servers and Cloud can't be intercepted that way. The follow-up also drops the debug-only manifest that pointed at the old debug resource, and adds a test that keeps the Cloud hosts in the policy in step with the URLs the app uses. Separately, the error in the "before" screenshot pointed Android users at an iPhone-only setting (Privacy & Security, Local Network). In 1.1.50 it says instead, for an https server, where to install your own certificate authority. Your commit is merged into |


Android rejects HTTPS connections to private-CA self-hosted servers even when the issuing CA is installed in the user's certificate store. Add the app-wide Network Security Configuration proposed in #140, trusting both system and user-installed CAs while retaining certificate-chain and hostname verification.
Reference the configuration from the main manifest and replace the debug-only resource so debug and release use the same policy. Preserve existing plain-HTTP self-hosting support with
cleartextTrafficPermitted="true". No server hostname is hardcoded.Validation on macOS with JDK 21 and Android SDK 36:
No emulator or device connectivity test was performed. Private-server TLS, login, and sync remain unverified at runtime; no installed APK or app data was modified. Follow-up testing should confirm private-CA connectivity with the CA installed, rejection of untrusted/expired/wrong-host certificates, and continued public-CA HTTPS and HTTP self-hosting support.
Related to #140. This PR does not claim runtime validation.