mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-04 10:32:16 +01:00
Merge branch 'generic_oauth2_clean'
This commit is contained in:
@@ -19,6 +19,7 @@ path = "src/rust/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = "2"
|
||||
http = "^0.2"
|
||||
hyper = "0.14"
|
||||
mime = "0.2"
|
||||
rustc-serialize = "*"
|
||||
@@ -30,4 +31,4 @@ strsim = "*"
|
||||
tokio = "^ 1.0"
|
||||
hyper-rustls = "^0.22"
|
||||
itertools = "^ 0.10"
|
||||
tower-service = "^0.3"
|
||||
tower-service = "^0.3"
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<a name="api-v2.0.0:cli-v2.0.0"></a>
|
||||
|
||||
## api/cli-vNEXT (YYYY-MM-DD)
|
||||
|
||||
- New `GetToken` trait for custom ways of specifying a token. The latter can now be a String or be
|
||||
`NoToken` as well.
|
||||
- Upgrade `mkdocs` to a more recent version that doesn't break in more recent python interpreters.
|
||||
|
||||
## api/cli-v3.0.0 (2022-3-8)
|
||||
|
||||
- Support for yup-oauth 0.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mako==1.1.4
|
||||
mako==1.2.2
|
||||
pyyaml<6
|
||||
mkdocs==0.11
|
||||
mkdocs==1.3.1
|
||||
pytest
|
||||
pytest-cov
|
||||
codecov
|
||||
|
||||
@@ -26,12 +26,16 @@ path = "src/main.rs"
|
||||
% endif
|
||||
|
||||
[dependencies]
|
||||
## TODO: temporary, remove when yup-oauth2 is optional
|
||||
anyhow = "^ 1.0"
|
||||
hyper-rustls = "0.23.0"
|
||||
## Must match the one hyper uses, otherwise there are duplicate similarly named `Mime` structs
|
||||
mime = "^ 0.2.0"
|
||||
serde = "^ 1.0"
|
||||
serde_json = "^ 1.0"
|
||||
serde_derive = "^ 1.0"
|
||||
## TODO: Make yup-oauth2 optional
|
||||
## yup-oauth2 = { version = "^ 7.0", optional = true }
|
||||
yup-oauth2 = "^ 7.0"
|
||||
itertools = "^ 0.10"
|
||||
% for dep in cargo.get('dependencies', list()):
|
||||
@@ -41,7 +45,7 @@ ${dep}
|
||||
<%
|
||||
api_name = util.library_name()
|
||||
crate_name_we_depend_on = None
|
||||
|
||||
|
||||
if make.depends_on_suffix is not None:
|
||||
crate_name_we_depend_on = library_to_crate_name(api_name, suffix=make.depends_on_suffix)
|
||||
%>\
|
||||
@@ -53,3 +57,7 @@ ${dep}
|
||||
path = "../${api_name}"
|
||||
version = "${util.crate_version()}"
|
||||
% endif
|
||||
|
||||
## TODO: Make yup-oauth2 optional
|
||||
# [features]
|
||||
# default = ["yup-oauth2"]
|
||||
|
||||
@@ -30,7 +30,7 @@ use http::Uri;
|
||||
use hyper::client::connect;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service;
|
||||
use crate::client;
|
||||
use crate::{client, client::GetToken};
|
||||
|
||||
// ##############
|
||||
// UTILITIES ###
|
||||
@@ -55,7 +55,7 @@ ${lib.hub_usage_example(c)}\
|
||||
#[derive(Clone)]
|
||||
pub struct ${hub_type}${ht_params} {
|
||||
pub client: hyper::Client<S, hyper::body::Body>,
|
||||
pub auth: oauth2::authenticator::Authenticator<S>,
|
||||
pub auth: Box<dyn client::GetToken>,
|
||||
_user_agent: String,
|
||||
_base_url: String,
|
||||
_root_url: String,
|
||||
@@ -65,10 +65,10 @@ impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> client::Hub for ${hub_type}${ht_para
|
||||
|
||||
impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> ${hub_type}${ht_params} {
|
||||
|
||||
pub fn new(client: hyper::Client<S, hyper::body::Body>, authenticator: oauth2::authenticator::Authenticator<S>) -> ${hub_type}${ht_params} {
|
||||
pub fn new<A: 'static + client::GetToken>(client: hyper::Client<S, hyper::body::Body>, auth: A) -> ${hub_type}${ht_params} {
|
||||
${hub_type} {
|
||||
client,
|
||||
auth: authenticator,
|
||||
auth: Box::new(auth),
|
||||
_user_agent: "${default_user_agent}".to_string(),
|
||||
_base_url: "${baseUrl}".to_string(),
|
||||
_root_url: "${rootUrl}".to_string(),
|
||||
|
||||
@@ -706,10 +706,21 @@ else {
|
||||
|
||||
loop {
|
||||
% if default_scope:
|
||||
let token = match ${auth_call}.token(&self.${api.properties.scopes}.keys().collect::<Vec<_>>()[..]).await {
|
||||
Ok(token) => token.clone(),
|
||||
let token = match ${auth_call}.get_token(&self.${api.properties.scopes}.keys().map(String::as_str).collect::<Vec<_>>()[..]).await {
|
||||
// TODO: remove Ok / Err branches
|
||||
Ok(Some(token)) => token.clone(),
|
||||
Ok(None) => {
|
||||
let err = oauth2::Error::OtherError(anyhow::Error::msg("unknown error occurred while generating oauth2 token"));
|
||||
match dlg.token(&err) {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
${delegate_finish}(false);
|
||||
return Err(client::Error::MissingToken(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
match dlg.token(&err) {
|
||||
match dlg.token(&err) {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
${delegate_finish}(false);
|
||||
|
||||
@@ -14,11 +14,12 @@ repo_url: ${util.github_source_root_url()}
|
||||
docs_dir: ${mkdocs.docs_dir}
|
||||
site_dir: ${mkdocs.site_dir}
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
nav:
|
||||
- Home: 'index.md'
|
||||
% for resource in sorted(c.rta_map.keys()):
|
||||
- '${pretty(resource)}':
|
||||
% for method in sorted(c.rta_map[resource]):
|
||||
- ['${subcommand_md_filename(resource, method)}', '${pretty(resource)}', '${pretty(method)}']
|
||||
- '${pretty(method)}': '${subcommand_md_filename(resource, method)}'
|
||||
% endfor # each method
|
||||
% endfor # each resource
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::error;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Display};
|
||||
use std::future::Future;
|
||||
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
@@ -105,12 +107,13 @@ pub trait Delegate: Send {
|
||||
None
|
||||
}
|
||||
|
||||
// TODO: Remove oauth2::Error
|
||||
/// Called whenever the Authenticator didn't yield a token. The delegate
|
||||
/// may attempt to provide one, or just take it as a general information about the
|
||||
/// impending failure.
|
||||
/// The given Error provides information about why the token couldn't be acquired in the
|
||||
/// first place
|
||||
fn token(&mut self, err: &oauth2::Error) -> Option<oauth2::AccessToken> {
|
||||
fn token(&mut self, err: &oauth2::Error) -> Option<String> {
|
||||
let _ = err;
|
||||
None
|
||||
}
|
||||
@@ -227,6 +230,7 @@ pub enum Error {
|
||||
/// Neither through the authenticator, nor through the Delegate.
|
||||
MissingAPIKey,
|
||||
|
||||
// TODO: Remove oauth2::Error
|
||||
/// We required a Token, but didn't get one from the Authenticator
|
||||
MissingToken(oauth2::Error),
|
||||
|
||||
@@ -272,6 +276,7 @@ impl Display for Error {
|
||||
writeln!(f, "Bad Request: {}", message)?;
|
||||
Ok(())
|
||||
}
|
||||
// TODO: Remove oauth2::Error
|
||||
Error::MissingToken(ref err) => {
|
||||
writeln!(f, "Token retrieval failed with error: {}", err)
|
||||
}
|
||||
@@ -785,3 +790,75 @@ pub async fn get_body_as_string(res_body: &mut hyper::Body) -> String {
|
||||
let res_body_string = String::from_utf8_lossy(&res_body_buf);
|
||||
res_body_string.to_string()
|
||||
}
|
||||
|
||||
// TODO: Simplify this to Option<String>
|
||||
type TokenResult = std::result::Result<Option<String>, oauth2::Error>;
|
||||
|
||||
pub trait GetToken: GetTokenClone {
|
||||
/// Called whenever there is the need for an oauth token after
|
||||
/// the official authenticator implementation didn't provide one, for some reason.
|
||||
/// If this method returns None as well, the underlying operation will fail
|
||||
fn get_token<'a>(&'a self, _scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=TokenResult> + 'a>> {
|
||||
Box::pin(async move { Ok(None) })
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GetTokenClone {
|
||||
fn clone_box(&self) -> Box<dyn GetToken>;
|
||||
}
|
||||
|
||||
impl<T> GetTokenClone for T
|
||||
where
|
||||
T: 'static + GetToken + Clone,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn GetToken> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn GetToken> {
|
||||
fn clone(&self) -> Box<dyn GetToken> {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetToken for String {
|
||||
fn get_token<'a>(&'a self, _scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=TokenResult> + 'a>> {
|
||||
Box::pin(async move { Ok(Some(self.clone())) })
|
||||
}
|
||||
}
|
||||
|
||||
/// In the event that the API endpoint does not require an oauth2 token, `NoToken` should be provided to the hub to avoid specifying an
|
||||
/// authenticator.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct NoToken;
|
||||
|
||||
impl GetToken for NoToken {}
|
||||
|
||||
// TODO: Make this optional
|
||||
// #[cfg(feature = "yup-oauth2")]
|
||||
mod yup_oauth2_impl {
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
|
||||
use super::{GetToken, TokenResult};
|
||||
|
||||
use tower_service::Service;
|
||||
use yup_oauth2::authenticator::Authenticator;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use http::Uri;
|
||||
use hyper::client::connect::Connection;
|
||||
|
||||
|
||||
impl<S> GetToken for Authenticator<S> where
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn std::error::Error + Send + Sync>> {
|
||||
fn get_token<'a>(&'a self, scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=TokenResult> + 'a>> {
|
||||
Box::pin(async move {
|
||||
self.token(scopes).await.map(|t| Some(t.as_str().to_owned()))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user