mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-14 12:46:49 +00:00
feat: Add support for MSC4484
This commit is contained in:
1 parent
3a20ad7ff2
commit
823ee9f6e1
11 files changed
+190
-76
No files matched your search
+57
-14
@@ -1,4 +1,7 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
collections::BTreeSet,
|
||||
};
|
||||
|
||||
use conduwuit::{
|
||||
Err, Error, Result, err,
|
||||
@@ -9,7 +12,7 @@ use ruma::{
|
||||
DeviceId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedServerName, OwnedUserId, UInt,
|
||||
UserId,
|
||||
api::{
|
||||
IncomingRequest,
|
||||
IncomingRequest, OAuthClientScope,
|
||||
auth_scheme::{
|
||||
AccessToken, AccessTokenOptional, AppserviceToken, AppserviceTokenOptional,
|
||||
AuthScheme, NoAccessToken, NoAuthentication,
|
||||
@@ -84,7 +87,7 @@ impl ClientIdentity {
|
||||
pub(crate) trait CheckAuth: AuthScheme {
|
||||
type Identity: Send;
|
||||
|
||||
fn check<R: IncomingRequest + Any>(
|
||||
fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
incoming_request: &hyper::Request<&[u8]>,
|
||||
authentication: Self::Output,
|
||||
@@ -95,7 +98,7 @@ pub(crate) trait CheckAuth: AuthScheme {
|
||||
impl CheckAuth for ServerSignatures {
|
||||
type Identity = OwnedServerName;
|
||||
|
||||
async fn check<R: IncomingRequest + Any>(
|
||||
async fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
incoming_request: &hyper::Request<&[u8]>,
|
||||
authentication: Self::Output,
|
||||
@@ -155,29 +158,42 @@ impl CheckAuth for ServerSignatures {
|
||||
impl CheckAuth for AccessToken {
|
||||
type Identity = ClientIdentity;
|
||||
|
||||
async fn check<R: IncomingRequest + Any>(
|
||||
async fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
_incoming_request: &hyper::Request<&[u8]>,
|
||||
authentication: Self::Output,
|
||||
query: AuthQueryParams,
|
||||
) -> Result<Self::Identity> {
|
||||
check_access_token(services, &authentication, query, TypeId::of::<R>()).await
|
||||
check_access_token(
|
||||
services,
|
||||
&authentication,
|
||||
query,
|
||||
TypeId::of::<R>(),
|
||||
R::required_client_scopes(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckAuth for AccessTokenOptional {
|
||||
type Identity = Option<ClientIdentity>;
|
||||
|
||||
async fn check<R: IncomingRequest + Any>(
|
||||
async fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
_incoming_request: &hyper::Request<&[u8]>,
|
||||
authentication: Self::Output,
|
||||
query: AuthQueryParams,
|
||||
) -> Result<Self::Identity> {
|
||||
if let Some(authentication) = authentication {
|
||||
check_access_token(services, &authentication, query, TypeId::of::<R>())
|
||||
.await
|
||||
.map(Some)
|
||||
check_access_token(
|
||||
services,
|
||||
&authentication,
|
||||
query,
|
||||
TypeId::of::<R>(),
|
||||
R::required_client_scopes(),
|
||||
)
|
||||
.await
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -200,7 +216,7 @@ impl CheckAuth for AppserviceToken {
|
||||
impl CheckAuth for AppserviceTokenOptional {
|
||||
type Identity = Option<RegistrationInfo>;
|
||||
|
||||
async fn check<R: IncomingRequest + Any>(
|
||||
async fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
_incoming_request: &hyper::Request<&[u8]>,
|
||||
authentication: Self::Output,
|
||||
@@ -219,7 +235,7 @@ impl CheckAuth for AppserviceTokenOptional {
|
||||
impl CheckAuth for NoAuthentication {
|
||||
type Identity = ();
|
||||
|
||||
fn check<R: IncomingRequest + Any>(
|
||||
fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
_services: &Services,
|
||||
_incoming_request: &hyper::Request<&[u8]>,
|
||||
_authentication: Self::Output,
|
||||
@@ -232,7 +248,7 @@ impl CheckAuth for NoAuthentication {
|
||||
impl CheckAuth for NoAccessToken {
|
||||
type Identity = Option<ClientIdentity>;
|
||||
|
||||
async fn check<R: IncomingRequest + Any>(
|
||||
async fn check<R: IncomingRequest<Authentication = Self> + Any>(
|
||||
services: &Services,
|
||||
incoming_request: &hyper::Request<&[u8]>,
|
||||
_authentication: Self::Output,
|
||||
@@ -245,7 +261,7 @@ impl CheckAuth for NoAccessToken {
|
||||
})?;
|
||||
|
||||
if let Some(authentication) = authentication {
|
||||
check_access_token(services, &authentication, query, TypeId::of::<R>())
|
||||
check_access_token(services, &authentication, query, TypeId::of::<R>(), &[])
|
||||
.await
|
||||
.map(Some)
|
||||
} else {
|
||||
@@ -259,6 +275,7 @@ async fn check_access_token(
|
||||
token: &str,
|
||||
query: AuthQueryParams,
|
||||
route: TypeId,
|
||||
required_scopes: &[OAuthClientScope],
|
||||
) -> Result<ClientIdentity> {
|
||||
if token.is_empty() {
|
||||
return Err!(Request(Unauthorized("Empty access token.")));
|
||||
@@ -292,6 +309,32 @@ async fn check_access_token(
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the user has the right scopes to use the route
|
||||
let user_scopes = if let Some(session_info) = services
|
||||
.oauth
|
||||
.get_session_info_for_device(&sender_user, &sender_device)
|
||||
.await
|
||||
{
|
||||
session_info.scopes
|
||||
} else {
|
||||
let mut scopes = BTreeSet::from_iter([OAuthClientScope::ApiFullAccess]);
|
||||
|
||||
if services.admin.user_is_admin(&sender_user).await {
|
||||
scopes.insert(OAuthClientScope::ServerAdministration);
|
||||
}
|
||||
|
||||
scopes
|
||||
};
|
||||
|
||||
if !required_scopes
|
||||
.iter()
|
||||
.any(|scope| user_scopes.contains(scope))
|
||||
{
|
||||
return Err!(Request(Forbidden(
|
||||
"You do not have permission to access this endpoint."
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(ClientIdentity::User { sender_user, sender_device })
|
||||
} else if let Ok(appservice_info) = services.appservice.find_from_token(token).await {
|
||||
let Ok(sender_user) = query.user_id.clone().map_or_else(
|
||||
|
||||
Reference in new issue
Block a user