Skip to content

Commit 03c3fc9

Browse files
committed
fix: Bubble homeserver error back to user cleanly. Remove middleware
1 parent 815c7c0 commit 03c3fc9

File tree

8 files changed

+24
-165
lines changed

8 files changed

+24
-165
lines changed

src/shared/homeserver_admin_api.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,4 @@ impl HomeserverAdminAPI {
5353
response.error_for_status()?;
5454
Ok(())
5555
}
56-
57-
/// Checks if the homeserver is responsive by making a GET request to the root URL
58-
/// This is NOT password protected so it won't validate the admin password.
59-
pub async fn health_check(&self) -> Result<(), reqwest::Error> {
60-
let url = self.base_url.join("/").expect("Failed to join URL path");
61-
let response = self.http_client.get(url).send().await?;
62-
response.error_for_status()?;
63-
Ok(())
64-
}
6556
}

src/shared/homeserver_health_middleware.rs

Lines changed: 0 additions & 135 deletions
This file was deleted.

src/shared/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
mod homeserver_admin_api;
2-
mod homeserver_health_middleware;
32

43
pub use homeserver_admin_api::HomeserverAdminAPI;
5-
pub use homeserver_health_middleware::check_homeserver_health;

src/sms_verification/app_state.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::{
88
pub struct AppState {
99
pub db: SqlDb,
1010
pub sms_verification: SmsVerificationService,
11-
pub homeserver_admin_api: HomeserverAdminAPI,
1211
}
1312

1413
impl AppState {
@@ -28,7 +27,6 @@ impl AppState {
2827
Self {
2928
db,
3029
sms_verification,
31-
homeserver_admin_api,
3230
}
3331
}
3432
}

src/sms_verification/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ pub enum SmsVerificationError {
2424
#[error("External service rate limit exceeded")]
2525
RateLimited { retry_after: Option<u64> },
2626

27+
#[error("Homeserver temporarily unavailable, please retry")]
28+
HomeserverUnavailable,
29+
2730
#[error("HTTP request failed: {0}")]
2831
RequestFailed(#[from] reqwest::Error),
2932

src/sms_verification/http.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use axum::{
22
Json, Router,
33
extract::State,
44
http::StatusCode,
5-
middleware,
65
response::{IntoResponse, Response},
76
routing::post,
87
};
@@ -22,22 +21,9 @@ pub async fn router(
2221
db: &crate::infrastructure::sql::SqlDb,
2322
) -> Result<Router, HttpServerError> {
2423
let state = AppState::new(config, db.clone());
25-
let homeserver_api = state.homeserver_admin_api.clone();
26-
27-
// NOTE: SMS verification routes REQUIRE homeserver health check middleware.
28-
// Unlike LN verification, SMS cannot use database transactions for atomicity because:
29-
// 1. Prelude API destructively marks verification as complete when check_code() succeeds
30-
// 2. If generate_signup_token() fails after that, we can't rollback Prelude's state
31-
// 3. This would create an inconsistent state: Prelude says "verified", our DB says "failed"
32-
//
33-
// The middleware mitigates this by failing fast (503) if homeserver is unreachable.
3424
Ok(Router::new()
3525
.route("/send_code", post(send_code_handler))
3626
.route("/validate_code", post(validate_code_handler))
37-
.route_layer(middleware::from_fn(move |req, next| {
38-
let api = homeserver_api.clone();
39-
crate::shared::check_homeserver_health(api, req, next)
40-
}))
4127
.with_state(state))
4228
}
4329

@@ -95,8 +81,12 @@ impl IntoResponse for SmsVerificationError {
9581
}
9682
return response;
9783
}
84+
SmsVerificationError::HomeserverUnavailable => {
85+
tracing::error!("Homeserver unavailable during SMS verification");
86+
StatusCode::INTERNAL_SERVER_ERROR
87+
}
9888
SmsVerificationError::RequestFailed(ref err) => {
99-
tracing::error!(error = %err, "Failed to communicate with SMS provider");
89+
tracing::error!(error = %err, "Failed to communicate with external service");
10090
StatusCode::INTERNAL_SERVER_ERROR
10191
}
10292
SmsVerificationError::Database(ref err) => {

src/sms_verification/service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl SmsVerificationService {
159159
PreludeCheckCodeResponse::Success { id, .. } => {
160160
let code = match self.homeserver_admin_api.generate_signup_token().await {
161161
Ok(code) => code,
162-
Err(e) => {
162+
Err(_e) => {
163163
if let Err(e) = SmsVerificationRepository::mark_failed(
164164
&mut executor,
165165
&id,
@@ -169,7 +169,7 @@ impl SmsVerificationService {
169169
{
170170
tracing::error!("{}", e);
171171
}
172-
return Err(e.into());
172+
return Err(SmsVerificationError::HomeserverUnavailable);
173173
}
174174
};
175175

src/sms_verification/tests.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,20 @@ async fn test_service_success_but_homeserver_fails_marks_failed(pool: PgPool) {
794794
record.failure_reason,
795795
Some("homeserver_signup_token_generation_failed".to_string())
796796
);
797+
798+
// Verify that failed verification does NOT count towards quota
799+
let phone_hash = test_phone_hasher().hash_phone_number(phone.as_str());
800+
let failed_count = SmsVerificationRepository::count_verified_sessions_in_last_days(
801+
&mut executor,
802+
&phone_hash,
803+
7,
804+
)
805+
.await
806+
.unwrap();
807+
assert_eq!(
808+
failed_count, 0,
809+
"Failed verification should NOT count towards weekly quota"
810+
);
797811
}
798812

799813
// This circumstance happens if validate_code() is called before send_code() - Prelude has no prelude_id for the verification session yet so it returns a dummy value which doesnt match to anything in our db.

0 commit comments

Comments
 (0)