fix: output full request body in reports, clean up get_player_po_token

This commit is contained in:
ThetaDev 2025-02-06 03:56:11 +01:00
parent b8cfe1b034
commit a0d850f8e0
No known key found for this signature in database
GPG key ID: E319D3C5148D65B6
2 changed files with 38 additions and 22 deletions

View file

@ -2170,7 +2170,11 @@ impl RustyPipeQuery {
Ok(po_token) Ok(po_token)
} }
/// Get a PO token /// Get a Proof-of-origin token
///
/// PO tokens are used by the web-based YouTube clients for requesting player data and video streams.
///
/// See <https://codeberg.org/ThetaDev/rustypipe-botguard> for more information
pub async fn get_po_token<S: AsRef<str>>(&self, ident: S) -> Result<PoToken, Error> { pub async fn get_po_token<S: AsRef<str>>(&self, ident: S) -> Result<PoToken, Error> {
let (tokens, valid_until) = self.get_po_tokens(&[ident.as_ref()]).await?; let (tokens, valid_until) = self.get_po_tokens(&[ident.as_ref()]).await?;
@ -2399,7 +2403,11 @@ impl RustyPipeQuery {
}) })
.collect(), .collect(),
), ),
req_body: serde_json::to_string(&req_res.body).ok(), req_body: request
.body()
.as_ref()
.and_then(|b| b.as_bytes())
.map(|b| String::from_utf8_lossy(b).into_owned()),
status: req_res.status.into(), status: req_res.status.into(),
resp_body: req_res.body, resp_body: req_res.body,
}, },

View file

@ -79,6 +79,13 @@ struct ServiceIntegrity {
po_token: String, po_token: String,
} }
#[derive(Default)]
struct PlayerPoToken {
visitor_data: Option<String>,
session_po_token: Option<PoToken>,
content_po_token: Option<ServiceIntegrity>,
}
impl RustyPipeQuery { impl RustyPipeQuery {
/// Get YouTube player data (video/audio streams + basic metadata) /// Get YouTube player data (video/audio streams + basic metadata)
pub async fn player<S: AsRef<str> + Debug>(&self, video_id: S) -> Result<VideoPlayer, Error> { pub async fn player<S: AsRef<str> + Debug>(&self, video_id: S) -> Result<VideoPlayer, Error> {
@ -143,31 +150,33 @@ impl RustyPipeQuery {
Err(last_e.unwrap_or(Error::Other("no clients".into()))) Err(last_e.unwrap_or(Error::Other("no clients".into())))
} }
async fn get_player_po_token( async fn get_player_po_token(&self, video_id: &str) -> Result<PlayerPoToken, Error> {
&self,
video_id: &str,
visitor_data: &str,
) -> Result<(Option<ServiceIntegrity>, Option<PoToken>), Error> {
if let Some(bg) = &self.client.inner.botguard { if let Some(bg) = &self.client.inner.botguard {
let visitor_data = self.get_visitor_data(false).await?;
if bg.po_token_cache { if bg.po_token_cache {
let session_token = self.get_session_po_token(visitor_data).await?; let session_token = self.get_session_po_token(&visitor_data).await?;
Ok((None, Some(session_token))) Ok(PlayerPoToken {
visitor_data: Some(visitor_data),
session_po_token: Some(session_token),
content_po_token: None,
})
} else { } else {
let (po_tokens, valid_until) = let (po_tokens, valid_until) =
self.get_po_tokens(&[video_id, visitor_data]).await?; self.get_po_tokens(&[video_id, &visitor_data]).await?;
let mut po_tokens = po_tokens.into_iter(); let mut po_tokens = po_tokens.into_iter();
let po_token = po_tokens.next().unwrap(); let po_token = po_tokens.next().unwrap();
let session_po_token = po_tokens.next().unwrap(); let session_po_token = po_tokens.next().unwrap();
Ok(( Ok(PlayerPoToken {
Some(ServiceIntegrity { po_token }), visitor_data: Some(visitor_data),
Some(PoToken { session_po_token: Some(PoToken {
po_token: session_po_token, po_token: session_po_token,
valid_until, valid_until,
}), }),
)) content_po_token: Some(ServiceIntegrity { po_token }),
})
} }
} else { } else {
Ok((None, None)) Ok(PlayerPoToken::default())
} }
} }
@ -179,9 +188,8 @@ impl RustyPipeQuery {
client_type: ClientType, client_type: ClientType,
) -> Result<VideoPlayer, Error> { ) -> Result<VideoPlayer, Error> {
let video_id = video_id.as_ref(); let video_id = video_id.as_ref();
let visitor_data = self.get_visitor_data(false).await?;
let (deobf, (service_integrity_dimensions, session_po_token)) = tokio::try_join!( let (deobf, player_po) = tokio::try_join!(
async { async {
if client_type.needs_deobf() { if client_type.needs_deobf() {
Ok::<_, Error>(Some(self.client.get_deobf_data().await?)) Ok::<_, Error>(Some(self.client.get_deobf_data().await?))
@ -191,9 +199,9 @@ impl RustyPipeQuery {
}, },
async { async {
if client_type.needs_po_token() { if client_type.needs_po_token() {
self.get_player_po_token(video_id, &visitor_data).await self.get_player_po_token(video_id).await
} else { } else {
Ok((None, None)) Ok(PlayerPoToken::default())
} }
} }
)?; )?;
@ -210,7 +218,7 @@ impl RustyPipeQuery {
video_id, video_id,
content_check_ok: true, content_check_ok: true,
racy_check_ok: true, racy_check_ok: true,
service_integrity_dimensions, service_integrity_dimensions: player_po.content_po_token,
}; };
self.execute_request_ctx::<response::Player, _, _>( self.execute_request_ctx::<response::Player, _, _>(
@ -220,10 +228,10 @@ impl RustyPipeQuery {
"player", "player",
&request_body, &request_body,
MapRespOptions { MapRespOptions {
visitor_data: Some(&visitor_data), visitor_data: player_po.visitor_data.as_deref(),
deobf: deobf.as_ref(), deobf: deobf.as_ref(),
unlocalized: true, unlocalized: true,
session_po_token, session_po_token: player_po.session_po_token,
..Default::default() ..Default::default()
}, },
) )