use switch to ruma and remove unneeded code
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
71590d6c60
commit
29093c51e3
@ -3,7 +3,7 @@ CREATE TABLE users(
|
|||||||
uuid TEXT PRIMARY KEY NOT NULL,
|
uuid TEXT PRIMARY KEY NOT NULL,
|
||||||
user_id CHAR(255) NOT NULL,
|
user_id CHAR(255) NOT NULL,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT NOT NULL,
|
||||||
password TEXT NOT NULL
|
password_hash TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX user_id_index ON users (user_id);
|
CREATE INDEX user_id_index ON users (user_id);
|
116
sqlx-data.json
116
sqlx-data.json
@ -102,7 +102,7 @@
|
|||||||
},
|
},
|
||||||
"query": "insert into sessions(uuid, device_uuid, key)\n values(?, ?, ?)\n returning uuid as 'uuid: Uuid', device_uuid as 'device_uuid: Uuid', key"
|
"query": "insert into sessions(uuid, device_uuid, key)\n values(?, ?, ?)\n returning uuid as 'uuid: Uuid', device_uuid as 'device_uuid: Uuid', key"
|
||||||
},
|
},
|
||||||
"383949b72c69bca95bf23ef06900cd1ac5a136cdd4a525cbb624d327ce0cdefb": {
|
"2b3409859921423dc051ce76a0166116f39ca7f26053bac5bde0a61313bfd68c": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -111,7 +111,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user_id: UserId",
|
"name": "user_id",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
@ -121,7 +121,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "password",
|
"name": "password_hash",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -136,9 +136,9 @@
|
|||||||
"Right": 1
|
"Right": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password\n from users where uuid = ?"
|
"query": "select uuid as 'uuid: Uuid', user_id, display_name, password_hash\n from users where user_id = ?"
|
||||||
},
|
},
|
||||||
"3fead3dac0e110757bc30be40bb0c6c2bc02127b6d9b6145bfc40fa5fe22ad06": {
|
"33f7c796b21878b2f06f3e012ada151226bd1ab58677ca6acc4edb10e0e1493a": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -147,7 +147,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user_id: UserId",
|
"name": "user_id",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
@ -157,7 +157,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "password",
|
"name": "password_hash",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@
|
|||||||
"Right": 4
|
"Right": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "insert into users(uuid, user_id, display_name, password)\n values (?, ?, ?, ?)\n returning uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password"
|
"query": "insert into users(uuid, user_id, display_name, password_hash)\n values (?, ?, ?, ?)\n returning uuid as 'uuid: Uuid', user_id, display_name, password_hash"
|
||||||
},
|
},
|
||||||
"58d27b1d424297504f1da2e3b9b4020121251c1155fbf5dc870dafbef97659f3": {
|
"58d27b1d424297504f1da2e3b9b4020121251c1155fbf5dc870dafbef97659f3": {
|
||||||
"describe": {
|
"describe": {
|
||||||
@ -192,7 +192,7 @@
|
|||||||
},
|
},
|
||||||
"query": "select user_id from users where user_id = ?"
|
"query": "select user_id from users where user_id = ?"
|
||||||
},
|
},
|
||||||
"778b7f0a1c66f00812f0232a5904b7b6b295720ebb75d1c2720afeeda4f66936": {
|
"9673bbe9506ba700923467fe8aaa141f9030158790db74234c13a5800adf2575": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -201,7 +201,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user_id: UserId",
|
"name": "user_id",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
@ -211,7 +211,7 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "password",
|
"name": "password_hash",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -223,10 +223,46 @@
|
|||||||
false
|
false
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Right": 5
|
"Right": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "update users set uuid = ?, user_id = ?, display_name = ?, password = ?\n where uuid = ?\n returning uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password"
|
"query": "select uuid as 'uuid: Uuid', user_id, display_name, password_hash\n from users where uuid = ?"
|
||||||
|
},
|
||||||
|
"9ee4afab2c653a23144bcb05943aa4ff1e8dc1ae5baa9c87827b52671ae47784": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "uuid: Uuid",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "user_uuid: Uuid",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "device_id",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "display_name",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "select uuid as 'uuid: Uuid', user_uuid as 'user_uuid: Uuid', device_id, display_name from devices where user_uuid = ? and device_id = ?"
|
||||||
},
|
},
|
||||||
"b38fd90504bea0c63e6517738c2354e6b057fcc6c643283019b27689e286bf2d": {
|
"b38fd90504bea0c63e6517738c2354e6b057fcc6c643283019b27689e286bf2d": {
|
||||||
"describe": {
|
"describe": {
|
||||||
@ -258,7 +294,7 @@
|
|||||||
},
|
},
|
||||||
"query": "select uuid as 'uuid: Uuid', device_uuid as 'device_uuid: Uuid', key\n from sessions where key = ?"
|
"query": "select uuid as 'uuid: Uuid', device_uuid as 'device_uuid: Uuid', key\n from sessions where key = ?"
|
||||||
},
|
},
|
||||||
"ddcc531c080b2a1c70166d29a940aaada6701abe2933c305a879e7f18baeaf3a": {
|
"f1b148ebcfe22d9680b8ea3dc3c334523496e88fca724ec7d08c5e2948e58526": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -267,17 +303,17 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user_uuid: Uuid",
|
"name": "user_id",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Int64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "device_id",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "display_name",
|
"name": "display_name",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "password_hash",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -289,45 +325,9 @@
|
|||||||
false
|
false
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Right": 1
|
"Right": 5
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "select uuid as 'uuid: Uuid', user_uuid as 'user_uuid: Uuid', device_id, display_name from devices where user_uuid = ?"
|
"query": "update users set uuid = ?, user_id = ?, display_name = ?, password_hash = ?\n where uuid = ?\n returning uuid as 'uuid: Uuid', user_id, display_name, password_hash"
|
||||||
},
|
|
||||||
"f57c49e5390c81f971851ff9ab35242a472b9efbb1ffa658de9b102188769750": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "uuid: Uuid",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_id: UserId",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "display_name",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "password",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password\n from users where user_id = ?"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,7 @@
|
|||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use sqlx::Statement;
|
|
||||||
|
|
||||||
use crate::responses::registration::RegistrationResponse;
|
|
||||||
use crate::types::error_code::ErrorCode;
|
use crate::types::error_code::ErrorCode;
|
||||||
|
|
||||||
use super::authentication_error::AuthenticationError;
|
use super::authentication_error::AuthenticationError;
|
||||||
|
@ -3,7 +3,7 @@ use std::{collections::HashMap, sync::Arc};
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::Query,
|
extract::Query,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Extension, Json,
|
Extension,
|
||||||
};
|
};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
@ -12,23 +12,14 @@ use crate::{
|
|||||||
api_error::ApiError, authentication_error::AuthenticationError,
|
api_error::ApiError, authentication_error::AuthenticationError,
|
||||||
registration_error::RegistrationError,
|
registration_error::RegistrationError,
|
||||||
},
|
},
|
||||||
models::sessions::Session,
|
models::{devices::Device, sessions::Session, users::User},
|
||||||
responses::{
|
ruma_wrapper::{RumaRequest, RumaResponse},
|
||||||
authentication::{AuthenticationResponse, AuthenticationSuccess},
|
|
||||||
registration::RegistrationResponse,
|
|
||||||
},
|
|
||||||
ruma_wrapper::RumaResponse,
|
|
||||||
};
|
|
||||||
use crate::{models::devices::Device, responses::registration::RegistrationSuccess};
|
|
||||||
use crate::{
|
|
||||||
models::users::User,
|
|
||||||
requests::registration::RegistrationRequest,
|
|
||||||
types::{authentication_data::AuthenticationData, user_id::UserId},
|
|
||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ruma::api::client::{
|
use ruma::api::client::{
|
||||||
account,
|
account, session,
|
||||||
session::get_login_types::v3::{LoginType, PasswordLoginType},
|
uiaa::{IncomingAuthData, IncomingUserIdentifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn routes() -> axum::Router {
|
pub fn routes() -> axum::Router {
|
||||||
@ -38,9 +29,10 @@ pub fn routes() -> axum::Router {
|
|||||||
.route("/r0/register/available", get(get_username_available))
|
.route("/r0/register/available", get(get_username_available))
|
||||||
}
|
}
|
||||||
|
|
||||||
use ruma::api::client::session;
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
async fn get_login() -> Result<RumaResponse<session::get_login_types::v3::Response>, ApiError> {
|
async fn get_login() -> Result<RumaResponse<session::get_login_types::v3::Response>, ApiError> {
|
||||||
|
use session::get_login_types::v3::*;
|
||||||
|
|
||||||
Ok(RumaResponse(session::get_login_types::v3::Response::new(
|
Ok(RumaResponse(session::get_login_types::v3::Response::new(
|
||||||
vec![LoginType::Password(PasswordLoginType::new())],
|
vec![LoginType::Password(PasswordLoginType::new())],
|
||||||
)))
|
)))
|
||||||
@ -48,43 +40,50 @@ async fn get_login() -> Result<RumaResponse<session::get_login_types::v3::Respon
|
|||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn post_login(
|
async fn post_login(
|
||||||
Extension(config): Extension<Arc<Config>>,
|
|
||||||
Extension(db): Extension<SqlitePool>,
|
Extension(db): Extension<SqlitePool>,
|
||||||
Json(body): Json<AuthenticationData>,
|
RumaRequest(req): RumaRequest<session::login::v3::IncomingRequest>,
|
||||||
) -> Result<Json<AuthenticationResponse>, ApiError> {
|
) -> Result<RumaResponse<session::login::v3::Response>, ApiError> {
|
||||||
match body {
|
use session::login::v3::*;
|
||||||
AuthenticationData::Password(auth_data) => {
|
|
||||||
let user = auth_data.user().unwrap();
|
|
||||||
let user_id = UserId::new(user, config.server_name())
|
|
||||||
.ok()
|
|
||||||
.ok_or(AuthenticationError::InvalidUserId)?;
|
|
||||||
|
|
||||||
let user = User::find_by_user_id(&db, &user_id).await?;
|
match req.login_info {
|
||||||
|
IncomingLoginInfo::Password(incoming_password) => {
|
||||||
|
let password = incoming_password.password;
|
||||||
|
let user_id = if let IncomingUserIdentifier::UserIdOrLocalpart(user_id) =
|
||||||
|
incoming_password.identifier
|
||||||
|
{
|
||||||
|
ruma::UserId::parse(user_id).map_err(|e| anyhow::anyhow!(e))?
|
||||||
|
} else {
|
||||||
|
return Err(AuthenticationError::InvalidUserId.into())
|
||||||
|
};
|
||||||
|
|
||||||
user.password_correct(auth_data.password())
|
let db_user = User::find_by_user_id(&db, user_id.as_str()).await?;
|
||||||
|
db_user
|
||||||
|
.password_correct(&password)
|
||||||
.ok()
|
.ok()
|
||||||
.ok_or(AuthenticationError::Forbidden)?;
|
.ok_or(AuthenticationError::Forbidden)?;
|
||||||
|
|
||||||
let device = if let Some(device_id) = auth_data.device_id() {
|
let device = if let Some(device_id) = req.device_id {
|
||||||
Device::find_for_user(&db, &user, device_id).await?
|
Device::find_for_user(&db, &db_user, device_id.as_str()).await?
|
||||||
} else {
|
} else {
|
||||||
let device_id = uuid::Uuid::new_v4().to_string();
|
let device_id = uuid::Uuid::new_v4().to_string();
|
||||||
let display_name =
|
let display_name = req
|
||||||
if let Some(display_name) = auth_data.initial_device_display_name() {
|
.initial_device_display_name
|
||||||
display_name.as_ref()
|
.unwrap_or_else(|| "Generic Device".into());
|
||||||
} else {
|
Device::new(&db_user, &device_id, &display_name)?
|
||||||
"Generic Device"
|
|
||||||
};
|
|
||||||
Device::new(&user, &device_id, display_name)?
|
|
||||||
.create(&db)
|
.create(&db)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|
||||||
let session = Session::new(&device)?.create(&db).await?;
|
let session = Session::new(&device)?.create(&db).await?;
|
||||||
|
let response = Response::new(
|
||||||
|
user_id,
|
||||||
|
session.key,
|
||||||
|
ruma::OwnedDeviceId::from(device.device_id),
|
||||||
|
);
|
||||||
|
|
||||||
let resp = AuthenticationSuccess::new(session.key(), device.device_id(), &user_id);
|
return Ok(RumaResponse(response));
|
||||||
Ok(Json(AuthenticationResponse::Success(resp)))
|
|
||||||
}
|
}
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,76 +93,77 @@ async fn get_username_available(
|
|||||||
Extension(db): Extension<SqlitePool>,
|
Extension(db): Extension<SqlitePool>,
|
||||||
Query(params): Query<HashMap<String, String>>,
|
Query(params): Query<HashMap<String, String>>,
|
||||||
) -> Result<RumaResponse<account::get_username_availability::v3::Response>, ApiError> {
|
) -> Result<RumaResponse<account::get_username_availability::v3::Response>, ApiError> {
|
||||||
|
use account::get_username_availability::v3::*;
|
||||||
|
|
||||||
let username = params
|
let username = params
|
||||||
.get("username")
|
.get("username")
|
||||||
.ok_or(RegistrationError::MissingUserId)?;
|
.ok_or(RegistrationError::MissingUserId)?;
|
||||||
let user_id = UserId::new(username, config.server_name())
|
let user_id = ruma::UserId::parse(username).map_err(|_| RegistrationError::InvalidUserId)?;
|
||||||
.ok()
|
|
||||||
.ok_or(RegistrationError::InvalidUserId)?;
|
|
||||||
let exists = User::exists(&db, &user_id).await?;
|
let exists = User::exists(&db, &user_id).await?;
|
||||||
|
|
||||||
Ok(RumaResponse(
|
Ok(RumaResponse(Response::new(!exists)))
|
||||||
account::get_username_availability::v3::Response::new(!exists),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn post_register(
|
async fn post_register(
|
||||||
Extension(config): Extension<Arc<Config>>,
|
Extension(config): Extension<Arc<Config>>,
|
||||||
Extension(db): Extension<SqlitePool>,
|
Extension(db): Extension<SqlitePool>,
|
||||||
Json(body): Json<RegistrationRequest>,
|
RumaRequest(req): RumaRequest<account::register::v3::IncomingRequest>,
|
||||||
) -> Result<Json<RegistrationResponse>, ApiError> {
|
) -> Result<RumaResponse<account::register::v3::Response>, ApiError> {
|
||||||
|
use account::register::v3::*;
|
||||||
|
|
||||||
config
|
config
|
||||||
.enable_registration()
|
.enable_registration()
|
||||||
.then(|| true)
|
.then(|| true)
|
||||||
.ok_or(RegistrationError::RegistrationDisabled)?;
|
.ok_or(RegistrationError::RegistrationDisabled)?;
|
||||||
body.auth()
|
|
||||||
.ok_or(RegistrationError::AdditionalAuthenticationInformation)?;
|
|
||||||
|
|
||||||
let (user, device) = match &body.auth().expect("must be Some") {
|
match req.auth {
|
||||||
AuthenticationData::Password(auth_data) => {
|
Some(auth) => match auth {
|
||||||
let username = body.username().ok_or(RegistrationError::MissingUserId)?;
|
IncomingAuthData::Password(incoming_password) => {
|
||||||
let user_id = UserId::new(username, config.server_name())
|
let password = incoming_password.password;
|
||||||
.ok()
|
let user_id = if let IncomingUserIdentifier::UserIdOrLocalpart(user_id) =
|
||||||
.ok_or(RegistrationError::InvalidUserId)?;
|
incoming_password.identifier
|
||||||
|
{
|
||||||
|
ruma::UserId::parse(user_id).map_err(|e| anyhow::anyhow!(e))?
|
||||||
|
} else {
|
||||||
|
Err(AuthenticationError::InvalidUserId)?
|
||||||
|
};
|
||||||
|
|
||||||
if User::exists(&db, &user_id).await? {
|
if User::exists(&db, &user_id).await? {
|
||||||
return Err(ApiError::from(RegistrationError::UserIdTaken));
|
return Err(ApiError::from(RegistrationError::UserIdTaken));
|
||||||
}
|
}
|
||||||
|
|
||||||
let display_name = match body.initial_device_display_name() {
|
let display_name = req
|
||||||
Some(display_name) => display_name.as_ref(),
|
.initial_device_display_name
|
||||||
None => "Random displayname",
|
.unwrap_or_else(|| "Random Display Name".into());
|
||||||
};
|
|
||||||
|
|
||||||
let user = User::new(&user_id, &user_id.to_string(), auth_data.password())?
|
let user = User::new(&user_id, &user_id.to_string(), &password)?
|
||||||
|
.create(&db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let device = Device::new(
|
||||||
|
&user,
|
||||||
|
uuid::Uuid::new_v4().to_string().as_ref(),
|
||||||
|
&display_name,
|
||||||
|
)?
|
||||||
.create(&db)
|
.create(&db)
|
||||||
.await?;
|
.await?;
|
||||||
|
let mut response = Response::new(
|
||||||
|
ruma::UserId::parse(&user.user_id).map_err(|e| anyhow::anyhow!(e))?,
|
||||||
|
);
|
||||||
|
if !req.inhibit_login {
|
||||||
|
let session = Session::new(&device)?.create(&db).await?;
|
||||||
|
response.access_token = Some(session.key);
|
||||||
|
}
|
||||||
|
if !req.inhibit_login {
|
||||||
|
response.device_id = Some(ruma::OwnedDeviceId::from(device.device_id));
|
||||||
|
}
|
||||||
|
|
||||||
let device = Device::new(
|
return Ok(RumaResponse(response));
|
||||||
&user,
|
}
|
||||||
uuid::Uuid::new_v4().to_string().as_ref(),
|
_ => todo!(),
|
||||||
display_name,
|
},
|
||||||
)?
|
None => Err(RegistrationError::AdditionalAuthenticationInformation)?,
|
||||||
.create(&db)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
(user, device)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
unreachable!()
|
||||||
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)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ use crate::{models::sessions::Session, types::error_code::ErrorCode};
|
|||||||
use super::errors::ErrorResponse;
|
use super::errors::ErrorResponse;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod thirdparty;
|
|
||||||
pub mod create_room;
|
pub mod create_room;
|
||||||
|
pub mod thirdparty;
|
||||||
|
|
||||||
async fn authentication_middleware<B>(mut req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
async fn authentication_middleware<B>(mut req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
||||||
let db: &SqlitePool = req.extensions().get().unwrap();
|
let db: &SqlitePool = req.extensions().get().unwrap();
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
use axum::{routing::get, Json};
|
use axum::routing::get;
|
||||||
|
|
||||||
use crate::responses::versions::Versions;
|
use crate::ruma_wrapper::RumaResponse;
|
||||||
|
|
||||||
pub fn routes() -> axum::Router {
|
pub fn routes() -> axum::Router {
|
||||||
axum::Router::new().route("/versions", get(get_client_versions))
|
axum::Router::new().route("/versions", get(get_client_versions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use ruma::api::client::discovery;
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
async fn get_client_versions() -> Json<Versions> {
|
async fn get_client_versions() -> RumaResponse<discovery::get_supported_versions::Response> {
|
||||||
Json(Versions::default())
|
use discovery::get_supported_versions::*;
|
||||||
|
|
||||||
|
RumaResponse(Response::new(vec!["v1.2".into()]))
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::types::server_name::ServerName;
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
db_path: String,
|
db_path: String,
|
||||||
server_name: ServerName,
|
server_name: ServerName,
|
||||||
enable_registration: bool
|
enable_registration: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@ -31,7 +31,7 @@ impl Default for Config {
|
|||||||
Self {
|
Self {
|
||||||
db_path: "sqlite://db.sqlite3".into(),
|
db_path: "sqlite://db.sqlite3".into(),
|
||||||
server_name: ServerName::new("fuckwit.dev").unwrap(),
|
server_name: ServerName::new("fuckwit.dev").unwrap(),
|
||||||
enable_registration: true
|
enable_registration: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,10 +12,8 @@ use tower_http::{cors::CorsLayer, trace::TraceLayer};
|
|||||||
mod api;
|
mod api;
|
||||||
mod config;
|
mod config;
|
||||||
mod models;
|
mod models;
|
||||||
mod requests;
|
|
||||||
mod responses;
|
mod responses;
|
||||||
mod ruma_wrapper;
|
mod ruma_wrapper;
|
||||||
mod state_resolution;
|
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -2,20 +2,20 @@ use sqlx::SqlitePool;
|
|||||||
|
|
||||||
use crate::types::uuid::Uuid;
|
use crate::types::uuid::Uuid;
|
||||||
|
|
||||||
use super::{sessions::Session, users::User};
|
use super::users::User;
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
user_uuid: Uuid,
|
pub user_uuid: Uuid,
|
||||||
device_id: String,
|
pub device_id: String,
|
||||||
display_name: String,
|
pub display_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
pub fn new(user: &User, device_id: &str, display_name: &str) -> anyhow::Result<Self> {
|
pub fn new(user: &User, device_id: &str, display_name: &str) -> anyhow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
uuid: uuid::Uuid::new_v4().into(),
|
uuid: uuid::Uuid::new_v4().into(),
|
||||||
user_uuid: user.uuid().clone(),
|
user_uuid: user.uuid.clone(),
|
||||||
device_id: device_id.to_owned(),
|
device_id: device_id.to_owned(),
|
||||||
display_name: display_name.to_owned(),
|
display_name: display_name.to_owned(),
|
||||||
})
|
})
|
||||||
@ -40,11 +40,11 @@ impl Device {
|
|||||||
user: &User,
|
user: &User,
|
||||||
device_id: &str,
|
device_id: &str,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let user_uuid = user.uuid();
|
let user_uuid = user.uuid.clone();
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"select uuid as 'uuid: Uuid', user_uuid as 'user_uuid: Uuid', device_id, display_name from devices where user_uuid = ?",
|
"select uuid as 'uuid: Uuid', user_uuid as 'user_uuid: Uuid', device_id, display_name from devices where user_uuid = ? and device_id = ?",
|
||||||
user_uuid)
|
user_uuid, device_id)
|
||||||
.fetch_one(conn).await?
|
.fetch_one(conn).await?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -67,22 +67,4 @@ impl Device {
|
|||||||
pub fn uuid(&self) -> &Uuid {
|
pub fn uuid(&self) -> &Uuid {
|
||||||
&self.uuid
|
&self.uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the device's user id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn user_uuid(&self) -> &Uuid {
|
|
||||||
&self.user_uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the device's device id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn device_id(&self) -> &str {
|
|
||||||
self.device_id.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the device's display name.
|
|
||||||
#[must_use]
|
|
||||||
pub fn display_name(&self) -> &str {
|
|
||||||
self.display_name.as_ref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use sqlx::SqlitePool;
|
/* use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::types::{uuid::Uuid, event_type::EventType};
|
use crate::types::{uuid::Uuid, event_type::EventType};
|
||||||
|
|
||||||
use super::{rooms::Room, users::User};
|
use super::{users::User};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
@ -70,3 +70,4 @@ impl Event {
|
|||||||
serde_json::from_str(&self.content).expect("has to be valid json")
|
serde_json::from_str(&self.content).expect("has to be valid json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod devices;
|
pub mod devices;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod rooms;
|
|
||||||
pub mod sessions;
|
pub mod sessions;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
use sqlx::SqlitePool;
|
|
||||||
|
|
||||||
use crate::types::uuid::Uuid;
|
|
||||||
|
|
||||||
use super::events::Event;
|
|
||||||
|
|
||||||
pub struct Room {
|
|
||||||
uuid: Uuid,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Room {
|
|
||||||
fn new(name: &str) -> anyhow::Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
uuid: uuid::Uuid::new_v4().into(),
|
|
||||||
name: name.to_owned(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create(&self, conn: &SqlitePool) -> anyhow::Result<Self> {
|
|
||||||
Ok(sqlx::query_as!(
|
|
||||||
Self,
|
|
||||||
"insert into rooms(uuid, name)
|
|
||||||
values(?, ?)
|
|
||||||
returning uuid as 'uuid: Uuid', name",
|
|
||||||
self.uuid,
|
|
||||||
self.name
|
|
||||||
)
|
|
||||||
.fetch_one(conn)
|
|
||||||
.await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn events(&self, conn: &SqlitePool) -> anyhow::Result<Vec<Event>> {
|
|
||||||
Event::all_for_room(conn, self).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the room's uuid.
|
|
||||||
#[must_use]
|
|
||||||
pub fn uuid(&self) -> &Uuid {
|
|
||||||
&self.uuid
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,9 +6,9 @@ use crate::types::uuid::Uuid;
|
|||||||
use super::devices::Device;
|
use super::devices::Device;
|
||||||
|
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
device_uuid: Uuid,
|
pub device_uuid: Uuid,
|
||||||
key: String,
|
pub key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
@ -51,22 +51,4 @@ impl Session {
|
|||||||
pub async fn device(&self, conn: &SqlitePool) -> anyhow::Result<Device> {
|
pub async fn device(&self, conn: &SqlitePool) -> anyhow::Result<Device> {
|
||||||
Device::find_by_uuid(conn, &self.device_uuid).await
|
Device::find_by_uuid(conn, &self.device_uuid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the session's id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn uuid(&self) -> &Uuid {
|
|
||||||
&self.uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the session's device id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn device_uuid(&self) -> &Uuid {
|
|
||||||
&self.device_uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the session's value.
|
|
||||||
#[must_use]
|
|
||||||
pub fn key(&self) -> &str {
|
|
||||||
self.key.as_ref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
use crate::types::uuid::Uuid;
|
use crate::types::uuid::Uuid;
|
||||||
use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use sqlx::{encode::IsNull, sqlite::SqliteTypeInfo, FromRow, Sqlite, SqlitePool};
|
use ruma::OwnedUserId;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
use crate::types::user_id::UserId;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
user_id: UserId,
|
pub user_id: String,
|
||||||
display_name: String,
|
pub display_name: String,
|
||||||
password: String,
|
pub password_hash: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
pub fn new(user_id: &UserId, display_name: &str, password: &str) -> anyhow::Result<Self> {
|
pub fn new(user_id: &OwnedUserId, display_name: &str, password: &str) -> anyhow::Result<Self> {
|
||||||
let argon2 = Argon2::default();
|
let argon2 = Argon2::default();
|
||||||
let salt = SaltString::generate(OsRng);
|
let salt = SaltString::generate(OsRng);
|
||||||
let password = argon2
|
let password_hash = argon2
|
||||||
.hash_password(password.as_bytes(), &salt)?
|
.hash_password(password.as_bytes(), &salt)?
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
uuid: uuid::Uuid::new_v4().into(),
|
uuid: uuid::Uuid::new_v4().into(),
|
||||||
user_id: user_id.clone(),
|
user_id: user_id.to_string(),
|
||||||
display_name: display_name.to_owned(),
|
display_name: display_name.to_owned(),
|
||||||
password,
|
password_hash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn exists(conn: &SqlitePool, user_id: &UserId) -> anyhow::Result<bool> {
|
pub async fn exists(conn: &SqlitePool, user_id: &OwnedUserId) -> anyhow::Result<bool> {
|
||||||
|
let user_id = user_id.to_string();
|
||||||
Ok(
|
Ok(
|
||||||
sqlx::query!("select user_id from users where user_id = ?", user_id)
|
sqlx::query!("select user_id from users where user_id = ?", user_id)
|
||||||
.fetch_optional(conn)
|
.fetch_optional(conn)
|
||||||
@ -41,13 +41,13 @@ impl User {
|
|||||||
pub async fn create(&self, conn: &SqlitePool) -> anyhow::Result<Self> {
|
pub async fn create(&self, conn: &SqlitePool) -> anyhow::Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"insert into users(uuid, user_id, display_name, password)
|
"insert into users(uuid, user_id, display_name, password_hash)
|
||||||
values (?, ?, ?, ?)
|
values (?, ?, ?, ?)
|
||||||
returning uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password",
|
returning uuid as 'uuid: Uuid', user_id, display_name, password_hash",
|
||||||
self.uuid,
|
self.uuid,
|
||||||
self.user_id,
|
self.user_id,
|
||||||
self.display_name,
|
self.display_name,
|
||||||
self.password
|
self.password_hash
|
||||||
)
|
)
|
||||||
.fetch_one(conn)
|
.fetch_one(conn)
|
||||||
.await?)
|
.await?)
|
||||||
@ -56,13 +56,13 @@ impl User {
|
|||||||
pub async fn update(&self, conn: &SqlitePool) -> anyhow::Result<Self> {
|
pub async fn update(&self, conn: &SqlitePool) -> anyhow::Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"update users set uuid = ?, user_id = ?, display_name = ?, password = ?
|
"update users set uuid = ?, user_id = ?, display_name = ?, password_hash = ?
|
||||||
where uuid = ?
|
where uuid = ?
|
||||||
returning uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password",
|
returning uuid as 'uuid: Uuid', user_id, display_name, password_hash",
|
||||||
self.uuid,
|
self.uuid,
|
||||||
self.user_id,
|
self.user_id,
|
||||||
self.display_name,
|
self.display_name,
|
||||||
self.password,
|
self.password_hash,
|
||||||
self.uuid
|
self.uuid
|
||||||
)
|
)
|
||||||
.fetch_one(conn)
|
.fetch_one(conn)
|
||||||
@ -72,7 +72,7 @@ impl User {
|
|||||||
pub async fn find_by_uuid(conn: &SqlitePool, uuid: &Uuid) -> anyhow::Result<Self> {
|
pub async fn find_by_uuid(conn: &SqlitePool, uuid: &Uuid) -> anyhow::Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password
|
"select uuid as 'uuid: Uuid', user_id, display_name, password_hash
|
||||||
from users where uuid = ?",
|
from users where uuid = ?",
|
||||||
uuid
|
uuid
|
||||||
)
|
)
|
||||||
@ -80,10 +80,10 @@ impl User {
|
|||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_by_user_id(conn: &SqlitePool, user_id: &UserId) -> anyhow::Result<Self> {
|
pub async fn find_by_user_id(conn: &SqlitePool, user_id: &str) -> anyhow::Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"select uuid as 'uuid: Uuid', user_id as 'user_id: UserId', display_name, password
|
"select uuid as 'uuid: Uuid', user_id, display_name, password_hash
|
||||||
from users where user_id = ?",
|
from users where user_id = ?",
|
||||||
user_id
|
user_id
|
||||||
)
|
)
|
||||||
@ -92,28 +92,10 @@ impl User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn password_correct(&self, password: &str) -> anyhow::Result<bool> {
|
pub fn password_correct(&self, password: &str) -> anyhow::Result<bool> {
|
||||||
let password_hash = PasswordHash::new(self.password())?;
|
let password_hash = PasswordHash::new(&self.password_hash)?;
|
||||||
|
|
||||||
Ok(Argon2::default()
|
Ok(Argon2::default()
|
||||||
.verify_password(password.as_bytes(), &password_hash)
|
.verify_password(password.as_bytes(), &password_hash)
|
||||||
.is_ok())
|
.is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the user's id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn uuid(&self) -> &Uuid {
|
|
||||||
&self.uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the user's user id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn user_id(&self) -> &UserId {
|
|
||||||
&self.user_id
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the user's password.
|
|
||||||
#[must_use]
|
|
||||||
pub fn password(&self) -> &str {
|
|
||||||
self.password.as_ref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use crate::types::user_id::UserId;
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize)]
|
|
||||||
pub struct CreateRoomRequest {
|
|
||||||
/// Extra keys, such as `m.federate`, to be added to the content of the `m.room.create` event.
|
|
||||||
creation_content: Option<()>,
|
|
||||||
/// List of state events to set in the initial room. Used for overriding the default state
|
|
||||||
initial_state: Vec<()>,
|
|
||||||
/// List of user IDs to invite to the room
|
|
||||||
invite: Option<Vec<String>>,
|
|
||||||
/// List of thirdparty IDs to invite to the room
|
|
||||||
invite_3pid: Option<Vec<()>>,
|
|
||||||
/// Indicate if room is a direct chat room
|
|
||||||
is_direct: Option<bool>,
|
|
||||||
/// Set name of the room
|
|
||||||
name: Option<String>,
|
|
||||||
/// Used to override the default power level event
|
|
||||||
power_level_content_override: Option<()>,
|
|
||||||
/// Preset for room creation
|
|
||||||
preset: Option<()>,
|
|
||||||
/// Desired room alias local part
|
|
||||||
room_alias_name: Option<String>,
|
|
||||||
/// Version of room to create. Defaults to server default
|
|
||||||
room_version: Option<String>,
|
|
||||||
/// Sets rooms topic
|
|
||||||
topic: Option<String>,
|
|
||||||
/// Sets rooms visibility
|
|
||||||
visibility: ()
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
pub mod registration;
|
|
||||||
pub mod create_room_request;
|
|
@ -1,48 +0,0 @@
|
|||||||
use crate::types::{authentication_data::AuthenticationData, flow::Flow, identifier::Identifier};
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize)]
|
|
||||||
pub struct RegistrationRequest {
|
|
||||||
auth: Option<AuthenticationData>,
|
|
||||||
device_id: Option<String>,
|
|
||||||
inhibit_login: Option<bool>,
|
|
||||||
initial_device_display_name: Option<String>,
|
|
||||||
password: Option<String>,
|
|
||||||
username: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegistrationRequest {
|
|
||||||
#[must_use]
|
|
||||||
pub fn auth(&self) -> Option<&AuthenticationData> {
|
|
||||||
self.auth.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the registration request's device id.
|
|
||||||
#[must_use]
|
|
||||||
pub fn device_id(&self) -> Option<&String> {
|
|
||||||
self.device_id.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the registration request's inhibit login.
|
|
||||||
#[must_use]
|
|
||||||
pub fn inhibit_login(&self) -> Option<bool> {
|
|
||||||
self.inhibit_login
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the registration request's initial device display name.
|
|
||||||
#[must_use]
|
|
||||||
pub fn initial_device_display_name(&self) -> Option<&String> {
|
|
||||||
self.initial_device_display_name.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the registration request's password.
|
|
||||||
#[must_use]
|
|
||||||
pub fn password(&self) -> Option<&String> {
|
|
||||||
self.password.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the registration request's username.
|
|
||||||
#[must_use]
|
|
||||||
pub fn username(&self) -> Option<&String> {
|
|
||||||
self.username.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
use axum::{response::IntoResponse, Json};
|
|
||||||
|
|
||||||
use crate::types::user_id::UserId;
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum AuthenticationResponse {
|
|
||||||
Success(AuthenticationSuccess),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
|
||||||
pub struct AuthenticationSuccess {
|
|
||||||
access_token: String,
|
|
||||||
device_id: String,
|
|
||||||
user_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuthenticationSuccess {
|
|
||||||
pub fn new(access_token: &str, device_id: &str, user_id: &UserId) -> Self {
|
|
||||||
Self {
|
|
||||||
access_token: access_token.to_owned(),
|
|
||||||
device_id: device_id.to_owned(),
|
|
||||||
user_id: user_id.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
use crate::types::flow::Flow;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
|
||||||
struct FlowWrapper {
|
|
||||||
#[serde(rename = "type")]
|
|
||||||
_type: Flow,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
|
||||||
pub struct Flows {
|
|
||||||
flows: Vec<FlowWrapper>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Flows {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
flows: vec![FlowWrapper {
|
|
||||||
_type: Flow::Password,
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1 @@
|
|||||||
pub mod authentication;
|
|
||||||
pub mod flow;
|
|
||||||
pub mod registration;
|
pub mod registration;
|
||||||
pub mod username_available;
|
|
||||||
pub mod versions;
|
|
||||||
|
@ -3,7 +3,6 @@ use crate::types::user_interactive_authorization::UserInteractiveAuthorizationIn
|
|||||||
#[derive(Debug, serde::Serialize)]
|
#[derive(Debug, serde::Serialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum RegistrationResponse {
|
pub enum RegistrationResponse {
|
||||||
Success(RegistrationSuccess),
|
|
||||||
UserInteractiveAuthorizationInfo(UserInteractiveAuthorizationInfo),
|
UserInteractiveAuthorizationInfo(UserInteractiveAuthorizationInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,21 +13,3 @@ impl RegistrationResponse {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
|
||||||
pub struct RegistrationSuccess {
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
access_token: Option<String>,
|
|
||||||
device_id: String,
|
|
||||||
user_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegistrationSuccess {
|
|
||||||
pub fn new(access_token: Option<&str>, device_id: &str, user_id: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
access_token: access_token.map(|v| v.to_owned()),
|
|
||||||
device_id: device_id.to_owned(),
|
|
||||||
user_id: user_id.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
#[derive(Debug, serde::Serialize)]
|
|
||||||
pub struct UsernameAvailable {
|
|
||||||
available: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UsernameAvailable {
|
|
||||||
pub fn new(available: bool) -> Self {
|
|
||||||
Self { available }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct Versions {
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
unstable_features: Option<HashMap<String, String>>,
|
|
||||||
versions: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Versions {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
unstable_features: None,
|
|
||||||
versions: vec!["v1.2".into()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
body::{Bytes, HttpBody, Full},
|
body::{Bytes, Full, HttpBody},
|
||||||
extract::{FromRequest, Path},
|
extract::{FromRequest, Path},
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
BoxError,
|
BoxError,
|
||||||
|
@ -1 +0,0 @@
|
|||||||
mod v2;
|
|
@ -1,102 +0,0 @@
|
|||||||
use crate::models::events::Event;
|
|
||||||
use std::{
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
future::Future,
|
|
||||||
};
|
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
type StateMap<T> = HashMap<StateTuple, T>;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
|
||||||
pub struct StateTuple {
|
|
||||||
event_type: String,
|
|
||||||
state_key: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct EventId {
|
|
||||||
id: Box<str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(state_sets, auth_chain_sets, get_event_callback))]
|
|
||||||
pub async fn resolve<F, Fut>(
|
|
||||||
room_id: &str, // TODO: own type
|
|
||||||
state_sets: Vec<StateMap<EventId>>,
|
|
||||||
auth_chain_sets: Vec<HashSet<EventId>>,
|
|
||||||
get_event_callback: F,
|
|
||||||
) -> StateMap<EventId>
|
|
||||||
where
|
|
||||||
F: Fn(&EventId) -> Fut,
|
|
||||||
Fut: Future<Output = Option<Event>>,
|
|
||||||
{
|
|
||||||
info!("Calculating conflicted state");
|
|
||||||
|
|
||||||
let (unconflicted_state, conflicted_state) = separate_state(&state_sets);
|
|
||||||
|
|
||||||
if conflicted_state.is_empty() {
|
|
||||||
return unconflicted_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{} conflicted_state entries", conflicted_state.len());
|
|
||||||
info!("Calculating auth_chain differences");
|
|
||||||
|
|
||||||
let conflicted_set =
|
|
||||||
get_auth_chain_differences(auth_chain_sets).chain(conflicted_state.into_values().flatten());
|
|
||||||
let mut conflicted = HashSet::new();
|
|
||||||
for eid in conflicted_set {
|
|
||||||
if let Some(event) = get_event_callback(&eid).await {
|
|
||||||
conflicted.insert(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// separates states from multiple state_maps into unconflicted and conflicted state
|
|
||||||
///
|
|
||||||
/// For the set of all state_tuples find all event_ids.
|
|
||||||
/// If one event_id is found it is unconflicted, otherwise it is conflicted
|
|
||||||
fn separate_state(
|
|
||||||
state_sets: &[StateMap<EventId>],
|
|
||||||
) -> (StateMap<EventId>, StateMap<HashSet<EventId>>) {
|
|
||||||
let mut unconflicted_state: StateMap<EventId> = StateMap::new();
|
|
||||||
let mut conflicted_state: HashMap<StateTuple, HashSet<EventId>> = StateMap::new();
|
|
||||||
|
|
||||||
for key in state_sets
|
|
||||||
.iter()
|
|
||||||
.flat_map(HashMap::keys)
|
|
||||||
.map(ToOwned::to_owned)
|
|
||||||
.collect::<HashSet<StateTuple>>()
|
|
||||||
{
|
|
||||||
let mut event_ids: HashSet<EventId> = state_sets
|
|
||||||
.iter()
|
|
||||||
.filter_map(|state_set| state_set.get(&key))
|
|
||||||
.map(ToOwned::to_owned)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if event_ids.len() == 1 {
|
|
||||||
unconflicted_state.insert(key, event_ids.into_iter().next().expect("len() is 1"));
|
|
||||||
} else {
|
|
||||||
conflicted_state.insert(key, event_ids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(unconflicted_state, conflicted_state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_auth_chain_differences(
|
|
||||||
auth_chain_sets: Vec<HashSet<EventId>>,
|
|
||||||
) -> impl Iterator<Item = EventId> {
|
|
||||||
let num_sets = auth_chain_sets.len();
|
|
||||||
|
|
||||||
let mut id_counts: HashMap<EventId, usize> = HashMap::new();
|
|
||||||
for id in auth_chain_sets.into_iter().flatten() {
|
|
||||||
*id_counts.entry(id).or_default() += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
id_counts
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(move |(id, count)| (count < num_sets).then(move || id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_control_event() {}
|
|
@ -1,12 +0,0 @@
|
|||||||
use super::{uuid::Uuid, user_id::UserId};
|
|
||||||
|
|
||||||
pub struct ClientEvent {
|
|
||||||
content: (),
|
|
||||||
event_id: Uuid,
|
|
||||||
origin_server_ts: u64,
|
|
||||||
room_id: String,
|
|
||||||
sender: UserId,
|
|
||||||
state_key: Option<String>,
|
|
||||||
r#type: String,
|
|
||||||
unsigned: ()
|
|
||||||
}
|
|
@ -20,7 +20,7 @@ impl<'e> sqlx::Encode<'e, Sqlite> for EventType {
|
|||||||
buf.push(sqlx::sqlite::SqliteArgumentValue::Text(
|
buf.push(sqlx::sqlite::SqliteArgumentValue::Text(
|
||||||
match self {
|
match self {
|
||||||
EventType::RoomCreate => "m.room.create",
|
EventType::RoomCreate => "m.room.create",
|
||||||
EventType::Unknown => "???"
|
EventType::Unknown => "???",
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
@ -47,7 +47,7 @@ impl serde::Serialize for EventType {
|
|||||||
{
|
{
|
||||||
serializer.serialize_str(match self {
|
serializer.serialize_str(match self {
|
||||||
EventType::RoomCreate => "m.room.create",
|
EventType::RoomCreate => "m.room.create",
|
||||||
EventType::Unknown => "dev.fuckwit.unknown_event"
|
EventType::Unknown => "dev.fuckwit.unknown_event",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
pub mod authentication_data;
|
pub mod authentication_data;
|
||||||
pub mod error_code;
|
pub mod error_code;
|
||||||
|
pub mod event_type;
|
||||||
pub mod flow;
|
pub mod flow;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod identifier_type;
|
pub mod identifier_type;
|
||||||
|
pub mod server_name;
|
||||||
pub mod user_id;
|
pub mod user_id;
|
||||||
pub mod user_interactive_authorization;
|
pub mod user_interactive_authorization;
|
||||||
pub mod uuid;
|
pub mod uuid;
|
||||||
pub mod server_name;
|
|
||||||
pub mod client_event;
|
|
||||||
pub mod room_event;
|
|
||||||
pub mod event_type;
|
|
@ -1,7 +0,0 @@
|
|||||||
pub enum RoomEvent {
|
|
||||||
Create(RoomCreateEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RoomCreateEvent {
|
|
||||||
|
|
||||||
}
|
|
@ -1,15 +1,15 @@
|
|||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum Hostname {
|
pub enum Hostname {
|
||||||
IPv4(Ipv4Addr),
|
IPv4(Ipv4Addr),
|
||||||
IPv6(Ipv6Addr),
|
IPv6(Ipv6Addr),
|
||||||
Fqdn(String),
|
Fqdn(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerName {
|
pub struct ServerName {
|
||||||
hostname: Hostname,
|
pub hostname: Hostname,
|
||||||
port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerName {
|
impl ServerName {
|
||||||
@ -57,18 +57,6 @@ impl ServerName {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the server name's hostname.
|
|
||||||
#[must_use]
|
|
||||||
fn hostname(&self) -> &Hostname {
|
|
||||||
&self.hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the server name's port.
|
|
||||||
#[must_use]
|
|
||||||
fn port(&self) -> Option<u16> {
|
|
||||||
self.port
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ServerName {
|
impl std::fmt::Display for ServerName {
|
||||||
@ -93,59 +81,59 @@ mod tests {
|
|||||||
fn parse_ipv4_without_port() {
|
fn parse_ipv4_without_port() {
|
||||||
let server_name = ServerName::new("127.0.0.1").unwrap();
|
let server_name = ServerName::new("127.0.0.1").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::IPv4("127.0.0.1".parse().unwrap())
|
Hostname::IPv4("127.0.0.1".parse().unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), None);
|
assert_eq!(server_name.port, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_ipv4_with_port() {
|
fn parse_ipv4_with_port() {
|
||||||
let server_name = ServerName::new("127.0.0.1:8080").unwrap();
|
let server_name = ServerName::new("127.0.0.1:8080").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::IPv4("127.0.0.1".parse().unwrap())
|
Hostname::IPv4("127.0.0.1".parse().unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), Some(8080));
|
assert_eq!(server_name.port, Some(8080));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_ipv6_without_port() {
|
fn parse_ipv6_without_port() {
|
||||||
let server_name = ServerName::new("[::1]").unwrap();
|
let server_name = ServerName::new("[::1]").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::IPv6("::1".parse().unwrap())
|
Hostname::IPv6("::1".parse().unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), None);
|
assert_eq!(server_name.port, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_ipv6_with_port() {
|
fn parse_ipv6_with_port() {
|
||||||
let server_name = ServerName::new("[::1]:8080").unwrap();
|
let server_name = ServerName::new("[::1]:8080").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::IPv6("::1".parse().unwrap())
|
Hostname::IPv6("::1".parse().unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), Some(8080));
|
assert_eq!(server_name.port, Some(8080));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_fqdn_without_port() {
|
fn parse_fqdn_without_port() {
|
||||||
let server_name = ServerName::new("example.com").unwrap();
|
let server_name = ServerName::new("example.com").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::Fqdn("example.com".into())
|
Hostname::Fqdn("example.com".into())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), None);
|
assert_eq!(server_name.port, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_fqdn_with_port() {
|
fn parse_fqdn_with_port() {
|
||||||
let server_name = ServerName::new("example.com:8080").unwrap();
|
let server_name = ServerName::new("example.com:8080").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server_name.hostname(),
|
server_name.hostname,
|
||||||
&Hostname::Fqdn("example.com".into())
|
Hostname::Fqdn("example.com".into())
|
||||||
);
|
);
|
||||||
assert_eq!(server_name.port(), Some(8080));
|
assert_eq!(server_name.port, Some(8080));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user