use std::{collections::HashMap, sync::Arc}; use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; use axum::{ extract::Query, http::StatusCode, routing::{get, post}, Extension, Json, }; use rand_core::OsRng; use sqlx::SqlitePool; use crate::{ api::client_server::errors::authentication_error::AuthenticationError, models::sessions::Session, responses::{ authentication::{AuthenticationResponse, AuthenticationSuccess}, registration::RegistrationResponse, }, }; use crate::{ models::devices::Device, responses::{flow::Flows, registration::RegistrationSuccess}, }; use crate::{ models::users::User, requests::registration::RegistrationRequest, responses::username_available::UsernameAvailable, types::{authentication_data::AuthenticationData, user_id::UserId}, Config, }; use super::errors::{api_error::ApiError, registration_error::RegistrationError}; pub fn routes() -> axum::Router { axum::Router::new() .route("/r0/login", get(get_login).post(post_login)) .route("/r0/register", post(post_register)) .route("/r0/register/available", get(get_username_available)) } #[tracing::instrument] async fn get_login() -> Result, ApiError> { Ok(Json(Flows::new())) } #[tracing::instrument(skip_all)] async fn post_login( Extension(config): Extension>, Extension(db): Extension, Json(body): Json, ) -> Result, ApiError> { let user = UserId::new("name", "server_name") .ok() .ok_or(AuthenticationError::InvalidUserId)?; let resp = AuthenticationSuccess::new("", "", &user); Ok(Json(AuthenticationResponse::Success(resp))) } #[tracing::instrument(skip_all)] async fn get_username_available( Extension(config): Extension>, Extension(db): Extension, Query(params): Query>, ) -> Result, ApiError> { let username = params .get("username") .ok_or(RegistrationError::MissingUserId)?; let user_id = UserId::new(username, &config.homeserver_name) .ok() .ok_or(RegistrationError::InvalidUserId)?; let exists = User::exists(&db, &user_id).await?; Ok(Json(UsernameAvailable::new(!exists))) } #[tracing::instrument(skip_all)] async fn post_register( Extension(config): Extension>, Extension(db): Extension, Json(body): Json, ) -> Result, ApiError> { body.auth() .ok_or(RegistrationError::AdditionalAuthenticationInformation)?; let (user, device) = match &body.auth().expect("must be Some") { AuthenticationData::Password(auth_data) => { let username = body.username().ok_or(RegistrationError::MissingUserId)?; let user_id = UserId::new(username, &config.homeserver_name) .ok() .ok_or(RegistrationError::InvalidUserId)?; if User::exists(&db, &user_id).await? { return Err(ApiError::from(RegistrationError::UserIdTaken)); } let display_name = match body.initial_device_display_name() { Some(display_name) => display_name.as_ref(), None => "Random displayname", }; let user = User::new(&user_id, &user_id.to_string(), auth_data.password())? .create(&db) .await?; let device = Device::new(&user, "test", display_name)? .create(&db) .await?; (user, device) } }; if body.inhibit_login().unwrap_or(false) { let resp = RegistrationSuccess::new(None, device.device_id(), &user.user_id().to_string()); Ok(Json(RegistrationResponse::Success(resp))) } else { let session = Session::new(&device)?.create(&db).await?; let resp = RegistrationSuccess::new( Some(session.key()), device.device_id(), &user.user_id().to_string(), ); Ok(Json(RegistrationResponse::Success(resp))) } }