From 1b2d1e7471224faec26f4cd31e0aff6fce4850d5 Mon Sep 17 00:00:00 2001 From: Matthew L McPeak Date: Wed, 17 Jun 2026 15:48:30 -0400 Subject: [PATCH] fix: ci --- .forgejo/workflows/ci.yml | 4 +- src/auth/middleware.rs | 33 ++++++++++------ src/cache/sweep.rs | 8 ++-- src/main.rs | 60 +++++++++++++++++++--------- src/models/blacklist.rs | 2 + src/models/permission.rs | 3 ++ src/models/query.rs | 2 + src/models/user.rs | 2 + src/routes/admin/api_keys.rs | 4 +- src/routes/admin/cache.rs | 2 +- src/routes/admin/mod.rs | 5 ++- src/routes/admin/queries.rs | 23 ++++++----- src/routes/admin/tables.rs | 37 ++++++++++-------- src/routes/auth.rs | 15 +++---- src/routes/crud.rs | 76 +++++++++++++++++++++++++----------- src/state.rs | 19 +++++---- 16 files changed, 190 insertions(+), 105 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 27e27f9..5381d75 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -41,8 +41,8 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Inject bunfig.toml - run: printf '[install.scopes]\n"@nychthemeron" = { token = "${BUN_AUTH_TOKEN}", url = "https://git.mcpeakdev.com/api/packages/McPeakDev/npm/" }\n' > ./bunfig.toml + - name: Inject Auth + run: echo "//git.mcpeakdev.com/api/packages/mcpeakdev/npm/:_authToken=${BUN_AUTH_TOKEN}" > /root/.npmrc env: BUN_AUTH_TOKEN: ${{ secrets.BUN_AUTH_TOKEN }} diff --git a/src/auth/middleware.rs b/src/auth/middleware.rs index 6f9dcc0..2817420 100644 --- a/src/auth/middleware.rs +++ b/src/auth/middleware.rs @@ -5,16 +5,15 @@ use axum::{ response::Response, }; -use crate::{auth::{decode_jwt, resolve_api_key, Claims}, state::AppState}; +use crate::{ + auth::{decode_jwt, resolve_api_key, Claims}, + state::AppState, +}; /// Resolves a Bearer token to Claims, trying JWT then API key. /// Inserts Claims into request extensions on success so downstream /// middleware can reuse them without an additional DB round-trip. -async fn authenticate( - token: &str, - state: &AppState, - req: &mut Request, -) -> Option { +async fn authenticate(token: &str, state: &AppState, req: &mut Request) -> Option { if let Some(existing) = req.extensions().get::().cloned() { return Some(existing); } @@ -42,7 +41,11 @@ pub async fn blacklist_layer( } else { 0 }; - if state.blacklist_cache.is_blocked(&method, &path, caller_mask).await { + if state + .blacklist_cache + .is_blocked(&method, &path, caller_mask) + .await + { return Err(StatusCode::FORBIDDEN); } Ok(next.run(req).await) @@ -62,7 +65,9 @@ pub async fn require_auth( next: Next, ) -> Result { let token = extract_bearer(&req).ok_or(StatusCode::UNAUTHORIZED)?; - authenticate(&token, &state, &mut req).await.ok_or(StatusCode::UNAUTHORIZED)?; + authenticate(&token, &state, &mut req) + .await + .ok_or(StatusCode::UNAUTHORIZED)?; Ok(next.run(req).await) } @@ -72,7 +77,9 @@ pub async fn require_super_admin( next: Next, ) -> Result { let token = extract_bearer(&req).ok_or(StatusCode::UNAUTHORIZED)?; - let claims = authenticate(&token, &state, &mut req).await.ok_or(StatusCode::UNAUTHORIZED)?; + let claims = authenticate(&token, &state, &mut req) + .await + .ok_or(StatusCode::UNAUTHORIZED)?; if !claims.has_permission(crate::auth::permissions::SUPER_ADMIN) { return Err(StatusCode::FORBIDDEN); } @@ -85,7 +92,9 @@ pub async fn require_admin_query( next: Next, ) -> Result { let token = extract_bearer(&req).ok_or(StatusCode::UNAUTHORIZED)?; - let claims = authenticate(&token, &state, &mut req).await.ok_or(StatusCode::UNAUTHORIZED)?; + let claims = authenticate(&token, &state, &mut req) + .await + .ok_or(StatusCode::UNAUTHORIZED)?; if !claims.has_permission(crate::auth::permissions::ADMIN_QUERY) { return Err(StatusCode::FORBIDDEN); } @@ -98,7 +107,9 @@ pub async fn require_admin_cache( next: Next, ) -> Result { let token = extract_bearer(&req).ok_or(StatusCode::UNAUTHORIZED)?; - let claims = authenticate(&token, &state, &mut req).await.ok_or(StatusCode::UNAUTHORIZED)?; + let claims = authenticate(&token, &state, &mut req) + .await + .ok_or(StatusCode::UNAUTHORIZED)?; if !claims.has_permission(crate::auth::permissions::ADMIN_CACHE) { return Err(StatusCode::FORBIDDEN); } diff --git a/src/cache/sweep.rs b/src/cache/sweep.rs index 01b2f52..bee1933 100644 --- a/src/cache/sweep.rs +++ b/src/cache/sweep.rs @@ -1,5 +1,5 @@ -use std::time::Duration; use crate::state::QueryCache; +use std::time::Duration; pub fn spawn_sweep_task(cache: QueryCache, idle_timeout_secs: u64, sweep_interval_secs: u64) { tokio::spawn(async move { @@ -7,9 +7,9 @@ pub fn spawn_sweep_task(cache: QueryCache, idle_timeout_secs: u64, sweep_interva loop { tokio::time::sleep(interval).await; let now = crate::state::unix_now(); - cache.map.retain(|_, entry| { - now.saturating_sub(entry.last_accessed()) < idle_timeout_secs - }); + cache + .map + .retain(|_, entry| now.saturating_sub(entry.last_accessed()) < idle_timeout_secs); } }); } diff --git a/src/main.rs b/src/main.rs index 6accdf5..aae180c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,17 @@ mod state; use std::io::{self, Write}; use std::sync::Arc; -use axum::{extract::DefaultBodyLimit, http::{header, HeaderValue, Method}, middleware, routing::{get, post}, Router}; -use tower_http::{cors::CorsLayer, services::{ServeDir, ServeFile}}; +use axum::{ + extract::DefaultBodyLimit, + http::{header, HeaderValue, Method}, + middleware, + routing::{get, post}, + Router, +}; +use tower_http::{ + cors::CorsLayer, + services::{ServeDir, ServeFile}, +}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use crate::{ @@ -19,11 +28,7 @@ use crate::{ config::Config, db::create_pool, models::blacklist::BlacklistEntry, - routes::{ - admin::admin_router, - auth::login, - crud::handle_crud, - }, + routes::{admin::admin_router, auth::login, crud::handle_crud}, state::{AppState, BlacklistCache, QueryCache}, }; @@ -34,13 +39,16 @@ fn build_cors(origins: &[String]) -> CorsLayer { if origins.iter().any(|o| o == "*") { return CorsLayer::permissive(); } - let parsed: Vec = origins - .iter() - .filter_map(|o| o.parse().ok()) - .collect(); + let parsed: Vec = origins.iter().filter_map(|o| o.parse().ok()).collect(); CorsLayer::new() .allow_origin(parsed) - .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE, Method::OPTIONS]) + .allow_methods([ + Method::GET, + Method::POST, + Method::PUT, + Method::DELETE, + Method::OPTIONS, + ]) .allow_headers([header::CONTENT_TYPE, header::AUTHORIZATION]) } @@ -49,8 +57,10 @@ async fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); tracing_subscriber::registry() - .with(tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| "mercury=info".into())) + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "mercury=info".into()), + ) .with(tracing_subscriber::fmt::layer()) .init(); @@ -122,13 +132,22 @@ async fn main() -> anyhow::Result<()> { let crud_routes = Router::new() .route("/api/:table", get(handle_crud).post(handle_crud)) .route("/api/:table/", get(handle_crud).post(handle_crud)) - .route("/api/:table/:id", get(handle_crud).put(handle_crud).delete(handle_crud)) - .route("/api/:table/:id/", get(handle_crud).put(handle_crud).delete(handle_crud)) - .layer(DefaultBodyLimit::max(1 * 1024 * 1024)) + .route( + "/api/:table/:id", + get(handle_crud).put(handle_crud).delete(handle_crud), + ) + .route( + "/api/:table/:id/", + get(handle_crud).put(handle_crud).delete(handle_crud), + ) + .layer(DefaultBodyLimit::max(1024 * 1024)) // require_auth is inner (added first); blacklist_layer is outer (added last, runs first). // Order: blacklist check → auth check → handler. .route_layer(middleware::from_fn_with_state(state.clone(), require_auth)) - .route_layer(middleware::from_fn_with_state(state.clone(), blacklist_layer)); + .route_layer(middleware::from_fn_with_state( + state.clone(), + blacklist_layer, + )); let cors_layer = build_cors(&config.cors_origins); @@ -136,7 +155,10 @@ async fn main() -> anyhow::Result<()> { .route("/auth/login", post(login)) .merge(crud_routes) .nest("/api/admin", admin_router(state.clone())) - .nest_service("/", ServeDir::new("ui/dist").fallback(ServeFile::new("ui/dist/index.html"))) + .nest_service( + "/", + ServeDir::new("ui/dist").fallback(ServeFile::new("ui/dist/index.html")), + ) .layer(cors_layer) .with_state(state); diff --git a/src/models/blacklist.rs b/src/models/blacklist.rs index 1ac312d..7ed6b2b 100644 --- a/src/models/blacklist.rs +++ b/src/models/blacklist.rs @@ -12,6 +12,7 @@ pub struct BlacklistEntry { pub created_at: DateTime, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct CreateBlacklistEntry { pub pattern: String, @@ -19,6 +20,7 @@ pub struct CreateBlacklistEntry { pub reason: Option, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct UpdateBlacklistEntry { pub pattern: Option, diff --git a/src/models/permission.rs b/src/models/permission.rs index 6383c89..cf702fc 100644 --- a/src/models/permission.rs +++ b/src/models/permission.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; +#[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct Permission { pub id: i32, @@ -8,12 +9,14 @@ pub struct Permission { pub description: Option, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct CreatePermission { pub name: String, pub description: Option, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct UpdatePermission { pub name: Option, diff --git a/src/models/query.rs b/src/models/query.rs index 07e469c..b0b8082 100644 --- a/src/models/query.rs +++ b/src/models/query.rs @@ -12,6 +12,7 @@ pub struct StoredQuery { pub updated_at: DateTime, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct CreateQuery { pub identifier: String, @@ -19,6 +20,7 @@ pub struct CreateQuery { pub description: Option, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct UpdateQuery { pub sql_template: Option, diff --git a/src/models/user.rs b/src/models/user.rs index 49b45d0..ec9ff38 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -11,6 +11,7 @@ pub struct User { pub created_at: DateTime, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct CreateUser { pub username: String, @@ -18,6 +19,7 @@ pub struct CreateUser { pub permissions_mask: Option, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct UpdateUser { pub username: Option, diff --git a/src/routes/admin/api_keys.rs b/src/routes/admin/api_keys.rs index f937917..0870f1e 100644 --- a/src/routes/admin/api_keys.rs +++ b/src/routes/admin/api_keys.rs @@ -11,9 +11,7 @@ use crate::{ state::AppState, }; -pub async fn list_api_keys( - State(state): State, -) -> Result>, StatusCode> { +pub async fn list_api_keys(State(state): State) -> Result>, StatusCode> { let keys = sqlx::query_as::<_, ApiKey>( "SELECT id, name, key_prefix, permissions_mask, created_at, expires_at, last_used_at FROM api_keys ORDER BY created_at DESC", diff --git a/src/routes/admin/cache.rs b/src/routes/admin/cache.rs index ca7dc11..b159eae 100644 --- a/src/routes/admin/cache.rs +++ b/src/routes/admin/cache.rs @@ -1,6 +1,6 @@ +use axum::extract::Extension; use axum::{extract::State, http::StatusCode, Json}; use serde_json::{json, Value}; -use axum::extract::Extension; use crate::{auth::Claims, state::AppState}; diff --git a/src/routes/admin/mod.rs b/src/routes/admin/mod.rs index 049ec20..0793e7d 100644 --- a/src/routes/admin/mod.rs +++ b/src/routes/admin/mod.rs @@ -31,7 +31,10 @@ pub fn admin_router(state: AppState) -> Router { )); let super_routes = Router::new() - .route("/tables", get(tables::list_tables).post(tables::create_table)) + .route( + "/tables", + get(tables::list_tables).post(tables::create_table), + ) .route( "/tables/:name", get(tables::get_table_preview).delete(tables::drop_table), diff --git a/src/routes/admin/queries.rs b/src/routes/admin/queries.rs index 483651b..ce4dd15 100644 --- a/src/routes/admin/queries.rs +++ b/src/routes/admin/queries.rs @@ -42,13 +42,10 @@ pub async fn execute_query( q = q.bind(val.as_str()); } - let rows = q - .fetch_all(&state.pool) - .await - .map_err(|e| { - tracing::error!("query execution error: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; + let rows = q.fetch_all(&state.pool).await.map_err(|e| { + tracing::error!("query execution error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; let json_rows: Vec = rows .into_iter() @@ -72,8 +69,16 @@ mod tests { for (i, (name, _)) in params.iter().enumerate() { sql = sql.replace(&format!(":{}", name), &format!("${}", i + 1)); } - assert!(!sql.contains(":username"), "placeholder not replaced: {}", sql); - assert!(!sql.contains(":user_id"), "placeholder not replaced: {}", sql); + assert!( + !sql.contains(":username"), + "placeholder not replaced: {}", + sql + ); + assert!( + !sql.contains(":user_id"), + "placeholder not replaced: {}", + sql + ); // username (len 8) comes first → $1; user_id (len 7) → $2 assert_eq!(sql, "SELECT * FROM t WHERE user_id = $2 AND username = $1"); } diff --git a/src/routes/admin/tables.rs b/src/routes/admin/tables.rs index 375716f..03eafcb 100644 --- a/src/routes/admin/tables.rs +++ b/src/routes/admin/tables.rs @@ -10,8 +10,18 @@ use sqlx::Row; use crate::{auth::Claims, routes::crud::pg_row_to_json, state::AppState}; const ALLOWED_TYPES: &[&str] = &[ - "TEXT", "INTEGER", "BIGINT", "SMALLINT", "BOOLEAN", "NUMERIC", - "FLOAT4", "FLOAT8", "UUID", "TIMESTAMPTZ", "DATE", "JSONB", + "TEXT", + "INTEGER", + "BIGINT", + "SMALLINT", + "BOOLEAN", + "NUMERIC", + "FLOAT4", + "FLOAT8", + "UUID", + "TIMESTAMPTZ", + "DATE", + "JSONB", ]; const PROTECTED_TABLES: &[&str] = &["users", "blacklist", "api_keys", "queries", "permissions"]; @@ -21,7 +31,6 @@ fn is_protected(name: &str) -> bool { PROTECTED_TABLES.iter().any(|&t| t == lower) } - #[derive(Debug, Deserialize)] pub struct ColumnDef { pub name: String, @@ -179,13 +188,10 @@ pub async fn create_table( let sql = format!("CREATE TABLE {} ({})", body.name, col_defs.join(", ")); - sqlx::query(&sql) - .execute(&state.pool) - .await - .map_err(|e| { - tracing::error!("create table error: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; + sqlx::query(&sql).execute(&state.pool).await.map_err(|e| { + tracing::error!("create table error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; Ok(Json(TableInfo { table_name: body.name, @@ -206,13 +212,10 @@ pub async fn drop_table( } let sql = format!("DROP TABLE IF EXISTS {}", name); - sqlx::query(&sql) - .execute(&state.pool) - .await - .map_err(|e| { - tracing::error!("drop table error: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; + sqlx::query(&sql).execute(&state.pool).await.map_err(|e| { + tracing::error!("drop table error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; Ok(Json(serde_json::json!({ "dropped": true }))) } diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 29d2986..e4cdf40 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -1,11 +1,7 @@ use axum::{extract::State, http::StatusCode, Json}; use serde_json::{json, Value}; -use crate::{ - auth::encode_jwt, - models::user::LoginRequest, - state::AppState, -}; +use crate::{auth::encode_jwt, models::user::LoginRequest, state::AppState}; pub async fn login( State(state): State, @@ -28,8 +24,13 @@ pub async fn login( } let mask: u128 = user.permissions_mask.parse().unwrap_or(0); - let token = encode_jwt(&user.username, mask, &state.config.jwt_secret, state.config.jwt_expiry_secs) - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let token = encode_jwt( + &user.username, + mask, + &state.config.jwt_secret, + state.config.jwt_expiry_secs, + ) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; Ok(Json(json!({ "token": token }))) } diff --git a/src/routes/crud.rs b/src/routes/crud.rs index 46db470..9f88669 100644 --- a/src/routes/crud.rs +++ b/src/routes/crud.rs @@ -11,7 +11,11 @@ use sqlx::Row; use sqlx::TypeInfo; use std::collections::HashMap; -use crate::{auth::Claims, models::blacklist::BlacklistEntry, state::{AppState, CacheEntry}}; +use crate::{ + auth::Claims, + models::blacklist::BlacklistEntry, + state::{AppState, CacheEntry}, +}; /// Returns (sql, ordered_param_values, cache_key). /// body_cols: (col_name, typed_value) pairs from request body. @@ -53,14 +57,22 @@ pub fn build_query( let key = format!("GET:{}:", table); Ok((sql, vec![], key)) } else { - let col_names: Vec = sorted_filters.iter().map(|(c, _)| c.clone()).collect(); + let col_names: Vec = + sorted_filters.iter().map(|(c, _)| c.clone()).collect(); let where_clause: Vec = col_names .iter() .enumerate() .map(|(i, c)| format!("{} = ${}", c, i + 1)) .collect(); - let sql = format!("SELECT * FROM {} WHERE {}", table, where_clause.join(" AND ")); - let params: Vec = sorted_filters.iter().map(|(_, v)| Value::String(v.clone())).collect(); + let sql = format!( + "SELECT * FROM {} WHERE {}", + table, + where_clause.join(" AND ") + ); + let params: Vec = sorted_filters + .iter() + .map(|(_, v)| Value::String(v.clone())) + .collect(); let key = format!("GET:{}:{}", table, col_names.join(",")); Ok((sql, params, key)) } @@ -136,7 +148,7 @@ pub fn pg_row_to_json(row: PgRow) -> Value { "FLOAT4" | "FLOAT8" => row .try_get::(col.ordinal()) .ok() - .and_then(|v| serde_json::Number::from_f64(v)) + .and_then(serde_json::Number::from_f64) .map(Value::Number) .unwrap_or(Value::Null), "BOOL" => row @@ -207,10 +219,10 @@ pub async fn handle_crud( // Enforce permission bits before doing any work. let required_bit = match method_str.to_uppercase().as_str() { - "GET" => crate::auth::permissions::READ, + "GET" => crate::auth::permissions::READ, "POST" | "PUT" => crate::auth::permissions::WRITE, - "DELETE" => crate::auth::permissions::DELETE, - _ => return Err(StatusCode::METHOD_NOT_ALLOWED), + "DELETE" => crate::auth::permissions::DELETE, + _ => return Err(StatusCode::METHOD_NOT_ALLOWED), }; if !claims.has_permission(required_bit) { return Err(StatusCode::FORBIDDEN); @@ -281,16 +293,13 @@ pub async fn handle_crud( v } "POST" | "PUT" => { - let row = q - .fetch_one(&state.pool) - .await - .map_err(|e| { - if e.to_string().contains("no rows") { - StatusCode::NOT_FOUND - } else { - StatusCode::INTERNAL_SERVER_ERROR - } - })?; + let row = q.fetch_one(&state.pool).await.map_err(|e| { + if e.to_string().contains("no rows") { + StatusCode::NOT_FOUND + } else { + StatusCode::INTERNAL_SERVER_ERROR + } + })?; let mut v = pg_row_to_json(row); if table == "users" { v = strip_password_hash(v); @@ -341,8 +350,17 @@ mod tests { ("name".into(), Value::String("Alice".into())), ]; let (sql, params, key) = build_query("POST", "users", None, &cols, &[]).unwrap(); - assert_eq!(sql, "INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *"); - assert_eq!(params, vec![Value::String("a@b.com".into()), Value::String("Alice".into())]); + assert_eq!( + sql, + "INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *" + ); + assert_eq!( + params, + vec![ + Value::String("a@b.com".into()), + Value::String("Alice".into()) + ] + ); assert_eq!(key, "POST:users:email,name"); } @@ -351,7 +369,10 @@ mod tests { let cols = vec![("name".into(), Value::String("Bob".into()))]; let (sql, params, key) = build_query("PUT", "users", Some("7"), &cols, &[]).unwrap(); assert_eq!(sql, "UPDATE users SET name = $1 WHERE id = $2 RETURNING *"); - assert_eq!(params, vec![Value::String("Bob".into()), Value::String("7".into())]); + assert_eq!( + params, + vec![Value::String("Bob".into()), Value::String("7".into())] + ); assert_eq!(key, "PUT:users:name:by_id"); } @@ -365,10 +386,19 @@ mod tests { #[test] fn test_build_select_with_filters() { - let filters = vec![("status".into(), "active".into()), ("role".into(), "admin".into())]; + let filters = vec![ + ("status".into(), "active".into()), + ("role".into(), "admin".into()), + ]; let (sql, params, key) = build_query("GET", "users", None, &[], &filters).unwrap(); assert_eq!(sql, "SELECT * FROM users WHERE role = $1 AND status = $2"); - assert_eq!(params, vec![Value::String("admin".into()), Value::String("active".into())]); + assert_eq!( + params, + vec![ + Value::String("admin".into()), + Value::String("active".into()) + ] + ); assert_eq!(key, "GET:users:role,status"); } diff --git a/src/state.rs b/src/state.rs index aaaedb1..b4d8482 100644 --- a/src/state.rs +++ b/src/state.rs @@ -91,6 +91,7 @@ impl QueryCache { self.map.insert(key, entry); } + #[allow(dead_code)] pub fn remove(&self, key: &str) { self.map.remove(key); } @@ -139,9 +140,11 @@ impl BlacklistCache { .bypass_mask .as_deref() .and_then(|s| s.parse::().ok()); - Pattern::new(&e.pattern) - .ok() - .map(|pattern| CompiledEntry { entry: e, pattern, bypass_mask }) + Pattern::new(&e.pattern).ok().map(|pattern| CompiledEntry { + entry: e, + pattern, + bypass_mask, + }) }) .collect(); let mut guard = self.inner.write().await; @@ -163,16 +166,16 @@ impl BlacklistCache { .entry .method .as_deref() - .map(|m| m.split(',').any(|part| part.trim().eq_ignore_ascii_case(method))) + .map(|m| { + m.split(',') + .any(|part| part.trim().eq_ignore_ascii_case(method)) + }) .unwrap_or(true); if !method_matches || !compiled.pattern.matches(path) { return false; } // If caller holds the bypass permission, they are not blocked. - match compiled.bypass_mask { - Some(mask) if caller_mask & mask != 0 => false, - _ => true, - } + !matches!(compiled.bypass_mask, Some(mask) if caller_mask & mask != 0) }) } }