summaryrefslogtreecommitdiff
path: root/src/routes
diff options
context:
space:
mode:
authorDaniel Hader <[email protected]>2026-06-05 19:29:40 -0500
committerDaniel Hader <[email protected]>2026-06-05 19:29:40 -0500
commitc071aca5c5c16d56aafe38ace2b2c158e1b875fc (patch)
treeaa947a0f6fa53be3de6fb879aa5c4d96bc087cf1 /src/routes
parent3ac68b8b59f150e08731a62026ce3ac825655614 (diff)
server text sanitation, username/email filters, and code length measurement
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/errors.rs4
-rw-r--r--src/routes/submission.rs16
-rw-r--r--src/routes/user.rs16
3 files changed, 32 insertions, 4 deletions
diff --git a/src/routes/errors.rs b/src/routes/errors.rs
index f6a0901..5161e9a 100644
--- a/src/routes/errors.rs
+++ b/src/routes/errors.rs
@@ -3,6 +3,7 @@ use serde_json::{json};
pub enum RouteError {
Internal(String),
+ MalformedField(String),
UserCreateEmailExists(String),
UserCreateUsernameExists(String),
UnregisteredEmail(String),
@@ -30,6 +31,9 @@ impl IntoResponse for RouteError {
},
RouteError::NotFound(resource) => {
(StatusCode::NOT_FOUND, format!("{resource} not found"))
+ },
+ RouteError::MalformedField(field) => {
+ (StatusCode::BAD_REQUEST, format!("malformed {field}"))
}
};
diff --git a/src/routes/submission.rs b/src/routes/submission.rs
index b3cf2b9..99767c2 100644
--- a/src/routes/submission.rs
+++ b/src/routes/submission.rs
@@ -1,3 +1,4 @@
+use ammonia::clean_text;
use axum::{Json, extract::{Path, State}, http::StatusCode, response::IntoResponse};
use serde::Deserialize;
@@ -18,15 +19,22 @@ pub async fn create_submission(
) -> Result<impl IntoResponse, RouteError> {
let user_id = claims.sub;
+ let code_length = request.code.len() as i64;
+
+ let language = clean_text(&request.language);
+ let details = clean_text(&request.details);
+ let code = clean_text(&request.code);
+
match state.database.insert_submission(
user_id,
request.problem_id,
- &request.language,
- &request.details,
- &request.code
+ &language,
+ &details,
+ &code,
+ code_length,
) {
Ok(submission) => Ok((StatusCode::CREATED, Json(submission))),
- Err(_) => Err(RouteError::Internal(format!("unable to insert submission")))
+ Err(e) => Err(RouteError::Internal(format!("unable to insert submission {e:?}")))
}
}
diff --git a/src/routes/user.rs b/src/routes/user.rs
index 178a272..31a5824 100644
--- a/src/routes/user.rs
+++ b/src/routes/user.rs
@@ -1,6 +1,7 @@
use axum::extract::{Json, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
+use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::AppState;
@@ -12,6 +13,7 @@ pub(crate) struct CreateUserRequest {
email: String,
username: String,
password: String,
+ register_code: String,
}
pub async fn create_user(
@@ -19,6 +21,20 @@ pub async fn create_user(
Json(request): Json<CreateUserRequest>
) -> Result<impl IntoResponse, RouteError> {
+ if request.register_code != state.register_code {
+ return Err(RouteError::AuthorizationFailure());
+ }
+
+ let email_re = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
+ if !email_re.is_match(&request.email) {
+ return Err(RouteError::MalformedField("email".into()));
+ }
+
+ let username_re = Regex::new(r"^[a-zA-Z0-9_\-]+$").unwrap();
+ if !username_re.is_match(&request.username) {
+ return Err(RouteError::MalformedField("username".into()));
+ }
+
match state.database.fetch_user_by_email(&request.email) {
Err(_) => return Err(RouteError::Internal("database action failed".into())),
Ok(Some(_)) => return Err(RouteError::UserCreateEmailExists(request.email)),