Skip to main content

lnu_elytra/method/
login.rs

1use std::time::{SystemTime, UNIX_EPOCH};
2
3use serde::Serialize;
4
5use crate::{
6    Client,
7    error::{Error, R},
8    utils::{
9        EncPwd, PublicKey, ToHtml, UseInputValue,
10        macros::{debug, error, info, trace},
11    },
12};
13
14impl Client {
15    /// 登录
16    pub async fn login(&mut self, username: &str, password: &str) -> R {
17        info!("正在登录...");
18
19        trace!("加载登录页");
20
21        let doc = self.get(&Client::LOGIN_URL).send().await?._doc().await?;
22
23        trace!("解析登录页,获取csrftoken");
24
25        let csrftoken = doc.use_val(&Client::S_CSRFTOKEN)?;
26
27        debug!("csrftoken: {}", csrftoken);
28
29        use std::borrow::Cow;
30        let mm = if let Ok(mmsfjm) = doc.use_val(&Client::S_INPUT_MMSFJM)
31            && mmsfjm == "0"
32        {
33            trace!("mmsfjm == '0'");
34            Cow::Borrowed(password)
35        } else {
36            trace!("获取公钥,使用公钥加密密码");
37            Cow::Owned(
38                self.get(&Client::PUBLIC_KEY_URL)
39                    .send()
40                    .await?
41                    .json::<PublicKey>()
42                    .await?
43                    .into_rsa_key()?
44                    .enc_pwd(password)?,
45            )
46        };
47
48        #[derive(Serialize, Debug)]
49        struct LoginData<'a> {
50            csrftoken: &'a str,
51            yhm: &'a str,
52            mm: &'a str,
53            language: &'a str,
54        }
55
56        let login_data = LoginData {
57            csrftoken: csrftoken,
58            yhm: username,
59            mm: &mm,
60            language: "zh_CN",
61        };
62
63        debug!("登录数据: {:?}", login_data);
64
65        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis();
66
67        trace!("发送登录请求");
68
69        let doc = self
70            .post(&Client::LOGIN_URL)
71            .query(&[("time", timestamp)])
72            .form(&login_data)
73            .send()
74            .await?
75            ._doc()
76            .await?;
77
78        let u = doc.use_val(&Client::S_SESSION_USER_KEY).or_else(|_| {
79            error!("登录失败,未找到 SESSION_USER_KEY");
80            return Err(Error::LoginFailed);
81        })?;
82
83        debug!("SESSION_USER_KEY: {}", u);
84
85        if u != username {
86            error!("登录失败,SESSION_USER_KEY 不匹配");
87            return Err(Error::LoginFailed);
88        }
89
90        info!("登录成功");
91
92        Ok(())
93    }
94}