perf(auth): cached image-free user-flags lookup for per-request guards
Every WebDAV / CalDAV / CardDAV request paid one full-row user fetch in
require_internal_user_layer just to read `is_external` (and the NC Basic
Auth middleware repeated it right after its own cache hit). That SELECT
includes the `image` column — a data URI of up to 512 KiB — so a sync
client issuing hundreds of PROPFINDs per minute dragged hundreds of MB
of avatar bytes out of Postgres to evaluate a boolean.
- New `UserFlags { role, is_external, active }` + a repo query selecting
only those three columns (inherent method, mirroring `update_image`).
- `AuthApplicationService::get_user_flags`: moka cache, 30 s TTL,
10k capacity. `change_user_role` / `set_user_active` invalidate
eagerly, so admin changes still apply immediately; anything else is
visible within the TTL — preserving the documented "no token rotation
needed" semantics at a per-request cost of zero DB round-trips when
warm.
- `require_internal_user`, `require_admin_user` and the NC Basic Auth
external check now go through the flags lookup.
https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx
This commit is contained in:
@@ -64,8 +64,7 @@ pub async fn basic_auth_middleware(
|
||||
|
||||
// Check account lockout before attempting password verification (saves CPU).
|
||||
// The lockout is per (account, IP), see #323 for rationale.
|
||||
let client_ip =
|
||||
crate::interfaces::middleware::rate_limit::extract_client_ip(&request);
|
||||
let client_ip = crate::interfaces::middleware::rate_limit::extract_client_ip(&request);
|
||||
if let Some(auth_svc) = state.auth_service.as_ref()
|
||||
&& let Err(secs) = auth_svc.login_lockout.check(&username, &client_ip)
|
||||
{
|
||||
@@ -103,11 +102,11 @@ pub async fn basic_auth_middleware(
|
||||
// this is the belt-and-braces check in case one slipped
|
||||
// through (e.g. user later flipped to is_external).
|
||||
if let Some(auth_svc) = state.auth_service.as_ref()
|
||||
&& let Ok(user) = auth_svc
|
||||
&& let Ok(flags) = auth_svc
|
||||
.auth_application_service
|
||||
.get_user_by_id(user_id)
|
||||
.get_user_flags(user_id)
|
||||
.await
|
||||
&& user.is_external
|
||||
&& flags.is_external
|
||||
{
|
||||
tracing::info!(
|
||||
target: "audit",
|
||||
|
||||
Reference in New Issue
Block a user