From 1eecdeef999dbdfe69ce5df7dafe724073d97f6d Mon Sep 17 00:00:00 2001 From: "D. Scott Boggs" Date: Fri, 29 Sep 2023 06:15:23 -0400 Subject: Add OAuth revocation method --- entities/src/auth/mod.rs | 6 +++ entities/src/forms/oauth/token.rs | 70 --------------------------- entities/src/forms/oauth/token/acquisition.rs | 70 +++++++++++++++++++++++++++ entities/src/forms/oauth/token/mod.rs | 5 ++ entities/src/forms/oauth/token/revocation.rs | 23 +++++++++ src/mastodon.rs | 2 + 6 files changed, 106 insertions(+), 70 deletions(-) delete mode 100644 entities/src/forms/oauth/token.rs create mode 100644 entities/src/forms/oauth/token/acquisition.rs create mode 100644 entities/src/forms/oauth/token/mod.rs create mode 100644 entities/src/forms/oauth/token/revocation.rs diff --git a/entities/src/auth/mod.rs b/entities/src/auth/mod.rs index 7a125a2..3fbda74 100644 --- a/entities/src/auth/mod.rs +++ b/entities/src/auth/mod.rs @@ -3,8 +3,14 @@ pub mod scopes; pub mod token; pub use scopes::{Scope, Scopes}; +use serde::{Deserialize, Serialize}; pub use token::Token; pub mod prelude { pub use super::{scopes, Scope, Scopes, Token}; } + +/// The empty object is returned by a request to revoke an OAuth token. This +/// type represents that. +#[derive(Debug, Default, Copy, Clone, Deserialize, Serialize)] +pub struct RevocationResponse {} diff --git a/entities/src/forms/oauth/token.rs b/entities/src/forms/oauth/token.rs deleted file mode 100644 index c47bf21..0000000 --- a/entities/src/forms/oauth/token.rs +++ /dev/null @@ -1,70 +0,0 @@ -use derive_builder::Builder; -use derive_is_enum_variant::is_enum_variant; -use serde::{Deserialize, Serialize}; - -use crate::prelude::{ClientId, ClientSecret, Scopes}; - -/// The value for the [`TokenRequest`] `grant_type` field. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, is_enum_variant, Default)] -#[serde(rename_all = "snake_case")] -pub enum GrantType { - AuthorizationCode, - #[default] - ClientCredentials, -} - -#[derive(Clone, Builder, Debug, Serialize, Deserialize, PartialEq)] -#[builder( - custom_constructor, - derive(Debug, PartialEq), - build_fn(error = "crate::Error", private, name = "try_build") -)] -/// A form which can be built to obtain an access token, to be used during API -/// calls that are not public. -/// -/// See also [the API documentation](https://docs.joinmastodon.org/methods/oauth/#token) -pub struct TokenRequest { - /// Set equal to [`GrantType::AuthorizationCode`] if code is provided in - /// order to gain user-level access. Otherwise, set equal to - /// [`GrantType::ClientCredentials`] to obtain app-level access only. - #[builder(default)] - grant_type: GrantType, - /// A user authorization code, obtained via - /// [`Mastodon::request_oauth_authorization()`](https://docs.rs/mastodon-async/latest/mastodon_async/mastodon/struct.Mastodon.html#method.request_oauth_authorization) - #[builder(setter(into, strip_option))] - code: Option, - /// The client ID, obtained during app registration. - #[builder(private)] - client_id: ClientId, - /// The client secret, obtained during app registration. - #[builder(private)] - client_secret: ClientSecret, - /// Set a URI to redirect the user to. If this parameter is set to - /// `"urn:ietf:wg:oauth:2.0:oob"` then the token will be shown instead. Must - /// match one of the `redirect_uri`s declared during app registration. - #[builder(default = r#""urn:ietf:wg:oauth:2.0:oob".into()"#)] - redirect_uri: String, - /// List of requested OAuth scopes. If code was provided, then this must be - /// equal to the scope requested from the user. Otherwise, it must be a - /// subset of scopes declared during app registration. If not provided, - /// defaults to [`Scope::Read(None)`](crate::prelude::Scope::Read). - #[builder(setter(strip_option))] - #[serde(skip_serializing_if = "Option::is_none")] - scope: Option, -} - -impl TokenRequest { - pub fn builder(client_id: ClientId, client_secret: ClientSecret) -> TokenRequestBuilder { - TokenRequestBuilder::create_empty() - .client_id(client_id) - .client_secret(client_secret) - .to_owned() - } -} - -impl TokenRequestBuilder { - pub fn build(&self) -> TokenRequest { - self.try_build() - .expect("One or more required fields are missing!") - } -} diff --git a/entities/src/forms/oauth/token/acquisition.rs b/entities/src/forms/oauth/token/acquisition.rs new file mode 100644 index 0000000..c47bf21 --- /dev/null +++ b/entities/src/forms/oauth/token/acquisition.rs @@ -0,0 +1,70 @@ +use derive_builder::Builder; +use derive_is_enum_variant::is_enum_variant; +use serde::{Deserialize, Serialize}; + +use crate::prelude::{ClientId, ClientSecret, Scopes}; + +/// The value for the [`TokenRequest`] `grant_type` field. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, is_enum_variant, Default)] +#[serde(rename_all = "snake_case")] +pub enum GrantType { + AuthorizationCode, + #[default] + ClientCredentials, +} + +#[derive(Clone, Builder, Debug, Serialize, Deserialize, PartialEq)] +#[builder( + custom_constructor, + derive(Debug, PartialEq), + build_fn(error = "crate::Error", private, name = "try_build") +)] +/// A form which can be built to obtain an access token, to be used during API +/// calls that are not public. +/// +/// See also [the API documentation](https://docs.joinmastodon.org/methods/oauth/#token) +pub struct TokenRequest { + /// Set equal to [`GrantType::AuthorizationCode`] if code is provided in + /// order to gain user-level access. Otherwise, set equal to + /// [`GrantType::ClientCredentials`] to obtain app-level access only. + #[builder(default)] + grant_type: GrantType, + /// A user authorization code, obtained via + /// [`Mastodon::request_oauth_authorization()`](https://docs.rs/mastodon-async/latest/mastodon_async/mastodon/struct.Mastodon.html#method.request_oauth_authorization) + #[builder(setter(into, strip_option))] + code: Option, + /// The client ID, obtained during app registration. + #[builder(private)] + client_id: ClientId, + /// The client secret, obtained during app registration. + #[builder(private)] + client_secret: ClientSecret, + /// Set a URI to redirect the user to. If this parameter is set to + /// `"urn:ietf:wg:oauth:2.0:oob"` then the token will be shown instead. Must + /// match one of the `redirect_uri`s declared during app registration. + #[builder(default = r#""urn:ietf:wg:oauth:2.0:oob".into()"#)] + redirect_uri: String, + /// List of requested OAuth scopes. If code was provided, then this must be + /// equal to the scope requested from the user. Otherwise, it must be a + /// subset of scopes declared during app registration. If not provided, + /// defaults to [`Scope::Read(None)`](crate::prelude::Scope::Read). + #[builder(setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + scope: Option, +} + +impl TokenRequest { + pub fn builder(client_id: ClientId, client_secret: ClientSecret) -> TokenRequestBuilder { + TokenRequestBuilder::create_empty() + .client_id(client_id) + .client_secret(client_secret) + .to_owned() + } +} + +impl TokenRequestBuilder { + pub fn build(&self) -> TokenRequest { + self.try_build() + .expect("One or more required fields are missing!") + } +} diff --git a/entities/src/forms/oauth/token/mod.rs b/entities/src/forms/oauth/token/mod.rs new file mode 100644 index 0000000..d40e417 --- /dev/null +++ b/entities/src/forms/oauth/token/mod.rs @@ -0,0 +1,5 @@ +mod acquisition; +pub mod revocation; + +pub use acquisition::*; +pub use revocation::Revocation; diff --git a/entities/src/forms/oauth/token/revocation.rs b/entities/src/forms/oauth/token/revocation.rs new file mode 100644 index 0000000..b64a970 --- /dev/null +++ b/entities/src/forms/oauth/token/revocation.rs @@ -0,0 +1,23 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ClientId, ClientSecret, OAuthToken}; + +/// Form to be submitted when revoking an OAuth token. +/// +/// See also the [API Documentation](https://docs.joinmastodon.org/methods/oauth/#revoke) +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct Revocation { + client_id: ClientId, + client_secret: ClientSecret, + token: OAuthToken, +} + +impl Revocation { + pub fn new(client_id: ClientId, client_secret: ClientSecret, token: OAuthToken) -> Self { + Self { + client_id, + client_secret, + token, + } + } +} diff --git a/src/mastodon.rs b/src/mastodon.rs index caafce1..795fabb 100644 --- a/src/mastodon.rs +++ b/src/mastodon.rs @@ -189,6 +189,8 @@ impl Mastodon { [patch] update_credentials(account::Credentials)@"/api/v1/accounts/update_credentials" -> Account, "Post a new status to the account." [post] new_status(NewStatus)@"/api/v1/statuses" -> Status, + "Revoke an access token to make it no longer valid for use." + [post] revoke_auth(forms::oauth::token::Revocation)@"/oauth/revoke" -> auth::RevocationResponse, } /// Edit existing status -- cgit v1.2.3