diff --git a/examples/github.rs b/examples/github.rs index 39082f0..9b36ca7 100644 --- a/examples/github.rs +++ b/examples/github.rs @@ -14,10 +14,11 @@ fn main() { let connector = HttpsConnector::new(tls); let https = hyper::Client::with_connector(connector); - let client = Client::::new( + let client = Client::new( + GitHub, String::from("01774654cd9a6051e478"), String::from("9f14d16d95d605e715ec1a9aecec220d2565fd5c"), - Some(String::from("https://cmcenroe.me/oauth2-paste/")) + Some(String::from("https://cmcenroe.me/oauth2-paste/")), ); let auth_uri = client.auth_uri(Some("user"), None).unwrap(); diff --git a/examples/google-installed.rs b/examples/google-installed.rs index 1d4cc17..30909d0 100644 --- a/examples/google-installed.rs +++ b/examples/google-installed.rs @@ -14,7 +14,8 @@ fn main() { let connector = HttpsConnector::new(tls); let https = hyper::Client::with_connector(connector); - let client = Client::::new( + let client = Client::new( + Installed, String::from("143225766783-ip2d9qv6sdr37276t77luk6f7bhd6bj5.apps.googleusercontent.com"), String::from("3kZ5WomzHFlN2f_XbhkyPd3o"), Some(String::from(REDIRECT_URI_OOB)), diff --git a/examples/google-web.rs b/examples/google-web.rs index 2fe8e79..f7070a3 100644 --- a/examples/google-web.rs +++ b/examples/google-web.rs @@ -14,7 +14,8 @@ fn main() { let connector = HttpsConnector::new(tls); let https = hyper::Client::with_connector(connector); - let client = Client::::new( + let client = Client::new( + Web, String::from("143225766783-0h4h5ktpvhc7kqp6ohbpd2sssqrap57n.apps.googleusercontent.com"), String::from("7Xjn-vRN-8qsz3Zh9zZGkHsM"), Some(String::from("https://cmcenroe.me/oauth2-paste/")), diff --git a/examples/imgur.rs b/examples/imgur.rs index 864df7d..99042b0 100644 --- a/examples/imgur.rs +++ b/examples/imgur.rs @@ -14,7 +14,8 @@ fn main() { let connector = HttpsConnector::new(tls); let https = hyper::Client::with_connector(connector); - let client = Client::::new( + let client = Client::new( + Imgur, String::from("505c8ca804230e0"), String::from("c898d8cf28404102752b2119a3a1c6aab49899c8"), Some(String::from("https://cmcenroe.me/oauth2-paste/")) diff --git a/src/client/mod.rs b/src/client/mod.rs index 237019a..5d3f04a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -17,7 +17,10 @@ use token::{Token, Lifetime, Refresh}; /// OAuth 2.0 client. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Client { +pub struct Client

{ + /// OAuth provider. + pub provider: P, + /// Client ID. pub client_id: String, @@ -26,13 +29,10 @@ pub struct Client { /// Redirect URI. pub redirect_uri: Option, - - /// The provider. - pub provider: P, } -impl Client

{ - /// Creates a client. +impl Client

{ + /// Creates a client. /// /// # Examples /// @@ -40,30 +40,24 @@ impl Client

{ /// use inth_oauth2::Client; /// use inth_oauth2::provider::google::Installed; /// - /// let client = Client::::new( + /// let client = Client::new( + /// Installed, /// String::from("CLIENT_ID"), /// String::from("CLIENT_SECRET"), - /// Some(String::from("urn:ietf:wg:oauth:2.0:oob")) + /// Some(String::from("urn:ietf:wg:oauth:2.0:oob")), /// ); /// ``` - pub fn new(client_id: String, client_secret: String, redirect_uri: Option) -> Self { - Client::with_provider(client_id, client_secret, P::default(), redirect_uri) - } -} - -impl Client

{ - /// Creates a client with a given Provider. Use when the provider needs non-default Initialization. - pub fn with_provider( - client_id: String, - client_secret: String, - provider: P, - redirect_uri: Option + pub fn new( + provider: P, + client_id: String, + client_secret: String, + redirect_uri: Option, ) -> Self { Client { + provider, client_id, client_secret, redirect_uri, - provider } } @@ -77,15 +71,16 @@ impl Client

{ /// use inth_oauth2::Client; /// use inth_oauth2::provider::google::Installed; /// - /// let client = Client::::new( + /// let client = Client::new( + /// Installed, /// String::from("CLIENT_ID"), /// String::from("CLIENT_SECRET"), - /// Some(String::from("urn:ietf:wg:oauth:2.0:oob")) + /// Some(String::from("urn:ietf:wg:oauth:2.0:oob")), /// ); /// /// let auth_uri = client.auth_uri( /// Some("https://www.googleapis.com/auth/userinfo.email"), - /// None + /// None, /// ); /// ``` pub fn auth_uri(&self, scope: Option<&str>, state: Option<&str>) -> Result @@ -112,12 +107,12 @@ impl Client

{ Ok(uri) } - fn post_token<'a>( - &'a self, + fn post_token( + &self, http_client: &hyper::Client, - mut body: Serializer + mut body: Serializer, ) -> Result { - if P::credentials_in_body() { + if self.provider.credentials_in_body() { body.append_pair("client_id", &self.client_id); body.append_pair("client_secret", &self.client_secret); } @@ -157,7 +152,7 @@ impl Client

{ pub fn request_token( &self, http_client: &hyper::Client, - code: &str + code: &str, ) -> Result { let mut body = Serializer::new(String::new()); body.append_pair("grant_type", "authorization_code"); @@ -173,7 +168,7 @@ impl Client

{ } } -impl Client

where P::Token: Token { +impl

Client

where P: Provider, P::Token: Token { /// Refreshes an access token. /// /// See [RFC 6749, section 6](http://tools.ietf.org/html/rfc6749#section-6). @@ -181,7 +176,7 @@ impl Client

where P::Token: Token { &self, http_client: &hyper::Client, token: P::Token, - scope: Option<&str> + scope: Option<&str>, ) -> Result { let mut body = Serializer::new(String::new()); body.append_pair("grant_type", "refresh_token"); @@ -197,7 +192,11 @@ impl Client

where P::Token: Token { } /// Ensures an access token is valid by refreshing it if necessary. - pub fn ensure_token(&self, http_client: &hyper::Client, token: P::Token) -> Result { + pub fn ensure_token( + &self, + http_client: &hyper::Client, + token: P::Token, + ) -> Result { if token.lifetime().expired() { self.refresh_token(http_client, token, None) } else { @@ -212,18 +211,17 @@ mod tests { use provider::Provider; use super::Client; - #[derive(Default)] struct Test; impl Provider for Test { type Lifetime = Static; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "http://example.com/oauth2/auth" } - fn token_uri(&self) -> &'static str { "http://example.com/oauth2/token" } + fn auth_uri(&self) -> &str { "http://example.com/oauth2/auth" } + fn token_uri(&self) -> &str { "http://example.com/oauth2/token" } } #[test] fn auth_uri() { - let client = Client::::new(String::from("foo"), String::from("bar"), None); + let client = Client::new(Test, String::from("foo"), String::from("bar"), None); assert_eq!( "http://example.com/oauth2/auth?response_type=code&client_id=foo", client.auth_uri(None, None).unwrap().as_str() @@ -232,10 +230,11 @@ mod tests { #[test] fn auth_uri_with_redirect_uri() { - let client = Client::::new( + let client = Client::new( + Test, String::from("foo"), String::from("bar"), - Some(String::from("http://example.com/oauth2/callback")) + Some(String::from("http://example.com/oauth2/callback")), ); assert_eq!( "http://example.com/oauth2/auth?response_type=code&client_id=foo&redirect_uri=http%3A%2F%2Fexample.com%2Foauth2%2Fcallback", @@ -245,7 +244,7 @@ mod tests { #[test] fn auth_uri_with_scope() { - let client = Client::::new(String::from("foo"), String::from("bar"), None); + let client = Client::new(Test, String::from("foo"), String::from("bar"), None); assert_eq!( "http://example.com/oauth2/auth?response_type=code&client_id=foo&scope=baz", client.auth_uri(Some("baz"), None).unwrap().as_str() @@ -254,7 +253,7 @@ mod tests { #[test] fn auth_uri_with_state() { - let client = Client::::new(String::from("foo"), String::from("bar"), None); + let client = Client::new(Test, String::from("foo"), String::from("bar"), None); assert_eq!( "http://example.com/oauth2/auth?response_type=code&client_id=foo&state=baz", client.auth_uri(None, Some("baz")).unwrap().as_str() diff --git a/src/lib.rs b/src/lib.rs index 0de5eb6..7b47169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,10 +34,11 @@ //! use inth_oauth2::Client; //! use inth_oauth2::provider::google::Installed; //! -//! let client = Client::::new( +//! let client = Client::new( +//! Installed, //! String::from("client_id"), //! String::from("client_secret"), -//! Some(String::from("redirect_uri")) +//! Some(String::from("redirect_uri")), //! ); //! ``` //! @@ -46,7 +47,7 @@ //! ``` //! # use inth_oauth2::Client; //! # use inth_oauth2::provider::google::Installed; -//! # let client = Client::::new(String::new(), String::new(), None); +//! # let client = Client::new(Installed, String::new(), String::new(), None); //! let auth_uri = client.auth_uri(Some("scope"), Some("state")).unwrap(); //! println!("Authorize the application by clicking on the link: {}", auth_uri); //! ``` @@ -61,7 +62,7 @@ //! use inth_oauth2::{Client, Token}; //! # use inth_oauth2::provider::google::Installed; //! # fn main() { -//! # let client = Client::::new(String::new(), String::new(), None); +//! # let client = Client::new(Installed, String::new(), String::new(), None); //! //! let mut code = String::new(); //! io::stdin().read_line(&mut code).unwrap(); @@ -80,7 +81,7 @@ //! ```no_run //! # use inth_oauth2::Client; //! # use inth_oauth2::provider::google::Installed; -//! # let client = Client::::new(String::new(), String::new(), None); +//! # let client = Client::new(Installed, String::new(), String::new(), None); //! # let https = Default::default(); //! # let token = client.request_token(&https, "").unwrap(); //! let token = client.refresh_token(&https, token, None).unwrap(); @@ -91,7 +92,7 @@ //! ```no_run //! # use inth_oauth2::Client; //! # use inth_oauth2::provider::google::Installed; -//! # let client = Client::::new(String::new(), String::new(), None); +//! # let client = Client::new(Installed, String::new(), String::new(), None); //! # let https = Default::default(); //! # let mut token = client.request_token(&https, "").unwrap(); //! // Refresh token only if it has expired. @@ -110,7 +111,7 @@ //! use hyper::header::Authorization; //! //! # fn main() { -//! # let oauth_client = Client::::new(String::new(), String::new(), None); +//! # let oauth_client = Client::new(Installed, String::new(), String::new(), None); //! # let https = Default::default(); //! # let token = oauth_client.request_token(&https, "").unwrap(); //! let request = https.get("https://example.com/resource") @@ -129,7 +130,7 @@ //! # use inth_oauth2::provider::google::Installed; //! # fn main() { //! # let http_client = Default::default(); -//! # let client = Client::::new(String::new(), String::new(), None); +//! # let client = Client::new(Installed, String::new(), String::new(), None); //! # let token = client.request_token(&http_client, "").unwrap(); //! let json = serde_json::to_string(&token).unwrap(); //! # } @@ -144,7 +145,7 @@ unused_extern_crates, unused_import_braces, unused_qualifications, - variant_size_differences + variant_size_differences, )] #[macro_use] diff --git a/src/provider.rs b/src/provider.rs index dae2d5b..e7b4cfe 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -13,15 +13,11 @@ pub trait Provider { /// The authorization endpoint URI. /// /// See [RFC 6749, section 3.1](http://tools.ietf.org/html/rfc6749#section-3.1). - /// - /// Note: likely to become an associated constant. fn auth_uri(&self) -> &str; /// The token endpoint URI. /// /// See [RFC 6749, section 3.2](http://tools.ietf.org/html/rfc6749#section-3.2). - /// - /// Note: likely to become an associated constant. fn token_uri(&self) -> &str; /// Provider requires credentials via request body. @@ -30,9 +26,7 @@ pub trait Provider { /// as part of the request body. /// /// See [RFC 6749, section 2.3.1](http://tools.ietf.org/html/rfc6749#section-2.3.1). - /// - /// Note: likely to become an associated constant. - fn credentials_in_body() -> bool { false } + fn credentials_in_body(&self) -> bool { false } } /// Google OAuth 2.0 providers. @@ -62,49 +56,49 @@ pub mod google { /// /// See [Using OAuth 2.0 for Web Server /// Applications](https://developers.google.com/identity/protocols/OAuth2WebServer). - #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Web; impl Provider for Web { type Lifetime = Expiring; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://accounts.google.com/o/oauth2/v2/auth" } - fn token_uri(&self) -> &'static str { "https://www.googleapis.com/oauth2/v4/token" } + fn auth_uri(&self) -> &str { "https://accounts.google.com/o/oauth2/v2/auth" } + fn token_uri(&self) -> &str { "https://www.googleapis.com/oauth2/v4/token" } } /// Google OAuth 2.0 provider for installed applications. /// /// See [Using OAuth 2.0 for Installed /// Applications](https://developers.google.com/identity/protocols/OAuth2InstalledApp). - #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Installed; impl Provider for Installed { type Lifetime = Refresh; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://accounts.google.com/o/oauth2/v2/auth" } - fn token_uri(&self) -> &'static str { "https://www.googleapis.com/oauth2/v4/token" } + fn auth_uri(&self) -> &str { "https://accounts.google.com/o/oauth2/v2/auth" } + fn token_uri(&self) -> &str { "https://www.googleapis.com/oauth2/v4/token" } } } /// GitHub OAuth 2.0 provider. /// /// See [OAuth, GitHub Developer Guide](https://developer.github.com/v3/oauth/). -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct GitHub; impl Provider for GitHub { type Lifetime = Static; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://github.com/login/oauth/authorize" } - fn token_uri(&self) -> &'static str { "https://github.com/login/oauth/access_token" } + fn auth_uri(&self) -> &str { "https://github.com/login/oauth/authorize" } + fn token_uri(&self) -> &str { "https://github.com/login/oauth/access_token" } } /// Imgur OAuth 2.0 provider. /// /// See [OAuth 2.0, Imgur](https://api.imgur.com/oauth2). -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Imgur; impl Provider for Imgur { type Lifetime = Refresh; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://api.imgur.com/oauth2/authorize" } - fn token_uri(&self) -> &'static str { "https://api.imgur.com/oauth2/token" } + fn auth_uri(&self) -> &str { "https://api.imgur.com/oauth2/authorize" } + fn token_uri(&self) -> &str { "https://api.imgur.com/oauth2/token" } } diff --git a/tests/auth_uri.rs b/tests/auth_uri.rs index f67e053..8035e30 100644 --- a/tests/auth_uri.rs +++ b/tests/auth_uri.rs @@ -19,7 +19,8 @@ fn assert_get_uri_ok(uri: Url) { #[test] fn google_web_auth_uri_ok() { - let client = Client::::new( + let client = Client::new( + google::Web, String::from("143225766783-0h4h5ktpvhc7kqp6ohbpd2sssqrap57n.apps.googleusercontent.com"), String::new(), Some(String::from("https://cmcenroe.me/oauth2-paste/")), @@ -33,24 +34,26 @@ fn google_web_auth_uri_ok() { #[test] fn google_installed_auth_uri_ok() { - let client = Client::::new( + let client = Client::new( + google::Installed, String::from("143225766783-ip2d9qv6sdr37276t77luk6f7bhd6bj5.apps.googleusercontent.com"), String::new(), - Some(String::from("urn:ietf:wg:oauth:2.0:oob")) + Some(String::from("urn:ietf:wg:oauth:2.0:oob")), ); let auth_uri = client.auth_uri( Some("https://www.googleapis.com/auth/userinfo.email"), - Some("state") + Some("state"), ).unwrap(); assert_get_uri_ok(auth_uri); } #[test] fn github_auth_uri_ok() { - let client = Client::::new( + let client = Client::new( + GitHub, String::from("01774654cd9a6051e478"), String::new(), - Some(String::from("https://cmcenroe.me/oauth2-paste/")) + Some(String::from("https://cmcenroe.me/oauth2-paste/")), ); let auth_uri = client.auth_uri(Some("user"), Some("state")).unwrap(); assert_get_uri_ok(auth_uri); @@ -58,10 +61,11 @@ fn github_auth_uri_ok() { #[test] fn imgur_auth_uri_ok() { - let client = Client::::new( + let client = Client::new( + Imgur, String::from("505c8ca804230e0"), String::new(), - Some(String::from("https://cmcenroe.me/oauth2-paste/")) + Some(String::from("https://cmcenroe.me/oauth2-paste/")), ); let auth_uri = client.auth_uri(None, Some("state")).unwrap(); assert_get_uri_ok(auth_uri); diff --git a/tests/mock.rs b/tests/mock.rs index ce21afc..874a955 100644 --- a/tests/mock.rs +++ b/tests/mock.rs @@ -12,31 +12,28 @@ mod provider { use inth_oauth2::token::{Bearer, Static, Expiring, Refresh}; use inth_oauth2::provider::Provider; - #[derive(Default)] pub struct BearerStatic; impl Provider for BearerStatic { type Lifetime = Static; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://example.com/oauth/auth" } - fn token_uri(&self) -> &'static str { "https://example.com/oauth/token" } + fn auth_uri(&self) -> &str { "https://example.com/oauth/auth" } + fn token_uri(&self) -> &str { "https://example.com/oauth/token" } } - #[derive(Default)] pub struct BearerExpiring; impl Provider for BearerExpiring { type Lifetime = Expiring; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://example.com/oauth/auth" } - fn token_uri(&self) -> &'static str { "https://example.com/oauth/token" } + fn auth_uri(&self) -> &str { "https://example.com/oauth/auth" } + fn token_uri(&self) -> &str { "https://example.com/oauth/token" } } - #[derive(Default)] pub struct BearerRefresh; impl Provider for BearerRefresh { type Lifetime = Refresh; type Token = Bearer; - fn auth_uri(&self) -> &'static str { "https://example.com/oauth/auth" } - fn token_uri(&self) -> &'static str { "https://example.com/oauth/token" } + fn auth_uri(&self) -> &str { "https://example.com/oauth/auth" } + fn token_uri(&self) -> &str { "https://example.com/oauth/token" } } } @@ -72,11 +69,12 @@ mod connector { } macro_rules! mock_client { - ($p:ty, $c:ty) => { - (Client::<$p>::new( + ($p:path, $c:ty) => { + (Client::new( + $p, String::from("client_id"), String::from("client_secret"), - None + None, ), hyper::Client::with_connector(<$c>::default())) }