fix: Return the correct error code for expired access tokens

This commit is contained in:
Ginger committed 2026-06-29 09:35:48 -04:00
1 parent 0d806a2038
commit b37480d6b2
5 files changed
+44 -12

No files matched your search

+24 -4
View File
@@ -1,6 +1,7 @@
use std::any::{Any, TypeId};
use conduwuit::{Err, Result, err};
use conduwuit::{Err, Error, Result, err};
use http::StatusCode;
use ruma::{
DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
api::{
@@ -10,12 +11,15 @@ use ruma::{
AuthScheme, NoAccessToken, NoAuthentication,
},
client,
error::{ErrorKind, UnknownTokenErrorData},
federation::authentication::ServerSignatures,
},
assign,
};
use service::{
Services,
server_keys::{PubKeyMap, PubKeys},
users::AccessTokenStatus,
};
use crate::{router::args::AuthQueryParams, service::appservice::RegistrationInfo};
@@ -165,8 +169,20 @@ impl CheckAuth for AccessToken {
if output.is_empty() {
return Err!(Request(Unauthorized("Missing access token.")));
}
if let Some((sender_user, sender_device)) = services.users.find_from_token(&output).await
if let Some((sender_user, sender_device, status)) =
services.users.find_from_token(&output).await
{
// If the token is expired we return a soft logout
if matches!(status, AccessTokenStatus::Expired) {
return Err(Error::Request(
ErrorKind::UnknownToken(
assign!(UnknownTokenErrorData::new(), { soft_logout: true }),
),
"This token has expired".into(),
StatusCode::UNAUTHORIZED,
));
}
// Locked users can only use /logout and /logout/all
if services
.users
@@ -177,7 +193,7 @@ impl CheckAuth for AccessToken {
if !(route == TypeId::of::<client::session::logout::v3::Request>()
|| route == TypeId::of::<client::session::logout_all::v3::Request>())
{
return Err!(Request(Unauthorized("Your account is locked.")));
return Err!(Request(UserLocked("Your account is locked.")));
}
}
@@ -228,7 +244,11 @@ impl CheckAuth for AccessToken {
appservice_info: Box::new(appservice_info),
})
} else {
Err!(Request(Unauthorized("Invalid access token.")))
Err(Error::Request(
ErrorKind::UnknownToken(UnknownTokenErrorData::new()),
"Invalid token".into(),
StatusCode::UNAUTHORIZED,
))
}
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ impl crate::Service for Service {
for (id, registration) in appservices {
// During startup, resolve any token collisions in favour of appservices
// by logging out conflicting user devices
if let Some((user_id, device_id)) = self
if let Some((user_id, device_id, _)) = self
.services
.users
.find_from_token(&registration.as_token)
+4 -2
View File
@@ -314,8 +314,10 @@ impl Service {
.deserialized::<RefreshTokenInfo>()
{
(refresh_token_info.user_id, refresh_token_info.device_id)
} else if let Some(user) = self.services.users.find_from_token(&token).await {
user
} else if let Some((user_id, device_id, _)) =
self.services.users.find_from_token(&token).await
{
(user_id, device_id)
} else {
return Err!("Invalid token");
};
+14 -5
View File
@@ -14,6 +14,12 @@ use ruminuwuity::invite_permission_config::{FilterLevel, InvitePermissionConfigE
use crate::users::{HashedPassword, UserSuspension};
/// The status of an access token.
pub enum AccessTokenStatus {
Valid,
Expired,
}
impl super::Service {
/// Returns true/false based on whether the recipient/receiving user has
/// ignored the sender.
@@ -242,10 +248,13 @@ impl super::Service {
/// Find out which user an access token belongs to. Will panic if the access
/// token is empty.
pub async fn find_from_token(&self, token: &str) -> Option<(OwnedUserId, OwnedDeviceId)> {
pub async fn find_from_token(
&self,
token: &str,
) -> Option<(OwnedUserId, OwnedDeviceId, AccessTokenStatus)> {
assert!(!token.is_empty(), "Empty access token");
let user = self
let (user_id, device_id) = self
.db
.token_userdeviceid
.get(token)
@@ -257,7 +266,7 @@ impl super::Service {
if let Some(expires) = self
.db
.userdeviceid_tokenexpires
.qry(&user)
.qry(&(&user_id, &device_id))
.await
.deserialized::<u64>()
.ok()
@@ -268,11 +277,11 @@ impl super::Service {
.expect("expiry time should not overflow SystemTime");
if SystemTime::now() > expires_at {
return None;
return Some((user_id, device_id, AccessTokenStatus::Expired));
}
}
Some(user)
Some((user_id, device_id, AccessTokenStatus::Valid))
}
/// Returns an iterator over all users on this homeserver.
+1
View File
@@ -7,6 +7,7 @@ pub(super) mod profile;
use std::{mem, sync::Arc};
pub use account::AccessTokenStatus;
use conduwuit::{
Err, Error, Result, Server, err,
utils::{self},