From ff8b3ede308d6660c058e93aae27073ebea31ff1 Mon Sep 17 00:00:00 2001 From: Mark Catley Date: Wed, 26 Jun 2019 21:35:23 +1200 Subject: [PATCH 1/2] Updates to allow retrieving a token using the device flow on Salesforce. --- src/device.rs | 16 +++++++++++----- src/types.rs | 23 ++++++++++++++--------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/device.rs b/src/device.rs index c4b60df..2beaaea 100644 --- a/src/device.rs +++ b/src/device.rs @@ -218,12 +218,17 @@ where return Err(RequestError::ClientError(err)); } Ok(res) => { + // This return type is defined in https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15#section-3.2 + // The alias is present as Google use a non-standard name for verification_uri. + // According to the standard interval is optional, however, all tested implementations provide it. + // verification_uri_complete is optional in the standard but not provided in tested implementations. #[derive(Deserialize)] struct JsonData { device_code: String, user_code: String, - verification_url: String, - expires_in: i64, + #[serde(alias = "verification_url")] + verification_uri: String, + expires_in: Option, interval: i64, } @@ -242,11 +247,12 @@ where let decoded: JsonData = json::from_str(&json_str).unwrap(); + let expires_in = decoded.expires_in.unwrap_or(60 * 60); + let pi = PollInformation { user_code: decoded.user_code, - verification_url: decoded.verification_url, - expires_at: Utc::now() - + chrono::Duration::seconds(decoded.expires_in), + verification_url: decoded.verification_uri, + expires_at: Utc::now() + chrono::Duration::seconds(expires_in), interval: Duration::from_secs(i64::abs(decoded.interval) as u64), }; Ok((pi, decoded.device_code)) diff --git a/src/types.rs b/src/types.rs index a4d200e..f4d6797 100644 --- a/src/types.rs +++ b/src/types.rs @@ -292,16 +292,18 @@ impl Token { if self.access_token.len() == 0 { panic!("called expired() on unset token"); } - self.expiry_date() - chrono::Duration::minutes(1) <= Utc::now() + if let Some(expiry_date) = self.expiry_date() { + expiry_date - chrono::Duration::minutes(1) <= Utc::now() + } else { + false + } } /// Returns a DateTime object representing our expiry date. - pub fn expiry_date(&self) -> DateTime { - Utc.timestamp( - self.expires_in_timestamp - .expect("Tokens without an absolute expiry are invalid"), - 0, - ) + pub fn expiry_date(&self) -> Option> { + let expires_in_timestamp = self.expires_in_timestamp?; + + Utc.timestamp(expires_in_timestamp, 0).into() } /// Adjust our stored expiry format to be absolute, using the current time. @@ -311,8 +313,11 @@ impl Token { return self; } - self.expires_in_timestamp = Some(Utc::now().timestamp() + self.expires_in.unwrap()); - self.expires_in = None; + if let Some(expires_in) = self.expires_in { + self.expires_in_timestamp = Some(Utc::now().timestamp() + expires_in); + self.expires_in = None; + } + self } } From 2ee218be5503a31a1f69ec435de97ca04fb235fb Mon Sep 17 00:00:00 2001 From: Mark Catley Date: Thu, 27 Jun 2019 11:10:48 +1200 Subject: [PATCH 2/2] Adding error logging to the Device Flow. --- src/device.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/device.rs b/src/device.rs index 2beaaea..e830e7d 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,9 +1,10 @@ use std::iter::{FromIterator, IntoIterator}; use std::time::Duration; +use ::log::{log, error}; use chrono::{self, Utc}; -use futures::stream::Stream; use futures::{future, prelude::*}; +use futures::stream::Stream; use http; use hyper; use hyper::header; @@ -150,11 +151,13 @@ where | Err(e @ PollError::Expired(_)) => { Box::new(Err(RequestError::Poll(e)).into_future()) } - Err(_) if i < maxn => { + Err(ref e) if i < maxn => { + error!("Unknown error from poll token api: {}", e); Box::new(Ok(future::Loop::Continue(i + 1)).into_future()) } // Too many attempts. Ok(None) | Err(_) => { + error!("Too many poll attempts"); Box::new(Err(RequestError::Poll(PollError::TimedOut)).into_future()) } })