j0rsa/transmission-rpc

Custom TLS cert not accepted

Closed this issue · 2 comments

I'm a beginner with Rust programming and I'm trying to use your library but I get the following error:

Error: reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("transmission")), port: None, path: "/transmission/rpc/", query: None, fragment: None }, source: hyper::Error(Connect, Custom { kind: Other, error: Custom { kind: InvalidData, error: InvalidCertificate(UnknownIssuer) } }) }

The transmission port is not the usual http on port 9091 but through the ingress and protected by a custom TLS that the MacOS already trusts:

curl https://transmission/transmission/rpc/
<h1>409: Conflict</h1><p>Your request had an invalid session-id header.</p><p>To fix this, follow these steps:<ol><li> When reading a response, get its X-Transmission-Session-Id header and remember it<li> Add the updated header to your outgoing requests<li> When you get this 409 error message, resend your request with the updated header</ol></p><p>This requirement has been added to help prevent <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF</a> attacks.</p><p><code>X-Transmission-Session-Id: kkQAmbQ6Q6g98bRgyIMieDSUmPj0FNbtVRrArbueiRvMT25v</code></p>

My code is similar with your example:

// extern crate url;
use url::Url;
use rustls_connector::RustlsConnector;
extern crate transmission_rpc;

// use std::env;

// use dotenvy::dotenv;
use transmission_rpc::{
    types::{BasicAuth, Result, RpcResponse, TorrentAddArgs, TorrentAddedOrDuplicate},
    TransClient,
};

#[tokio::main]
async fn main() -> Result<()> {
    // dotenv().ok();
    // env_logger::init();
    // let url = env::var("https://transmission")?;
    let connector = RustlsConnector::new_with_native_certs().unwrap();
    let basic_auth = BasicAuth {
        user: "radu".to_owned(),
        password: "SECRET".to_owned(),
    };
    let mut client = TransClient::with_auth(Url::parse("https://transmission/transmission/rpc/")?, basic_auth);
    let add: TorrentAddArgs = TorrentAddArgs {
        filename: Some(
            "https://www.releases.ubuntu.com/23.10/ubuntu-23.10-live-server-amd64.iso.torrent"
                .to_owned(),
        ),
        download_dir: Some(
            "/other".to_owned(),
        ),
        ..TorrentAddArgs::default()
    };
    let res: RpcResponse<TorrentAddedOrDuplicate> = client.torrent_add(add).await?;
    println!("Add result: {:?}", &res.is_ok());
    println!("response: {:?}", &res);

    Ok(())
}

I tried to replicate the issue in reqwest with the following code (I understand you build your client on reqwest):

// use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // let resp = reqwest::get("https://httpbin.org/ip")
    let resp = reqwest::get("https://transmission/tranmission/rpc/")
        .await?
        .text()
        // .json::<HashMap<String, String>>()
        .await?;
    println!("{:#?}", resp);
    Ok(())
}

And the answer is similar with what curl returns:

cargo run
   Compiling custom-tls-test v0.1.0 (/Users/radu/devel/rust/custom-tls-test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/custom-tls-test`
"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><link rel=\"shortcut icon\" href=\"/favicon.ico\"><title>Combustion - Transmission Web Interface</title><link href=\"main.77f9cffc.css\" rel=\"stylesheet\"></head><body><div id=\"root\"></div><script type=\"text/javascript\" src=\"static/js/main.9c210f2d.js\"></script></body></html>"

What am I doing wrong to not be able to connect to custom TLS protected port 443 in front of /transmission/rpc/ path.

Thank you,
Radu

Communication with Transmission over SSL is always a pain. It is not a limitation of the library, but probably of the transmission itself. Prove me wrong, but I couldn't make it working.

Are you using Cloudflare proxy by any chance?

Hi Aleksandr,
The SSL endpoint is on a Traefik ingress protected with a self-signed CA that I use at home (my linux and mac devices trust it after manually added the CA). No Cloudflare proxy.

I added a NodePort towards the same Transmission without SSL protection and the library works as expected (the password is not protected by SSL but at home it should be ok).

Thank you for your library