implement auto reauth
This commit is contained in:
parent
6ad2534983
commit
7838ca1978
@ -11,11 +11,11 @@ async fn main() -> Result<()> {
|
|||||||
let ip = args.next().expect("no ip specified");
|
let ip = args.next().expect("no ip specified");
|
||||||
let code = args.next().expect("no code specified");
|
let code = args.next().expect("no code specified");
|
||||||
|
|
||||||
let connect_box = ConnectBox::new(ip)?;
|
let connect_box = ConnectBox::new(ip, code)?;
|
||||||
connect_box.login(&code).await?;
|
connect_box.login().await?;
|
||||||
|
|
||||||
let devices = connect_box.get_devices().await?;
|
let devices = connect_box.get_devices().await?;
|
||||||
println!("{devices:?}");
|
println!("{devices:#?}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ pub enum Error {
|
|||||||
IncorrectCode,
|
IncorrectCode,
|
||||||
#[error("unexpected response from the server: {0:?}")]
|
#[error("unexpected response from the server: {0:?}")]
|
||||||
UnexpectedResponse(String),
|
UnexpectedResponse(String),
|
||||||
|
#[error("you are not logged in, or perhaps the session has expired")]
|
||||||
|
NotAuthorized,
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
URLParseError(#[from] url::ParseError),
|
URLParseError(#[from] url::ParseError),
|
||||||
|
@ -21,14 +21,16 @@ type Field<'a, 'b> = (Cow<'a, str>, Cow<'b, str>);
|
|||||||
/// The entry point of the library - the API client
|
/// The entry point of the library - the API client
|
||||||
pub struct ConnectBox {
|
pub struct ConnectBox {
|
||||||
http: Client,
|
http: Client,
|
||||||
|
code: String,
|
||||||
cookie_store: Arc<Jar>,
|
cookie_store: Arc<Jar>,
|
||||||
base_url: Url,
|
base_url: Url,
|
||||||
getter_url: Url,
|
getter_url: Url,
|
||||||
setter_url: Url,
|
setter_url: Url,
|
||||||
|
auto_reauth: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectBox {
|
impl ConnectBox {
|
||||||
pub fn new(address: impl Display) -> Result<Self> {
|
pub fn new(address: impl Display, code: String) -> Result<Self> {
|
||||||
let cookie_store = Arc::new(Jar::default());
|
let cookie_store = Arc::new(Jar::default());
|
||||||
let http = Client::builder()
|
let http = Client::builder()
|
||||||
.user_agent("Mozilla/5.0")
|
.user_agent("Mozilla/5.0")
|
||||||
@ -44,6 +46,8 @@ impl ConnectBox {
|
|||||||
base_url,
|
base_url,
|
||||||
getter_url,
|
getter_url,
|
||||||
setter_url,
|
setter_url,
|
||||||
|
code,
|
||||||
|
auto_reauth: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,46 +68,60 @@ impl ConnectBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn xml_getter<T: DeserializeOwned>(&self, function: u32) -> Result<T> {
|
async fn xml_getter<T: DeserializeOwned>(&self, function: u32) -> Result<T> {
|
||||||
|
let mut reauthed = false;
|
||||||
|
loop {
|
||||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||||
let form: Vec<Field> = vec![
|
let form: Vec<Field> = vec![
|
||||||
("token".into(), session_token.into()),
|
("token".into(), session_token.into()),
|
||||||
("fun".into(), function.to_string().into()),
|
("fun".into(), function.to_string().into()),
|
||||||
];
|
];
|
||||||
let req = self.http.post(self.getter_url.clone()).form(&form);
|
let req = self.http.post(self.getter_url.clone()).form(&form);
|
||||||
let resp = req.send().await?.text().await?;
|
let resp = req.send().await?;
|
||||||
let obj = quick_xml::de::from_str(&resp)?;
|
if resp.status().is_redirection() {
|
||||||
Ok(obj)
|
if self.auto_reauth && !reauthed {
|
||||||
|
reauthed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Err(Error::NotAuthorized)
|
||||||
|
}
|
||||||
|
return Ok(quick_xml::de::from_str(&resp.text().await?)?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn xml_setter(
|
async fn xml_setter(
|
||||||
&self,
|
&self,
|
||||||
function: u32,
|
function: u32,
|
||||||
fields: Option<impl IntoIterator<Item = Field<'_, '_>>>,
|
fields: Option<impl AsRef<[Field<'_, '_>]>>,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
|
let mut reauthed = false;
|
||||||
|
loop {
|
||||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||||
let mut form = vec![
|
let mut form: Vec<(Cow<str>, Cow<str>)> = vec![
|
||||||
("token".into(), session_token.into()),
|
("token".into(), session_token.into()),
|
||||||
("fun".into(), function.to_string().into()),
|
("fun".into(), function.to_string().into()),
|
||||||
];
|
];
|
||||||
if let Some(fields) = fields {
|
if let Some(fields) = &fields {
|
||||||
form.extend(fields);
|
for (key, value) in fields.as_ref() {
|
||||||
|
form.push((key.clone(), value.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let req = self.http.post(self.setter_url.clone()).form(&form);
|
let req = self.http.post(self.setter_url.clone()).form(&form);
|
||||||
let resp = req.send().await?;
|
let resp = req.send().await?;
|
||||||
Ok(resp.text().await?)
|
if resp.status().is_redirection() {
|
||||||
|
if self.auto_reauth && !reauthed {
|
||||||
|
reauthed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Err(Error::NotAuthorized)
|
||||||
|
}
|
||||||
|
return Ok(resp.text().await?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login(&self, code: impl AsRef<str>) -> Result<()> {
|
async fn _login(&self) -> Result<()> {
|
||||||
// get the session cookie
|
|
||||||
self.http
|
|
||||||
.get(self.base_url.join("common_page/login.html")?)
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// log in
|
|
||||||
let fields = vec![
|
let fields = vec![
|
||||||
("Username".into(), "NULL".into()),
|
("Username".into(), "NULL".into()),
|
||||||
("Password".into(), code.as_ref().into()),
|
("Password".into(), (&self.code).into()),
|
||||||
];
|
];
|
||||||
let response = self.xml_setter(functions::LOGIN, Some(fields)).await?;
|
let response = self.xml_setter(functions::LOGIN, Some(fields)).await?;
|
||||||
if response == "idloginincorrect" {
|
if response == "idloginincorrect" {
|
||||||
@ -118,6 +136,16 @@ impl ConnectBox {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn login(&self) -> Result<()> {
|
||||||
|
// get the session cookie
|
||||||
|
self.http
|
||||||
|
.get(self.base_url.join("common_page/login.html")?)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self._login().await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_devices(&self) -> Result<models::LanUserTable> {
|
pub async fn get_devices(&self) -> Result<models::LanUserTable> {
|
||||||
self.xml_getter(functions::LAN_TABLE).await
|
self.xml_getter(functions::LAN_TABLE).await
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user