diff --git a/.gitignore b/.gitignore index 6012afdb..95f7b19a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ dist yarn.lock package-lock.json pnpm-lock.yamlor.log -bun.lockb +bun.lock* # Generated by Tauri # will have schema files for capabilities auto-completion diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c6b872c0..d6812dd1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -939,7 +939,6 @@ dependencies = [ "sea-orm", "serde", "serde_json", - "tao 1.0.0", "tauri", "tauri-build", "tauri-plugin-autostart", @@ -1124,15 +1123,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "croner" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fd53511eaf0b00a185613875fee58b208dfce016577d0ad4bb548e1c4fb3ee" -dependencies = [ - "chrono", -] - [[package]] name = "crossbeam-channel" version = "0.5.14" @@ -5726,27 +5716,6 @@ dependencies = [ "x11-dl", ] -[[package]] -name = "tao" -version = "1.0.0" -dependencies = [ - "async-trait", - "chrono", - "common", - "entity", - "global-hotkey", - "google-drive3", - "migration", - "sea-orm", - "serde", - "serde_json", - "tauri", - "tauri-plugin-dialog", - "tl", - "tokio", - "tokio-cron-scheduler", -] - [[package]] name = "tao-macros" version = "0.1.3" @@ -6063,7 +6032,7 @@ dependencies = [ "percent-encoding", "raw-window-handle", "softbuffer", - "tao 0.31.1", + "tao", "tauri-runtime", "tauri-utils", "url", @@ -6295,21 +6264,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-cron-scheduler" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5597b569b4712cf78aa0c9ae29742461b7bda1e49c2a5fdad1d79bf022f8f0" -dependencies = [ - "chrono", - "croner", - "num-derive", - "num-traits", - "tokio", - "tracing", - "uuid", -] - [[package]] name = "tokio-macros" version = "2.5.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c8539012..8ab15ac2 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ name = "tauri_app_lib" crate-type = ["staticlib", "cdylib", "rlib"] [workspace] -members = [".", "migration", "entity", "common", "tao"] +members = [".", "migration", "entity", "common"] [build-dependencies] tauri-build = { version = "2", features = [] } @@ -24,7 +24,6 @@ tauri-build = { version = "2", features = [] } entity = { path = "entity" } migration = { path = "migration" } common = { path = "common" } -tao = { path = "tao" } tauri = { version = "2", features = [ "macos-private-api", diff --git a/src-tauri/entity/src/clipboard.rs b/src-tauri/entity/src/clipboard.rs index 3be55dbb..bb663d78 100644 --- a/src-tauri/entity/src/clipboard.rs +++ b/src-tauri/entity/src/clipboard.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/clipboard_file.rs b/src-tauri/entity/src/clipboard_file.rs index a93a2c5e..1c6a1fe6 100644 --- a/src-tauri/entity/src/clipboard_file.rs +++ b/src-tauri/entity/src/clipboard_file.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; @@ -18,12 +18,12 @@ impl EntityName for Entity { pub struct Model { pub id: Uuid, pub clipboard_id: Uuid, - pub name: Option, + pub name: String, + pub size: i32, pub extension: Option, - pub size: Option, pub mime_type: Option, - pub created_date: Option, - pub modified_date: Option, + pub created_date: DateTime, + pub modified_date: DateTime, pub data: Vec, } @@ -32,8 +32,8 @@ pub enum Column { Id, ClipboardId, Name, - Extension, Size, + Extension, MimeType, CreatedDate, ModifiedDate, @@ -63,12 +63,12 @@ impl ColumnTrait for Column { match self { Self::Id => ColumnType::Uuid.def(), Self::ClipboardId => ColumnType::Uuid.def(), - Self::Name => ColumnType::String(StringLen::None).def().null(), + Self::Name => ColumnType::String(StringLen::None).def(), + Self::Size => ColumnType::Integer.def(), Self::Extension => ColumnType::String(StringLen::None).def().null(), - Self::Size => ColumnType::Integer.def().null(), Self::MimeType => ColumnType::String(StringLen::None).def().null(), - Self::CreatedDate => ColumnType::DateTime.def().null(), - Self::ModifiedDate => ColumnType::DateTime.def().null(), + Self::CreatedDate => ColumnType::DateTime.def(), + Self::ModifiedDate => ColumnType::DateTime.def(), Self::Data => ColumnType::Blob.def(), } } diff --git a/src-tauri/entity/src/clipboard_html.rs b/src-tauri/entity/src/clipboard_html.rs index 2f5e8a31..3c085201 100644 --- a/src-tauri/entity/src/clipboard_html.rs +++ b/src-tauri/entity/src/clipboard_html.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/clipboard_image.rs b/src-tauri/entity/src/clipboard_image.rs index c82dfd90..4fec597b 100644 --- a/src-tauri/entity/src/clipboard_image.rs +++ b/src-tauri/entity/src/clipboard_image.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/clipboard_rtf.rs b/src-tauri/entity/src/clipboard_rtf.rs index 5c9bad7a..f64931ee 100644 --- a/src-tauri/entity/src/clipboard_rtf.rs +++ b/src-tauri/entity/src/clipboard_rtf.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/clipboard_text.rs b/src-tauri/entity/src/clipboard_text.rs index fa5adf0f..93764ccb 100644 --- a/src-tauri/entity/src/clipboard_text.rs +++ b/src-tauri/entity/src/clipboard_text.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/hotkey.rs b/src-tauri/entity/src/hotkey.rs index 01a9ca98..7ff3b217 100644 --- a/src-tauri/entity/src/hotkey.rs +++ b/src-tauri/entity/src/hotkey.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/entity/src/lib.rs b/src-tauri/entity/src/lib.rs index 8eed0141..983e6840 100644 --- a/src-tauri/entity/src/lib.rs +++ b/src-tauri/entity/src/lib.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 pub mod prelude; diff --git a/src-tauri/entity/src/prelude.rs b/src-tauri/entity/src/prelude.rs index 0810789a..2bc950ef 100644 --- a/src-tauri/entity/src/prelude.rs +++ b/src-tauri/entity/src/prelude.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 pub use super::clipboard::Entity as Clipboard; pub use super::clipboard_file::Entity as ClipboardFile; diff --git a/src-tauri/entity/src/settings.rs b/src-tauri/entity/src/settings.rs index b155edf6..ebff8441 100644 --- a/src-tauri/entity/src/settings.rs +++ b/src-tauri/entity/src/settings.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.2 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.4 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/migration/src/m000006_create_clipboard_file.rs b/src-tauri/migration/src/m000006_create_clipboard_file.rs index c63d3996..cd87b710 100644 --- a/src-tauri/migration/src/m000006_create_clipboard_file.rs +++ b/src-tauri/migration/src/m000006_create_clipboard_file.rs @@ -1,7 +1,7 @@ use crate::m000001_create_clipboard::Clipboard; use sea_orm_migration::{ prelude::*, - schema::{blob, date_time_null, integer_null, string_null, uuid}, + schema::{blob, date_time, integer, string, string_null, uuid}, }; #[derive(Iden)] @@ -31,12 +31,12 @@ impl MigrationTrait for Migration { .if_not_exists() .col(uuid(ClipboardFile::Id).not_null().primary_key()) .col(uuid(ClipboardFile::ClipboardId)) - .col(string_null(ClipboardFile::Name)) + .col(string(ClipboardFile::Name)) + .col(integer(ClipboardFile::Size).default(0)) .col(string_null(ClipboardFile::Extension)) - .col(integer_null(ClipboardFile::Size)) .col(string_null(ClipboardFile::MimeType)) - .col(date_time_null(ClipboardFile::CreatedDate)) - .col(date_time_null(ClipboardFile::ModifiedDate)) + .col(date_time(ClipboardFile::CreatedDate)) + .col(date_time(ClipboardFile::ModifiedDate)) .col(blob(ClipboardFile::Data)) .foreign_key( ForeignKey::create() diff --git a/src-tauri/src/commands/clipboard.rs b/src-tauri/src/commands/clipboard.rs index f3f63107..8657e2bd 100644 --- a/src-tauri/src/commands/clipboard.rs +++ b/src-tauri/src/commands/clipboard.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use crate::tao::global::{get_app, get_main_window}; use crate::{ service::clipboard::{ clear_clipboards_db, copy_clipboard_from_id, delete_clipboards_db, get_clipboard_count_db, @@ -17,7 +18,6 @@ use common::{ }; use sea_orm::prelude::Uuid; use std::fs::File; -use tao::global::{get_app, get_main_window}; use tauri::{Emitter, Manager}; #[tauri::command] diff --git a/src-tauri/src/commands/settings.rs b/src-tauri/src/commands/settings.rs index 683aec54..04bbe5d0 100644 --- a/src-tauri/src/commands/settings.rs +++ b/src-tauri/src/commands/settings.rs @@ -1,7 +1,6 @@ -use crate::service::settings::{autostart, get_settings_db, update_settings_db}; +use crate::{service::settings::{autostart, get_settings_db, update_settings_db}, tao::config::{change_clipboard_db_location_enable, reset_clipboard_db_location_disable}}; use common::types::types::CommandError; use entity::settings::Model; -use tao::config::{change_clipboard_db_location_enable, reset_clipboard_db_location_disable}; #[tauri::command] pub async fn get_settings() -> Result { diff --git a/src-tauri/src/commands/sync.rs b/src-tauri/src/commands/sync.rs index 7ae502d3..c8a926e8 100644 --- a/src-tauri/src/commands/sync.rs +++ b/src-tauri/src/commands/sync.rs @@ -1,11 +1,10 @@ -use crate::service::{ +use crate::{service::{ settings::{get_global_settings, init_settings_window, set_global_settings}, sync::{get_sync_provider, sync_toggle, upsert_settings_sync}, -}; +}, tao::connection::db}; use common::types::types::CommandError; use entity::settings::{self, ActiveModel}; use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait}; -use tao::connection::db; #[tauri::command] pub async fn sync_authenticate_toggle() -> Result { diff --git a/src-tauri/src/commands/window.rs b/src-tauri/src/commands/window.rs index 7b280e05..d7b0c0d8 100644 --- a/src-tauri/src/commands/window.rs +++ b/src-tauri/src/commands/window.rs @@ -1,11 +1,10 @@ -use crate::service::{ +use crate::{service::{ clipboard::count_clipboards_db, window::open_window, -}; +}, tao::config::get_data_path}; use common::types::{ enums::{FolderLocation, WebWindow}, types::{CommandError, Config, DatabaseInfo}, }; -use tao::config::get_data_path; use std::{ fs::{self, read_to_string}, path::PathBuf, diff --git a/src-tauri/src/config/setup.rs b/src-tauri/src/config/setup.rs index a7f8facb..9152ac3c 100644 --- a/src-tauri/src/config/setup.rs +++ b/src-tauri/src/config/setup.rs @@ -4,9 +4,9 @@ use crate::{ clipboard_events::init_clipboard_listener, hotkey_events::init_hotkey_listener, window_events::init_window_event_listener, }, - service::{settings::init_settings, sync::init_sync_interval, window::init_window}, + service::{encrypt::set_encryption_key, settings::init_settings, sync::init_sync_interval, window::init_window}, + tao::{config::create_config, tao_constants::init_globals}, }; -use tao::{config::create_config, tauri_constants::init_globals}; pub fn setup(app: &mut tauri::App) -> Result<(), Box<(dyn std::error::Error + 'static)>> { init_globals(app); @@ -20,6 +20,6 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<(dyn std::error::Error + 's init_hotkey_listener(); init_window_event_listener(); init_sync_interval(); - + set_encryption_key("asd").expect("Failed to set encryption key"); Ok(()) } diff --git a/src-tauri/src/config/tray.rs b/src-tauri/src/config/tray.rs index 813a2345..8f1c9bed 100644 --- a/src-tauri/src/config/tray.rs +++ b/src-tauri/src/config/tray.rs @@ -1,5 +1,4 @@ -use crate::service::window::toggle_main_window; -use tao::global::get_app; +use crate::{service::window::toggle_main_window, tao::global::get_app}; use tauri::{ menu::{Menu, MenuItem}, tray::TrayIconBuilder, diff --git a/src-tauri/src/events/clipboard_events.rs b/src-tauri/src/events/clipboard_events.rs index 1b76df54..1ca0943f 100644 --- a/src-tauri/src/events/clipboard_events.rs +++ b/src-tauri/src/events/clipboard_events.rs @@ -1,6 +1,5 @@ -use crate::utils::clipboard_manager::ClipboardManagerExt; +use crate::{tao::global::get_app, utils::clipboard_manager::ClipboardManagerExt}; use common::types::orm_query::FullClipboardDbo; -use tao::global::get_app; use tauri::{Listener, Manager}; use tauri_plugin_clipboard::Clipboard; diff --git a/src-tauri/src/events/hotkey_events.rs b/src-tauri/src/events/hotkey_events.rs index 95cb0831..01249f0f 100644 --- a/src-tauri/src/events/hotkey_events.rs +++ b/src-tauri/src/events/hotkey_events.rs @@ -1,6 +1,7 @@ use crate::commands::sync::sync_authenticate_toggle; use crate::prelude::*; use crate::service::window::open_window; +use crate::tao::global::{get_app, get_hotkey_running, get_hotkey_stop_tx, get_hotkey_store, get_main_window}; use crate::{ service::{ clipboard::copy_clipboard_from_index, @@ -14,9 +15,6 @@ use common::types::types::Key; use core::time::Duration; use global_hotkey::{GlobalHotKeyEvent, HotKeyState}; use regex::Regex; -use tao::global::{ - get_app, get_hotkey_running, get_hotkey_stop_tx, get_hotkey_store, get_main_window, -}; use tauri::Emitter; use tokio::sync::oneshot; diff --git a/src-tauri/src/events/window_events.rs b/src-tauri/src/events/window_events.rs index a7d1074d..8e1808a0 100644 --- a/src-tauri/src/events/window_events.rs +++ b/src-tauri/src/events/window_events.rs @@ -1,7 +1,7 @@ -use crate::prelude::*; +use crate::tao::global::{get_hotkey_running, get_window_stop_tx}; +use crate::{prelude::*, tao::global::get_main_window}; use crate::utils::hotkey_manager::unregister_hotkeys; use common::types::enums::ListenEvent; -use tao::global::{get_hotkey_running, get_main_window, get_window_stop_tx}; use tauri::{Emitter, WindowEvent}; use tokio::sync::oneshot; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2cb04150..cde0da82 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -4,6 +4,7 @@ mod events; mod prelude; mod service; mod utils; +mod tao; use commands::{cipher, clipboard, hotkey, settings, sync, window}; use config::setup; diff --git a/src-tauri/src/service/clipboard.rs b/src-tauri/src/service/clipboard.rs index 488c5c88..47f003fc 100644 --- a/src-tauri/src/service/clipboard.rs +++ b/src-tauri/src/service/clipboard.rs @@ -1,6 +1,8 @@ use super::settings::get_global_settings; use super::sync::{get_sync_manager, get_sync_provider}; use crate::prelude::*; +use crate::tao::connection::db; +use crate::tao::global::{get_app, get_app_window, get_main_window}; use chrono::NaiveDateTime; use common::builder::keyword::KeywordBuilder; use common::io::clipboard::trim_clipboard_data; @@ -19,8 +21,6 @@ use sea_orm::{ }; use std::collections::HashMap; use std::sync::Mutex; -use tao::connection::db; -use tao::global::{get_app, get_app_window, get_main_window}; use tauri::{Emitter, Manager}; use tauri_plugin_clipboard::Clipboard; use tokio::try_join; @@ -456,7 +456,7 @@ pub async fn delete_clipboards_db( .emit(ListenEvent::InitClipboards.to_string().as_str(), ()) .expect("Failed to emit event"); } - + for clippy in clipboards { printlog!( "deleting remote clipboard: {:?} command: {:?}", @@ -668,7 +668,7 @@ pub async fn copy_clipboard_from_id( .filter_map(|f| { let path = std::env::temp_dir().join(format!( "{}.{}", - f.name.as_ref().expect("Failed to get file name"), + &f.name, f.extension.as_ref().expect("Failed to get file extension") )); std::fs::write(&path, &f.data).ok()?; diff --git a/src-tauri/src/service/decrypt.rs b/src-tauri/src/service/decrypt.rs index 30cf0cc9..12771b11 100644 --- a/src-tauri/src/service/decrypt.rs +++ b/src-tauri/src/service/decrypt.rs @@ -1,37 +1,219 @@ -use super::{clipboard::load_clipboards_with_relations, encrypt::looks_like_encrypted_data}; -use common::types::{ - crypto::{EncryptionError, ENCRYPTION_KEY}, - types::CommandError, +use super::{ + clipboard::load_clipboards_with_relations, encrypt::looks_like_encrypted_data, + settings::get_global_settings, sync::get_sync_provider, +}; +use crate::{ + prelude::*, + tao::{connection::db, global::get_app}, +}; +use base64::{engine::general_purpose::STANDARD, Engine}; +use common::{ + printlog, + types::{ + crypto::{EncryptionError, ENCRYPTION_KEY}, + enums::ListenEvent, + orm_query::FullClipboardDto, + types::{CommandError, Progress}, + }, +}; +use entity::{ + clipboard, clipboard_file, clipboard_html, clipboard_image, clipboard_rtf, clipboard_text, }; -use entity::{clipboard, clipboard_text}; use ring::aead; -use sea_orm::EntityTrait; -use tao::connection::db; +use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter}; +use tauri::{Emitter, EventTarget}; pub async fn decrypt_all_clipboards() -> Result<(), CommandError> { + let settings = get_global_settings(); let db = db().await?; - let clipboards = - load_clipboards_with_relations(clipboard::Entity::find().all(&db).await?).await; + let clipboards = load_clipboards_with_relations( + clipboard::Entity::find() + .filter(clipboard::Column::Encrypted.eq(true)) + .all(&db) + .await?, + ) + .await; - for clipboard in clipboards { - if let Some(mut text) = clipboard.text { - if looks_like_encrypted_data(text.data.as_bytes()) { - text.data = - String::from_utf8(decrypt_data(text.data.as_bytes())?).unwrap_or_default(); + let (remote_clipboards, provider) = if settings.sync { + let provider = get_sync_provider().await; + ( + provider + .fetch_all_clipboards() + .await + .expect("Failed to fetch remote clipboards"), + Some(provider), + ) + } else { + (Vec::new(), None) + }; - let clipboard_text: clipboard_text::ActiveModel = text.into(); + let total_clipboards = clipboards.len() as u64; + for (index, clipboard) in clipboards.into_iter().enumerate() { + let encrypted_clipboard = decrypt_clipboard(clipboard).await?; - clipboard_text::Entity::update(clipboard_text) - .exec(&db) - .await?; + if let Some(provider) = &provider { + if let Some(remote_clipboards) = &remote_clipboards + .iter() + .find(|c| c.id == encrypted_clipboard.clipboard.id) + { + provider + .update_clipboard(&encrypted_clipboard, &remote_clipboards) + .await + .expect("Failed to upsert clipboard"); } } + + let progress = Progress { + total: total_clipboards as u64, + current: (index + 1) as u64, + }; + + printlog!("Emitting progress event {:?}", progress); + + get_app() + .emit_to( + EventTarget::any(), + ListenEvent::Progress.to_string().as_str(), + progress, + ) + .expect("Failed to emit download progress event"); } Ok(()) } +pub async fn decrypt_clipboard( + mut clipboard: FullClipboardDto, +) -> Result { + let db = db().await.expect("Database connection failed"); + + if let Some(text) = &mut clipboard.text { + if let Ok(data) = STANDARD.decode(text.data.clone()) { + text.data = + String::from_utf8(decrypt_data(&data).expect("Failed to decrypt clipboard data")) + .expect("Failed to convert decrypted data to string"); + + let clipboard_text: clipboard_text::ActiveModel = text.clone().into(); + clipboard_text::Entity::update(clipboard_text.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted text in database"); + } + } + + if let Some(html) = &mut clipboard.html { + if let Ok(data) = STANDARD.decode(html.data.clone()) { + html.data = + String::from_utf8(decrypt_data(&data).expect("Failed to decrypt clipboard data")) + .expect("Failed to convert decrypted data to string"); + + let clipboard_html: clipboard_html::ActiveModel = html.clone().into(); + clipboard_html::Entity::update(clipboard_html.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted HTML in database"); + } + } + + if let Some(rtf) = &mut clipboard.rtf { + if let Ok(data) = STANDARD.decode(rtf.data.clone()) { + rtf.data = + String::from_utf8(decrypt_data(&data).expect("Failed to decrypt clipboard data")) + .expect("Failed to convert decrypted data to string"); + + let clipboard_rtf: clipboard_rtf::ActiveModel = rtf.clone().into(); + + clipboard_rtf::Entity::update(clipboard_rtf.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted RTF in database"); + } + } + + if let Some(image) = &mut clipboard.image { + image.data = + decrypt_data(&image.data.as_slice()).expect("Failed to decrypt clipboard data"); + + if let Ok(thumbnail) = STANDARD.decode(image.thumbnail.clone()) { + image.thumbnail = STANDARD.encode( + decrypt_data(&thumbnail).expect("Failed to decrypt clipboard thumbnail data"), + ); + } + + let image: clipboard_image::ActiveModel = image.clone().into(); + clipboard_image::Entity::update(image.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted image in database"); + } + + if !clipboard.files.is_empty() { + for file in &mut clipboard.files { + if STANDARD.decode(file.name.clone()).is_ok() { + file.data = + decrypt_data(file.data.as_slice()).expect("File data encryption failed"); + + file.name = String::from_utf8( + decrypt_data( + STANDARD + .decode(file.name.clone()) + .expect("Filename encryption failed") + .as_slice(), + ) + .expect("Filename encryption failed"), + ) + .expect("Failed to convert decrypted data to string"); + + if let Some(extension) = &file.extension { + file.extension = Some( + String::from_utf8( + decrypt_data( + STANDARD + .decode(extension) + .expect("Filename encryption failed") + .as_slice(), + ) + .expect("File extension encryption failed"), + ) + .expect("Failed to convert decrypted data to string"), + ); + } + + if let Some(mime_type) = &file.mime_type { + file.mime_type = Some( + String::from_utf8( + decrypt_data( + STANDARD + .decode(mime_type) + .expect("Filename encryption failed") + .as_slice(), + ) + .expect("MIME type encryption failed"), + ) + .expect("Failed to convert decrypted data to string"), + ); + } + + let file: clipboard_file::ActiveModel = file.clone().into(); + clipboard_file::Entity::update(file.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted file in database"); + } + } + } + + clipboard.clipboard.encrypted = false; + let entity: clipboard::ActiveModel = clipboard.clipboard.clone().into(); + clipboard::Entity::update(entity.reset_all()) + .exec(&db) + .await + .expect("Failed to update clipboard encryption status"); + + Ok(clipboard) +} + /// Decrypts data using AES-256-GCM pub fn decrypt_data(encrypted_data: &[u8]) -> Result, EncryptionError> { if encrypted_data.len() < 12 { diff --git a/src-tauri/src/service/encrypt.rs b/src-tauri/src/service/encrypt.rs index 0c85b358..943a9162 100644 --- a/src-tauri/src/service/encrypt.rs +++ b/src-tauri/src/service/encrypt.rs @@ -2,6 +2,8 @@ use super::clipboard::load_clipboards_with_relations; use super::sync::get_sync_provider; use crate::prelude::*; use crate::service::settings::get_global_settings; +use crate::tao::connection::db; +use crate::tao::global::get_app; use base64::{engine::general_purpose::STANDARD, Engine}; use common::types::crypto::{EncryptionError, ENCRYPTION_KEY}; use common::types::enums::ListenEvent; @@ -12,17 +14,20 @@ use entity::{ }; use ring::rand::SecureRandom; use ring::{aead, rand}; -use sea_orm::EntityTrait; -use tao::connection::db; -use tao::global::get_app; +use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter}; use tauri::{Emitter, EventTarget}; pub async fn encrypt_all_clipboards() -> Result<(), CommandError> { let settings = get_global_settings(); let db = db().await?; - let clipboards = - load_clipboards_with_relations(clipboard::Entity::find().all(&db).await?).await; + let clipboards = load_clipboards_with_relations( + clipboard::Entity::find() + .filter(clipboard::Column::Encrypted.eq(false)) + .all(&db) + .await?, + ) + .await; let (provider, remote_clipboards) = if settings.sync { let provider = get_sync_provider().await; @@ -53,7 +58,7 @@ pub async fn encrypt_all_clipboards() -> Result<(), CommandError> { } } - let progress: Progress = Progress { + let progress = Progress { total: total_clipboards as u64, current: (index + 1) as u64, }; @@ -75,84 +80,102 @@ pub async fn encrypt_all_clipboards() -> Result<(), CommandError> { pub async fn encrypt_clipboard( mut clipboard: FullClipboardDto, ) -> Result { - let db = db().await?; + let db = db().await.expect("Database connection failed"); if let Some(text) = &mut clipboard.text { - if !looks_like_encrypted_data(text.data.as_bytes()) { - text.data = String::from_utf8(encrypt_data(text.data.as_bytes())?).unwrap_or_default(); + if !STANDARD.decode(text.data.clone()).is_ok() { + text.data = STANDARD + .encode(encrypt_data(text.data.as_bytes()).expect("Text encryption failed")); let clipboard_text: clipboard_text::ActiveModel = text.clone().into(); - clipboard_text::Entity::update(clipboard_text) + printlog!("Encrypting text {:?}", clipboard_text); + clipboard_text::Entity::update(clipboard_text.reset_all()) .exec(&db) - .await?; + .await + .expect("Failed to update encrypted text in database"); } } if let Some(html) = &mut clipboard.html { - if !looks_like_encrypted_data(html.data.as_bytes()) { - html.data = String::from_utf8(encrypt_data(html.data.as_bytes())?).unwrap_or_default(); + if !STANDARD.decode(html.data.clone()).is_ok() { + html.data = STANDARD + .encode(encrypt_data(html.data.as_bytes()).expect("HTML encryption failed")); let clipboard_html: clipboard_html::ActiveModel = html.clone().into(); - clipboard_html::Entity::update(clipboard_html) + clipboard_html::Entity::update(clipboard_html.reset_all()) .exec(&db) - .await?; + .await + .expect("Failed to update encrypted HTML in database"); } } if let Some(rtf) = &mut clipboard.rtf { - if !looks_like_encrypted_data(rtf.data.as_bytes()) { - rtf.data = String::from_utf8(encrypt_data(rtf.data.as_bytes())?).unwrap_or_default(); + if !STANDARD.decode(rtf.data.clone()).is_ok() { + rtf.data = + STANDARD.encode(encrypt_data(rtf.data.as_bytes()).expect("RTF encryption failed")); let clipboard_rtf: clipboard_rtf::ActiveModel = rtf.clone().into(); - clipboard_rtf::Entity::update(clipboard_rtf) + clipboard_rtf::Entity::update(clipboard_rtf.reset_all()) .exec(&db) - .await?; + .await + .expect("Failed to update encrypted RTF in database"); } } if let Some(image) = &mut clipboard.image { - if !looks_like_encrypted_data(image.data.as_slice()) { - image.data = encrypt_data(image.data.as_slice())?; - if let Ok(thumbnail_bytes) = STANDARD.decode(image.thumbnail.clone()) { - let encrypted_thumbnail = encrypt_data(&thumbnail_bytes)?; - image.thumbnail = STANDARD.encode(&encrypted_thumbnail); - } - let image: clipboard_image::ActiveModel = image.clone().into(); - clipboard_image::Entity::update(image).exec(&db).await?; + image.data = encrypt_data(image.data.as_slice()).expect("Image encryption failed"); + if let Ok(thumbnail_bytes) = STANDARD.decode(image.thumbnail.clone()) { + let encrypted_thumbnail = + encrypt_data(&thumbnail_bytes).expect("Thumbnail encryption failed"); + image.thumbnail = STANDARD.encode(&encrypted_thumbnail); } + let image: clipboard_image::ActiveModel = image.clone().into(); + clipboard_image::Entity::update(image.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted image in database"); } if !clipboard.files.is_empty() { for file in &mut clipboard.files { - if !looks_like_encrypted_data(file.data.as_slice()) { - file.data = encrypt_data(file.data.as_slice())?; + if !STANDARD.decode(file.name.clone()).is_ok() { + file.data = + encrypt_data(file.data.as_slice()).expect("File data encryption failed"); - if let Some(name) = &file.name { - file.name = - Some(String::from_utf8(encrypt_data(name.as_bytes())?).unwrap_or_default()); - } + file.name = STANDARD.encode( + encrypt_data(file.name.as_bytes()).expect("Filename encryption failed"), + ); if let Some(extension) = &file.extension { file.extension = Some( - String::from_utf8(encrypt_data(extension.as_bytes())?).unwrap_or_default(), + STANDARD.encode( + encrypt_data(extension.as_bytes()) + .expect("File extension encryption failed"), + ), ); } if let Some(mime_type) = &file.mime_type { - file.mime_type = Some( - String::from_utf8(encrypt_data(mime_type.as_bytes())?).unwrap_or_default(), - ); + file.mime_type = Some(STANDARD.encode( + encrypt_data(mime_type.as_bytes()).expect("MIME type encryption failed"), + )); } let file: clipboard_file::ActiveModel = file.clone().into(); - clipboard_file::Entity::update(file).exec(&db).await?; + clipboard_file::Entity::update(file.reset_all()) + .exec(&db) + .await + .expect("Failed to update encrypted file in database"); } } } clipboard.clipboard.encrypted = true; let entity: clipboard::ActiveModel = clipboard.clipboard.clone().into(); - clipboard::Entity::update(entity).exec(&db).await?; + clipboard::Entity::update(entity.reset_all()) + .exec(&db) + .await + .expect("Failed to update clipboard encryption status"); Ok(clipboard) } @@ -169,8 +192,6 @@ pub fn set_encryption_key(password: &str) -> Result<(), EncryptionError> { .lock() .map_err(|_| EncryptionError::KeyLockFailed)? = Some(key_bytes); - printlog!("Setting encryption key {:?}", password); - Ok(()) } diff --git a/src-tauri/src/service/hotkey.rs b/src-tauri/src/service/hotkey.rs index 2ac66919..3b8bde28 100644 --- a/src-tauri/src/service/hotkey.rs +++ b/src-tauri/src/service/hotkey.rs @@ -1,8 +1,7 @@ -use crate::prelude::*; +use crate::{prelude::*, tao::{connection::db, global::get_app}}; use common::types::enums::ListenEvent; use entity::hotkey::{self, ActiveModel, Model}; use sea_orm::{ActiveModelTrait, EntityTrait}; -use tao::{connection::db, global::get_app}; use tauri::{Emitter, EventTarget}; pub async fn get_all_hotkeys_db() -> Result, DbErr> { diff --git a/src-tauri/src/service/keyboard.rs b/src-tauri/src/service/keyboard.rs index dafc25d6..56bda9e9 100644 --- a/src-tauri/src/service/keyboard.rs +++ b/src-tauri/src/service/keyboard.rs @@ -1,8 +1,8 @@ use crate::service::clipboard::get_last_clipboard_db; +use crate::tao::global::get_app; use common::types::enums::ClipboardType; use common::types::orm_query::FullClipboardDto; use enigo::{Enigo, Keyboard, Settings}; -use tao::global::get_app; use std::{process::Command, time::Duration}; use tauri_plugin_dialog::DialogExt; use tauri_plugin_dialog::{MessageDialogButtons, MessageDialogKind}; diff --git a/src-tauri/src/service/settings.rs b/src-tauri/src/service/settings.rs index a9290a84..b99fc3d0 100644 --- a/src-tauri/src/service/settings.rs +++ b/src-tauri/src/service/settings.rs @@ -2,6 +2,8 @@ use super::clipboard::get_last_clipboard_db; use super::sync::upsert_settings_sync; use crate::prelude::*; use crate::service::window::get_monitor_scale_factor; +use crate::tao::connection::db; +use crate::tao::global::get_app; use common::io::language::get_system_language; use common::types::enums::ListenEvent; use common::types::types::CommandError; @@ -9,8 +11,6 @@ use entity::settings; use sea_orm::{ActiveModelTrait, EntityTrait}; use std::collections::HashMap; use std::sync::Mutex; -use tao::connection::db; -use tao::global::get_app; use tauri::Manager; use tauri::{Emitter, EventTarget}; use tauri_plugin_autostart::AutoLaunchManager; diff --git a/src-tauri/src/service/sync.rs b/src-tauri/src/service/sync.rs index 83858e16..dec09462 100644 --- a/src-tauri/src/service/sync.rs +++ b/src-tauri/src/service/sync.rs @@ -1,12 +1,10 @@ use super::settings::{get_global_settings, update_settings_synchronize_db}; use crate::{ - prelude::*, - utils::{providers::google_drive::GoogleDriveProviderImpl, sync_manager::SyncManager}, + prelude::*, tao::global::get_app, utils::{providers::google_drive::GoogleDriveProviderImpl, sync_manager::SyncManager} }; use common::types::{enums::SyncProviderType, sync::SyncProvider, types::CommandError}; use entity::settings; use std::{collections::HashMap, sync::Arc}; -use tao::global::get_app; use tauri::{Manager, State}; use tokio::sync::Mutex; diff --git a/src-tauri/src/service/window.rs b/src-tauri/src/service/window.rs index 6fad97bc..7ef7a4c2 100644 --- a/src-tauri/src/service/window.rs +++ b/src-tauri/src/service/window.rs @@ -1,5 +1,6 @@ use super::settings::get_global_settings; use crate::prelude::*; +use crate::tao::global::{get_app, get_main_window, get_window_stop_tx}; use crate::utils::hotkey_manager::{register_hotkeys, unregister_hotkeys}; use common::constants::{ ABOUT_WINDOW_X, ABOUT_WINDOW_Y, MAIN_WINDOW_X, MAIN_WINDOW_Y, MAX_IMAGE_DIMENSIONS, @@ -8,7 +9,6 @@ use common::constants::{ use common::types::enums::{ClippyPosition, HotkeyEvent, ListenEvent, WebWindow}; use std::env; use std::process::Command; -use tao::global::{get_app, get_main_window, get_window_stop_tx}; use tauri::{Emitter, LogicalSize, Manager, WebviewUrl}; use tauri::{PhysicalPosition, WebviewWindowBuilder}; use tauri_plugin_positioner::{Position, WindowExt}; diff --git a/src-tauri/tao/src/config.rs b/src-tauri/src/tao/config.rs similarity index 99% rename from src-tauri/tao/src/config.rs rename to src-tauri/src/tao/config.rs index d5f71b7c..d385a1f6 100644 --- a/src-tauri/tao/src/config.rs +++ b/src-tauri/src/tao/config.rs @@ -1,4 +1,4 @@ -use crate::global::get_app; +use crate::tao::global::get_app; use common::{ constants::{CONFIG_NAME, DB_NAME}, printlog, diff --git a/src-tauri/tao/src/connection.rs b/src-tauri/src/tao/connection.rs similarity index 96% rename from src-tauri/tao/src/connection.rs rename to src-tauri/src/tao/connection.rs index 7bfd6cd3..94d82048 100644 --- a/src-tauri/tao/src/connection.rs +++ b/src-tauri/src/tao/connection.rs @@ -1,4 +1,4 @@ -use crate::config::{get_config, get_data_path}; +use super::config::{get_config, get_data_path}; use common::{constants::DB_NAME, types::types::Config}; use migration::{DbErr, Migrator, MigratorTrait}; use sea_orm::{Database, DbConn}; diff --git a/src-tauri/tao/src/global.rs b/src-tauri/src/tao/global.rs similarity index 98% rename from src-tauri/tao/src/global.rs rename to src-tauri/src/tao/global.rs index 9d00be00..d90470f7 100644 --- a/src-tauri/tao/src/global.rs +++ b/src-tauri/src/tao/global.rs @@ -1,4 +1,4 @@ -use crate::tauri_constants::{ +use super::tao_constants::{ APP, HOTKEYS, HOTKEY_MANAGER, HOTKEY_RUNNING, HOTKEY_STOP_TX, MAIN_WINDOW, WINDOW_STOP_TX, }; use common::types::{enums::WebWindow, hotkey::SafeHotKeyManager, types::Key}; diff --git a/src-tauri/tao/src/lib.rs b/src-tauri/src/tao/mod.rs similarity index 67% rename from src-tauri/tao/src/lib.rs rename to src-tauri/src/tao/mod.rs index 1e79ebdd..36b5d386 100644 --- a/src-tauri/tao/src/lib.rs +++ b/src-tauri/src/tao/mod.rs @@ -1,4 +1,4 @@ -pub mod tauri_constants; +pub mod tao_constants; pub mod global; pub mod connection; pub mod config; \ No newline at end of file diff --git a/src-tauri/tao/src/tauri_constants.rs b/src-tauri/src/tao/tao_constants.rs similarity index 100% rename from src-tauri/tao/src/tauri_constants.rs rename to src-tauri/src/tao/tao_constants.rs diff --git a/src-tauri/src/utils/clipboard_manager.rs b/src-tauri/src/utils/clipboard_manager.rs index ff49a3f5..1b47a805 100644 --- a/src-tauri/src/utils/clipboard_manager.rs +++ b/src-tauri/src/utils/clipboard_manager.rs @@ -4,6 +4,7 @@ use crate::service::{ clipboard::{get_last_clipboard_db, insert_clipboard_dbo}, window::calculate_thumbnail_dimensions, }; +use crate::tao::global::{get_app, get_app_window}; use base64::{engine::general_purpose::STANDARD, Engine}; use chrono::DateTime; use common::types::enums::{ClipboardTextType, ClipboardType, ListenEvent, WebWindow}; @@ -14,7 +15,6 @@ use sea_orm::prelude::Uuid; use std::fs; use std::io::Cursor; use std::path::Path; -use tao::global::{get_app, get_app_window}; use tauri::{Emitter, Manager}; use tauri_plugin_clipboard::Clipboard; @@ -50,6 +50,16 @@ impl ClipboardManagerExt for FullClipboardDbo { let clipboard = get_app().state::(); let mut manager = Self::new(); + printlog!( + "clipboard model: {:?} size: {:?}", + clipboard.read_files().ok().map_or_else(|| vec![], |f| f), + clipboard + .read_files() + .ok() + .map_or_else(|| vec![], |f| f) + .len() + ); + manager.parse_model( clipboard.read_text().ok(), clipboard.read_html().ok(), @@ -331,12 +341,16 @@ impl ClipboardManagerExt for FullClipboardDbo { if let Ok(file_bytes) = fs::read(path) { let file_model = entity::clipboard_file::ActiveModel { - name: Set(Some(file_name)), + name: Set(file_name), extension: Set(file_ext), - size: Set(Some(metadata.len() as i32)), + size: Set(metadata.len() as i32), mime_type: Set(mime_type), - created_date: Set(created), - modified_date: Set(modified), + created_date: Set( + created.unwrap_or_else(|| chrono::Local::now().naive_utc()) + ), + modified_date: Set( + modified.unwrap_or_else(|| chrono::Local::now().naive_utc()) + ), data: Set(file_bytes), ..Default::default() }; diff --git a/src-tauri/src/utils/hotkey_manager.rs b/src-tauri/src/utils/hotkey_manager.rs index e3eabeec..bfe19cc6 100644 --- a/src-tauri/src/utils/hotkey_manager.rs +++ b/src-tauri/src/utils/hotkey_manager.rs @@ -1,10 +1,10 @@ -use crate::prelude::*; use crate::service::hotkey::get_all_hotkeys_db; +#[cfg(any(target_os = "windows", target_os = "macos"))] +use crate::tao::global::get_app; +use crate::tao::global::get_hotkey_manager; +use crate::{prelude::*, tao::global::get_hotkey_store}; use common::{constants::GLOBAL_EVENTS, types::types::Key}; use global_hotkey::hotkey::HotKey; -#[cfg(any(target_os = "windows", target_os = "macos"))] -use tao::global::get_app; -use tao::global::{get_hotkey_manager, get_hotkey_store}; pub fn register_hotkeys(all: bool) { #[cfg(any(target_os = "windows", target_os = "macos"))] diff --git a/src-tauri/src/utils/providers/google_drive.rs b/src-tauri/src/utils/providers/google_drive.rs index 9ba78ff0..7d3434b3 100644 --- a/src-tauri/src/utils/providers/google_drive.rs +++ b/src-tauri/src/utils/providers/google_drive.rs @@ -1,7 +1,6 @@ use super::parse_clipboard_info; use crate::{ - service::settings::{get_global_settings, update_settings_synchronize_db}, - utils::providers::create_clipboard_filename, + service::settings::{get_global_settings, update_settings_synchronize_db}, tao::{config::get_data_path, global::get_app}, utils::providers::create_clipboard_filename }; use chrono::{NaiveDateTime, TimeZone, Utc}; use common::{ @@ -24,7 +23,6 @@ use migration::async_trait; use sea_orm::prelude::Uuid; use serde_json::Value; use std::{collections::HashMap, future::Future, io::Cursor, pin::Pin}; -use tao::{config::get_data_path, global::get_app}; use tauri::Manager; use tauri_plugin_clipboard::Clipboard; use tauri_plugin_opener::OpenerExt; diff --git a/src-tauri/tao/Cargo.toml b/src-tauri/tao/Cargo.toml deleted file mode 100644 index 40b71590..00000000 --- a/src-tauri/tao/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "tao" -version = "1.0.0" -edition = "2021" - -[lib] -name = "tao" -path = "src/lib.rs" - -[dependencies] -entity = { path = "../entity" } -common = { path = "../common" } -migration = { path = "../migration" } - -async-trait = "0" -tokio = "1" -tokio-cron-scheduler = "0" -serde = "1" -serde_json = "1" - -tauri = "2" -tauri-plugin-dialog = "2" -google-drive3 = "6" -global-hotkey = "0" -sea-orm = "1" -tl = "0" -chrono = "0" diff --git a/src/components/elements/toggle.tsx b/src/components/elements/toggle.tsx index 76eb51b7..5ee302bf 100644 --- a/src/components/elements/toggle.tsx +++ b/src/components/elements/toggle.tsx @@ -23,7 +23,7 @@ export const Toggle: Component = (props) => { class={cn( "relative h-4 w-11 rounded-full peer-focus:outline-hidden after:absolute after:start-[2px] after:top-0 after:h-4 after:w-4 after:rounded-full after:border after:border-transparent after:bg-white after:transition-all after:content-[''] peer-checked:after:translate-x-[150%] peer-checked:after:border-transparent peer-checked:rtl:after:-translate-x-full dark:border-gray-600", "dark:bg-opacity-20 peer-checked:bg-indigo-60 bg-gray-200 after:z-40 dark:after:bg-zinc-700", - props.checked ? "dark:bg-indigo-700" : "dark:bg-dark-light", + props.checked ? "bg-indigo-700 dark:bg-indigo-700" : "dark:bg-dark-light", props?.disabled ? "cursor-not-allowed" : "cursor-pointer" )} >