Compare commits

..

14 Commits

Author SHA1 Message Date
phundrak c700d65b34 style: format code
Publish Docker Images / push-docker (push) Has been cancelled
Publish Docker Images / build-docker (push) Has been cancelled
Publish Docker Images / coverage-and-sonar (push) Has been cancelled
2026-06-06 15:49:19 +02:00
phundrak 8bf2917eb7 chore(audit): deny wildcard versions in Cargo.toml 2026-06-06 15:49:19 +02:00
phundrak fc8dc805a9 feat(RateLimit): add Retry-After header for 429 errors 2026-06-06 15:49:19 +02:00
phundrak 5b6dd0c4f7 fix(health): move test to dedicated test mod 2026-06-06 15:49:19 +02:00
phundrak b29a095a38 refactor(RateLimitConfig): replace magic values with struct method 2026-06-06 15:49:19 +02:00
phundrak 85621d9364 feat(contact): sanitize user-submitted data 2026-06-06 15:49:19 +02:00
phundrak 5baa73d272 fix: typo 2026-06-06 15:33:45 +02:00
phundrak ff6aa10d91 feat(logs): only activate json or pretty logs one at a time 2026-06-06 15:33:45 +02:00
phundrak 598af596c7 refactor: simplify code 2026-06-06 15:33:45 +02:00
phundrak 9f576d7509 fix(contact): sanatize user-supplied data in logs 2026-06-06 15:33:45 +02:00
phundrak 2216d7da58 fix(logs): make tracing target consistent 2026-06-06 15:33:45 +02:00
phundrak d4fdc2f468 refactor: better value cloning 2026-06-06 15:33:33 +02:00
phundrak dcb3dc60a4 fix(RateLimit): apply rate limiting based on client IP 2026-06-06 15:33:33 +02:00
phundrak b38e6110d2 feat(settings): proper CORS in production
If the backend starts in production mode with no `frontend_url` is set,
immediately panic and stop.
2026-06-06 15:33:33 +02:00
3 changed files with 9 additions and 7 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ impl Error for ContactError {}
/// issues beyond the client's control. /// issues beyond the client's control.
impl From<lettre::transport::smtp::Error> for ContactError { impl From<lettre::transport::smtp::Error> for ContactError {
fn from(value: lettre::transport::smtp::Error) -> Self { fn from(value: lettre::transport::smtp::Error) -> Self {
tracing::event!(target: "contact", tracing::Level::ERROR, "SMTP Error details: {}", format!("{value:?}")); tracing::event!(target: "backend::contact", tracing::Level::ERROR, "SMTP Error details: {}", format!("{value:?}"));
Self::OtherError(value.to_string()) Self::OtherError(value.to_string())
} }
} }
+2 -2
View File
@@ -186,7 +186,6 @@ impl ContactApi {
remote_addr: Option<poem::web::Data<&poem::web::RemoteAddr>>, remote_addr: Option<poem::web::Data<&poem::web::RemoteAddr>>,
) -> ContactApiResponse { ) -> ContactApiResponse {
let mut body = body.0; let mut body = body.0;
body.sanitize();
if let Some(ref honeypot) = body.honeypot if let Some(ref honeypot) = body.honeypot
&& !honeypot.trim().is_empty() && !honeypot.trim().is_empty()
{ {
@@ -198,6 +197,7 @@ impl ContactApi {
); );
return ContactApiResponse::Ok(ContactResponse::honeypot_response().into()); return ContactApiResponse::Ok(ContactResponse::honeypot_response().into());
} }
body.sanitize();
if let Err(e) = body.validate() { if let Err(e) = body.validate() {
return ContactApiResponse::BadRequest( return ContactApiResponse::BadRequest(
<validator::ValidationErrors as std::convert::Into<ContactResponse>>::into(e) <validator::ValidationErrors as std::convert::Into<ContactResponse>>::into(e)
@@ -251,7 +251,7 @@ impl ContactApi {
.subject(format!("Contact Form: {}", request.name)) .subject(format!("Contact Form: {}", request.name))
.header(ContentType::TEXT_PLAIN) .header(ContentType::TEXT_PLAIN)
.body(email_body)?; .body(email_body)?;
tracing::event!(target: "contact", tracing::Level::DEBUG, "Email to be sent: {}", format!("{email:?}")); tracing::event!(target: "backend::contact", tracing::Level::DEBUG, "Email to be sent: {}", format!("{email:?}"));
Ok(email) Ok(email)
} }
+6 -4
View File
@@ -84,10 +84,12 @@ impl From<Application> for RunnableApplication {
let cors = if value.settings.debug { let cors = if value.settings.debug {
Cors::new() Cors::new()
} else { } else {
assert!( if !cfg!(test) {
!cfg!(test) || !frontend_url.is_empty(), assert!(
"CORS: frontend_url must be configured in production" !frontend_url.is_empty(),
); "CORS: frontend_url must be configured in production"
);
}
Cors::new().allow_origin(frontend_url) Cors::new().allow_origin(frontend_url)
}; };
let app = value let app = value