Start Matrix client authentication
This commit is contained in:
115
matrixgw_backend/src/matrix_connection/matrix_client.rs
Normal file
115
matrixgw_backend/src/matrix_connection/matrix_client.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::users::UserEmail;
|
||||
use crate::utils::rand_utils::rand_string;
|
||||
use matrix_sdk::authentication::oauth::OAuthError;
|
||||
use matrix_sdk::authentication::oauth::error::OAuthDiscoveryError;
|
||||
use matrix_sdk::ruma::serde::Raw;
|
||||
use matrix_sdk::{Client, ClientBuildError};
|
||||
use url::Url;
|
||||
|
||||
/// Matrix Gateway session errors
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
enum MatrixClientError {
|
||||
#[error("Failed to create Matrix database storage directory! {0}")]
|
||||
CreateMatrixDbDir(std::io::Error),
|
||||
#[error("Failed to create database passphrase! {0}")]
|
||||
CreateDbPassphrase(std::io::Error),
|
||||
#[error("Failed to read database passphrase! {0}")]
|
||||
ReadDbPassphrase(std::io::Error),
|
||||
#[error("Failed to build Matrix client! {0}")]
|
||||
BuildMatrixClient(ClientBuildError),
|
||||
#[error("Failed to clear Matrix database storage directory! {0}")]
|
||||
ClearMatrixDbDir(std::io::Error),
|
||||
#[error("Failed to remove database passphrase! {0}")]
|
||||
ClearDbPassphrase(std::io::Error),
|
||||
#[error("Failed to fetch server metadata! {0}")]
|
||||
FetchServerMetadata(OAuthDiscoveryError),
|
||||
#[error("Failed to parse auth redirect URL! {0}")]
|
||||
ParseAuthRedirectURL(url::ParseError),
|
||||
#[error("Failed to build auth request! {0}")]
|
||||
BuildAuthRequest(OAuthError),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MatrixClient {
|
||||
pub email: UserEmail,
|
||||
pub client: Client,
|
||||
}
|
||||
|
||||
impl MatrixClient {
|
||||
/// Start to build Matrix client to initiate user authentication
|
||||
pub async fn build_client(email: &UserEmail) -> anyhow::Result<Self> {
|
||||
let db_path = AppConfig::get().user_matrix_db_path(email);
|
||||
std::fs::create_dir_all(&db_path).map_err(MatrixClientError::CreateMatrixDbDir)?;
|
||||
|
||||
// Generate or load passphrase
|
||||
let passphrase_path = AppConfig::get().user_matrix_passphrase_path(email);
|
||||
if !passphrase_path.exists() {
|
||||
std::fs::write(&passphrase_path, rand_string(32))
|
||||
.map_err(MatrixClientError::CreateDbPassphrase)?;
|
||||
}
|
||||
let passphrase = std::fs::read_to_string(passphrase_path)
|
||||
.map_err(MatrixClientError::ReadDbPassphrase)?;
|
||||
|
||||
let client = Client::builder()
|
||||
.server_name_or_homeserver_url(&AppConfig::get().matrix_homeserver)
|
||||
// Automatically refresh tokens if needed
|
||||
.handle_refresh_tokens()
|
||||
.sqlite_store(&db_path, Some(&passphrase))
|
||||
.build()
|
||||
.await
|
||||
.map_err(MatrixClientError::BuildMatrixClient)?;
|
||||
|
||||
// Check metadata
|
||||
let server_metadata = client
|
||||
.oauth()
|
||||
.server_metadata()
|
||||
.await
|
||||
.map_err(MatrixClientError::FetchServerMetadata)?;
|
||||
log::info!("OAuth2 server issuer: {:?}", server_metadata.issuer);
|
||||
|
||||
// TODO : restore client if client already existed
|
||||
|
||||
Ok(Self {
|
||||
email: email.clone(),
|
||||
client,
|
||||
})
|
||||
}
|
||||
|
||||
/// Destroy this Matrix client instance
|
||||
pub fn destroy(&self) -> anyhow::Result<()> {
|
||||
let db_path = AppConfig::get().user_matrix_db_path(&self.email);
|
||||
if db_path.is_file() {
|
||||
std::fs::remove_dir_all(&db_path).map_err(MatrixClientError::ClearMatrixDbDir)?;
|
||||
}
|
||||
|
||||
let passphrase_path = AppConfig::get().user_matrix_passphrase_path(&self.email);
|
||||
if passphrase_path.is_file() {
|
||||
std::fs::remove_file(passphrase_path).map_err(MatrixClientError::ClearDbPassphrase)?;
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Initiate oauth authentication
|
||||
pub async fn initiate_login(&self) -> anyhow::Result<Url> {
|
||||
let oauth = self.client.oauth();
|
||||
|
||||
let metadata = AppConfig::get().matrix_client_metadata();
|
||||
let client_metadata = Raw::new(&metadata).expect("Couldn't serialize client metadata");
|
||||
|
||||
let auth = oauth
|
||||
.login(
|
||||
Url::parse(&AppConfig::get().matrix_oauth_redirect_url())
|
||||
.map_err(MatrixClientError::ParseAuthRedirectURL)?,
|
||||
None,
|
||||
Some(client_metadata.into()),
|
||||
None,
|
||||
)
|
||||
.build()
|
||||
.await
|
||||
.map_err(MatrixClientError::BuildAuthRequest)?;
|
||||
|
||||
Ok(auth.url)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user