record-daemon: fix league websocket connection

This commit is contained in:
2026-03-19 18:38:51 +01:00
parent f062cee010
commit 2ddb953321
3 changed files with 168 additions and 13 deletions

View File

@@ -656,9 +656,9 @@ dependencies = [
"futures-util", "futures-util",
"http 0.2.12", "http 0.2.12",
"hyper", "hyper",
"rustls", "rustls 0.21.12",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.24.1",
] ]
[[package]] [[package]]
@@ -1087,6 +1087,8 @@ dependencies = [
"parking_lot", "parking_lot",
"regex", "regex",
"reqwest", "reqwest",
"rustls 0.22.4",
"rustls-pki-types",
"serde", "serde",
"serde_json", "serde_json",
"signal-hook", "signal-hook",
@@ -1175,7 +1177,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls", "rustls 0.21.12",
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",
@@ -1183,13 +1185,13 @@ dependencies = [
"sync_wrapper", "sync_wrapper",
"system-configuration", "system-configuration",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.24.1",
"tower-service", "tower-service",
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots 0.25.4",
"winreg", "winreg",
] ]
@@ -1228,10 +1230,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring",
"rustls-webpki", "rustls-webpki 0.101.7",
"sct", "sct",
] ]
[[package]]
name = "rustls"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
dependencies = [
"log",
"ring",
"rustls-pki-types",
"rustls-webpki 0.102.8",
"subtle",
"zeroize",
]
[[package]] [[package]]
name = "rustls-pemfile" name = "rustls-pemfile"
version = "1.0.4" version = "1.0.4"
@@ -1241,6 +1257,15 @@ dependencies = [
"base64 0.21.7", "base64 0.21.7",
] ]
[[package]]
name = "rustls-pki-types"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
dependencies = [
"zeroize",
]
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.101.7" version = "0.101.7"
@@ -1251,6 +1276,17 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "rustls-webpki"
version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.22" version = "1.0.22"
@@ -1451,6 +1487,12 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.117" version = "2.0.117"
@@ -1586,7 +1628,18 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [ dependencies = [
"rustls", "rustls 0.21.12",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [
"rustls 0.22.4",
"rustls-pki-types",
"tokio", "tokio",
] ]
@@ -1620,8 +1673,12 @@ checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
"rustls 0.22.4",
"rustls-pki-types",
"tokio", "tokio",
"tokio-rustls 0.25.0",
"tungstenite", "tungstenite",
"webpki-roots 0.26.11",
] ]
[[package]] [[package]]
@@ -1764,6 +1821,8 @@ dependencies = [
"httparse", "httparse",
"log", "log",
"rand", "rand",
"rustls 0.22.4",
"rustls-pki-types",
"sha1", "sha1",
"thiserror", "thiserror",
"url", "url",
@@ -1990,6 +2049,24 @@ version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]]
name = "webpki-roots"
version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.6",
]
[[package]]
name = "webpki-roots"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
dependencies = [
"rustls-pki-types",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.62.2" version = "0.62.2"
@@ -2374,6 +2451,12 @@ dependencies = [
"synstructure", "synstructure",
] ]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]] [[package]]
name = "zerotrie" name = "zerotrie"
version = "0.2.3" version = "0.2.3"

View File

@@ -15,8 +15,10 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
toml = "0.8" toml = "0.8"
# WebSocket for LQP # WebSocket for LQP (with TLS support)
tokio-tungstenite = "0.21" tokio-tungstenite = { version = "0.21", features = ["rustls-tls-webpki-roots"] }
rustls = "0.22"
rustls-pki-types = "1"
# HTTP client for LQP REST API # HTTP client for LQP REST API
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] } reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }

View File

