Patrick Michl 3b8c529183
All checks were successful
continuous-integration/drone/push Build is passing
rework DB Models
2022-04-30 23:59:21 +02:00

130 lines
4.1 KiB
Rust

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<Json<Flows>, ApiError> {
Ok(Json(Flows::new()))
}
#[tracing::instrument(skip_all)]
async fn post_login(
Extension(config): Extension<Arc<Config>>,
Extension(db): Extension<SqlitePool>,
Json(body): Json<AuthenticationData>,
) -> Result<Json<AuthenticationResponse>, 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<Arc<Config>>,
Extension(db): Extension<SqlitePool>,
Query(params): Query<HashMap<String, String>>,
) -> Result<Json<UsernameAvailable>, 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<Arc<Config>>,
Extension(db): Extension<SqlitePool>,
Json(body): Json<RegistrationRequest>,
) -> Result<Json<RegistrationResponse>, 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)))
}
}