//! Regression: with ring and aws-lc-rs both linked (atproto-crates' reqwest brings aws-lc-rs), rustls cannot pick //! a process default and every wss:// subscribe panicked until atlibs_host::tls(). This test never calls tls(): //! ws::subscribe (com.atproto.sync.subscribeRepos, echo's `watch`) must. The only test in this binary, so the //! process default is untouched by anything else. Fixture: tests/fixtures/localhost.pem (self-signed, not a CA). use std::sync::Arc; use std::time::Duration; use atlibs_host::Signal; use atlibs_host::ws::{encode_cbor, subscribe, ws_url}; use futures_util::SinkExt; use rustls::pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject}; use serde_json::json; use tokio_tungstenite::tungstenite::Message; #[tokio::test] async fn wss_subscribe_with_two_crypto_providers_linked() { let fixtures = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures"); let cert = format!("{fixtures}/localhost.pem"); // SAFETY: the only test in this binary, and nothing else reads the environment concurrently. unsafe { std::env::set_var("ATLIBS_EXTRA_CA", &cert) }; // the server names its provider, so only the client side depends on the process default let config = rustls::ServerConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider())) .with_safe_default_protocol_versions() .unwrap() .with_no_client_auth() .with_single_cert( CertificateDer::pem_file_iter(&cert).unwrap().map(Result::unwrap).collect(), PrivateKeyDer::from_pem_file(format!("{fixtures}/localhost.key.pem")).unwrap(), ) .unwrap(); let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config)); let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let port = listener.local_addr().unwrap().port(); tokio::spawn(async move { let (tcp, _) = listener.accept().await.unwrap(); let mut ws = tokio_tungstenite::accept_async(acceptor.accept(tcp).await.unwrap()).await.unwrap(); let frame = encode_cbor(&[json!({ "op": 1, "t": "#commit" }), json!({ "seq": 1 })]).unwrap(); ws.send(Message::binary(frame)).await.unwrap(); ws.close(None).await.unwrap(); }); let nsid = "com.atproto.sync.subscribeRepos"; let url = ws_url(&format!("https://127.0.0.1:{port}"), nsid, None).unwrap(); assert!(url.starts_with("wss://")); let mut sub = subscribe(url, nsid.into(), None, None, vec![], Signal::new()); let first = tokio::time::timeout(Duration::from_secs(10), sub.messages.recv()).await.unwrap(); assert_eq!( first, Some(Ok(json!({ "$type": "com.atproto.sync.subscribeRepos#commit", "seq": 1 }))), "no message: the subscribe task died (a CryptoProvider panic above means tls() was not called)" ); }