use crate::error::{FinTSError, Result};
use crate::protocol::*;
use crate::types::{SystemId, TaskReference, ChallengeText, HhdUcData, UserId, Pin, ProductId};
use crate::workflow::{BankOps, Dkb, FetchResult, InitiateOutcome};
pub enum Session {
WaitingForTan {
dialog: Dialog<TanPending>,
task_reference: TaskReference,
bank: Dkb,
system_id: SystemId,
},
Ready {
dialog: Dialog<Open>,
bank: Dkb,
system_id: SystemId,
},
}
pub struct Challenge {
pub challenge: ChallengeText,
pub challenge_hhduc: Option<HhdUcData>,
pub decoupled: bool,
pub no_tan_required: bool,
}
pub use crate::workflow::FetchResult as SyncData;
pub async fn connect(
username: &UserId,
pin: &Pin,
product_id: &ProductId,
system_id: Option<&SystemId>,
) -> Result<(Session, Challenge)> {
let bank = Dkb::new();
let outcome = bank.initiate(username, pin, product_id, system_id, None, None).await?;
match outcome {
InitiateOutcome::NeedTan(result) => {
let challenge = Challenge {
challenge: result.challenge.challenge.clone(),
challenge_hhduc: result.challenge.challenge_hhduc.clone(),
decoupled: result.challenge.decoupled,
no_tan_required: false,
};
let session = Session::WaitingForTan {
dialog: result.dialog,
task_reference: result.challenge.task_reference,
bank,
system_id: result.system_id,
};
Ok((session, challenge))
}
InitiateOutcome::Authenticated(result) => {
let challenge = Challenge {
challenge: ChallengeText::new(""),
challenge_hhduc: None,
decoupled: false,
no_tan_required: true,
};
let session = Session::Ready {
dialog: result.dialog,
bank,
system_id: result.system_id,
};
Ok((session, challenge))
}
}
}
impl Session {
pub async fn fetch(
self,
account: &Account,
days: u32,
) -> Result<FetchResult> {
match self {
Session::WaitingForTan { dialog, task_reference, bank, .. } => {
let poll_result = dialog.poll(&task_reference).await?;
match poll_result {
PollResult::Confirmed(mut open, _response) => {
let result = bank.fetch(&mut open, account, days).await?;
open.end().await.ok();
Ok(result)
}
PollResult::Pending(_dialog) => {
Err(FinTSError::Dialog(
"TAN still pending: user has not yet confirmed in banking app".into()
))
}
}
}
Session::Ready { mut dialog, bank, .. } => {
let result = bank.fetch(&mut dialog, account, days).await?;
dialog.end().await.ok();
Ok(result)
}
}
}
pub fn system_id(&self) -> &SystemId {
match self {
Session::WaitingForTan { system_id, .. } => system_id,
Session::Ready { system_id, .. } => system_id,
}
}
}