diff --git a/Cargo.toml b/Cargo.toml index 6771387..57e54df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bitsrun" description = "A headless login and logout CLI for 10.0.0.55 at BIT" -version = "0.3.1" +version = "0.4.0" edition = "2021" license = "MIT" homepage = "https://github.com/spencerwooo/bitsrun-rs" @@ -42,6 +42,6 @@ pretty_env_logger = "0.5.0" strip = "symbols" [package.metadata.deb] -copyright = "2023 Spencer Woo" +copyright = "2024 Spencer Woo" maintainer-scripts = "debian/" systemd-units = { enable = true, start = false } diff --git a/src/client.rs b/src/client.rs index 8131ba2..6b5fc8f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -23,6 +23,9 @@ pub const SRUN_PORTAL: &str = "http://10.0.0.55"; pub const SRUN_TYPE: &str = "1"; pub const SRUN_N: &str = "200"; +/// An arbitrary HTTP URL for srun to redirect +pub const CAPTIVE_PORTAL_TEST: &str = "http://www.bit.edu.cn"; + /// The response from the `/rad_user_info` endpoint /// /// This response is used to determine if the device is logged in or not, and if it is logged in, @@ -128,12 +131,12 @@ pub async fn get_login_state(client: &Client, verbose: bool) -> Result Result { - let resp = client.get(SRUN_PORTAL).send().await.with_context(|| { +/// Get the ac_id of the current device by visiting a URL +async fn get_acid_by_url(client: &Client, url: &str) -> Result { + let resp = client.get(url).send().await.with_context(|| { format!( "failed to get ac_id from `{}`", - SRUN_PORTAL.if_supports_color(Stdout, |t| t.underline()) + url.if_supports_color(Stdout, |t| t.underline()) ) })?; let redirect_url = resp.url().to_string(); @@ -154,6 +157,20 @@ async fn get_acid(client: &Client) -> Result { Ok(ac_id.1) } +/// Get the ac_id of the current device +async fn get_acid(client: &Client) -> Result { + // Try to visit `CAPTIVE_PORTAL_TEST`. + // If not logged in, it will be redirected to `SRUN_PORTAL` with ac_id. + // Otherwise, we fall back to visit `SRUN_PORTAL` directly. + // https://en.wikipedia.org/wiki/Captive_portal#Detection + // + // Because of ITC's double authentication mechanism, visiting `SRUN_PORTAL` directly is not preferred. + // https://itc.bit.edu.cn/fwzn/zxbl/f2c0c8e939ce4e9cace880d5403fe4b5.htm + get_acid_by_url(client, CAPTIVE_PORTAL_TEST) + .await + .or(get_acid_by_url(client, SRUN_PORTAL).await) +} + /// SRUN portal response type when calling login/logout /// /// Note that fields that are not used are omitted