diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 85782e2..4d77a1f 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -109,3 +109,4 @@ jobs: provenance-name: provenance-id-${{ matrix.os }}.intoto.jsonl base64-subjects: "${{ needs.build.outputs[format('hash-{0}', matrix.os)] }}" upload-assets: true # Optional: Upload to a new release + draft-release: true # Optional: Upload to a draft release diff --git a/Cargo.lock b/Cargo.lock index 38457e7..e85c9fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,13 +160,14 @@ checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "bourso-cli" -version = "0.5.2" +version = "0.5.3" dependencies = [ "anyhow", "bourso_api", "clap", "directories", "futures-util", + "qrcode", "rpassword", "serde", "serde_json", @@ -177,7 +178,7 @@ dependencies = [ [[package]] name = "bourso_api" -version = "0.5.2" +version = "0.5.3" dependencies = [ "anyhow", "async-stream", @@ -186,7 +187,6 @@ dependencies = [ "cookie_store", "futures-util", "lazy_static", - "qrcode", "rand", "regex", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index c1559e6..d17a500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bourso-cli" -version = "0.5.2" +version = "0.5.3" edition = "2021" repository = "https://github.com/azerpas/bourso-api" @@ -18,6 +18,7 @@ serde_json = { version = "1.0.107" } tracing = { version = "0.1.41" } tracing-subscriber = { version = "0.3.20", features = ["fmt", "env-filter", "json"] } futures-util = { version = "0.3.31" } +qrcode = { version = "0.14.1" } [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] } diff --git a/src/bourso_api/Cargo.toml b/src/bourso_api/Cargo.toml index 9e3e845..2eafc1b 100644 --- a/src/bourso_api/Cargo.toml +++ b/src/bourso_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bourso_api" -version = "0.5.2" +version = "0.5.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -19,7 +19,6 @@ chrono = { version = "0.4.39" } tracing = { version = "0.1.41" } futures-util = { version = "0.3.31" } async-stream = { version = "0.3.6" } -qrcode = { version = "0.14.1" } rand = { version = "0.9.2" } [lints.rust] diff --git a/src/bourso_api/src/client/error.rs b/src/bourso_api/src/client/error.rs index 231cc4c..c0ea62b 100644 --- a/src/bourso_api/src/client/error.rs +++ b/src/bourso_api/src/client/error.rs @@ -4,6 +4,7 @@ use std::fmt; pub enum ClientError { InvalidCredentials, MfaRequired, + QRCodeRequired(String), InvalidMfa, } @@ -12,6 +13,7 @@ impl fmt::Display for ClientError { match self { ClientError::InvalidCredentials => write!(f, "Invalid credentials"), ClientError::MfaRequired => write!(f, "MFA required"), + ClientError::QRCodeRequired(msg) => write!(f, "{}", msg), ClientError::InvalidMfa => write!(f, "Invalid MFA"), } } diff --git a/src/bourso_api/src/client/mod.rs b/src/bourso_api/src/client/mod.rs index 06e1e23..266b150 100644 --- a/src/bourso_api/src/client/mod.rs +++ b/src/bourso_api/src/client/mod.rs @@ -1,7 +1,6 @@ pub mod account; pub mod config; pub mod error; -pub mod qrcode; pub mod trade; pub mod transfer; pub mod virtual_pad; @@ -516,17 +515,9 @@ impl BoursoWebClient { debug!("⏳ MFA not yet validated"); if json_body["qrcode"].is_string() { - match qrcode::generate_qr_code(json_body["qrcode"].as_str().unwrap()) { - Ok(qr) => { - println!(); - println!("{}", qrcode::render_to_terminal(&qr)); - println!(); - } - Err(e) => bail!("Could not render the QR code {}", e), - } - info!( - "Please scan the latest QR code in your BoursoBank app to validate the login request." - ); + bail!(ClientError::QRCodeRequired( + json_body["qrcode"].as_str().unwrap().to_string() + )); } Ok(false) diff --git a/src/lib.rs b/src/lib.rs index 1389a4a..a491f3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ use clap::ArgMatches; use futures_util::{pin_mut, StreamExt}; use tracing::{debug, info, warn}; +pub mod qrcode; pub mod settings; pub mod validate; @@ -174,28 +175,56 @@ pub async fn parse_matches(matches: ArgMatches) -> Result<()> { "Checking MFA status... (waited {}s/{})", wait_time, max_wait_time ); - let mfa_validated = web_client + match web_client .check_mfa( mfa_type.clone(), otp_id.clone(), form_state.clone(), token.clone(), ) - .await?; - - if mfa_validated { - break; - } - - if wait_time >= max_wait_time { - return Err(anyhow::anyhow!( - "MFA validation timed out after {} seconds", - max_wait_time - )); + .await + { + Ok(mfa_validated) => { + if mfa_validated { + break; + } + + if wait_time >= max_wait_time { + return Err(anyhow::anyhow!( + "MFA validation timed out after {} seconds", + max_wait_time + )); + } + + wait_time += wait_interval; + tokio::time::sleep(std::time::Duration::from_secs(wait_interval)).await; + } + Err(e) => match e.downcast_ref() { + Some(bourso_api::client::error::ClientError::QRCodeRequired(code)) => { + match qrcode::generate_qr_code(code) { + Ok(qr) => { + println!(); + println!("{}", qrcode::render_to_terminal(&qr)); + println!(); + } + Err(e) => { + debug!("{:#?}", e); + return Err(e); + } + } + info!( + "Please scan the latest QR code in your BoursoBank app to validate the login request." + ); + wait_time += wait_interval; + tokio::time::sleep(std::time::Duration::from_secs(wait_interval)) + .await; + } + _ => { + debug!("{:#?}", e); + return Err(e); + } + }, } - - wait_time += wait_interval; - tokio::time::sleep(std::time::Duration::from_secs(wait_interval)).await; } info!("MFA successful ✅"); diff --git a/src/bourso_api/src/client/qrcode.rs b/src/qrcode.rs similarity index 100% rename from src/bourso_api/src/client/qrcode.rs rename to src/qrcode.rs