use crate::client::TREEHOLE_BASE;
use anyhow::{anyhow, Context, Result};
use colored::Colorize;
use pkuinfo_common::credential;
use serde::Deserialize;
pub const CODE_SMS_REQUIRED: i64 = 40002;
#[derive(Deserialize)]
struct ApiResponse {
#[serde(default)]
code: i64,
success: bool,
message: String,
}
pub async fn check_and_verify(
client: &reqwest::Client,
jwt_token: &str,
uuid: &str,
) -> Result<()> {
let resp: ApiResponse = client
.get(format!(
"{TREEHOLE_BASE}/chapi/api/v3/hole/list_comments?page=1&limit=1&comment_limit=0&comment_stream=1"
))
.header("authorization", format!("Bearer {jwt_token}"))
.header("uuid", uuid)
.send()
.await
.context("验证登录状态失败")?
.json()
.await
.context("解析验证响应失败")?;
if resp.code == CODE_SMS_REQUIRED {
println!(
"{} 需要短信验证(首次登录或定期验证)",
"[!]".yellow()
);
handle_sms_verification(client, jwt_token, uuid).await
} else if !resp.success {
Err(anyhow!(
"登录验证失败: code={}, message={}",
resp.code,
resp.message
))
} else {
Ok(())
}
}
async fn handle_sms_verification(
client: &reqwest::Client,
jwt_token: &str,
uuid: &str,
) -> Result<()> {
if !credential::confirm_send_sms("是否发送短信验证码? [Y/n] ")? {
return Err(anyhow!("用户取消短信验证"));
}
let send_resp: ApiResponse = client
.post(format!("{TREEHOLE_BASE}/chapi/api/jwt_send_msg"))
.header("authorization", format!("Bearer {jwt_token}"))
.header("uuid", uuid)
.json(&serde_json::json!({}))
.send()
.await
.context("发送短信验证码失败")?
.json()
.await?;
if !send_resp.success {
return Err(anyhow!("发送短信失败: {}", send_resp.message));
}
println!("{} 验证码已发送到绑定手机", "✓".green());
let code = credential::resolve_sms_code("请输入验证码: ")?;
let verify_resp: ApiResponse = client
.post(format!("{TREEHOLE_BASE}/chapi/api/jwt_msg_verify"))
.header("authorization", format!("Bearer {jwt_token}"))
.header("uuid", uuid)
.json(&serde_json::json!({ "valid_code": code }))
.send()
.await
.context("提交验证码失败")?
.json()
.await?;
if verify_resp.success {
println!("{} 短信验证通过", "✓".green());
Ok(())
} else {
Err(anyhow!("短信验证失败: {}", verify_resp.message))
}
}