Automatically disconnect user when token is invalid
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::matrix_connection::matrix_manager::MatrixManagerMsg;
|
||||
use crate::users::UserEmail;
|
||||
use crate::utils::rand_utils::rand_string;
|
||||
use anyhow::Context;
|
||||
use matrix_sdk::authentication::oauth::error::OAuthDiscoveryError;
|
||||
use matrix_sdk::authentication::oauth::error::{
|
||||
BasicErrorResponseType, OAuthDiscoveryError, RequestTokenError,
|
||||
};
|
||||
use matrix_sdk::authentication::oauth::{
|
||||
ClientId, OAuthError, OAuthSession, UrlOrQuery, UserSession,
|
||||
};
|
||||
use matrix_sdk::ruma::serde::Raw;
|
||||
use matrix_sdk::{Client, ClientBuildError};
|
||||
use matrix_sdk::{Client, ClientBuildError, RefreshTokenError};
|
||||
use ractor::ActorRef;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
@@ -48,6 +52,10 @@ enum MatrixClientError {
|
||||
DecodeStoredSession(serde_json::Error),
|
||||
#[error("Failed to restore stored session! {0}")]
|
||||
RestoreSession(matrix_sdk::Error),
|
||||
#[error("Failed to disconnect user! {0}")]
|
||||
DisconnectUser(anyhow::Error),
|
||||
#[error("Failed to refresh access token! {0}")]
|
||||
InitialRefreshToken(RefreshTokenError),
|
||||
#[error("Failed to parse auth redirect URL! {0}")]
|
||||
ParseAuthRedirectURL(url::ParseError),
|
||||
#[error("Failed to build auth request! {0}")]
|
||||
@@ -66,13 +74,17 @@ pub struct FinishMatrixAuth {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MatrixClient {
|
||||
manager: ActorRef<MatrixManagerMsg>,
|
||||
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> {
|
||||
pub async fn build_client(
|
||||
manager: ActorRef<MatrixManagerMsg>,
|
||||
email: &UserEmail,
|
||||
) -> anyhow::Result<Self> {
|
||||
// Check if we are restoring a previous state
|
||||
let session_file_path = AppConfig::get().user_matrix_session_file_path(email);
|
||||
let is_restoring = session_file_path.is_file();
|
||||
@@ -102,8 +114,14 @@ impl MatrixClient {
|
||||
.await
|
||||
.map_err(MatrixClientError::BuildMatrixClient)?;
|
||||
|
||||
let client = Self {
|
||||
manager,
|
||||
email: email.clone(),
|
||||
client,
|
||||
};
|
||||
|
||||
// Check metadata
|
||||
let oauth = client.oauth();
|
||||
let oauth = client.client.oauth();
|
||||
let server_metadata = oauth
|
||||
.server_metadata()
|
||||
.await
|
||||
@@ -118,20 +136,33 @@ impl MatrixClient {
|
||||
)
|
||||
.map_err(MatrixClientError::DecodeStoredSession)?;
|
||||
|
||||
// Restore data
|
||||
// Restore session
|
||||
client
|
||||
.client
|
||||
.restore_session(OAuthSession {
|
||||
client_id: session.client_id,
|
||||
user: session.user_session,
|
||||
})
|
||||
.await
|
||||
.map_err(MatrixClientError::RestoreSession)?;
|
||||
}
|
||||
|
||||
let client = Self {
|
||||
email: email.clone(),
|
||||
client,
|
||||
};
|
||||
// Force token refresh to make sure session is still alive, otherwise disconnect user
|
||||
if let Err(refresh_error) = client.client.oauth().refresh_access_token().await {
|
||||
if let RefreshTokenError::OAuth(e) = &refresh_error
|
||||
&& let OAuthError::RefreshToken(RequestTokenError::ServerResponse(e)) = &**e
|
||||
&& e.error() == &BasicErrorResponseType::InvalidGrant
|
||||
{
|
||||
log::warn!(
|
||||
"Refresh token rejected by server, token must have been invalidated! {refresh_error}"
|
||||
);
|
||||
client
|
||||
.disconnect()
|
||||
.await
|
||||
.map_err(MatrixClientError::DisconnectUser)?;
|
||||
}
|
||||
return Err(MatrixClientError::InitialRefreshToken(refresh_error).into());
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically save session when token gets refreshed
|
||||
client.setup_background_session_save().await;
|
||||
@@ -212,6 +243,13 @@ impl MatrixClient {
|
||||
match update {
|
||||
matrix_sdk::SessionChange::UnknownToken { soft_logout } => {
|
||||
log::warn!("Received an unknown token error; soft logout? {soft_logout:?}");
|
||||
if let Err(e) = this
|
||||
.manager
|
||||
.cast(MatrixManagerMsg::DisconnectClient(this.email))
|
||||
{
|
||||
log::warn!("Failed to propagate invalid token error: {e}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
matrix_sdk::SessionChange::TokensRefreshed => {
|
||||
// The tokens have been refreshed, persist them to disk.
|
||||
@@ -254,4 +292,16 @@ impl MatrixClient {
|
||||
log::debug!("Updating the stored session: done!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Disconnect user from client
|
||||
pub async fn disconnect(self) -> anyhow::Result<()> {
|
||||
if let Err(e) = self.client.logout().await {
|
||||
log::warn!("Failed to send logout request: {e}");
|
||||
}
|
||||
|
||||
// Destroy user associated data
|
||||
Self::destroy_data(&self.email)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user