Start Matrix client authentication

This commit is contained in:
2025-11-05 16:30:06 +01:00
parent a44327ddb0
commit 3dab9f41d2
13 changed files with 2960 additions and 10 deletions

View 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)
}
}