diff --git a/src/common.rs b/src/common.rs index fbfe082..7876bd9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -108,16 +108,16 @@ pub struct ApplicationSecret { /// as returned by the [google developer console](https://code.google.com/apis/console) #[derive(RustcDecodable, RustcEncodable)] pub struct ConsoleApplicationSecret { - web: Option, - installed: Option + pub web: Option, + pub installed: Option } #[cfg(test)] -mod tests { +pub mod tests { use super::*; - const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; + pub const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; #[test] fn console_secret() { diff --git a/src/device.rs b/src/device.rs index 810abae..a713bb8 100644 --- a/src/device.rs +++ b/src/device.rs @@ -442,7 +442,7 @@ pub trait DeviceFlowHelperDelegate { #[cfg(test)] -mod tests { +pub mod tests { use super::*; use std::default::Default; use hyper; @@ -505,24 +505,4 @@ mod tests { // As our mock has only 3 items, we would panic on this call flow.poll_token(); } - - #[test] - fn authenticator() { - struct TestHandler; - impl DeviceFlowHelperDelegate for TestHandler { - fn present_user_code(&mut self, pi: PollInformation) { - println!("{:?}", pi); - } - } - if let Some(t) = DeviceFlowHelper::new(&mut TestHandler) - .retrieve_token(hyper::Client::with_connector( - ::default()), - "bogus_client_id", - "bogus_secret", - &["https://www.googleapis.com/auth/youtube.upload"]) { - assert_eq!(t.access_token, "1/fFAGRNJru1FTz70BzhT3Zg") - } else { - panic!("Expected to retrieve token in one go"); - } - } } \ No newline at end of file diff --git a/src/helper.rs b/src/helper.rs index 60e21cb..5e5e4f1 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -24,6 +24,7 @@ pub trait TokenStorage { } /// A storage that remembers nothing. +#[derive(Default)] pub struct NullStorage; impl TokenStorage for NullStorage { @@ -32,6 +33,7 @@ impl TokenStorage for NullStorage { } /// A storage that remembers values for one session only. +#[derive(Default)] pub struct MemoryStorage { pub tokens: HashMap } @@ -68,7 +70,7 @@ pub struct Authenticator { impl Authenticator where D: AuthenticatorDelegate, - S: BorrowMut, + S: TokenStorage, NC: hyper::net::NetworkConnector, C: BorrowMut> { @@ -86,7 +88,7 @@ impl Authenticator /// * `flow_type` - the kind of authentication to use to obtain a token for the /// required scopes. If unset, it will be derived from the secret. /// [dev-con]: https://console.developers.google.com - fn new(secret: &ApplicationSecret, + pub fn new(secret: &ApplicationSecret, delegate: D, client: C, storage: S, flow_type: Option) -> Authenticator { Authenticator { @@ -103,7 +105,7 @@ impl Authenticator /// decided to abort the attempt, or the user decided not to authorize the application. /// In any failure case, the returned token will be None, otherwise it is guaranteed to be /// valid for the given scopes. - fn token<'b, I, T>(&mut self, scopes: I) -> Option + pub fn token<'b, I, T>(&mut self, scopes: I) -> Option where T: Str + Ord, I: IntoIterator { let (scope_key, scope, scopes) = { @@ -120,7 +122,7 @@ impl Authenticator }; // Get cached token. Yes, let's do an explicit return - return match self.storage.borrow().get(scope_key) { + return match self.storage.get(scope_key) { Some(mut t) => { // t needs refresh ? if t.expired() { @@ -142,7 +144,7 @@ impl Authenticator }, RefreshResult::Success(ref new_t) => { t = new_t.clone(); - self.storage.borrow_mut().set(scope_key, Some(t.clone())); + self.storage.set(scope_key, Some(t.clone())); } }// RefreshResult handling }// refresh loop @@ -156,7 +158,7 @@ impl Authenticator }; // store it, no matter what. If tokens have become invalid, it's ok // to indicate that to the storage. - self.storage.borrow_mut().set(scope_key, ot.clone()); + self.storage.set(scope_key, ot.clone()); ot }, } @@ -271,3 +273,37 @@ pub enum Retry { /// Signals you want to retry after the given duration After(Duration) } + + +#[cfg(test)] +mod tests { + use super::*; + use super::super::device::tests::MockGoogleAuth; + use super::super::common::tests::SECRET; + use super::super::common::{ConsoleApplicationSecret, Token}; + use super::super::device::PollInformation; + use std::default::Default; + use hyper; + + #[test] + fn flow() { + use rustc_serialize::json; + + struct TestHandler; + impl AuthenticatorDelegate for TestHandler { + fn present_user_code(&mut self, pi: PollInformation) { + println!("{:?}", pi); + } + } + let secret = json::decode::(SECRET).unwrap().installed.unwrap(); + let res = Authenticator::new(&secret, TestHandler, + hyper::Client::with_connector(::default()), + ::default(), None) + .token(&["https://www.googleapis.com/auth/youtube.upload"]); + + match res { + Some(t) => assert_eq!(t.access_token, "1/fFAGRNJru1FTz70BzhT3Zg"), + _ => panic!("Expected to retrieve token in one go"), + } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f07fb66..e9b6842 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(old_io, std_misc, core)] +#![feature(old_io, std_misc, core, hash)] //! This library can be used to acquire oauth2.0 authentication for services. //! At the time of writing, only one way of doing so is implemented, the [device flow](https://developers.google.com/youtube/v3/guides/authentication#devices), along with a flow //! for [refreshing tokens](https://developers.google.com/youtube/v3/guides/authentication#devices)