Implement FromResponse for tokens

This commit is contained in:
Curtis McEnroe 2015-12-23 23:46:21 -05:00
parent 3aa66c2d30
commit 2628759a2e
5 changed files with 93 additions and 3 deletions

View File

@ -82,4 +82,14 @@ impl<'a> JsonObjectHelper<'a> {
pub fn get_string(&self, key: &'static str) -> Result<&'a str, ParseError> {
self.get_string_option(key).ok_or(ParseError::ExpectedFieldType(key, "string"))
}
/// Gets a field as an i64 or returns `None`.
pub fn get_i64_option(&self, key: &'static str) -> Option<i64> {
self.0.get(key).and_then(Json::as_i64)
}
/// Gets a field as an i64 or fails with `ParseError::ExpectedFieldType`.
pub fn get_i64(&self, key: &'static str) -> Result<i64, ParseError> {
self.get_i64_option(key).ok_or(ParseError::ExpectedFieldType(key, "i64"))
}
}

View File

@ -1,6 +1,8 @@
use hyper::header;
use rustc_serialize::json::Json;
use super::{Token, Lifetime};
use client::response::{FromResponse, ParseError, JsonHelper};
/// The bearer token type.
///
@ -23,3 +25,35 @@ impl<'a, L: Lifetime> Into<header::Authorization<header::Bearer>> for &'a Bearer
header::Authorization(header::Bearer { token: self.access_token.clone() })
}
}
impl<L: Lifetime> Bearer<L> {
fn from_response_and_lifetime(json: &Json, lifetime: L) -> Result<Self, ParseError> {
let obj = try!(JsonHelper(json).as_object());
let token_type = try!(obj.get_string("token_type"));
if token_type != "Bearer" && token_type != "bearer" {
return Err(ParseError::ExpectedFieldValue("token_type", "Bearer"));
}
let access_token = try!(obj.get_string("access_token"));
let scope = obj.get_string_option("scope");
Ok(Bearer {
access_token: access_token.into(),
scope: scope.map(Into::into),
lifetime: lifetime,
})
}
}
impl<L: Lifetime> FromResponse for Bearer<L> {
fn from_response(json: &Json) -> Result<Self, ParseError> {
let lifetime = try!(FromResponse::from_response(json));
Bearer::from_response_and_lifetime(json, lifetime)
}
fn from_response_inherit(json: &Json, prev: &Self) -> Result<Self, ParseError> {
let lifetime = try!(FromResponse::from_response_inherit(json, &prev.lifetime));
Bearer::from_response_and_lifetime(json, lifetime)
}
}

View File

@ -1,6 +1,8 @@
use chrono::{DateTime, UTC};
use chrono::{DateTime, UTC, Duration};
use rustc_serialize::json::Json;
use super::Lifetime;
use client::response::{FromResponse, ParseError, JsonHelper};
/// An expiring token.
#[derive(Debug)]
@ -22,3 +24,32 @@ impl Expiring {
impl Lifetime for Expiring {
fn expired(&self) -> bool { self.expires < UTC::now() }
}
impl FromResponse for Expiring {
fn from_response(json: &Json) -> Result<Self, ParseError> {
let obj = try!(JsonHelper(json).as_object());
let refresh_token = try!(obj.get_string("refresh_token"));
let expires_in = try!(obj.get_i64("expires_in"));
Ok(Expiring {
refresh_token: refresh_token.into(),
expires: UTC::now() + Duration::seconds(expires_in),
})
}
fn from_response_inherit(json: &Json, prev: &Self) -> Result<Self, ParseError> {
let obj = try!(JsonHelper(json).as_object());
let refresh_token = try! {
obj.get_string("refresh_token")
.or(Ok(&prev.refresh_token))
};
let expires_in = try!(obj.get_i64("expires_in"));
Ok(Expiring {
refresh_token: refresh_token.into(),
expires: UTC::now() + Duration::seconds(expires_in),
})
}
}

View File

@ -5,10 +5,12 @@
//!
//! Expiring and non-expiring tokens are abstracted through the `Lifetime` trait.
use client::response::FromResponse;
/// OAuth 2.0 tokens.
///
/// See [RFC 6749, section 5](http://tools.ietf.org/html/rfc6749#section-5).
pub trait Token<L: Lifetime> {
pub trait Token<L: Lifetime>: FromResponse {
/// Returns the access token.
///
/// See [RF C6749, section 1.4](http://tools.ietf.org/html/rfc6749#section-1.4).
@ -22,7 +24,7 @@ pub trait Token<L: Lifetime> {
}
/// OAuth 2.0 token lifetimes.
pub trait Lifetime {
pub trait Lifetime: FromResponse {
/// Returns true if the access token is no longer valid.
fn expired(&self) -> bool;
}

View File

@ -1,4 +1,7 @@
use rustc_serialize::json::Json;
use super::Lifetime;
use client::response::{FromResponse, ParseError, JsonHelper};
/// A static, non-expiring token.
#[derive(Debug)]
@ -7,3 +10,13 @@ pub struct Static;
impl Lifetime for Static {
fn expired(&self) -> bool { false }
}
impl FromResponse for Static {
fn from_response(json: &Json) -> Result<Self, ParseError> {
let obj = try!(JsonHelper(json).as_object());
if obj.0.contains_key("expires_in") {
return Err(ParseError::UnexpectedField("expires_in"));
}
Ok(Static)
}
}