refactor: read client_secret.json from disk instead of env vars
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use yup_oauth2::{
|
use yup_oauth2::{
|
||||||
authenticator::Authenticator, hyper::client::connect::HttpConnector,
|
authenticator::Authenticator, hyper::client::connect::HttpConnector,
|
||||||
hyper_rustls::HttpsConnector, ApplicationSecret, InstalledFlowAuthenticator,
|
hyper_rustls::HttpsConnector, InstalledFlowAuthenticator, InstalledFlowReturnMethod,
|
||||||
InstalledFlowReturnMethod,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::domain::models::*;
|
use crate::domain::models::*;
|
||||||
@@ -37,7 +36,7 @@ pub struct ApiClient {
|
|||||||
const SCOPES: &[&str] = &["https://www.googleapis.com/auth/tasks"];
|
const SCOPES: &[&str] = &["https://www.googleapis.com/auth/tasks"];
|
||||||
|
|
||||||
impl ApiClient {
|
impl ApiClient {
|
||||||
pub async fn new(client_id: String, client_secret: String) -> Result<Self, ApiError> {
|
pub async fn new(secret_path: impl AsRef<Path>) -> Result<Self, ApiError> {
|
||||||
let token_path = dirs::config_dir()
|
let token_path = dirs::config_dir()
|
||||||
.unwrap_or_else(|| PathBuf::from("."))
|
.unwrap_or_else(|| PathBuf::from("."))
|
||||||
.join("task_app")
|
.join("task_app")
|
||||||
@@ -47,17 +46,9 @@ impl ApiClient {
|
|||||||
std::fs::create_dir_all(parent).ok();
|
std::fs::create_dir_all(parent).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let secret = ApplicationSecret {
|
let secret = yup_oauth2::read_application_secret(secret_path)
|
||||||
client_id,
|
.await
|
||||||
client_secret,
|
.map_err(|e| ApiError::Auth(format!("Failed to read secret file: {}", e)))?;
|
||||||
auth_uri: "https://accounts.google.com/o/oauth2/v2/auth".to_string(),
|
|
||||||
token_uri: "https://oauth2.googleapis.com/token".to_string(),
|
|
||||||
redirect_uris: vec!["http://127.0.0.1:8080/".to_string()],
|
|
||||||
client_email: None,
|
|
||||||
client_x509_cert_url: None,
|
|
||||||
project_id: None,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let authenticator = InstalledFlowAuthenticator::builder(
|
let authenticator = InstalledFlowAuthenticator::builder(
|
||||||
secret,
|
secret,
|
||||||
|
|||||||
+40
-7
@@ -4,6 +4,7 @@ mod infrastructure;
|
|||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossterm::event::{self, Event};
|
use crossterm::event::{self, Event};
|
||||||
@@ -19,9 +20,33 @@ use crate::infrastructure::api::ApiClient;
|
|||||||
use crate::infrastructure::db::Db;
|
use crate::infrastructure::db::Db;
|
||||||
use crate::ui::{draw, AppView, NetworkStatus};
|
use crate::ui::{draw, AppView, NetworkStatus};
|
||||||
|
|
||||||
|
fn find_secret_file() -> Option<PathBuf> {
|
||||||
|
if let Ok(path) = std::env::var("GOOGLE_CLIENT_SECRET_FILE") {
|
||||||
|
let p = PathBuf::from(&path);
|
||||||
|
if p.exists() {
|
||||||
|
return Some(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let config_path = dirs::config_dir()
|
||||||
|
.unwrap_or_else(|| PathBuf::from("."))
|
||||||
|
.join("task_app")
|
||||||
|
.join("client_secret.json");
|
||||||
|
if config_path.exists() {
|
||||||
|
return Some(config_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let local_path = PathBuf::from("client_secret.json");
|
||||||
|
if local_path.exists() {
|
||||||
|
return Some(local_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
let db_path = dirs::data_dir()
|
let db_path = dirs::data_dir()
|
||||||
.unwrap_or_else(|| std::path::PathBuf::from("."))
|
.unwrap_or_else(|| PathBuf::from("."))
|
||||||
.join("task_app")
|
.join("task_app")
|
||||||
.join("tasks.db");
|
.join("tasks.db");
|
||||||
|
|
||||||
@@ -29,6 +54,17 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
let db = Arc::new(Db::new(db_path.to_str().unwrap()).expect("Failed to open database"));
|
let db = Arc::new(Db::new(db_path.to_str().unwrap()).expect("Failed to open database"));
|
||||||
|
|
||||||
|
let secret_path = find_secret_file().unwrap_or_else(|| {
|
||||||
|
eprintln!(
|
||||||
|
"ERROR: Google client secret file not found.\n\
|
||||||
|
Place client_secret.json in one of:\n\
|
||||||
|
- Set GOOGLE_CLIENT_SECRET_FILE env var\n\
|
||||||
|
- ~/.config/task_app/client_secret.json\n\
|
||||||
|
- ./client_secret.json (current directory)"
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
stdout.execute(EnterAlternateScreen)?;
|
stdout.execute(EnterAlternateScreen)?;
|
||||||
@@ -39,12 +75,9 @@ fn main() -> io::Result<()> {
|
|||||||
tokio::runtime::Runtime::new()
|
tokio::runtime::Runtime::new()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(async {
|
.block_on(async {
|
||||||
ApiClient::new(
|
ApiClient::new(&secret_path)
|
||||||
std::env::var("GOOGLE_CLIENT_ID").unwrap_or_default(),
|
.await
|
||||||
std::env::var("GOOGLE_CLIENT_SECRET").unwrap_or_default(),
|
.expect("Failed to create ApiClient")
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("Failed to create ApiClient")
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user