From 4bc7712ee4996b2d9f379d6eba82fba829a47482 Mon Sep 17 00:00:00 2001
From: Marcel <mtrnord1@gmail.com>
Date: Fri, 1 May 2020 23:17:25 +0200
Subject: [PATCH] [ClientServer] Add /_matrix/client/r0/register/available
 endpoint

Took 1 hour 25 minutes
---
 src/client_server.rs | 50 +++++++++++++++++++++++++++++++++++++-------
 src/main.rs          |  1 +
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/src/client_server.rs b/src/client_server.rs
index 6b56fb13..8113bcec 100644
--- a/src/client_server.rs
+++ b/src/client_server.rs
@@ -1,11 +1,15 @@
-use crate::{server_server, utils, Data, MatrixResult, Ruma};
+use std::{
+    collections::BTreeMap,
+    convert::{TryFrom, TryInto},
+    time::{Duration, SystemTime},
+};
 
 use log::debug;
 use rocket::{get, options, post, put, State};
 use ruma_client_api::{
     error::{Error, ErrorKind},
     r0::{
-        account::register,
+        account::{get_username_availability, register},
         alias::get_alias,
         capabilities::get_capabilities,
         client_exchange::send_event_to_device,
@@ -39,11 +43,8 @@ use ruma_client_api::{
 use ruma_events::{collections::only::Event as EduEvent, EventType};
 use ruma_identifiers::{RoomId, UserId};
 use serde_json::json;
-use std::{
-    collections::BTreeMap,
-    convert::{TryFrom, TryInto},
-    time::{Duration, SystemTime},
-};
+
+use crate::{server_server, utils, Data, MatrixResult, Ruma};
 
 const GUEST_NAME_LENGTH: usize = 10;
 const DEVICE_ID_LENGTH: usize = 10;
@@ -58,6 +59,41 @@ pub fn get_supported_versions_route() -> MatrixResult<get_supported_versions::Re
     }))
 }
 
+#[get("/_matrix/client/r0/register/available", data = "<body>")]
+pub fn get_register_available_route(
+    data: State<Data>,
+    body: Ruma<get_username_availability::Request>,
+) -> MatrixResult<get_username_availability::Response> {
+    // Validate user id
+    let user_id: UserId =
+        match (*format!("@{}:{}", body.username.clone(), data.hostname())).try_into() {
+            Err(_) => {
+                debug!("Username invalid");
+                return MatrixResult(Err(Error {
+                    kind: ErrorKind::InvalidUsername,
+                    message: "Username was invalid.".to_owned(),
+                    status_code: http::StatusCode::BAD_REQUEST,
+                }));
+            }
+            Ok(user_id) => user_id,
+        };
+
+    // Check if username is creative enough
+    if data.user_exists(&user_id) {
+        debug!("ID already taken");
+        return MatrixResult(Err(Error {
+            kind: ErrorKind::UserInUse,
+            message: "Desired user ID is already taken.".to_owned(),
+            status_code: http::StatusCode::BAD_REQUEST,
+        }));
+    }
+
+    // TODO add check for appservice namespaces
+
+    // If no if check is true we have an username that's available to be used.
+    MatrixResult(Ok(get_username_availability::Response { available: true }))
+}
+
 #[post("/_matrix/client/r0/register", data = "<body>")]
 pub fn register_route(
     data: State<Data>,
diff --git a/src/main.rs b/src/main.rs
index 1b6e7aaf..db97599b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,6 +24,7 @@ fn setup_rocket() -> rocket::Rocket {
             "/",
             routes![
                 client_server::get_supported_versions_route,
+                client_server::get_register_available_route,
                 client_server::register_route,
                 client_server::get_login_route,
                 client_server::login_route,