fix: 修复刷新凭据相关的异常

This commit is contained in:
amtoaer
2024-03-31 14:02:16 +08:00
parent 5e73b5c0bf
commit 5515cf2323
2 changed files with 30 additions and 21 deletions
+14 -3
View File
@@ -1,6 +1,7 @@
use reqwest::{header, Method}; use reqwest::{header, Method};
use crate::bilibili::Credential; use crate::bilibili::Credential;
use crate::config::CONFIG;
use crate::Result; use crate::Result;
// 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求 // 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求
@@ -20,7 +21,13 @@ impl Client {
header::REFERER, header::REFERER,
header::HeaderValue::from_static("https://www.bilibili.com"), 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 // 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 { let Some(credential) = self.credential.as_mut() else {
return Ok(()); return Ok(());
}; };
if credential.check(&self.client).await? { if !credential.need_refresh(&self.client).await? {
return Ok(()); 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()
} }
} }
+16 -18
View File
@@ -1,5 +1,4 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::time::{SystemTime, UNIX_EPOCH};
use cookie::Cookie; use cookie::Cookie;
use regex::Regex; use regex::Regex;
@@ -7,11 +6,12 @@ use reqwest::{header, Method};
use rsa::pkcs8::DecodePublicKey; use rsa::pkcs8::DecodePublicKey;
use rsa::sha2::Sha256; use rsa::sha2::Sha256;
use rsa::{Oaep, RsaPublicKey}; use rsa::{Oaep, RsaPublicKey};
use serde::{Deserialize, Serialize};
use crate::bilibili::Client; use crate::bilibili::Client;
use crate::Result; use crate::Result;
#[derive(Default)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Credential { pub struct Credential {
pub sessdata: String, pub sessdata: String,
pub bili_jct: String, pub bili_jct: String,
@@ -32,7 +32,7 @@ impl Credential {
} }
/// 检查凭据是否有效 /// 检查凭据是否有效
pub async fn check(&self, client: &Client) -> Result<bool> { pub async fn need_refresh(&self, client: &Client) -> Result<bool> {
let res = client let res = client
.request( .request(
Method::GET, Method::GET,
@@ -43,7 +43,7 @@ impl Credential {
.await? .await?
.json::<serde_json::Value>() .json::<serde_json::Value>()
.await?; .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<()> { pub async fn refresh(&mut self, client: &Client) -> Result<()> {
@@ -59,14 +59,14 @@ impl Credential {
// 调用频率很低,让 key 在函数内部构造影响不大 // 调用频率很低,让 key 在函数内部构造影响不大
let key = RsaPublicKey::from_public_key_pem( let key = RsaPublicKey::from_public_key_pem(
"-----BEGIN PUBLIC KEY----- "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg
Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71 Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71
nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40 nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40
JNrRuoEUXpabUzGB8QIDAQAB JNrRuoEUXpabUzGB8QIDAQAB
-----END PUBLIC KEY-----", -----END PUBLIC KEY-----",
) )
.unwrap(); .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 data = format!("refresh_{}", ts).into_bytes();
let mut rng = rand::rngs::OsRng; let mut rng = rand::rngs::OsRng;
let encrypted = key.encrypt(&mut rng, Oaep::new::<Sha256>(), &data).unwrap(); let encrypted = key.encrypt(&mut rng, Oaep::new::<Sha256>(), &data).unwrap();
@@ -109,19 +109,17 @@ impl Credential {
]) ])
.send() .send()
.await?; .await?;
let set_cookie = res let set_cookies = res.headers().get_all(header::SET_COOKIE);
.headers()
.get(header::SET_COOKIE)
.ok_or("no set_cookie header")?
.to_str()?;
let mut credential = Credential { let mut credential = Credential {
buvid3: self.buvid3.clone(), buvid3: self.buvid3.clone(),
..Default::default() ..Default::default()
}; };
let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]); let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]);
let cookies: Vec<Cookie> = Cookie::split_parse_encoded(set_cookie) let cookies: Vec<Cookie> = set_cookies
.filter(|x| x.as_ref().is_ok_and(|x| required_cookies.contains(x.name()))) .iter()
.map(|x| x.unwrap()) .filter_map(|x| x.to_str().ok())
.filter_map(|x| Cookie::parse(x).ok())
.filter(|x| required_cookies.contains(x.name()))
.collect(); .collect();
if cookies.len() != required_cookies.len() { if cookies.len() != required_cookies.len() {
return Err("not all required cookies found".into()); return Err("not all required cookies found".into());