Files
twba.uploader/src/client/youtube/auth.rs
2024-04-20 16:17:25 +02:00

111 lines
3.8 KiB
Rust

use crate::client::youtube::flow_delegate::CustomFlowDelegate;
use crate::prelude::*;
use anyhow::{anyhow, Context};
use google_youtube3::api::Scope;
use google_youtube3::{hyper::client::HttpConnector, hyper_rustls::HttpsConnector, oauth2};
use std::collections::HashMap;
use std::fmt::Debug;
use std::path::{Path, PathBuf};
use tokio::fs;
use tracing::instrument;
use yup_oauth2::authenticator::Authenticator;
#[instrument]
pub(super) async fn get_auth<USER: EasyString>(
application_secret_path: &String,
scopes: &Vec<Scope>,
user: Option<USER>,
) -> Result<Authenticator<HttpsConnector<HttpConnector>>> {
trace!(
"getting auth for user: {:?} with scopes: {:?} and secret_path: {:?}",
user,
scopes,
application_secret_path
);
let app_secret = oauth2::read_application_secret(application_secret_path)
.await
.context("could not read application secret from path")?;
let persistent_path =
get_and_validate_persistent_path(&crate::CONF.google.path_auth_cache, user.clone()).await?;
trace!(
"persistent path for auth for user: {:?}: {:?}",
user,
&persistent_path
);
trace!("creating authenticator");
let user = user.map(|x| x.into());
let method = oauth2::InstalledFlowReturnMethod::Interactive;
let auth = oauth2::InstalledFlowAuthenticator::builder(app_secret, method)
.flow_delegate(Box::new(CustomFlowDelegate::new(user, &crate::CONF)))
.persist_tokens_to_disk(persistent_path)
.force_account_selection(true)
.build()
.await
.context("error creating authenticator")?;
trace!("got authenticator, requesting scopes");
let access_token = auth
.token(scopes)
.await
.context("could not get access to the requested scopes")?;
trace!("got scope access: {:?}", access_token);
Ok(auth)
}
async fn get_and_validate_persistent_path<TEMPLATE: EasyString, USER: EasyString>(
persistent_path_template: TEMPLATE,
user: Option<USER>,
) -> Result<PathBuf> {
let persistent_path = get_persistent_path(persistent_path_template, user.clone())?;
let persistent_path = Path::new(&persistent_path);
info!(
"Persistent auth path for user:{:?} => {}",
user,
persistent_path.display()
);
if persistent_path.is_dir() {
warn!("persistent path is a dir: {}", persistent_path.display());
}
let persistent_path_parent_folder = persistent_path
.parent()
.context("could not get parent folder")?;
if !persistent_path_parent_folder.exists() {
debug!(
"persistent path parent folder does not exist, creating it: {}",
persistent_path_parent_folder.display()
);
fs::create_dir_all(persistent_path_parent_folder)
.await
.context("could not create dirs")?;
} else if !persistent_path_parent_folder.is_dir() {
error!(
"persistent path parent folder is not a dir: {}",
persistent_path_parent_folder.display()
);
return Err(anyhow!(
"persistent path parent folder is not a dir: {}",
persistent_path_parent_folder.display()
)
.into());
}
Ok(persistent_path.to_path_buf())
}
fn get_persistent_path<TEMPLATE: EasyString, USER: EasyString>(
persistent_path_template: TEMPLATE,
user: Option<USER>,
) -> Result<String> {
let user: String = match user {
Some(user) => user.into(),
None => "unknown".to_string(),
};
let vars: HashMap<String, String> = HashMap::from([("user".to_string(), user)]);
let persistent_path = strfmt::strfmt(&persistent_path_template.into(), &vars)
.context("could not replace user in persistent path")?;
Ok(persistent_path)
}