Reject invalid ban/mute duration instead of silently defaulting to permanent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 files changed,
+10 insertions,
-9 deletions
| 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 |
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 |
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
|