Microservice to bring 2FA to self hosted PDSes

Some clippy warning clean ups

Changed files
+38 -57
src
+4 -4
src/main.rs
··· 1 + #![warn(clippy::unwrap_used)] 1 2 use crate::xrpc::com_atproto_server::{create_session, get_session, update_email}; 2 - use axum::middleware as ax_middleware; 3 - mod middleware; 4 3 use axum::body::Body; 5 4 use axum::handler::Handler; 6 5 use axum::http::{Method, header}; 6 + use axum::middleware as ax_middleware; 7 7 use axum::routing::post; 8 8 use axum::{Router, routing::get}; 9 9 use axum_template::engine::Engine; ··· 24 24 use tracing::{error, log}; 25 25 use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 26 26 27 + mod middleware; 27 28 mod xrpc; 28 29 29 30 type HyperUtilClient = hyper_util::client::legacy::Client<HttpConnector, Body>; ··· 87 88 //TODO prod 88 89 dotenvy::from_path(Path::new("./pds.env"))?; 89 90 let pds_root = env::var("PDS_DATA_DIRECTORY")?; 90 - // let pds_root = "/home/baileytownsend/Documents/code/docker_compose/pds/pds_data"; 91 91 let account_db_url = format!("{}/account.sqlite", pds_root); 92 92 log::info!("accounts_db_url: {}", account_db_url); 93 93 ··· 110 110 .connect_with(options) 111 111 .await?; 112 112 113 - // Run migrations for the bells_and_whistles database 113 + // Run migrations for the extra database 114 114 // Note: the migrations are embedded at compile time from the given directory 115 115 // sqlx 116 116 sqlx::migrate!("./migrations")
+11 -28
src/middleware.rs
··· 7 7 use jwt_compact::{AlgorithmExt, Claims, Token, UntrustedToken, ValidationError}; 8 8 use serde::{Deserialize, Serialize}; 9 9 use std::env; 10 + use tracing::log; 10 11 11 12 #[derive(Clone, Debug)] 12 13 pub struct Did(pub Option<String>); ··· 22 23 match token { 23 24 Ok(token) => { 24 25 match token { 25 - None => { 26 - return json_error_response( 27 - StatusCode::BAD_REQUEST, 28 - "TokenRequired", 29 - "", 30 - ).unwrap(); 31 - } 26 + None => json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "").unwrap(), 32 27 Some(token) => { 33 28 let token = UntrustedToken::new(&token); 34 29 //Doing weird unwraps cause I can't do Result for middleware? 35 30 if token.is_err() { 36 - return json_error_response( 37 - StatusCode::BAD_REQUEST, 38 - "TokenRequired", 39 - "", 40 - ).unwrap(); 31 + return json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "") 32 + .unwrap(); 41 33 } 42 34 let parsed_token = token.unwrap(); 43 35 let claims: Result<Claims<TokenClaims>, ValidationError> = 44 36 parsed_token.deserialize_claims_unchecked(); 45 37 if claims.is_err() { 46 - return json_error_response( 47 - StatusCode::BAD_REQUEST, 48 - "TokenRequired", 49 - "", 50 - ).unwrap(); 38 + return json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "") 39 + .unwrap(); 51 40 } 52 41 53 42 let key = Hs256Key::new(env::var("PDS_JWT_SECRET").unwrap()); 54 43 let token: Result<Token<TokenClaims>, ValidationError> = 55 44 Hs256.validator(&key).validate(&parsed_token); 56 45 if token.is_err() { 57 - return json_error_response( 58 - StatusCode::BAD_REQUEST, 59 - "InvalidToken", 60 - "", 61 - ).unwrap(); 46 + return json_error_response(StatusCode::BAD_REQUEST, "InvalidToken", "") 47 + .unwrap(); 62 48 } 63 49 let token = token.unwrap(); 64 50 //Not going to worry about expiration since it still goes to the PDS ··· 69 55 } 70 56 } 71 57 } 72 - Err(_) => { 73 - return json_error_response( 74 - StatusCode::BAD_REQUEST, 75 - "InvalidToken", 76 - "", 77 - ).unwrap(); 58 + Err(err) => { 59 + log::error!("Error extracting token: {}", err); 60 + json_error_response(StatusCode::BAD_REQUEST, "InvalidToken", "").unwrap() 78 61 } 79 62 } 80 63 }
+23 -25
src/xrpc/helpers.rs
··· 121 121 122 122 pub enum IdentifierType { 123 123 Email, 124 - DID, 124 + Did, 125 125 Handle, 126 126 } 127 127 ··· 130 130 if identifier.contains("@") { 131 131 IdentifierType::Email 132 132 } else if identifier.contains("did:") { 133 - IdentifierType::DID 133 + IdentifierType::Did 134 134 } else { 135 135 IdentifierType::Handle 136 136 } ··· 207 207 .fetch_optional(&state.account_pool) 208 208 .await 209 209 .map_err(|_| StatusCode::BAD_REQUEST)?, 210 - IdentifierType::DID => sqlx::query_as::<_, (String, String, String, String)>( 210 + IdentifierType::Did => sqlx::query_as::<_, (String, String, String, String)>( 211 211 "SELECT account.did, account.passwordScrypt, account.email, actor.handle 212 212 FROM actor 213 213 LEFT JOIN account ON actor.did = account.did ··· 224 224 let required_opt = sqlx::query_as::<_, (u8,)>( 225 225 "SELECT required FROM two_factor_accounts WHERE did = ? LIMIT 1", 226 226 ) 227 - .bind(&did.clone()) 227 + .bind(did.clone()) 228 228 .fetch_optional(&state.pds_gatekeeper_pool) 229 229 .await 230 230 .map_err(|_| StatusCode::BAD_REQUEST)?; ··· 239 239 let verified = verify_password(password, &password_scrypt).await?; 240 240 if !verified { 241 241 //Theres a chance it could be an app password so check that as well 242 - return match verify_app_password(&state.account_pool, &did, &password).await { 242 + return match verify_app_password(&state.account_pool, &did, password).await { 243 243 Ok(valid) => { 244 244 if valid { 245 245 //Was a valid app password up to the PDS now ··· 257 257 //Two factor is required and a taken was provided 258 258 if let Some(two_factor_code) = two_factor_code { 259 259 //It seems it sends over a empty on login without it set? As in no input is shown on the ui for the first login try 260 - if two_factor_code != "" { 260 + if !two_factor_code.is_empty() { 261 261 return match assert_valid_token( 262 262 &state.account_pool, 263 263 did.clone(), ··· 332 332 ) -> anyhow::Result<String> { 333 333 let purpose = "2fa_code"; 334 334 335 - loop { 336 - let token = get_random_token(); 337 - let right_now = Utc::now(); 335 + let token = get_random_token(); 336 + let right_now = Utc::now(); 338 337 339 - let res = sqlx::query( 340 - "INSERT INTO email_token (purpose, did, token, requestedAt) 338 + let res = sqlx::query( 339 + "INSERT INTO email_token (purpose, did, token, requestedAt) 341 340 VALUES (?, ?, ?, ?) 342 341 ON CONFLICT(purpose, did) DO UPDATE SET 343 342 token=excluded.token, 344 343 requestedAt=excluded.requestedAt", 345 - ) 346 - .bind(purpose) 347 - .bind(&did) 348 - .bind(&token) 349 - .bind(right_now) 350 - .execute(account_db) 351 - .await; 344 + ) 345 + .bind(purpose) 346 + .bind(&did) 347 + .bind(&token) 348 + .bind(right_now) 349 + .execute(account_db) 350 + .await; 352 351 353 - return match res { 354 - Ok(_) => Ok(token), 355 - Err(e) => { 356 - log::error!("Error creating a two factor token: {}", e); 357 - Err(anyhow::anyhow!(e)) 358 - } 359 - }; 352 + match res { 353 + Ok(_) => Ok(token), 354 + Err(e) => { 355 + log::error!("Error creating a two factor token: {}", e); 356 + Err(anyhow::anyhow!(e)) 357 + } 360 358 } 361 359 } 362 360