aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDankDumpster <[email protected]>2021-01-14 08:19:30 +0100
committerDankDumpster <[email protected]>2021-01-14 08:19:30 +0100
commitec7b0fbcd2f3273d51e15c5c1b34b45cb5a4f46f (patch)
treed407e0ee19ce0551a558f6e757b613783ef06067 /src
parentInitial commit (diff)
downloadoauth-ec7b0fbcd2f3273d51e15c5c1b34b45cb5a4f46f.tar.xz
oauth-ec7b0fbcd2f3273d51e15c5c1b34b45cb5a4f46f.zip
added reqwest support
Diffstat (limited to 'src')
-rw-r--r--src/bridge/hyper.rs8
-rw-r--r--src/bridge/mod.rs1
-rw-r--r--src/bridge/reqwest.rs139
-rw-r--r--src/constants.rs6
-rw-r--r--src/error.rs12
-rw-r--r--src/lib.rs12
-rw-r--r--src/model.rs26
-rw-r--r--src/utils.rs8
8 files changed, 178 insertions, 34 deletions
diff --git a/src/bridge/hyper.rs b/src/bridge/hyper.rs
index 4a7eba2..093b234 100644
--- a/src/bridge/hyper.rs
+++ b/src/bridge/hyper.rs
@@ -1,16 +1,16 @@
//! Bridged support for the `hyper` HTTP client.
-use hyper::client::{Body, Client as HyperClient};
+use hyper::client::{Client as HyperClient, Body};
use hyper::header::ContentType;
use serde_json;
use serde_urlencoded;
-use ::constants::BASE_TOKEN_URI;
-use ::model::{
+use crate::constants::BASE_TOKEN_URI;
+use crate::model::{
AccessTokenExchangeRequest,
AccessTokenResponse,
RefreshTokenRequest,
};
-use ::Result;
+use crate::Result;
/// A trait used that implements methods for interacting with Discord's OAuth2
/// API on Hyper's client.
diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs
index 92be3da..d635011 100644
--- a/src/bridge/mod.rs
+++ b/src/bridge/mod.rs
@@ -4,3 +4,4 @@
//! functions that create one-off clients for ease of use.
pub mod hyper;
+pub mod reqwest; \ No newline at end of file
diff --git a/src/bridge/reqwest.rs b/src/bridge/reqwest.rs
new file mode 100644
index 0000000..30943b5
--- /dev/null
+++ b/src/bridge/reqwest.rs
@@ -0,0 +1,139 @@
+//! Bridged support for the `reqwest` HTTP client.
+use crate::constants::BASE_TOKEN_URI;
+use crate::model::{AccessTokenExchangeRequest, AccessTokenResponse, RefreshTokenRequest};
+use crate::{Error, Result};
+use reqwest::blocking::Client as ReqwestClient;
+use reqwest::header::CONTENT_TYPE;
+use serde_json;
+use serde_json::Error as JsonError;
+use serde_urlencoded;
+
+// TODO Update this
+/// A trait used that implements methods for interacting with Discord's OAuth2
+/// API on Reqwest's client.
+///
+/// # Examples
+///
+/// Bringing in the trait and creating a client. Since the trait is in scope,
+/// the instance of hyper's Client will have those methods available:
+///
+/// ```rust,no_run
+/// extern crate hyper;
+/// extern crate serenity_oauth;
+///
+/// # fn main() {
+/// use hyper::Client;
+///
+/// let client = Client::new();
+///
+/// // At this point, the methods defined by the trait are not in scope. By
+/// // using the trait, they will be.
+/// use serenity_oauth::DiscordOAuthHyperRequester;
+///
+/// // The methods defined by `DiscordOAuthHyperRequester` are now in scope and
+/// // implemented on the instance of hyper's `Client`.
+/// # }
+/// ```
+///
+/// For examples of how to use the trait with the Client, refer to the trait's
+/// methods.
+pub trait DiscordOAuthReqwestRequester {
+ /// Exchanges a code for the user's access token.
+ ///
+ /// # Examples
+ ///
+ /// Exchange a code for an access token:
+ ///
+ /// ```rust,no_run
+ /// extern crate hyper;
+ /// extern crate serenity_oauth;
+ ///
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use hyper::Client;
+ /// use serenity_oauth::model::AccessTokenExchangeRequest;
+ /// use serenity_oauth::DiscordOAuthHyperRequester;
+ ///
+ /// let request_data = AccessTokenExchangeRequest::new(
+ /// 249608697955745802,
+ /// "dd99opUAgs7SQEtk2kdRrTMU5zagR2a4",
+ /// "user code here",
+ /// "https://myapplication.website",
+ /// );
+ ///
+ /// let client = Client::new();
+ /// let response = client.exchange_code(&request_data)?;
+ ///
+ /// println!("Access token: {}", response.access_token);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ fn exchange_code(&self, request: &AccessTokenExchangeRequest) -> Result<AccessTokenResponse>;
+
+ /// Exchanges a refresh token, returning a new refresh token and fresh
+ /// access token.
+ ///
+ /// # Examples
+ ///
+ /// Exchange a refresh token:
+ ///
+ /// ```rust,no_run
+ /// extern crate hyper;
+ /// extern crate serenity_oauth;
+ ///
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use hyper::Client;
+ /// use serenity_oauth::model::RefreshTokenRequest;
+ /// use serenity_oauth::DiscordOAuthHyperRequester;
+ ///
+ /// let request_data = RefreshTokenRequest::new(
+ /// 249608697955745802,
+ /// "dd99opUAgs7SQEtk2kdRrTMU5zagR2a4",
+ /// "user code here",
+ /// "https://myapplication.website",
+ /// );
+ ///
+ /// let client = Client::new();
+ /// let response = client.exchange_refresh_token(&request_data)?;
+ ///
+ /// println!("Fresh access token: {}", response.access_token);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ fn exchange_refresh_token(&self, request: &RefreshTokenRequest) -> Result<AccessTokenResponse>;
+}
+
+impl DiscordOAuthReqwestRequester for ReqwestClient {
+ fn exchange_code(&self, request: &AccessTokenExchangeRequest) -> Result<AccessTokenResponse> {
+ let body = serde_urlencoded::to_string(request)?;
+
+ let response = sel
+ .post(BASE_TOKEN_URI)
+ .header(CONTENT_TYPE, "application/x-www-form-urlencoded")
+ .body(body)
+ .send()?;
+ let body = response.text().unwrap();
+
+ serde_json::from_str(&*body).map_err(From::from)
+ }
+
+ fn exchange_refresh_token(&self, request: &RefreshTokenRequest) -> Result<AccessTokenResponse> {
+ let body = serde_json::to_string(request)?;
+
+ let response = self.post(BASE_TOKEN_URI).body(body).send()?;
+ let body = response.text().unwrap();
+
+ serde_json::from_str(&*body).map_err(From::from)
+ }
+}
diff --git a/src/constants.rs b/src/constants.rs
index 76e4e0c..5078120 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -1,9 +1,9 @@
//! A set of constants around the OAuth2 API.
/// The base authorization URI, used for authorizing an application.
-pub const BASE_AUTHORIZE_URI: &str = "https://discordapp.com/api/oauth2/authorize";
+pub const BASE_AUTHORIZE_URI: &str = "https://discord.com/api/oauth2/authorize";
/// The revocation URL, used to revoke an access token.
-pub const BASE_REVOKE_URI: &str = "https://discordapp.com/api/oauth2/revoke";
+pub const BASE_REVOKE_URI: &str = "https://discord.com/api/oauth2/revoke";
/// The token URI, used for exchanging a refresh token for a fresh access token
/// and new refresh token.
-pub const BASE_TOKEN_URI: &str = "https://discordapp.com/api/oauth2/token";
+pub const BASE_TOKEN_URI: &str = "https://discord.com/api/oauth2/token";
diff --git a/src/error.rs b/src/error.rs
index 3e6a66e..a1fc9f1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,4 +1,5 @@
use hyper::Error as HyperError;
+use reqwest::Error as ReqwestError;
use serde_json::Error as JsonError;
use serde_urlencoded::ser::Error as UrlEncodeError;
use std::error::Error as StdError;
@@ -13,6 +14,8 @@ pub type Result<T> = StdResult<T, Error>;
pub enum Error {
/// An error from the `hyper` crate.
Hyper(HyperError),
+ /// An error from the `reqwest` crate.
+ Reqwest(ReqwestError),
/// An error from the `serde_json` crate.
Json(JsonError),
/// An error from the `serde_urlencoded` crate.
@@ -25,6 +28,12 @@ impl From<HyperError> for Error {
}
}
+impl From<ReqwestError> for Error {
+ fn from(err: ReqwestError) -> Self {
+ Error::Reqwest(err)
+ }
+}
+
impl From<JsonError> for Error {
fn from(err: JsonError) -> Self {
Error::Json(err)
@@ -39,7 +48,7 @@ impl From<UrlEncodeError> for Error {
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
- f.write_str(self.description())
+ f.write_str(self.to_string().as_str())
}
}
@@ -47,6 +56,7 @@ impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::Hyper(ref inner) => inner.description(),
+ Error::Reqwest(ref inner) => inner.description(),
Error::Json(ref inner) => inner.description(),
Error::UrlEncode(ref inner) => inner.description(),
}
diff --git a/src/lib.rs b/src/lib.rs
index 9fd0556..9d96bd3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,4 @@
+#![warn(missing_docs)]
//! # serenity-oauth
//!
//! `serenity-oauth` is a collection of HTTP library support bridges for
@@ -23,14 +24,8 @@
#![deny(missing_docs)]
-#[macro_use] extern crate serde_derive;
-
-extern crate hyper;
-extern crate percent_encoding;
-extern crate serde;
-extern crate serde_json;
-extern crate serde_urlencoded;
-extern crate serenity_model;
+#[macro_use]
+extern crate serde_derive;
pub mod bridge;
pub mod constants;
@@ -41,5 +36,6 @@ mod error;
mod scope;
pub use bridge::hyper::DiscordOAuthHyperRequester;
+pub use bridge::reqwest::DiscordOAuthReqwestRequester;
pub use error::{Error, Result};
pub use scope::Scope;
diff --git a/src/model.rs b/src/model.rs
index 86e3005..91c5fbe 100644
--- a/src/model.rs
+++ b/src/model.rs
@@ -1,7 +1,7 @@
//! A collection of models that can be deserialized from response bodies and
//! serialized into request bodies.
-use serenity_model::{PartialGuild, Webhook};
+use serenity::model::prelude::{PartialGuild, Webhook};
/// Structure of data used as the body of a request to exchange the [`code`] for
/// an access token.
@@ -45,12 +45,12 @@ impl AccessTokenExchangeRequest {
///
/// assert_eq!(request.grant_type, "authorization_code");
/// ```
- pub fn new<S, T, U>(
- client_id: u64,
- client_secret: S,
- code: T,
- redirect_uri: U,
- ) -> Self where S: Into<String>, T: Into<String>, U: Into<String> {
+ pub fn new<S, T, U>(client_id: u64, client_secret: S, code: T, redirect_uri: U) -> Self
+ where
+ S: Into<String>,
+ T: Into<String>,
+ U: Into<String>,
+ {
Self {
client_secret: client_secret.into(),
code: code.into(),
@@ -156,12 +156,12 @@ impl RefreshTokenRequest {
///
/// assert_eq!(request.grant_type, "refresh_token");
/// ```
- pub fn new<S, T, U>(
- client_id: u64,
- client_secret: S,
- redirect_uri: T,
- refresh_token: U,
- ) -> Self where S: Into<String>, T: Into<String>, U: Into<String> {
+ pub fn new<S, T, U>(client_id: u64, client_secret: S, redirect_uri: T, refresh_token: U) -> Self
+ where
+ S: Into<String>,
+ T: Into<String>,
+ U: Into<String>,
+ {
Self {
client_secret: client_secret.into(),
grant_type: "refresh_token".to_owned(),
diff --git a/src/utils.rs b/src/utils.rs
index e11a313..dca680f 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -3,9 +3,9 @@
//! This includes functions for easily generating URLs to redirect users to for
//! authorization.
-pub use serenity_model::Permissions;
+pub use serenity::model::prelude::permissions::Permissions;
-use constants::BASE_AUTHORIZE_URI;
+use crate::constants::BASE_AUTHORIZE_URI;
use percent_encoding;
use super::Scope;
use std::fmt::Write;
@@ -22,11 +22,9 @@ use std::fmt::Write;
/// "Send Messages" permissions:
///
/// ```rust
-/// extern crate serenity_model;
-/// extern crate serenity_oauth;
///
/// # fn main() {
-/// use serenity_model::Permissions;
+/// use serenity_oauth::utils::Permissions;
///
/// let client_id = 249608697955745802;
/// let required = Permissions::ADD_REACTIONS | Permissions::SEND_MESSAGES;