mirror of
https://github.com/OMGeeky/yup-oauth2.git
synced 2026-01-17 16:07:11 +01:00
refactor(all): More flows demand for a different structure
I mainly resolved some circular dependencies that had crept in, and moved code around. I renamed helper.rs because that was not really an appropriate name anymore, and moved the delegate code into a new module.
This commit is contained in:
153
src/authenticator_delegate.rs
Normal file
153
src/authenticator_delegate.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
use hyper;
|
||||
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::error::Error;
|
||||
|
||||
use authenticator::Retry;
|
||||
use common::RequestError;
|
||||
|
||||
use chrono::{DateTime, Local, UTC};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Contains state of pending authentication requests
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PollInformation {
|
||||
/// Code the user must enter ...
|
||||
pub user_code: String,
|
||||
/// ... at the verification URL
|
||||
pub verification_url: String,
|
||||
|
||||
/// The `user_code` expires at the given time
|
||||
/// It's the time the user has left to authenticate your application
|
||||
pub expires_at: DateTime<UTC>,
|
||||
/// The interval in which we may poll for a status change
|
||||
/// The server responds with errors of we poll too fast.
|
||||
pub interval: Duration,
|
||||
}
|
||||
|
||||
impl fmt::Display for PollInformation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
writeln!(f, "Proceed with polling until {}", self.expires_at)
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates all possible results of a `poll_token(...)` operation
|
||||
#[derive(Debug)]
|
||||
pub enum PollError {
|
||||
/// Connection failure - retry if you think it's worth it
|
||||
HttpError(hyper::Error),
|
||||
/// indicates we are expired, including the expiration date
|
||||
Expired(DateTime<UTC>),
|
||||
/// Indicates that the user declined access. String is server response
|
||||
AccessDenied,
|
||||
}
|
||||
|
||||
impl fmt::Display for PollError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
PollError::HttpError(ref err) => err.fmt(f),
|
||||
PollError::Expired(ref date) => writeln!(f, "Authentication expired at {}", date),
|
||||
PollError::AccessDenied => "Access denied by user".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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
|
||||
}
|
||||
|
||||
/// 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,
|
||||
/// it was `TokenStorage.get(...)`
|
||||
fn token_storage_failure(&mut self, is_set: bool, _: &Error) -> Retry {
|
||||
let _ = is_set;
|
||||
Retry::Abort
|
||||
}
|
||||
|
||||
/// The server denied the attempt to obtain a request code
|
||||
fn request_failure(&mut self, RequestError) {}
|
||||
|
||||
/// Called if the request code is expired. You will have to start over in this case.
|
||||
/// This will be the last call the delegate receives.
|
||||
/// Given `DateTime` is the expiration date
|
||||
fn expired(&mut self, &DateTime<UTC>) {}
|
||||
|
||||
/// 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
|
||||
/// by the server.
|
||||
/// This call is made for the delegate's information only.
|
||||
fn token_refresh_failed(&mut self, error: &String, error_description: &Option<String>) {
|
||||
{
|
||||
let _ = error;
|
||||
}
|
||||
{
|
||||
let _ = error_description;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// is larger than the interval desired by the server.
|
||||
fn pending(&mut self, &PollInformation) -> Retry {
|
||||
Retry::After(Duration::from_secs(5))
|
||||
}
|
||||
|
||||
/// The server has returned a `user_code` which must be shown to the user,
|
||||
/// along with the `verification_url`.
|
||||
/// # Notes
|
||||
/// * 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",
|
||||
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));
|
||||
}
|
||||
|
||||
/// Only method currently used by the InstalledFlow.
|
||||
/// We need the user to navigate to a URL using their browser and potentially paste back a code
|
||||
/// (or maybe not). Whether they have to enter a code depends on the InstalledFlowReturnMethod
|
||||
/// used.
|
||||
fn present_user_url(&mut self, url: &String, need_code: bool) -> Option<String> {
|
||||
if need_code {
|
||||
println!("Please direct your browser to {}, follow the instructions and enter the \
|
||||
code displayed here: ",
|
||||
url);
|
||||
|
||||
let mut code = String::new();
|
||||
io::stdin().read_line(&mut code).ok().map(|_| code)
|
||||
} else {
|
||||
println!("Please direct your browser to {} and follow the instructions displayed \
|
||||
there.",
|
||||
url);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses all default implementations by AuthenticatorDelegate, and makes the trait's
|
||||
/// implementation usable in the first place.
|
||||
pub struct DefaultAuthenticatorDelegate;
|
||||
impl AuthenticatorDelegate for DefaultAuthenticatorDelegate {}
|
||||
Reference in New Issue
Block a user