diff --git a/Cargo.toml b/Cargo.toml index 7b574a3..e724acd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" authors = ["Curtis McEnroe "] [dependencies] +chrono = "0.2.17" url = "0.5.0" diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..dff696b --- /dev/null +++ b/src/client.rs @@ -0,0 +1,86 @@ +use url::{Url, ParseResult}; + +/// OAuth 2.0 client. +pub struct Client { + auth_uri: String, + token_uri: String, + + client_id: String, + client_secret: String, + redirect_uri: Option, +} + +impl Client { + /// Creates an OAuth 2.0 client. + pub fn new>( + auth_uri: S, + token_uri: S, + client_id: S, + client_secret: S, + redirect_uri: Option + ) -> Self { + Client { + auth_uri: auth_uri.into(), + token_uri: token_uri.into(), + + client_id: client_id.into(), + client_secret: client_secret.into(), + redirect_uri: redirect_uri.map(Into::::into), + } + } + + /// Creates a Google OAuth 2.0 client. + pub fn google>( + client_id: S, + client_secret: S, + redirect_uri: Option + ) -> Self { + Client { + auth_uri: String::from("https://accounts.google.com/o/oauth2/auth"), + token_uri: String::from("https://accounts.google.com/o/oauth2/token"), + + client_id: client_id.into(), + client_secret: client_secret.into(), + redirect_uri: redirect_uri.map(Into::::into), + } + } + + /// Creates a GitHub OAuth 2.0 client. + pub fn github>( + client_id: S, + client_secret: S, + redirect_uri: Option + ) -> Self { + Client { + auth_uri: String::from("https://github.com/login/oauth/authorize"), + token_uri: String::from("https://github.com/login/oauth/access_token"), + + client_id: client_id.into(), + client_secret: client_secret.into(), + redirect_uri: redirect_uri.map(Into::::into), + } + } + + /// Constructs an authorization request URI. + pub fn auth_uri(&self, scope: Option<&str>, state: Option<&str>) -> ParseResult { + let mut uri = try!(Url::parse(&self.auth_uri)); + + let mut query_pairs = vec![ + ("response_type", "code"), + ("client_id", &self.client_id), + ]; + if let Some(ref redirect_uri) = self.redirect_uri { + query_pairs.push(("redirect_uri", redirect_uri)); + } + if let Some(scope) = scope { + query_pairs.push(("scope", scope)); + } + if let Some(state) = state { + query_pairs.push(("state", state)); + } + + uri.set_query_from_pairs(query_pairs.iter()); + + Ok(uri.serialize()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 57a8850..c9e8797 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,88 +1,9 @@ +extern crate chrono; +extern crate hyper; extern crate url; -use url::{Url, ParseResult}; +pub use client::Client; +mod client; -/// OAuth 2.0 client. -pub struct Client { - auth_uri: String, - token_uri: String, - - client_id: String, - client_secret: String, - redirect_uri: Option, -} - -impl Client { - /// Creates an OAuth 2.0 client. - pub fn new>( - auth_uri: S, - token_uri: S, - client_id: S, - client_secret: S, - redirect_uri: Option - ) -> Self { - Client { - auth_uri: auth_uri.into(), - token_uri: token_uri.into(), - - client_id: client_id.into(), - client_secret: client_secret.into(), - redirect_uri: redirect_uri.map(Into::::into), - } - } - - /// Creates a Google OAuth 2.0 client. - pub fn google>( - client_id: S, - client_secret: S, - redirect_uri: Option - ) -> Self { - Client { - auth_uri: String::from("https://accounts.google.com/o/oauth2/auth"), - token_uri: String::from("https://accounts.google.com/o/oauth2/token"), - - client_id: client_id.into(), - client_secret: client_secret.into(), - redirect_uri: redirect_uri.map(Into::::into), - } - } - - /// Creates a GitHub OAuth 2.0 client. - pub fn github>( - client_id: S, - client_secret: S, - redirect_uri: Option - ) -> Self { - Client { - auth_uri: String::from("https://github.com/login/oauth/authorize"), - token_uri: String::from("https://github.com/login/oauth/access_token"), - - client_id: client_id.into(), - client_secret: client_secret.into(), - redirect_uri: redirect_uri.map(Into::::into), - } - } - - /// Constructs an authorization request URI. - pub fn auth_uri(&self, scope: Option<&str>, state: Option<&str>) -> ParseResult { - let mut uri = try!(Url::parse(&self.auth_uri)); - - let mut query_pairs = vec![ - ("response_type", "code"), - ("client_id", &self.client_id), - ]; - if let Some(ref redirect_uri) = self.redirect_uri { - query_pairs.push(("redirect_uri", redirect_uri)); - } - if let Some(scope) = scope { - query_pairs.push(("scope", scope)); - } - if let Some(state) = state { - query_pairs.push(("state", state)); - } - - uri.set_query_from_pairs(query_pairs.iter()); - - Ok(uri.serialize()) - } -} +pub use token::Token; +mod token; diff --git a/src/token.rs b/src/token.rs new file mode 100644 index 0000000..68c5be6 --- /dev/null +++ b/src/token.rs @@ -0,0 +1,17 @@ +use chrono::{DateTime, UTC}; + +/// OAuth 2.0 access token. +pub struct Token { + pub access_token: String, + pub token_type: String, + pub expires: Option>, + pub refresh_token: Option, + pub scope: Option, +} + +impl Token { + /// Returns true if token is expired. + pub fn expired(&self) -> bool { + self.expires.map_or(false, |dt| dt < UTC::now()) + } +}