~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
51 lines · 2.8 KB Raw History
//! 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)"
    );
}