mirror of
https://github.com/rustdesk/hbb_common.git
synced 2026-10-25 13:40:11 +00:00
webrtc: decode TURN userinfo before handing it to the ICE agent
`Url` returns the username and password percent-encoded, and they went into the ICE server configuration as-is, so a password containing `@`, `/`, `?`, `#`, `%` or a space (written encoded, the only way the URL can carry it) failed the long-term credential check with a 401 and TURN never produced a relay candidate. Decode both, as the web client does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXJJGEGdgu26wgCppvUXdZ
This commit is contained in:
1 parent
846daf86f0
commit
00f0a720b5
2 files changed
+18
-2
No files matched your search
@@ -52,6 +52,7 @@ thiserror = "1.0"
|
|||||||
httparse = "1.10"
|
httparse = "1.10"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
url = "2.5"
|
url = "2.5"
|
||||||
|
percent-encoding = "2"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
whoami = "1.5"
|
whoami = "1.5"
|
||||||
|
|
||||||
|
|||||||
+17
-2
@@ -41,6 +41,7 @@ use webrtc::peer_connection::RTCPeerConnection;
|
|||||||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
use percent_encoding::percent_decode_str;
|
||||||
use tokio::sync::{mpsc, watch, Mutex, Semaphore};
|
use tokio::sync::{mpsc, watch, Mutex, Semaphore};
|
||||||
use tokio::time::{timeout, timeout_at, Instant};
|
use tokio::time::{timeout, timeout_at, Instant};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@@ -395,8 +396,14 @@ impl WebRTCStream {
|
|||||||
if host.is_empty() {
|
if host.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let username = u.username().to_string();
|
// `Url` hands userinfo back percent-encoded; the TURN server expects the value,
|
||||||
let credential = u.password().unwrap_or_default().to_string();
|
// so `p%40ss` must reach it as `p@ss` for the long-term credential to verify.
|
||||||
|
let username = percent_decode_str(u.username())
|
||||||
|
.decode_utf8_lossy()
|
||||||
|
.into_owned();
|
||||||
|
let credential = percent_decode_str(u.password().unwrap_or_default())
|
||||||
|
.decode_utf8_lossy()
|
||||||
|
.into_owned();
|
||||||
// A TURN server without credentials is not merely useless: webrtc-rs validates every
|
// A TURN server without credentials is not merely useless: webrtc-rs validates every
|
||||||
// configured server in `new_peer_connection`, so one credential-less entry makes EVERY
|
// configured server in `new_peer_connection`, so one credential-less entry makes EVERY
|
||||||
// peer connection fail — including plain non-relay ones that never wanted TURN. The
|
// peer connection fail — including plain non-relay ones that never wanted TURN. The
|
||||||
@@ -1468,6 +1475,14 @@ mod tests {
|
|||||||
"turn:example.com:3478"
|
"turn:example.com:3478"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Userinfo arrives percent-encoded from the URL parser; the TURN server wants the
|
||||||
|
// value, so a password written `p%40ss` authenticates as `p@ss`.
|
||||||
|
let encoded =
|
||||||
|
WebRTCStream::get_ice_server_from_url("turn://us%20er:p%40s%2Fs%25@example.com")
|
||||||
|
.expect("encoded credentials are usable");
|
||||||
|
assert_eq!(encoded.username, "us er");
|
||||||
|
assert_eq!(encoded.credential, "p@s/s%");
|
||||||
|
|
||||||
// TURN without both halves of the credential is dropped rather than passed on:
|
// TURN without both halves of the credential is dropped rather than passed on:
|
||||||
// webrtc-rs validates every configured server when the peer connection is built, so
|
// webrtc-rs validates every configured server when the peer connection is built, so
|
||||||
// one such entry fails EVERY connection, including those that never wanted TURN.
|
// one such entry fails EVERY connection, including those that never wanted TURN.
|
||||||
|
|||||||
Reference in new issue
Block a user