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 serde::{Deserialize, Serialize};
|
||||||
use http::status::StatusCode;
|
use http::status::StatusCode;
|
||||||
use tracing::{event, instrument, Level};
|
use tracing::{event, instrument, Level};
|
||||||
|
use atproto::types::Handle;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct CreateAccountInput {
|
pub struct CreateAccountInput {
|
||||||
|
|
@ -96,15 +98,85 @@ pub async fn create_account(data: ProcedureInput<CreateAccountInput>) -> Respons
|
||||||
error(StatusCode::OK, "success", "Account created successfully")
|
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
|
// TODO: Implement these helper functions
|
||||||
|
|
||||||
async fn validate_inputs(input: &CreateAccountInput) -> Result<ValidatedInput, Response> {
|
async fn validate_inputs(input: &CreateAccountInput) -> Result<ValidatedInput, Response> {
|
||||||
// Based on validateInputsForLocalPds in the TypeScript version
|
// Based on validateInputsForLocalPds in the TypeScript version
|
||||||
// - Validate email format and not disposable
|
|
||||||
// - Validate password length
|
// Validate email is provided and has basic format
|
||||||
// - Check invite code if required
|
let email = match &input.email {
|
||||||
// - Normalize and validate handle
|
Some(e) if !e.is_empty() => e.clone(),
|
||||||
todo!("Implement input validation")
|
_ => {
|
||||||
|
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> {
|
async fn check_availability(input: &ValidatedInput) -> Result<(), Response> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue