diff --git a/src/device.rs b/src/device.rs index bcbfde4..a5ded6a 100644 --- a/src/device.rs +++ b/src/device.rs @@ -74,7 +74,7 @@ pub enum RequestError { HttpError(hyper::Error), /// The OAuth client was not found InvalidClient, - /// Some requested scopes were invalid. String contains the scopes as part of + /// Some requested scopes were invalid. String contains the scopes as part of /// the server error message InvalidScope(String), /// A 'catch-all' variant containing the server error and description @@ -99,7 +99,7 @@ impl fmt::Display for RequestError { match *self { RequestError::HttpError(ref err) => err.fmt(f), RequestError::InvalidClient => "Invalid Client".fmt(f), - RequestError::InvalidScope(ref scope) + RequestError::InvalidScope(ref scope) => writeln!(f, "Invalid Scope: '{}'", scope), RequestError::NegativeServerResponse(ref error, ref desc) => { try!(error.fmt(f)); @@ -135,7 +135,7 @@ impl fmt::Display for PollError { } -impl DeviceFlow +impl DeviceFlow where C: BorrowMut { /// # Examples @@ -143,7 +143,7 @@ impl DeviceFlow /// extern crate hyper; /// extern crate yup_oauth2 as oauth2; /// use oauth2::DeviceFlow; - /// + /// /// # #[test] fn new() { /// let mut f = DeviceFlow::new(hyper::Client::new()); /// # } @@ -161,14 +161,14 @@ impl DeviceFlow /// The first step involves asking the server for a code that the user /// can type into a field at a specified URL. It is called only once, assuming - /// there was no connection error. Otherwise, it may be called again until + /// there was no connection error. Otherwise, it may be called again until /// you receive an `Ok` result. /// # Arguments /// * `client_id` & `client_secret` - as obtained when [registering your application](https://developers.google.com/youtube/registering_an_application) - /// * `scopes` - an iterator yielding String-like objects which are URLs defining what your + /// * `scopes` - an iterator yielding String-like objects which are URLs defining what your /// application is able to do. It is considered good behaviour to authenticate /// only once, with all scopes you will ever require. - /// However, you can also manage multiple tokens for different scopes, if your + /// However, you can also manage multiple tokens for different scopes, if your /// application is providing distinct read-only and write modes. /// # Panics /// * If called after a successful result was returned at least once. @@ -176,7 +176,7 @@ impl DeviceFlow /// See test-cases in source code for a more complete example. pub fn request_code<'b, T, I>(&mut self, client_id: &str, client_secret: &str, scopes: I) -> Result - where T: AsRef, + where T: AsRef + 'b, I: IntoIterator { if self.state.is_some() { panic!("Must not be called after we have obtained a token and have no error"); @@ -246,16 +246,16 @@ impl DeviceFlow /// If the first call is successful, this method may be called. /// As long as we are waiting for authentication, it will return `Ok(None)`. - /// You should call it within the interval given the previously returned + /// You should call it within the interval given the previously returned /// `PollInformation.interval` field. /// /// The operation was successful once you receive an Ok(Some(Token)) for the first time. /// Subsequent calls will return the previous result, which may also be an error state. /// - /// Do not call after `PollError::Expired|PollError::AccessDenied` was among the + /// Do not call after `PollError::Expired|PollError::AccessDenied` was among the /// `Err(PollError)` variants as the flow will not do anything anymore. /// Thus in any unsuccessful case which is not `PollError::HttpError`, you will have to start /// over the entire flow, which requires a new instance of this type. - /// + /// /// > ⚠️ **Warning**: We assume the caller doesn't call faster than `interval` and are not /// > protected against this kind of mis-use. /// @@ -264,7 +264,7 @@ impl DeviceFlow pub fn poll_token(&mut self) -> Result, &PollError> { // clone, as we may re-assign our state later let pi = match self.state { - Some(ref s) => + Some(ref s) => match *s { DeviceFlowState::Pending(ref pi) => pi.clone(), DeviceFlowState::Error => return Err(self.error.as_ref().unwrap()), @@ -286,7 +286,7 @@ impl DeviceFlow ("code", &self.device_code), ("grant_type", "http://oauth.net/grant_type/device/1.0")]); - let json_str = + let json_str = match self.client.borrow_mut().post(GOOGLE_TOKEN_URL) .header(ContentType("application/x-www-form-urlencoded".parse().unwrap())) .body(&*req) @@ -403,7 +403,7 @@ pub mod tests { _ => unreachable!(), } - let t = + let t = match flow.poll_token() { Ok(Some(t)) => { assert_eq!(t.access_token, "1/fFAGRNJru1FTz70BzhT3Zg"); diff --git a/src/helper.rs b/src/helper.rs index 49f617f..0b29395 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -79,7 +79,7 @@ impl TokenStorage for MemoryStorage { } } -/// A generalized authenticator which will keep tokens valid and store them. +/// A generalized authenticator which will keep tokens valid and store them. /// /// It is the go-to helper to deal with any kind of supported authentication flow, /// which will be kept valid and usable. @@ -92,7 +92,7 @@ impl TokenStorage for MemoryStorage { /// * presenting the user code /// * inform the user about the progress or errors /// * abort the operation -/// +/// /// # Usage /// Please have a look at the library's landing page. pub struct Authenticator { @@ -151,7 +151,7 @@ impl Error for StringError { /// if no user is involved. pub trait GetToken { fn token<'b, I, T>(&mut self, scopes: I) -> Result> - where T: AsRef + Ord, + where T: AsRef + Ord + 'b, I: IntoIterator; fn api_key(&mut self) -> Option; @@ -162,21 +162,21 @@ impl Authenticator S: TokenStorage, C: BorrowMut { - + /// Returns a new `Authenticator` instance /// /// # Arguments - /// * `secret` - usually obtained from a client secret file produced by the + /// * `secret` - usually obtained from a client secret file produced by the /// [developer console][dev-con] /// * `delegate` - Used to further refine the flow of the authentication. /// * `client` - used for all authentication https requests /// * `storage` - used to cache authorization tokens tokens permanently. However, /// the implementation doesn't have any particular semantic requirement, which /// is why `NullStorage` and `MemoryStorage` can be used as well. - /// * `flow_type` - the kind of authentication to use to obtain a token for the + /// * `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 - pub fn new(secret: &ApplicationSecret, + pub fn new(secret: &ApplicationSecret, delegate: D, client: C, storage: S, flow_type: Option) -> Authenticator { Authenticator { @@ -194,7 +194,7 @@ impl Authenticator // PHASE 1: REQUEST CODE let pi: PollInformation; loop { - let res = flow.request_code(&self.secret.client_id, + let res = flow.request_code(&self.secret.client_id, &self.secret.client_secret, scopes.iter()); pi = match res { @@ -232,7 +232,7 @@ impl Authenticator match poll_err { &&PollError::HttpError(ref err) => { match self.delegate.connection_error(err) { - Retry::Abort|Retry::Skip + Retry::Abort|Retry::Skip => return Err(Box::new(StringError::from(err as &Error))), Retry::After(d) => sleep_ms(d.num_milliseconds() as u32), } @@ -247,9 +247,9 @@ impl Authenticator }, }; // end match poll_err }, - Ok(None) => + Ok(None) => match self.delegate.pending(&pi) { - Retry::Abort|Retry::Skip + Retry::Abort|Retry::Skip => return Err(Box::new(StringError::new("Pending authentication aborted".to_string(), None))), Retry::After(d) => sleep_ms(min(d, pi.interval).num_milliseconds() as u32), }, @@ -264,13 +264,13 @@ impl GetToken for Authenticator S: TokenStorage, C: BorrowMut { - /// Blocks until a token was retrieved from storage, from the server, or until the delegate + /// Blocks until a token was retrieved from storage, from the server, or until the delegate /// decided to abort the attempt, or the user decided not to authorize the application. - /// In any failure case, the delegate will be provided with additional information, and + /// In any failure case, the delegate will be provided with additional information, and /// the caller will be informed about storage related errors. /// Otherwise it is guaranteed to be valid for the given scopes. fn token<'b, I, T>(&mut self, scopes: I) -> Result> - where T: AsRef + Ord, + where T: AsRef + Ord + 'b, I: IntoIterator { let (scope_key, scopes) = { let mut sv: Vec<&str> = scopes.into_iter() @@ -292,12 +292,12 @@ impl GetToken for Authenticator let mut rf = RefreshFlow::new(self.client.borrow_mut()); loop { match *rf.refresh_token(self.flow_type, - &self.secret.client_id, - &self.secret.client_secret, + &self.secret.client_id, + &self.secret.client_secret, &t.refresh_token) { RefreshResult::Error(ref err) => { match self.delegate.connection_error(err) { - Retry::Abort|Retry::Skip => + Retry::Abort|Retry::Skip => return Err(Box::new(StringError::new( err.description().to_string(), None))), @@ -306,7 +306,7 @@ impl GetToken for Authenticator }, RefreshResult::RefreshError(ref err_str, ref err_description) => { self.delegate.token_refresh_failed(&err_str, &err_description); - let storage_err = + let storage_err = match self.storage.set(scope_key, &scopes, None) { Ok(_) => String::new(), Err(err) => err.to_string(), @@ -339,7 +339,7 @@ impl GetToken for Authenticator Ok(None) => { // Nothing was in storage - get a new token // get new token. The respective sub-routine will do all the logic. - match + match match self.flow_type { FlowType::Device => self.retrieve_device_token(&scopes), } @@ -387,13 +387,13 @@ impl GetToken for Authenticator /// A partially implemented trait to interact with the `Authenticator` -/// +/// /// The only method that needs to be implemented manually is `present_user_code(...)`, /// as no assumptions are made on how this presentation should happen. pub trait AuthenticatorDelegate { /// Called whenever there is an HttpError, usually if there are network problems. - /// + /// /// Return retry information. fn connection_error(&mut self, &hyper::Error) -> Retry { Retry::Abort @@ -402,7 +402,7 @@ pub trait AuthenticatorDelegate { /// Called whenever we failed to retrieve a token or set a token due to a storage error. /// You may use it to either ignore the incident or retry. /// This can be useful if the underlying `TokenStorage` may fail occasionally. - /// if `is_set` is true, the failure resulted from `TokenStorage.set(...)`. Otherwise, + /// if `is_set` is true, the failure resulted from `TokenStorage.set(...)`. Otherwise, /// it was `TokenStorage.get(...)` fn token_storage_failure(&mut self, is_set: bool, _: &Error) -> Retry { let _ = is_set; @@ -417,11 +417,11 @@ pub trait AuthenticatorDelegate { /// Given `DateTime` is the expiration date fn expired(&mut self, &DateTime) {} - /// Called if the user denied access. You would have to start over. + /// Called if the user denied access. You would have to start over. /// This will be the last call the delegate receives. fn denied(&mut self) {} - /// Called if we could not acquire a refresh token for a reason possibly specified + /// Called if we could not acquire a refresh token for a reason possibly specified /// by the server. /// This call is made for the delegate's information only. fn token_refresh_failed(&mut self, error: &String, error_description: &Option) { @@ -431,7 +431,7 @@ pub trait AuthenticatorDelegate { /// Called as long as we are waiting for the user to authorize us. /// Can be used to print progress information, or decide to time-out. - /// + /// /// If the returned `Retry` variant is a duration. /// # Notes /// * Only used in `DeviceFlow`. Return value will only be used if it @@ -446,7 +446,7 @@ pub trait AuthenticatorDelegate { /// * Will be called exactly once, provided we didn't abort during `request_code` phase. /// * Will only be called if the Authenticator's flow_type is `FlowType::Device`. fn present_user_code(&mut self, pi: &PollInformation) { - println!("Please enter {} at {} and grant access to this application", + println!("Please enter {} at {} and grant access to this application", pi.user_code, pi.verification_url); println!("Do not close this application until you either denied or granted access."); println!("You have time until {}.", pi.expires_at.with_timezone(&Local)); @@ -494,4 +494,4 @@ mod tests { _ => panic!("Expected to retrieve token in one go"), } } -} \ No newline at end of file +}