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]: {