mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
fix: Return the correct error code for expired access tokens
This commit is contained in:
+23
-4
@@ -1,6 +1,7 @@
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
use conduwuit::{Err, Result, err};
|
use conduwuit::{Err, Error, Result, err};
|
||||||
|
use http::StatusCode;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
|
DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
|
||||||
api::{
|
api::{
|
||||||
@@ -10,12 +11,15 @@ use ruma::{
|
|||||||
AuthScheme, NoAccessToken, NoAuthentication,
|
AuthScheme, NoAccessToken, NoAuthentication,
|
||||||
},
|
},
|
||||||
client,
|
client,
|
||||||
|
error::{ErrorKind, UnknownTokenErrorData},
|
||||||
federation::authentication::ServerSignatures,
|
federation::authentication::ServerSignatures,
|
||||||
},
|
},
|
||||||
|
assign,
|
||||||
};
|
};
|
||||||
use service::{
|
use service::{
|
||||||
Services,
|
Services,
|
||||||
server_keys::{PubKeyMap, PubKeys},
|
server_keys::{PubKeyMap, PubKeys},
|
||||||
|
users::AccessTokenStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{router::args::AuthQueryParams, service::appservice::RegistrationInfo};
|
use crate::{router::args::AuthQueryParams, service::appservice::RegistrationInfo};
|
||||||
@@ -153,7 +157,18 @@ impl CheckAuth for AccessToken {
|
|||||||
query: AuthQueryParams,
|
query: AuthQueryParams,
|
||||||
route: TypeId,
|
route: TypeId,
|
||||||
) -> Result<Self::Identity> {
|
) -> Result<Self::Identity> {
|
||||||
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
|
// Locked users can only use /logout and /logout/all
|
||||||
if services
|
if services
|
||||||
.users
|
.users
|
||||||
@@ -164,7 +179,7 @@ impl CheckAuth for AccessToken {
|
|||||||
if !(route == TypeId::of::<client::session::logout::v3::Request>()
|
if !(route == TypeId::of::<client::session::logout::v3::Request>()
|
||||||
|| route == TypeId::of::<client::session::logout_all::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.")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +230,11 @@ impl CheckAuth for AccessToken {
|
|||||||
appservice_info: Box::new(appservice_info),
|
appservice_info: Box::new(appservice_info),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err!(Request(Unauthorized("Invalid access token.")))
|
Err(Error::Request(
|
||||||
|
ErrorKind::UnknownToken(UnknownTokenErrorData::new()),
|
||||||
|
"Invalid token".into(),
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ impl crate::Service for Service {
|
|||||||
for (id, registration) in appservices {
|
for (id, registration) in appservices {
|
||||||
// During startup, resolve any token collisions in favour of appservices
|
// During startup, resolve any token collisions in favour of appservices
|
||||||
// by logging out conflicting user devices
|
// by logging out conflicting user devices
|
||||||
if let Some((user_id, device_id)) = self
|
if let Some((user_id, device_id, _)) = self
|
||||||
.services
|
.services
|
||||||
.users
|
.users
|
||||||
.find_from_token(®istration.as_token)
|
.find_from_token(®istration.as_token)
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ impl HashedPassword {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The status of an access token.
|
||||||
|
pub enum AccessTokenStatus {
|
||||||
|
Valid,
|
||||||
|
Expired,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
services: Services,
|
services: Services,
|
||||||
db: Data,
|
db: Data,
|
||||||
@@ -347,7 +353,10 @@ impl Service {
|
|||||||
pub async fn count(&self) -> usize { self.db.userid_password.count().await }
|
pub async fn count(&self) -> usize { self.db.userid_password.count().await }
|
||||||
|
|
||||||
/// Find out which user an access token belongs to.
|
/// Find out which user an access token belongs to.
|
||||||
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)> {
|
||||||
let user = self
|
let user = self
|
||||||
.db
|
.db
|
||||||
.token_userdeviceid
|
.token_userdeviceid
|
||||||
@@ -357,11 +366,11 @@ impl Service {
|
|||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// Check if the token has expired
|
// Check if the token has expired
|
||||||
if let Some(user) = &user {
|
if let Some((user_id, device_id)) = user {
|
||||||
if let Some(expires) = self
|
if let Some(expires) = self
|
||||||
.db
|
.db
|
||||||
.userdeviceid_tokenexpires
|
.userdeviceid_tokenexpires
|
||||||
.qry(user)
|
.qry(&(&user_id, &device_id))
|
||||||
.await
|
.await
|
||||||
.deserialized::<u64>()
|
.deserialized::<u64>()
|
||||||
.ok()
|
.ok()
|
||||||
@@ -372,12 +381,14 @@ impl Service {
|
|||||||
.expect("expiry time should not overflow SystemTime");
|
.expect("expiry time should not overflow SystemTime");
|
||||||
|
|
||||||
if SystemTime::now() > expires_at {
|
if SystemTime::now() > expires_at {
|
||||||
return None;
|
return Some((user_id, device_id, AccessTokenStatus::Expired));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
user
|
Some((user_id, device_id, AccessTokenStatus::Valid))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all users on this homeserver.
|
/// Returns an iterator over all users on this homeserver.
|
||||||
|
|||||||
Reference in New Issue
Block a user