From 5515cf23234186669fc6c30801b6a1642d1b01e1 Mon Sep 17 00:00:00 2001 From: amtoaer Date: Sun, 31 Mar 2024 14:02:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=87=AD=E6=8D=AE=E7=9B=B8=E5=85=B3=E7=9A=84=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bilibili/client.rs | 17 ++++++++++++++--- src/bilibili/credential.rs | 34 ++++++++++++++++------------------ 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/bilibili/client.rs b/src/bilibili/client.rs index a7f3e67..2be6d99 100644 --- a/src/bilibili/client.rs +++ b/src/bilibili/client.rs @@ -1,6 +1,7 @@ use reqwest::{header, Method}; use crate::bilibili::Credential; +use crate::config::CONFIG; use crate::Result; // 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求 @@ -20,7 +21,13 @@ impl Client { header::REFERER, header::HeaderValue::from_static("https://www.bilibili.com"), ); - Self(reqwest::Client::builder().default_headers(headers).build().unwrap()) + Self( + reqwest::Client::builder() + .default_headers(headers) + .gzip(true) + .build() + .unwrap(), + ) } // a wrapper of reqwest::Client::request to add credential to the request @@ -65,9 +72,13 @@ impl BiliClient { let Some(credential) = self.credential.as_mut() else { return Ok(()); }; - if credential.check(&self.client).await? { + if !credential.need_refresh(&self.client).await? { return Ok(()); } - credential.refresh(&self.client).await + credential.refresh(&self.client).await?; + + let mut config = CONFIG.lock().unwrap(); + config.credential = Some(credential.clone()); + config.save() } } diff --git a/src/bilibili/credential.rs b/src/bilibili/credential.rs index 0993956..758a119 100644 --- a/src/bilibili/credential.rs +++ b/src/bilibili/credential.rs @@ -1,5 +1,4 @@ use std::collections::HashSet; -use std::time::{SystemTime, UNIX_EPOCH}; use cookie::Cookie; use regex::Regex; @@ -7,11 +6,12 @@ use reqwest::{header, Method}; use rsa::pkcs8::DecodePublicKey; use rsa::sha2::Sha256; use rsa::{Oaep, RsaPublicKey}; +use serde::{Deserialize, Serialize}; use crate::bilibili::Client; use crate::Result; -#[derive(Default)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct Credential { pub sessdata: String, pub bili_jct: String, @@ -32,7 +32,7 @@ impl Credential { } /// 检查凭据是否有效 - pub async fn check(&self, client: &Client) -> Result { + pub async fn need_refresh(&self, client: &Client) -> Result { let res = client .request( Method::GET, @@ -43,7 +43,7 @@ impl Credential { .await? .json::() .await?; - res["refresh"].as_bool().ok_or("check refresh failed".into()) + res["data"]["refresh"].as_bool().ok_or("check refresh failed".into()) } pub async fn refresh(&mut self, client: &Client) -> Result<()> { @@ -59,14 +59,14 @@ impl Credential { // 调用频率很低,让 key 在函数内部构造影响不大 let key = RsaPublicKey::from_public_key_pem( "-----BEGIN PUBLIC KEY----- - MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg - Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71 - nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40 - JNrRuoEUXpabUzGB8QIDAQAB - -----END PUBLIC KEY-----", +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg +Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71 +nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40 +JNrRuoEUXpabUzGB8QIDAQAB +-----END PUBLIC KEY-----", ) .unwrap(); - let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(); + let ts = chrono::Local::now().timestamp_millis(); let data = format!("refresh_{}", ts).into_bytes(); let mut rng = rand::rngs::OsRng; let encrypted = key.encrypt(&mut rng, Oaep::new::(), &data).unwrap(); @@ -109,19 +109,17 @@ impl Credential { ]) .send() .await?; - let set_cookie = res - .headers() - .get(header::SET_COOKIE) - .ok_or("no set_cookie header")? - .to_str()?; + let set_cookies = res.headers().get_all(header::SET_COOKIE); let mut credential = Credential { buvid3: self.buvid3.clone(), ..Default::default() }; let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]); - let cookies: Vec = Cookie::split_parse_encoded(set_cookie) - .filter(|x| x.as_ref().is_ok_and(|x| required_cookies.contains(x.name()))) - .map(|x| x.unwrap()) + let cookies: Vec = set_cookies + .iter() + .filter_map(|x| x.to_str().ok()) + .filter_map(|x| Cookie::parse(x).ok()) + .filter(|x| required_cookies.contains(x.name())) .collect(); if cookies.len() != required_cookies.len() { return Err("not all required cookies found".into());