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 code = args.next().expect("no code specified");
|
||||
|
||||
let connect_box = ConnectBox::new(ip)?;
|
||||
connect_box.login(&code).await?;
|
||||
let connect_box = ConnectBox::new(ip, code)?;
|
||||
connect_box.login().await?;
|
||||
|
||||
let devices = connect_box.get_devices().await?;
|
||||
println!("{devices:?}");
|
||||
println!("{devices:#?}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ pub enum Error {
|
||||
IncorrectCode,
|
||||
#[error("unexpected response from the server: {0:?}")]
|
||||
UnexpectedResponse(String),
|
||||
#[error("you are not logged in, or perhaps the session has expired")]
|
||||
NotAuthorized,
|
||||
|
||||
#[error(transparent)]
|
||||
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
|
||||
pub struct ConnectBox {
|
||||
http: Client,
|
||||
code: String,
|
||||
cookie_store: Arc<Jar>,
|
||||
base_url: Url,
|
||||
getter_url: Url,
|
||||
setter_url: Url,
|
||||
auto_reauth: bool
|
||||
}
|
||||
|
||||
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 http = Client::builder()
|
||||
.user_agent("Mozilla/5.0")
|
||||
@ -44,6 +46,8 @@ impl ConnectBox {
|
||||
base_url,
|
||||
getter_url,
|
||||
setter_url,
|
||||
code,
|
||||
auto_reauth: false
|
||||
})
|
||||
}
|
||||
|
||||
@ -64,46 +68,60 @@ impl ConnectBox {
|
||||
}
|
||||
|
||||
async fn xml_getter<T: DeserializeOwned>(&self, function: u32) -> Result<T> {
|
||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||
let form: Vec<Field> = vec![
|
||||
("token".into(), session_token.into()),
|
||||
("fun".into(), function.to_string().into()),
|
||||
];
|
||||
let req = self.http.post(self.getter_url.clone()).form(&form);
|
||||
let resp = req.send().await?.text().await?;
|
||||
let obj = quick_xml::de::from_str(&resp)?;
|
||||
Ok(obj)
|
||||
let mut reauthed = false;
|
||||
loop {
|
||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||
let form: Vec<Field> = vec![
|
||||
("token".into(), session_token.into()),
|
||||
("fun".into(), function.to_string().into()),
|
||||
];
|
||||
let req = self.http.post(self.getter_url.clone()).form(&form);
|
||||
let resp = req.send().await?;
|
||||
if resp.status().is_redirection() {
|
||||
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(
|
||||
&self,
|
||||
function: u32,
|
||||
fields: Option<impl IntoIterator<Item = Field<'_, '_>>>,
|
||||
fields: Option<impl AsRef<[Field<'_, '_>]>>,
|
||||
) -> Result<String> {
|
||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||
let mut form = vec![
|
||||
("token".into(), session_token.into()),
|
||||
("fun".into(), function.to_string().into()),
|
||||
];
|
||||
if let Some(fields) = fields {
|
||||
form.extend(fields);
|
||||
let mut reauthed = false;
|
||||
loop {
|
||||
let session_token = self.cookie("sessionToken")?.ok_or(Error::NoSessionToken)?;
|
||||
let mut form: Vec<(Cow<str>, Cow<str>)> = vec![
|
||||
("token".into(), session_token.into()),
|
||||
("fun".into(), function.to_string().into()),
|
||||
];
|
||||
if let Some(fields) = &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 resp = req.send().await?;
|
||||
if resp.status().is_redirection() {
|
||||
if self.auto_reauth && !reauthed {
|
||||
reauthed = true;
|
||||
continue;
|
||||
}
|
||||
return Err(Error::NotAuthorized)
|
||||
}
|
||||
return Ok(resp.text().await?);
|
||||
}
|
||||
let req = self.http.post(self.setter_url.clone()).form(&form);
|
||||
let resp = req.send().await?;
|
||||
Ok(resp.text().await?)
|
||||
}
|
||||
|
||||
pub async fn login(&self, code: impl AsRef<str>) -> Result<()> {
|
||||
// get the session cookie
|
||||
self.http
|
||||
.get(self.base_url.join("common_page/login.html")?)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
// log in
|
||||
async fn _login(&self) -> Result<()> {
|
||||
let fields = vec![
|
||||
("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?;
|
||||
if response == "idloginincorrect" {
|
||||
@ -118,6 +136,16 @@ impl ConnectBox {
|
||||
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> {
|
||||
self.xml_getter(functions::LAN_TABLE).await
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user