@@ -6,13 +6,65 @@ use std::sync::Arc;
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use tokio::sync::{broadcast, RwLock}; use tokio::sync::{broadcast, RwLock};
use tokio_tungstenite::{connect_async_with_config, tungstenite::protocol::Message}; use tokio_tungstenite::{connect_async_tls_with_config, tungstenite::protocol::Message};
use tracing::{debug, error, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
use super::auth::LockfileCredentials; use super::auth::LockfileCredentials;
use super::events::GameEvent; use super::events::GameEvent;
use crate::error::{LqpError, Result}; use crate::error::{LqpError, Result};
/// Custom certificate verifier that accepts any certificate.
/// This is needed because the League Client uses a self-signed certificate.
#[derive(Debug)]
struct InsecureVerifier;
impl rustls::client::danger::ServerCertVerifier for InsecureVerifier {
fn verify_server_cert(
&self,
_end_entity: &rustls::pki_types::CertificateDer<'_>,
_intermediates: &[rustls::pki_types::CertificateDer<'_>],
_server_name: &rustls::pki_types::ServerName<'_>,
_ocsp_response: &[u8],
_now: rustls::pki_types::UnixTime,
) -> std::result::Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
// Accept any certificate - League Client uses self-signed certificates
Ok(rustls::client::danger::ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &rustls::pki_types::CertificateDer<'_>,
_dss: &rustls::DigitallySignedStruct,
) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
}
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &rustls::pki_types::CertificateDer<'_>,
_dss: &rustls::DigitallySignedStruct,
) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
vec![
rustls::SignatureScheme::RSA_PKCS1_SHA256,
rustls::SignatureScheme::RSA_PKCS1_SHA384,
rustls::SignatureScheme::RSA_PKCS1_SHA512,
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
rustls::SignatureScheme::RSA_PSS_SHA256,
rustls::SignatureScheme::RSA_PSS_SHA384,
rustls::SignatureScheme::RSA_PSS_SHA512,
rustls::SignatureScheme::ED25519,
]
}
}
/// LQP WebSocket endpoints to subscribe to. /// LQP WebSocket endpoints to subscribe to.
const SUBSCRIBE_ENDPOINTS: &[&str] = &[ const SUBSCRIBE_ENDPOINTS: &[&str] = &[
"/lol-gameflow/v1/gameflow-phase", "/lol-gameflow/v1/gameflow-phase",
@@ -186,16 +238,34 @@ impl LqpClient {
info!("Connecting to LQP WebSocket at {}", ws_url); info!("Connecting to LQP WebSocket at {}", ws_url);
// Create a TLS connector that accepts the self-signed certificate from League Client
use tokio_tungstenite::Connector;
use tokio_tungstenite::tungstenite::http::HeaderValue;
let config = rustls::ClientConfig::builder()
.dangerous()
.with_custom_certificate_verifier(Arc::new(InsecureVerifier))
.with_no_client_auth();
let connector = Connector::Rustls(Arc::new(config));
// Build WebSocket request with auth header // Build WebSocket request with auth header
let request = tokio_tungstenite::tungstenite::http::Request::builder() let request = tokio_tungstenite::tungstenite::http::Request::builder()
.uri(&ws_url) .uri(&ws_url)
.header("Authorization", auth_header) .header("Authorization", auth_header)
.header("Host", format!("127.0.0.1:{}", creds.port))
.header("Connection", "Upgrade")
.header("Upgrade", "websocket")
.header("Sec-WebSocket-Version", "13")
.header("Sec-WebSocket-Key", tokio_tungstenite::tungstenite::handshake::client::generate_key())
.body(()) .body(())
.map_err(|e| LqpError::ConnectionFailed(e.to_string()))?; .map_err(|e| LqpError::ConnectionFailed(e.to_string()))?;
let (ws_stream, _) = connect_async_with_config( let (ws_stream, _) = connect_async_tls_with_config(
request, None, false, request,
// None, None,
false,
Some(connector),
) )
.await .await
.map_err(|e| LqpError::WebSocketError(e.to_string()))?; .map_err(|e| LqpError::WebSocketError(e.to_string()))?;