Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extend login handler to support more than just passwords #31

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ http = "0.2.11"
mime = "0.3.17"
openssl = { version = "0.10.63", features = ["vendored"] }
openssl-sys = { version = "0.9.99", features = ["vendored"] }
rand = "0.8.5"
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "multipart"] }
serde = "1.0.192"
serde_json = "1.0.108"
Expand Down
2 changes: 1 addition & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ path = "src/lib.rs"
[dependencies]
handlebars = "5.0.0"
lettre = "0.11"
rand = "0.8.5"
redis = { version = "0.24.0", features = ["aio", "tokio-comp"] }
thiserror = "1.0.50"
validator = { version = "0.16", features = ["derive"] }

# Workspace
http = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tracing = { workspace = true }
Expand Down
46 changes: 14 additions & 32 deletions crates/core/src/account/service.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::sync::Arc;

use matrix::{
admin::resources::user::UserService, client::resources::session::Session, ruma_common::UserId,
admin::resources::user::UserService,
client::resources::{session::SessionHandle, thirdparty::ThirdPartyHandle},
ruma_common::UserId,
};
use tracing::instrument;
use url::Url;
use uuid::Uuid;
use validator::{Validate, ValidationError};

use matrix::{
admin::resources::user::{CreateUserBody, ListUsersQuery, LoginAsUserBody, ThreePid},
admin::resources::user::{CreateUserBody, LoginAsUserBody, ThreePid},
Client as MatrixAdminClient,
};

Expand All @@ -22,7 +23,6 @@ use crate::{

use super::{error::AccountErrorCode, model::Account};

const DEFAULT_AVATAR_URL: &str = "https://via.placeholder.com/150";
const MIN_USERNAME_LENGTH: usize = 1;
const MAX_USERNAME_LENGTH: usize = 255;
const MIN_PASSWORD_LENGTH: usize = 8;
Expand Down Expand Up @@ -115,28 +115,15 @@ impl AccountService {

/// Returs `true` if the given `email address` is NOT registered in the
/// Matrix Server
pub async fn is_email_available(&self, email: &str) -> Result<bool> {
let user_id = format!("@{}:{}", email, self.admin.server_name());
let user_id = <&UserId>::try_from(user_id.as_str()).map_err(|err| {
// TODO
tracing::error!(?err, "Failed to parse username");
Error::Unknown
})?;

let exists = UserService::list(
&self.admin,
ListUsersQuery {
user_id: Some(user_id.to_string()),
..Default::default()
},
)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to list users");
Error::Unknown
})?;
pub async fn is_email_available(&self, email: impl AsRef<str>) -> Result<bool> {
ThirdPartyHandle::request_email_token(&self.admin, email.as_ref(), None)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to request 3PID token for email");

Ok(exists.users.is_empty())
Error::Unknown
})
.map(|ok| ok.expect("Homeserver does not allow 3PID"))
}

/// Sends a verification code to the given email address
Expand Down Expand Up @@ -218,19 +205,14 @@ impl AccountService {
Error::Unknown
})?;

let avatar_url = Url::parse(DEFAULT_AVATAR_URL).map_err(|err| {
tracing::error!(?err, "Failed to parse default avatar url");
Error::Unknown
})?;

