WIP: Implemented input validation for createAccount
This commit is contained in:
parent
7eb0be102e
commit
b522c062c0
1 changed files with 77 additions and 5 deletions
|
|
@ -2,6 +2,8 @@ use router::xrpc::{ProcedureInput, Response, error};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use http::status::StatusCode;
|
||||
use tracing::{event, instrument, Level};
|
||||
use atproto::types::Handle;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct CreateAccountInput {
|
||||
|
|
@ -96,15 +98,85 @@ pub async fn create_account(data: ProcedureInput<CreateAccountInput>) -> Respons
|
|||
error(StatusCode::OK, "success", "Account created successfully")
|
||||
}
|
||||
|
||||
// Maximum password length (matches atproto TypeScript implementation)
|
||||
const NEW_PASSWORD_MAX_LENGTH: usize = 256;
|
||||
|
||||
// TODO: Implement these helper functions
|
||||
|
||||
async fn validate_inputs(input: &CreateAccountInput) -> Result<ValidatedInput, Response> {
|
||||
// Based on validateInputsForLocalPds in the TypeScript version
|
||||
// - Validate email format and not disposable
|
||||
// - Validate password length
|
||||
// - Check invite code if required
|
||||
// - Normalize and validate handle
|
||||
todo!("Implement input validation")
|
||||
|
||||
// Validate email is provided and has basic format
|
||||
let email = match &input.email {
|
||||
Some(e) if !e.is_empty() => e.clone(),
|
||||
_ => {
|
||||
return Err(error(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"InvalidRequest",
|
||||
"Email is required"
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Validate email format (basic validation for now)
|
||||
// TODO: Improve email validation - add proper RFC validation and disposable email checking
|
||||
// TypeScript version uses @hapi/address for validation and disposable-email-domains-js for disposable check
|
||||
if !is_valid_email(&email) {
|
||||
return Err(error(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"InvalidRequest",
|
||||
"This email address is not supported, please use a different email."
|
||||
));
|
||||
}
|
||||
|
||||
// Validate password length if provided
|
||||
if let Some(password) = &input.password {
|
||||
if password.len() > NEW_PASSWORD_MAX_LENGTH {
|
||||
return Err(error(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"InvalidRequest",
|
||||
&format!("Password too long. Maximum length is {} characters.", NEW_PASSWORD_MAX_LENGTH)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate and normalize handle using atproto types
|
||||
let handle = Handle::from_str(&input.handle).map_err(|_| {
|
||||
error(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"InvalidRequest",
|
||||
"Invalid handle format"
|
||||
)
|
||||
})?;
|
||||
|
||||
// TODO: Invite codes - not supported for now but leave placeholder
|
||||
if input.invite_code.is_some() {
|
||||
event!(Level::INFO, "Invite codes not yet supported, ignoring");
|
||||
}
|
||||
|
||||
Ok(ValidatedInput {
|
||||
handle: handle.to_string(),
|
||||
email: email.to_lowercase(), // Normalize email to lowercase
|
||||
password: input.password.clone(),
|
||||
invite_code: input.invite_code.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
// Basic email validation - checks for @ and . in reasonable positions
|
||||
// TODO: Replace with proper email validation library like email-address crate
|
||||
fn is_valid_email(email: &str) -> bool {
|
||||
// Very basic email validation
|
||||
let at_pos = email.find('@');
|
||||
let last_dot_pos = email.rfind('.');
|
||||
|
||||
match (at_pos, last_dot_pos) {
|
||||
(Some(at), Some(dot)) => {
|
||||
// @ must come before the last dot
|
||||
// Must have content before @, between @ and dot, and after dot
|
||||
at > 0 && dot > at + 1 && dot < email.len() - 1
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_availability(input: &ValidatedInput) -> Result<(), Response> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue