diff --git a/crates/tranquil-api/src/server/session.rs b/crates/tranquil-api/src/server/session.rs index 3fb1075..a8b186b 100644 --- a/crates/tranquil-api/src/server/session.rs +++ b/crates/tranquil-api/src/server/session.rs @@ -163,6 +163,7 @@ pub async fn create_session( let email_2fa_enabled = row.email_2fa_enabled; let is_legacy_login = has_totp || email_2fa_enabled; let twofa_ctx = tranquil_pds::auth::legacy_2fa::Legacy2faContext { + is_app_password: app_password_name.is_some(), email_2fa_enabled, has_totp, allow_legacy_login: row.allow_legacy_login, diff --git a/crates/tranquil-pds/src/auth/legacy_2fa.rs b/crates/tranquil-pds/src/auth/legacy_2fa.rs index 2f9aa88..daf6ae6 100644 --- a/crates/tranquil-pds/src/auth/legacy_2fa.rs +++ b/crates/tranquil-pds/src/auth/legacy_2fa.rs @@ -156,6 +156,7 @@ pub enum Legacy2faOutcome { } pub struct Legacy2faContext { + pub is_app_password: bool, pub email_2fa_enabled: bool, pub has_totp: bool, pub allow_legacy_login: bool, @@ -163,7 +164,7 @@ pub struct Legacy2faContext { impl Legacy2faContext { pub fn requires_2fa(&self) -> bool { - self.email_2fa_enabled || self.has_totp + !self.is_app_password && (self.email_2fa_enabled || self.has_totp) } pub fn is_blocked(&self) -> bool { @@ -418,6 +419,7 @@ mod tests { let cache = MockCache::new(); let did = Did::new("did:plc:test".to_string()).unwrap(); let ctx = Legacy2faContext { + is_app_password: false, email_2fa_enabled: false, has_totp: false, allow_legacy_login: true, @@ -427,11 +429,27 @@ mod tests { assert!(matches!(outcome, Legacy2faOutcome::NotRequired)); } + #[tokio::test] + async fn test_process_flow_not_required_because_app_password() { + let cache = MockCache::new(); + let did = Did::new("did:plc:test".to_string()).unwrap(); + let ctx = Legacy2faContext { + is_app_password: true, + email_2fa_enabled: false, + has_totp: true, + allow_legacy_login: true, + }; + + let outcome = process_legacy_2fa(&cache, &did, &ctx, None).await.unwrap(); + assert!(matches!(outcome, Legacy2faOutcome::NotRequired)); + } + #[tokio::test] async fn test_process_flow_blocked() { let cache = MockCache::new(); let did = Did::new("did:plc:test".to_string()).unwrap(); let ctx = Legacy2faContext { + is_app_password: false, email_2fa_enabled: false, has_totp: true, allow_legacy_login: false, @@ -446,6 +464,7 @@ mod tests { let cache = MockCache::new(); let did = Did::new("did:plc:test".to_string()).unwrap(); let ctx = Legacy2faContext { + is_app_password: false, email_2fa_enabled: false, has_totp: true, allow_legacy_login: true, @@ -460,6 +479,7 @@ mod tests { let cache = MockCache::new(); let did = Did::new("did:plc:test2".to_string()).unwrap(); let ctx = Legacy2faContext { + is_app_password: false, email_2fa_enabled: true, has_totp: false, allow_legacy_login: false, @@ -474,6 +494,7 @@ mod tests { let cache = MockCache::new(); let did = Did::new("did:plc:test".to_string()).unwrap(); let ctx = Legacy2faContext { + is_app_password: false, email_2fa_enabled: true, has_totp: false, allow_legacy_login: false,