UserService::create(
&self.admin,
user_id,
CreateUserBody {
displayname: Some(dto.username),
password: dto.password.to_string(),
logout_devices: false,
avatar_url: Some(avatar_url),
avatar_url: None,
threepids: vec![ThreePid {
medium: "email".to_string(),
address: dto.email.clone(),
Expand Down Expand Up @@ -288,7 +270,7 @@ impl AccountService {
}

pub async fn whoami(&self, access_token: &Secret) -> Result<Account> {
let session = Session::get(&self.admin, access_token.to_string())
let session = SessionHandle::get(&self.admin, access_token.to_string())
.await
.map_err(|err| {
tracing::error!(?err, "Failed to get session from matrix as client");
Expand Down
53 changes: 26 additions & 27 deletions crates/core/src/auth/service.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::sync::Arc;

use matrix::{
client::resources::login::{Login, LoginFlows as LoginFlowsResponse},
client::resources::login::{LoginFlowResponse, LoginHandle},
ruma_common::OwnedUserId,
Client as MatrixAdminClient,
};
use redis::AsyncCommands;
Expand All @@ -17,15 +18,11 @@ const REDIS_VERIFICATION_CODE_PREFIX: &str = "commune::verification_code::";
/// TTL for the verification code in Redis
const REDIS_VERIFICATION_CODE_SECS: u64 = 60 * 5;

pub struct LoginCredentials {
pub struct PasswordLoginDto {
pub username: String,
pub password: Secret,
}

pub struct LoginCredentialsResponse {
pub access_token: Secret,
}

pub struct AuthService {
admin: Arc<MatrixAdminClient>,
redis: Arc<redis::Client>,
Expand All @@ -36,29 +33,31 @@ impl AuthService {
Self { admin, redis }
}

pub async fn login(&self, credentials: LoginCredentials) -> Result<LoginCredentialsResponse> {
let login_response = Login::login_credentials(
&self.admin,
credentials.username,
credentials.password.inner(),
)
.await
// ???
.unwrap();

Ok(LoginCredentialsResponse {
access_token: Secret::new(login_response.access_token),
})
pub async fn login(&self, credentials: PasswordLoginDto) -> Result<Secret> {
let user_id = OwnedUserId::try_from(credentials.username.as_str()).or(
OwnedUserId::try_from(format!(
"@{}:{}",
credentials.username.as_str(),
self.admin.server_name()
)),
)?;

let login_response =
LoginHandle::login(&self.admin, &user_id, credentials.password.inner())
.await
.unwrap();

Ok(Secret::new(login_response.access_token))
}

pub async fn get_login_flows(&self) -> Result<LoginFlowsResponse> {
match Login::get_login_flows(&self.admin).await {
Ok(flows) => Ok(flows),
Err(err) => {
tracing::error!("Failed to get login flows: {}", err);
Err(Error::Unknown)
}
}
pub async fn get_login_flows(&self) -> Result<LoginFlowResponse> {
LoginHandle::get_login_flows(&self.admin)
.await
.map_err(|e| {
tracing::error!("Failed to get login flows: {}", e);

Error::Unknown
})
}

pub async fn send_verification_code(
Expand Down
5 changes: 5 additions & 0 deletions crates/core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use http::StatusCode;
use thiserror::Error;
use matrix::ruma_common::IdParseError;

use crate::{
account::error::AccountErrorCode, auth::error::AuthErrorCode, mail::error::MailErrorCode,
Expand All @@ -25,6 +26,8 @@ pub enum Error {
Mail(#[from] MailErrorCode),
#[error("An error occured while starting up. {0}")]
Startup(String),
#[error("{0}")]
Validation(#[from] IdParseError),
#[error("Unknown Error Occured")]
Unknown,
}
Expand All @@ -42,6 +45,7 @@ impl HttpStatusCode for Error {
Error::User(err) => err.status_code(),
Error::Mail(err) => err.status_code(),
Error::Room(err) => err.status_code(),
Error::Validation(_) => StatusCode::BAD_REQUEST,
Error::Startup(_) | Error::Unknown => StatusCode::INTERNAL_SERVER_ERROR,
}
}
Expand All @@ -52,6 +56,7 @@ impl HttpStatusCode for Error {
Error::User(err) => err.error_code(),
Error::Mail(err) => err.error_code(),
Error::Room(err) => err.error_code(),
Error::Validation(_) => "BAD_REQUEST",
Error::Startup(_) => "SERVER_STARTUP_ERROR",
Error::Unknown => "UNKNOWN_ERROR",
}
Expand Down
2 changes: 2 additions & 0 deletions crates/matrix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ anyhow = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
mime = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
rand = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
4 changes: 2 additions & 2 deletions crates/matrix/src/client/resources/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tracing::instrument;

use crate::{admin::resources::room::Direction, error::MatrixError, Client};

pub struct EventsService;
pub struct EventsHandle;

#[derive(Debug, Default, Clone, Serialize)]
pub struct GetMessagesQuery {
Expand Down Expand Up @@ -84,7 +84,7 @@ pub struct SendRedactionResponse {
pub event_id: OwnedEventId,
}

impl EventsService {
impl EventsHandle {
#[instrument(skip(client, access_token))]
pub async fn get_event(
client: &Client,
Expand Down
Loading
Loading