Files
SpotiFLAC-Mobile/rust_backend/crates/network/src/tls.rs
T
zarzet aa99726439 feat(backend): migrate production backend to Rust
Replace the Go backend with the Rust workspace and route Android/iOS through
UniFFI bindings. Include the migrated extension runtime, network, providers,
media metadata, downloads and library operations, with version 5.0.0+147.

Remove Go sources, adapters, native build selection and CI dependencies.
Build Rust unconditionally and lock the iOS Rust pod using a relative path.
Retain legacy source and migration evidence in a local ignored archive.

Validation: Android Kotlin compile and 53 native tests; Swift Rust-branch
equivalence and syntax; CocoaPods install; workflow, shell, Ruby, plist and
diff checks. Reuse the preceding 100 Rust tests, fmt/Clippy and five-ABI
build checkpoint; no new APK or iOS application build for this cleanup.

Known follow-up: URL/URLSearchParams globals are missing from the Rust JS
runtime. A controlled extension replay confirms a URL-resolution regression;
this commit does not fix that runtime gap.
2026-09-14 22:58:27 +07:00

74 lines
3.0 KiB
Rust

use rustls::ClientConfig;
use rustls::pki_types::CertificateDer;
use std::io;
use std::sync::Arc;
pub(crate) fn configuration(extra_roots: &[CertificateDer<'static>]) -> io::Result<ClientConfig> {
let provider = Arc::new(rustls::crypto::ring::default_provider());
let builder = ClientConfig::builder_with_provider(Arc::clone(&provider))
.with_safe_default_protocol_versions()
.map_err(io::Error::other)?;
let supplemental = rustls_pemfile::certs(&mut include_bytes!("roots.pem").as_slice())
.collect::<Result<Vec<_>, _>>()?;
#[cfg(target_vendor = "apple")]
let builder = {
// This is the OS certificate and hostname verifier, including iOS's
// system trust store. It never skips certificate verification.
let mut supplemental = supplemental;
supplemental.extend_from_slice(extra_roots);
let verifier =
rustls_platform_verifier::Verifier::new_with_extra_roots(supplemental, provider)
.map_err(io::Error::other)?;
builder
.dangerous()
.with_custom_certificate_verifier(Arc::new(verifier))
};
#[cfg(not(target_vendor = "apple"))]
let builder = {
let load = || {
let mut roots = rustls::RootCertStore::empty();
roots.add_parsable_certificates(rustls_native_certs::load_native_certs().certs);
#[cfg(target_os = "android")]
for directory in [
"/system/etc/security/cacerts",
"/data/misc/keychain/certs-added",
"/apex/com.android.conscrypt/cacerts",
] {
if let Ok(entries) = std::fs::read_dir(directory) {
for entry in entries.flatten() {
if let Ok(pem) = std::fs::read(entry.path()) {
roots.add_parsable_certificates(
rustls_pemfile::certs(&mut pem.as_slice()).flatten(),
);
}
}
}
}
roots.add_parsable_certificates(supplemental);
Arc::new(roots)
};
// Match Go's process-wide system CA snapshot on Android. Only immutable
// trust anchors are shared; caller-supplied roots never enter this cache.
#[cfg(target_os = "android")]
let roots = {
static ROOTS: std::sync::OnceLock<Arc<rustls::RootCertStore>> =
std::sync::OnceLock::new();
Arc::clone(ROOTS.get_or_init(load))
};
#[cfg(not(target_os = "android"))]
let roots = load();
let roots = if extra_roots.is_empty() {
roots
} else {
let mut scoped = (*roots).clone();
scoped.add_parsable_certificates(extra_roots.iter().cloned());
Arc::new(scoped)
};
builder.with_root_certificates(roots)
};
let mut config = builder.with_no_client_auth();
config.resumption = rustls::client::Resumption::in_memory_sessions(64);
Ok(config)
}