use anyhow::anyhow;
use matrix_sdk::{
Client,
authentication::oauth::{
OAuthAuthorizationData,
registration::{ApplicationType, ClientMetadata, Localized, OAuthGrantType},
},
ruma::serde::Raw,
utils::UrlOrQuery,
};
use tokio::sync::mpsc;
use tracing::{debug, error, info};
use url::Url;
use crate::{
CLIENT,
init::singletons::{TEMP_CLIENT, TEMP_CLIENT_SESSION, get_event_bridge},
models::events::EmitEvent,
};
fn client_metadata(client_uri: Url, callback_url: Url) -> Raw<ClientMetadata> {
let client_uri = Localized::new(client_uri, None);
debug!("Using client URI {client_uri:?} and callback_url {callback_url:?}");
let metadata = ClientMetadata {
client_name: Some(Localized::new("Matrix Svelte Client".to_owned(), [])),
policy_uri: None,
logo_uri: None,
tos_uri: None,
..ClientMetadata::new(
ApplicationType::Native,
vec![OAuthGrantType::AuthorizationCode {
redirect_uris: vec![callback_url],
}],
client_uri,
)
};
Raw::new(&metadata).expect("Couldn't serialize client metadata")
}
pub(crate) async fn register_and_login_oauth(
client: &Client,
mut oauth_deeplink_receiver: mpsc::Receiver<Url>,
client_uri: &Url,
callback_url: &Url,
) -> anyhow::Result<String> {
let oauth = client.oauth();
loop {
let OAuthAuthorizationData { url, .. } = oauth
.login(
callback_url.to_owned(),
None,
Some(client_metadata(client_uri.to_owned(), callback_url.to_owned()).into()),
None,
)
.build()
.await?;
get_event_bridge()
.expect("bridge should be defined at this point")
.emit(EmitEvent::OAuthUrl(url.to_string()));
let query_string = oauth_deeplink_receiver
.recv()
.await
.expect("no url was sent");
match oauth
.finish_login(UrlOrQuery::Query(
query_string
.query()
.expect("no query params passed to auth callback")
.to_owned(),
))
.await
{
Ok(()) => {
info!("Logged in");
break;
}
Err(err) => {
error!("Error: failed to login: {err}");
continue;
}
}
}
let user_session = oauth
.full_session()
.expect("Should have session after login");
let full = super::session::FullMatrixSession::new(
TEMP_CLIENT_SESSION
.lock()
.unwrap()
.clone()
.ok_or(anyhow!("No temporary session has been set !"))?,
matrix_sdk::AuthSession::OAuth(Box::new(user_session)),
);
CLIENT
.set(
TEMP_CLIENT
.lock
.lock()
.unwrap()
.clone()
.ok_or(anyhow!("No temporary client was set !"))?,
)
.expect("Client already set !");
let serialized = serde_json::to_string(&full)?;
Ok(serialized)
}