Microservice to bring 2FA to self hosted PDSes

logging

authored by baileytownsend.dev and committed by Tangled 01148f8a 94e9b2ee

Changed files
+29 -11
src
+29 -11
src/xrpc/com_atproto_server.rs
··· 10 use axum::{Extension, Json, debug_handler, extract, extract::Request}; 11 use serde::{Deserialize, Serialize}; 12 use serde_json; 13 use tracing::log; 14 15 #[derive(Serialize, Deserialize, Debug, Clone)] ··· 155 // Email update asked for 156 if email_auth_update { 157 let email = payload.email.clone(); 158 - let email_confirmed = sqlx::query_as::<_, (String,)>( 159 "SELECT did FROM account WHERE emailConfirmedAt IS NOT NULL AND email = ?", 160 ) 161 .bind(&email) 162 .fetch_optional(&state.account_pool) 163 .await 164 - .map_err(|_| StatusCode::BAD_REQUEST)?; 165 166 //Since the email is already confirmed we can enable 2fa 167 return match email_confirmed { ··· 184 if !email_auth_update && !email_auth_not_set { 185 //User wants auth turned off and has a token 186 if let Some(token) = &payload.token { 187 - let token_found = sqlx::query_as::<_, (String,)>( 188 "SELECT token FROM email_token WHERE token = ? AND did = ? AND purpose = 'update_email'", 189 ) 190 .bind(token) 191 .bind(&did.0) 192 .fetch_optional(&state.account_pool) 193 - .await 194 - .map_err(|_| StatusCode::BAD_REQUEST)?; 195 196 return if token_found.is_some() { 197 - let _ = sqlx::query( 198 "INSERT INTO two_factor_accounts (did, required) VALUES (?, 0) ON CONFLICT(did) DO UPDATE SET required = 0", 199 ) 200 .bind(&did.0) 201 .execute(&state.pds_gatekeeper_pool) 202 - .await 203 - .map_err(|_| StatusCode::BAD_REQUEST)?; 204 205 Ok(StatusCode::OK.into_response()) 206 } else { ··· 275 ); 276 277 // Rewrite the URI to point at the upstream PDS; keep headers, method, and body intact 278 - *req.uri_mut() = uri 279 - .parse() 280 - .map_err(|_| StatusCode::BAD_REQUEST)?; 281 282 let proxied = state 283 .reverse_proxy_client
··· 10 use axum::{Extension, Json, debug_handler, extract, extract::Request}; 11 use serde::{Deserialize, Serialize}; 12 use serde_json; 13 + use sqlx::Error; 14 + use sqlx::sqlite::SqliteQueryResult; 15 use tracing::log; 16 17 #[derive(Serialize, Deserialize, Debug, Clone)] ··· 157 // Email update asked for 158 if email_auth_update { 159 let email = payload.email.clone(); 160 + let email_confirmed = match sqlx::query_as::<_, (String,)>( 161 "SELECT did FROM account WHERE emailConfirmedAt IS NOT NULL AND email = ?", 162 ) 163 .bind(&email) 164 .fetch_optional(&state.account_pool) 165 .await 166 + { 167 + Ok(row) => row, 168 + Err(err) => { 169 + log::error!("Error checking if email is confirmed: {err}"); 170 + return Err(StatusCode::BAD_REQUEST); 171 + } 172 + }; 173 174 //Since the email is already confirmed we can enable 2fa 175 return match email_confirmed { ··· 192 if !email_auth_update && !email_auth_not_set { 193 //User wants auth turned off and has a token 194 if let Some(token) = &payload.token { 195 + let token_found = match sqlx::query_as::<_, (String,)>( 196 "SELECT token FROM email_token WHERE token = ? AND did = ? AND purpose = 'update_email'", 197 ) 198 .bind(token) 199 .bind(&did.0) 200 .fetch_optional(&state.account_pool) 201 + .await{ 202 + Ok(token) => token, 203 + Err(err) => { 204 + log::error!("Error checking if token is valid: {err}"); 205 + return Err(StatusCode::BAD_REQUEST); 206 + } 207 + }; 208 209 return if token_found.is_some() { 210 + //TODO I think there may be a bug here and need to do some retry logic 211 + // First try was erroring, seconds was allowing 212 + match sqlx::query( 213 "INSERT INTO two_factor_accounts (did, required) VALUES (?, 0) ON CONFLICT(did) DO UPDATE SET required = 0", 214 ) 215 .bind(&did.0) 216 .execute(&state.pds_gatekeeper_pool) 217 + .await { 218 + Ok(_) => {} 219 + Err(err) => { 220 + log::error!("Error updating email auth: {err}"); 221 + return Err(StatusCode::BAD_REQUEST); 222 + } 223 + } 224 225 Ok(StatusCode::OK.into_response()) 226 } else { ··· 295 ); 296 297 // Rewrite the URI to point at the upstream PDS; keep headers, method, and body intact 298 + *req.uri_mut() = uri.parse().map_err(|_| StatusCode::BAD_REQUEST)?; 299 300 let proxied = state 301 .reverse_proxy_client