Skip to main content

max / makenotwork

Reject invalid ban/mute duration instead of silently defaulting to permanent Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-04-26 20:06 UTC
Commit: 141b0f64271798e764763eb9564e99e8f3924e4a
Parent: c3956c1
2 files changed, +10 insertions, -9 deletions
@@ -272,14 +272,15 @@ pub(crate) async fn check_user_post_rate(
272 272 }
273 273
274 274 /// Parse a ban duration string into an optional expiration datetime.
275 - pub(crate) fn parse_duration(duration: &str) -> Option<DateTime<Utc>> {
275 + /// Returns `Err` for unrecognized durations to prevent accidental permanent bans.
276 + pub(crate) fn parse_duration(duration: &str) -> Result<Option<DateTime<Utc>>, Response> {
276 277 match duration {
277 - "permanent" => None,
278 - "1h" => Some(Utc::now() + Duration::hours(1)),
279 - "1d" => Some(Utc::now() + Duration::days(1)),
280 - "7d" => Some(Utc::now() + Duration::days(7)),
281 - "30d" => Some(Utc::now() + Duration::days(30)),
282 - _ => None,
278 + "permanent" => Ok(None),
279 + "1h" => Ok(Some(Utc::now() + Duration::hours(1))),
280 + "1d" => Ok(Some(Utc::now() + Duration::days(1))),
281 + "7d" => Ok(Some(Utc::now() + Duration::days(7))),
282 + "30d" => Ok(Some(Utc::now() + Duration::days(30))),
283 + _ => Err((StatusCode::UNPROCESSABLE_ENTITY, "Invalid duration.").into_response()),
283 284 }
284 285 }
285 286
@@ -244,7 +244,7 @@ pub(super) async fn ban_user_handler(
244 244 return Err((StatusCode::FORBIDDEN, "Only owners can ban moderators.").into_response());
245 245 }
246 246
247 - let expires_at = parse_duration(&form.duration);
247 + let expires_at = parse_duration(&form.duration)?;
248 248 let reason = form.reason.as_deref().filter(|r| !r.trim().is_empty());
249 249
250 250 if let Some(r) = reason
@@ -329,7 +329,7 @@ pub(super) async fn mute_user_handler(
329 329 return Err((StatusCode::FORBIDDEN, "Only owners can mute moderators.").into_response());
330 330 }
331 331
332 - let expires_at = parse_duration(&form.duration);
332 + let expires_at = parse_duration(&form.duration)?;
333 333 let reason = form.reason.as_deref().filter(|r| !r.trim().is_empty());
334 334
335 335 if let Some(r) = reason