MT audit remediation: typed enums, batch inserts, indexes, session logging - Add sqlx::Type derives to CommunityRole, BanType, ModAction for typed query returns - Replace COUNT(*) > 0 with EXISTS in ban/mute/endorsement checks - Batch INSERT for set_thread_tags and insert_mentions (eliminates N+1) - Wrap toggle_endorsement in transaction to prevent race conditions - Add 5 performance indexes (migration 023) - Add LIMIT to unbounded queries (list_all_communities, list_community_members) - Log session operation failures in auth.rs instead of silently discarding - Complete .env.example with S3 and INTERNAL_SHARED_SECRET vars - Fix test create_post calls to include is_reply parameter
- Co-Authored-By
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> - 2026-04-16 05:31 UTC
Commit:
58e52d58f45b430f109bb9c86517dfd76952958fParent:
18 files changed,
+179 insertions,
-83 deletions
# Platform admin (UUID of the MNW account that can access /_admin)# PLATFORM_ADMIN_ID=00000000-0000-0000-0000-000000000000# S3 storage (optional — required for image uploads)# S3_ENDPOINT=https://s3.us-east-1.amazonaws.com# S3_BUCKET=mt-uploads# S3_ACCESS_KEY=your-access-key# S3_SECRET_KEY=your-secret-key# S3_REGION=us-east-1# Internal API shared secret (HMAC-SHA256 auth for MNW → MT calls)# INTERNAL_SHARED_SECRET=your-shared-secretversion = "0.3.3"dependencies = [ "chrono", "serde", "sqlx",][[package]] } async fn save_to_session(&self, session: &Session) { let _ = session.insert(SESSION_USER_ID, self.user_id).await; let _ = session.insert(SESSION_USERNAME, &self.username).await; let _ = session .insert(SESSION_DISPLAY_NAME, &self.display_name) .await; if let Err(e) = session.insert(SESSION_USER_ID, self.user_id).await { tracing::error!(error = %e, "failed to save user_id to session"); } if let Err(e) = session.insert(SESSION_USERNAME, &self.username).await { tracing::error!(error = %e, "failed to save username to session"); } if let Err(e) = session.insert(SESSION_DISPLAY_NAME, &self.display_name).await { tracing::error!(error = %e, "failed to save display_name to session"); } }} let challenge = pkce_challenge(&verifier); let oauth_state = generate_state_nonce(); let _ = session.insert(SESSION_PKCE_VERIFIER, &verifier).await; let _ = session.insert(SESSION_OAUTH_STATE, &oauth_state).await; if let Err(e) = session.insert(SESSION_PKCE_VERIFIER, &verifier).await { tracing::error!(error = %e, "failed to save PKCE verifier to session"); } if let Err(e) = session.insert(SESSION_OAUTH_STATE, &oauth_state).await { tracing::error!(error = %e, "failed to save OAuth state to session"); } let url = format!( "{}/oauth/authorize?response_type=code&client_id={}&redirect_uri={}&state={}&code_challenge={}&code_challenge_method=S256", }; // Clean up OAuth session data let _ = session.remove::<String>(SESSION_OAUTH_STATE).await; let _ = session.remove::<String>(SESSION_PKCE_VERIFIER).await; if let Err(e) = session.remove::<String>(SESSION_OAUTH_STATE).await { tracing::warn!(error = %e, "failed to remove OAuth state from session"); } if let Err(e) = session.remove::<String>(SESSION_PKCE_VERIFIER).await { tracing::warn!(error = %e, "failed to remove PKCE verifier from session"); } // Exchange code for token (retry up to 2 attempts on network/5xx errors) let token_url = format!("{}/oauth/token", state.config.mnw_base_url);/// `POST /auth/logout` — flush session, redirect home.#[tracing::instrument(skip_all)]pub async fn logout(session: Session) -> impl IntoResponse { let _ = session.flush().await; if let Err(e) = session.flush().await { tracing::warn!(error = %e, "failed to flush session on logout"); } Redirect::to("/")}[dependencies]chrono = { workspace = true }serde = { workspace = true }sqlx = { workspace = true } user_id: Uuid, community_id: Uuid,) -> Result<Option<CommunityRole>, Response> { let role_str = mt_db::queries::get_user_role(db, user_id, community_id) mt_db::queries::get_user_role(db, user_id, community_id) .await .map_err(|e| { tracing::error!(error = ?e, "db error fetching role"); (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response() })?; Ok(role_str.and_then(|s| CommunityRole::from_db(&s))) })}/// Look up a user by username, returning 422 if not found. .map(|b| BanListRow { username: b.username, display_name: b.display_name, ban_type: b.ban_type, ban_type: b.ban_type.to_string(), reason: b.reason, expires: b.expires_at.map(mt_core::time_format::relative_timestamp), created: mt_core::time_format::relative_timestamp(b.created_at), .into_iter() .map(|e| ModLogRow { actor: e.actor_username, action: e.action, action: e.action.to_string(), target: e.target_username, reason: e.reason, timestamp: mt_core::time_format::relative_timestamp(e.created_at), // Upload to S3 s3.upload(&s3_key, validated_ct, data).await.map_err(|e| { tracing::error!(error = %e, "S3 upload failed"); (StatusCode::INTERNAL_SERVER_ERROR, "Upload failed.").into_response() StatusCode::INTERNAL_SERVER_ERROR.into_response() })?; // Record in DB