feat(daemon): GetPendingStatus D-Bus method + 2 integration tests
Drops the #[allow(dead_code)] on AppState::get_pending_status — it's now called from the D-Bus dispatch. Two new p2p tests cover the absent and the round-trip cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
use crate::polkit::Polkit;
|
use crate::polkit::Polkit;
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use authforge_common::policy::Policy;
|
use authforge_common::policy::Policy;
|
||||||
use authforge_common::types::{Credential, PendingFlag, PolicyApplyResult, RecoveryCodeSummary};
|
use authforge_common::types::{
|
||||||
|
Credential, PendingFlag, PendingStatus, PolicyApplyResult, RecoveryCodeSummary,
|
||||||
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct AuthForge {
|
pub struct AuthForge {
|
||||||
@@ -129,6 +131,14 @@ impl AuthForge {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_pending_status(&self, user: String) -> zbus::fdo::Result<PendingStatus> {
|
||||||
|
// No polkit gate — pure read; daemon's pattern is gates on writes only.
|
||||||
|
self.state
|
||||||
|
.get_pending_status(&user)
|
||||||
|
.await
|
||||||
|
.map_err(|e| zbus::fdo::Error::Failed(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
async fn generate_recovery_code(&self, user: String) -> zbus::fdo::Result<String> {
|
async fn generate_recovery_code(&self, user: String) -> zbus::fdo::Result<String> {
|
||||||
self.authz("io.dangerousthings.AuthForge.generate-recovery")
|
self.authz("io.dangerousthings.AuthForge.generate-recovery")
|
||||||
.await?;
|
.await?;
|
||||||
@@ -387,6 +397,34 @@ central_path = "{}"
|
|||||||
assert!(!state.has_pending("alice").await.unwrap());
|
assert!(!state.has_pending("alice").await.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn pending_status_is_absent_for_fresh_user() {
|
||||||
|
let (_srv, client, _state, _tmp) = p2p_pair().await;
|
||||||
|
let p = proxy(&client).await;
|
||||||
|
let s: PendingStatus = p.call("GetPendingStatus", &("alice",)).await.unwrap();
|
||||||
|
assert!(!s.present);
|
||||||
|
assert!(s.flag.required_methods.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn pending_status_round_trips_set_flag() {
|
||||||
|
let (_srv, client, _state, _tmp) = p2p_pair().await;
|
||||||
|
let p = proxy(&client).await;
|
||||||
|
let flag = PendingFlag {
|
||||||
|
required_methods: vec![Method::Fido2],
|
||||||
|
created_unix: 100,
|
||||||
|
deadline_unix: 200,
|
||||||
|
re_enroll: true,
|
||||||
|
};
|
||||||
|
let _: () = p
|
||||||
|
.call("SetPendingFlag", &("alice", flag.clone()))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let s: PendingStatus = p.call("GetPendingStatus", &("alice",)).await.unwrap();
|
||||||
|
assert!(s.present);
|
||||||
|
assert_eq!(s.flag, flag);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn generate_recovery_code_returns_8_digits() {
|
async fn generate_recovery_code_returns_8_digits() {
|
||||||
let (_srv, client, _state, _tmp) = p2p_pair().await;
|
let (_srv, client, _state, _tmp) = p2p_pair().await;
|
||||||
|
|||||||
@@ -259,7 +259,6 @@ impl AppState {
|
|||||||
Ok(self.pending.get(user)?.is_some())
|
Ok(self.pending.get(user)?.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // wired through D-Bus in Task 5.
|
|
||||||
pub async fn get_pending_status(&self, user: &str) -> Result<PendingStatus, StateError> {
|
pub async fn get_pending_status(&self, user: &str) -> Result<PendingStatus, StateError> {
|
||||||
match self.pending.get(user)? {
|
match self.pending.get(user)? {
|
||||||
Some(flag) => Ok(PendingStatus { present: true, flag }),
|
Some(flag) => Ok(PendingStatus { present: true, flag }),
|
||||||
|
|||||||
Reference in New Issue
Block a user