diff --git a/crates/core/src/handlers/oauth2/authorization.rs b/crates/core/src/handlers/oauth2/authorization.rs index b689752e..f0c5906b 100644 --- a/crates/core/src/handlers/oauth2/authorization.rs +++ b/crates/core/src/handlers/oauth2/authorization.rs @@ -35,6 +35,7 @@ use oauth2_types::{ AccessTokenResponse, AuthorizationRequest, AuthorizationResponse, ResponseMode, ResponseType, }, + scope::ScopeToken, }; use rand::{distributions::Alphanumeric, thread_rng, Rng}; use serde::{Deserialize, Serialize}; @@ -353,11 +354,27 @@ async fn get( None }; + // Generate the device ID + // TODO: this should probably be done somewhere else? + let device_id: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(10) + .map(char::from) + .collect(); + let device_scope: ScopeToken = format!("urn:matrix:device:{}", device_id) + .parse() + .wrap_error()?; + let scope = { + let mut s = params.auth.scope.clone(); + s.insert(device_scope); + s + }; + let grant = new_authorization_grant( &mut txn, client.client_id.clone(), redirect_uri.clone(), - params.auth.scope, + scope, code, params.auth.state, params.auth.nonce, diff --git a/crates/oauth2-types/src/scope.rs b/crates/oauth2-types/src/scope.rs index 0352f73b..1cf6ec92 100644 --- a/crates/oauth2-types/src/scope.rs +++ b/crates/oauth2-types/src/scope.rs @@ -28,17 +28,20 @@ pub struct InvalidScope; pub struct ScopeToken(Cow<'static, str>); impl ScopeToken { - const fn well_known(token: &'static str) -> Self { + /// Create a `ScopeToken` from a static string. The validity of it is not + /// checked since it has to be valid in const contexts + #[must_use] + pub const fn from_static(token: &'static str) -> Self { Self(Cow::Borrowed(token)) } } -pub const OPENID: ScopeToken = ScopeToken::well_known("openid"); -pub const PROFILE: ScopeToken = ScopeToken::well_known("profile"); -pub const EMAIL: ScopeToken = ScopeToken::well_known("email"); -pub const ADDRESS: ScopeToken = ScopeToken::well_known("address"); -pub const PHONE: ScopeToken = ScopeToken::well_known("phone"); -pub const OFFLINE_ACCESS: ScopeToken = ScopeToken::well_known("offline_access"); +pub const OPENID: ScopeToken = ScopeToken::from_static("openid"); +pub const PROFILE: ScopeToken = ScopeToken::from_static("profile"); +pub const EMAIL: ScopeToken = ScopeToken::from_static("email"); +pub const ADDRESS: ScopeToken = ScopeToken::from_static("address"); +pub const PHONE: ScopeToken = ScopeToken::from_static("phone"); +pub const OFFLINE_ACCESS: ScopeToken = ScopeToken::from_static("offline_access"); // As per RFC6749 appendix A: // https://datatracker.ietf.org/doc/html/rfc6749#appendix-A @@ -114,6 +117,10 @@ impl Scope { .map(|token| self.0.contains(&token)) .unwrap_or(false) } + + pub fn insert(&mut self, value: ScopeToken) -> bool { + self.0.insert(value) + } } impl ToString for Scope {