From 8f39c09c0ffb84a143c6aa88557083709deb0c60 Mon Sep 17 00:00:00 2001 From: 0-don <70039285+0-don@users.noreply.github.com> Date: Tue, 31 Dec 2024 00:53:54 +0100 Subject: [PATCH] add google drive --- package.json | 4 +- src-tauri/Cargo.lock | 206 +++++++++++++++++++- src-tauri/Cargo.toml | 1 + src-tauri/common/Cargo.toml | 1 + src-tauri/common/src/constants.rs | 1 + src-tauri/common/src/types/types.rs | 3 + src-tauri/src/commands/auth.rs | 14 ++ src-tauri/src/commands/mod.rs | 1 + src-tauri/src/lib.rs | 4 +- src-tauri/src/service/auth.rs | 0 src-tauri/src/tauri_config/config.rs | 1 + src-tauri/src/utils/google_drive_manager.rs | 58 ++++++ src-tauri/src/utils/mod.rs | 1 + src/components/navigation/app-sidebar.tsx | 8 + src/components/pages/app/app.tsx | 1 + src/types/tauri-invoke.ts | 11 +- 16 files changed, 307 insertions(+), 8 deletions(-) create mode 100644 src-tauri/src/commands/auth.rs create mode 100644 src-tauri/src/service/auth.rs create mode 100644 src-tauri/src/utils/google_drive_manager.rs diff --git a/package.json b/package.json index b0e4b5bd..c6746c0c 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "icon": "tauri icon" }, "dependencies": { - "@corvu/tooltip": "^0.2.1", - "@solid-primitives/i18n": "^2.1.1", + "@corvu/tooltip": "0.2.1", + "@solid-primitives/i18n": "2.1.1", "@tauri-apps/api": "2.1.1", "dayjs": "1.11.13", "solid-icons": "1.1.0", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2d279cfd..9526122e 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -938,6 +938,7 @@ dependencies = [ "enigo", "entity", "global-hotkey", + "google-drive3", "image", "infer", "migration", @@ -1026,6 +1027,7 @@ version = "1.0.0" dependencies = [ "entity", "global-hotkey", + "google-drive3", "sea-orm", "serde", "serde_json", @@ -1746,6 +1748,7 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -2097,9 +2100,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "global-hotkey" @@ -2140,6 +2143,49 @@ dependencies = [ "system-deps", ] +[[package]] +name = "google-apis-common" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7530ee92a7e9247c3294ae1b84ea98474dbc27563c49a14d3938e816499bf38f" +dependencies = [ + "base64 0.22.1", + "chrono", + "http", + "http-body-util", + "hyper", + "hyper-util", + "itertools 0.13.0", + "mime", + "percent-encoding", + "serde", + "serde_json", + "serde_with", + "tokio", + "url", + "yup-oauth2", +] + +[[package]] +name = "google-drive3" +version = "6.0.0+20240618" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e3944ee656d220932785cf1d8275519c0989830b9b239453983ac44f328d9f" +dependencies = [ + "chrono", + "google-apis-common", + "hyper", + "hyper-rustls", + "hyper-util", + "mime", + "serde", + "serde_json", + "serde_with", + "tokio", + "url", + "yup-oauth2", +] + [[package]] name = "gtk" version = "0.18.2" @@ -2192,6 +2238,25 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.7.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -2341,6 +2406,12 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.5.2" @@ -2350,9 +2421,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2", "http", "http-body", "httparse", + "httpdate", "itoa 1.0.14", "pin-project-lite", "smallvec", @@ -2360,6 +2433,24 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.10" @@ -2698,6 +2789,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -3317,6 +3417,15 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -3571,6 +3680,12 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "option-ext" version = "0.2.0" @@ -3624,7 +3739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" dependencies = [ "heck 0.4.1", - "itertools", + "itertools 0.12.1", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -4252,7 +4367,7 @@ dependencies = [ "built", "cfg-if", "interpolate_name", - "itertools", + "itertools 0.12.1", "libc", "libfuzzer-sys", "log", @@ -4576,6 +4691,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -4617,6 +4744,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "schemars" version = "0.8.21" @@ -4821,6 +4957,29 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "security-framework" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.22.0" @@ -6065,7 +6224,9 @@ checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa 1.0.14", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -6149,6 +6310,16 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -7434,6 +7605,33 @@ dependencies = [ "synstructure", ] +[[package]] +name = "yup-oauth2" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed5f19242090128c5809f6535cc7b8d4e2c32433f6c6005800bbc20a644a7f0" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.22.1", + "futures", + "http", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "seahash", + "serde", + "serde_json", + "time", + "tokio", + "url", +] + [[package]] name = "zbus" version = "4.4.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c379eb37..11ae8ded 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -58,6 +58,7 @@ tree_magic_mini = "3" color-backtrace = "0" +google-drive3 = { version = "6.0.0" } [profile.release] # panic = "abort" # codegen-units = 1 diff --git a/src-tauri/common/Cargo.toml b/src-tauri/common/Cargo.toml index 1338c90f..70413b5e 100644 --- a/src-tauri/common/Cargo.toml +++ b/src-tauri/common/Cargo.toml @@ -9,6 +9,7 @@ path = "src/lib.rs" [dependencies] entity = { path = "../entity" } +google-drive3 = { version = "6.0.0" } global-hotkey = "0" sea-orm = "1" serde = "1" diff --git a/src-tauri/common/src/constants.rs b/src-tauri/common/src/constants.rs index 278d0b8c..0954ad1c 100644 --- a/src-tauri/common/src/constants.rs +++ b/src-tauri/common/src/constants.rs @@ -11,6 +11,7 @@ pub static GLOBAL_EVENTS: LazyLock<Vec<String>> = LazyLock::new(|| { pub static DB_NAME: &str = "clippy.sqlite"; pub static CONFIG_NAME: &str = "config.json"; +pub static TOKEN_NAME: &str = "token.json"; pub static MAIN_WINDOW_X: i32 = 375; pub static MAIN_WINDOW_Y: i32 = 600; diff --git a/src-tauri/common/src/types/types.rs b/src-tauri/common/src/types/types.rs index c6add41f..da05d029 100644 --- a/src-tauri/common/src/types/types.rs +++ b/src-tauri/common/src/types/types.rs @@ -1,9 +1,12 @@ use global_hotkey::hotkey::HotKey; +use google_drive3::yup_oauth2; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct Config { pub db: String, + #[serde(default)] + pub drive_token: Option<yup_oauth2::AccessToken>, } #[derive(Serialize, Deserialize, Debug)] diff --git a/src-tauri/src/commands/auth.rs b/src-tauri/src/commands/auth.rs new file mode 100644 index 00000000..3f29144a --- /dev/null +++ b/src-tauri/src/commands/auth.rs @@ -0,0 +1,14 @@ +use common::types::types::CommandError; + +use crate::utils::google_drive_manager::DriveManager; + +#[tauri::command] +pub async fn auth_google_drive() -> Result<(), CommandError> { + let drive_manager = DriveManager::new().await?; + + if drive_manager.is_authenticated().await { + Ok(()) + } else { + Err(CommandError::Error("Authentication failed".to_string())) + } +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 7573f925..2ae9f479 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -2,3 +2,4 @@ pub mod clipboard; pub mod hotkey; pub mod settings; pub mod window; +pub mod auth; \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 274c0505..7e86839a 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -6,7 +6,7 @@ mod service; mod tauri_config; mod utils; -use commands::{clipboard, hotkey, settings, window}; +use commands::{auth, clipboard, hotkey, settings, window}; use tauri_config::setup; use tauri_plugin_autostart::MacosLauncher; @@ -48,6 +48,8 @@ pub fn run() { window::get_db_path, window::get_config_path, window::open_folder, + // + auth::auth_google_drive, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/service/auth.rs b/src-tauri/src/service/auth.rs new file mode 100644 index 00000000..e69de29b diff --git a/src-tauri/src/tauri_config/config.rs b/src-tauri/src/tauri_config/config.rs index a90937b5..5d4a94cc 100644 --- a/src-tauri/src/tauri_config/config.rs +++ b/src-tauri/src/tauri_config/config.rs @@ -60,6 +60,7 @@ pub fn create_config() { let config = Config { db: format!("{}", &data_path.db_file_path), + drive_token: None, }; let _ = fs::write( diff --git a/src-tauri/src/utils/google_drive_manager.rs b/src-tauri/src/utils/google_drive_manager.rs new file mode 100644 index 00000000..b6e66c2b --- /dev/null +++ b/src-tauri/src/utils/google_drive_manager.rs @@ -0,0 +1,58 @@ +use common::{constants::TOKEN_NAME, types::types::CommandError}; +use google_drive3::{hyper_rustls, hyper_util, yup_oauth2, DriveHub}; +use hyper_util::client::legacy::connect::HttpConnector; + +pub struct DriveManager { + hub: Option<DriveHub<hyper_rustls::HttpsConnector<HttpConnector>>>, +} + +impl DriveManager { + pub async fn new() -> Result<Self, CommandError> { + let secret = yup_oauth2::ApplicationSecret { + client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com".to_string(), + client_secret: "".to_string(), + auth_uri: "https://accounts.google.com/o/oauth2/auth".to_string(), + token_uri: "https://oauth2.googleapis.com/token".to_string(), + redirect_uris: vec!["http://127.0.0.1:1420/oauth/callback".to_string()], + ..Default::default() + }; + + // Use the config directory for token storage + let data_path = crate::service::settings::get_data_path(); + let token_path = std::path::Path::new(&data_path.config_path).join(TOKEN_NAME); + + let auth = yup_oauth2::InstalledFlowAuthenticator::builder( + secret, + yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect, + ) + .persist_tokens_to_disk(token_path) + .build() + .await + .map_err(|e| CommandError::Error(e.to_string()))?; + + let client = + hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()) + .build( + hyper_rustls::HttpsConnectorBuilder::new() + .with_native_roots() + .unwrap() + .https_or_http() + .enable_http1() + .build(), + ); + + let hub = DriveHub::new(client, auth); + Ok(Self { hub: Some(hub) }) + } + + pub async fn is_authenticated(&self) -> bool { + if let Some(hub) = &self.hub { + hub.auth + .get_token(&["https://www.googleapis.com/auth/drive.file"]) + .await + .is_ok() + } else { + false + } + } +} diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 88862524..b71796b4 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod clipboard_manager; pub mod hotkey_manager; +pub mod google_drive_manager; \ No newline at end of file diff --git a/src/components/navigation/app-sidebar.tsx b/src/components/navigation/app-sidebar.tsx index 1e5003fc..30e6fc68 100644 --- a/src/components/navigation/app-sidebar.tsx +++ b/src/components/navigation/app-sidebar.tsx @@ -1,6 +1,8 @@ import { Component, For, Show } from "solid-js"; +import { invokeCommand } from "../../lib/tauri"; import { AppStore } from "../../store/app-store"; import { HotkeyStore } from "../../store/hotkey-store"; +import { InvokeCommand } from "../../types/tauri-invoke"; import { useLanguage } from "../provider/language-provider"; interface AppSidebarProps {} @@ -36,6 +38,12 @@ export const AppSidebar: Component<AppSidebarProps> = ({}) => { ); }} </For> + <button + onClick={() => invokeCommand(InvokeCommand.AuthGoogleDrive)} + class="relative flex h-6 w-full cursor-pointer select-none items-center justify-center py-5 text-xl text-black hover:text-black dark:text-white dark:hover:text-white" + > + test + </button> </Show> ); }; diff --git a/src/components/pages/app/app.tsx b/src/components/pages/app/app.tsx index 5d23e46d..899dbefc 100644 --- a/src/components/pages/app/app.tsx +++ b/src/components/pages/app/app.tsx @@ -17,6 +17,7 @@ function App() { <div class="flex h-full w-full overflow-hidden bg-white text-black dark:bg-dark dark:text-white"> <div class="flex w-12 flex-col items-center space-y-3 bg-gray-200 pt-2 dark:bg-dark-light"> <AppSidebar /> + </div> <div class="flex h-screen min-w-0 flex-1 flex-col"> <div class="z-10 flex w-full justify-between overflow-visible px-2 py-1"> diff --git a/src/types/tauri-invoke.ts b/src/types/tauri-invoke.ts index 562306d3..dff78e59 100644 --- a/src/types/tauri-invoke.ts +++ b/src/types/tauri-invoke.ts @@ -2,6 +2,9 @@ import { ClipboardResponse, ClipboardWhere, DatabaseInfo, Hotkey, Settings } fro import { ClipboardType, FolderLocation, WebWindow } from "./enums"; export enum InvokeCommand { + //Auth + AuthGoogleDrive = "auth_google_drive", + // Clipboard commands GetClipboards = "get_clipboards", DeleteClipboard = "delete_clipboard", @@ -35,6 +38,12 @@ export enum InvokeCommand { } export interface TauriInvokeCommands { + //Auth + [InvokeCommand.AuthGoogleDrive]: { + args: undefined; + return: void; + }; + // Clipboard commands [InvokeCommand.GetClipboards]: { args: ClipboardWhere; @@ -95,7 +104,7 @@ export interface TauriInvokeCommands { // Window commands [InvokeCommand.OpenNewWindow]: { - args: { windowName: WebWindow, title: string }; + args: { windowName: WebWindow; title: string }; return: void; }; [InvokeCommand.OpenBrowserUrl]: {