diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1360e46..0dcf8f4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -62,6 +62,7 @@ jobs: - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} # Updater private key with: tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version. releaseName: 'Tauri v__VERSION__' diff --git a/package.json b/package.json index 525d6e7..1daac1a 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,45 @@ { - "name": "discappear", - "private": true, - "version": "0.1.2", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "bump": "pnpm dlx tauri-version patch", - "tauri": "tauri", - "format": "pnpm dlx @biomejs/biome format --write ." - }, - "dependencies": { - "@biomejs/biome": "^1.9.3", - "@radix-ui/react-checkbox": "^1.1.2", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-progress": "^1.1.0", - "@radix-ui/react-scroll-area": "^1.2.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-tabs": "^1.1.1", - "@tauri-apps/api": "^2.0.2", - "@tauri-apps/plugin-shell": ">=2.0.0", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "lucide-react": "^0.447.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "tailwind-merge": "^2.5.3", - "tailwindcss-animate": "^1.0.7" - }, - "devDependencies": { - "@tauri-apps/cli": ">=2.0.0", - "@types/node": "^22.7.5", - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.13", - "typescript": "^5.2.2", - "vite": "^5.3.1" - } -} + "name": "discappear", + "private": true, + "version": "0.1.3", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "bump": "pnpm dlx tauri-version patch", + "tauri": "tauri", + "format": "pnpm dlx @biomejs/biome format --write ." + }, + "dependencies": { + "@biomejs/biome": "^1.9.3", + "@radix-ui/react-checkbox": "^1.1.2", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-scroll-area": "^1.2.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.1", + "@tauri-apps/api": "^2.0.2", + "@tauri-apps/plugin-shell": ">=2.0.0", + "@tauri-apps/plugin-updater": "~2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.447.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tailwind-merge": "^2.5.3", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@tauri-apps/cli": ">=2.0.0", + "@types/node": "^22.7.5", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.13", + "typescript": "^5.2.2", + "vite": "^5.3.1" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 698885f..66cd66f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: '@tauri-apps/plugin-shell': specifier: '>=2.0.0' version: 2.0.0 + '@tauri-apps/plugin-updater': + specifier: ~2 + version: 2.0.0 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -787,6 +790,9 @@ packages: '@tauri-apps/plugin-shell@2.0.0': resolution: {integrity: sha512-OpW2+ycgJLrEoZityWeWYk+6ZWP9VyiAfbO+N/O8VfLkqyOym8kXh7odKDfINx9RAotkSGBtQM4abyKfJDkcUg==} + '@tauri-apps/plugin-updater@2.0.0': + resolution: {integrity: sha512-N0cl71g7RPr7zK2Fe5aoIwzw14NcdLcz7XMGFWZVjprsqgDRWoxbnUkknyCQMZthjhGkppCd/wN2MIsUz+eAhQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1973,6 +1979,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.0.2 + '@tauri-apps/plugin-updater@2.0.0': + dependencies: + '@tauri-apps/api': 2.0.2 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.25.7 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index d11db4d..68b294b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -62,6 +62,15 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "atk" version = "0.18.0" @@ -560,6 +569,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -606,7 +626,7 @@ dependencies = [ [[package]] name = "discappear" -version = "0.1.2" +version = "0.1.3" dependencies = [ "reqwest", "serde", @@ -614,6 +634,7 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-shell", + "tauri-plugin-updater", "tokio", ] @@ -623,6 +644,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "dlopen2" version = "0.7.0" @@ -762,6 +794,18 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "flate2" version = "1.0.34" @@ -1358,6 +1402,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -1676,6 +1721,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall", ] [[package]] @@ -1756,6 +1802,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minisign-verify" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a05b5d0594e0cb1ad8cee3373018d2b84e25905dc75b2468114cc9a8e86cfc20" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -2433,6 +2485,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.37" @@ -2605,7 +2705,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -2613,6 +2716,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower-service", "url", @@ -2620,6 +2724,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", "windows-registry", ] @@ -2644,6 +2749,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2673,6 +2784,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3259,6 +3371,17 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "tar" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -3416,6 +3539,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd3d2fe0f02bf52eebb5a9d23b987fffac6684646ab6fd683d706dafb18da87" +dependencies = [ + "base64 0.22.1", + "dirs", + "flate2", + "futures-util", + "http", + "infer", + "minisign-verify", + "percent-encoding", + "reqwest", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror", + "time", + "tokio", + "url", + "windows-sys 0.59.0", + "zip", +] + [[package]] name = "tauri-runtime" version = "2.0.1" @@ -4106,6 +4259,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.33.0" @@ -4574,6 +4736,17 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4600,3 +4773,18 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zip" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "indexmap 2.6.0", + "memchr", + "thiserror", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 386a961..6fbc6f1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "discappear" -version = "0.1.2" +version = "0.1.3" description = "A Tauri App" authors = ["you"] edition = "2021" @@ -28,3 +28,6 @@ reqwest = { version = "0.12.8"} [profile.release] lto = true +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +tauri-plugin-updater = "2" + diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json new file mode 100644 index 0000000..3a8358b --- /dev/null +++ b/src-tauri/capabilities/desktop.json @@ -0,0 +1,5 @@ +{ + "identifier": "desktop-capability", + "platforms": ["macOS", "windows", "linux"], + "permissions": ["updater:default"] +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 57132fb..65c1b19 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,20 +1,25 @@ +use reqwest::header::AUTHORIZATION; use serde::{de, Deserialize, Deserializer, Serialize}; use serde_json::{json, Value}; +use std::{ + fmt, fs, + path::{Path, PathBuf}, +}; use tauri::Manager; -use std::{fmt, fs, path::{Path, PathBuf}}; -use reqwest::header::AUTHORIZATION; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() + .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_shell::init()) - .invoke_handler(tauri::generate_handler![read_discord_backup, delete_message]) + .invoke_handler(tauri::generate_handler![ + read_discord_backup, + delete_message + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } - - fn string_or_number<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -84,11 +89,10 @@ struct DiscordBackup { guilds: Vec, } - fn get_or_create_deleted_messages_path(app_handle: &tauri::AppHandle) -> Result { // Get the application data directory let app_data_path = app_handle.path().app_data_dir().unwrap(); - + // Ensure the directory exists if !app_data_path.exists() { fs::create_dir_all(&app_data_path).map_err(|e| e.to_string())?; @@ -99,8 +103,16 @@ fn get_or_create_deleted_messages_path(app_handle: &tauri::AppHandle) -> Result< } #[tauri::command] -async fn delete_message(app_handle: tauri::AppHandle, token: String, channel_id: String, message_id: String) -> Result { - let url = format!("https://discord.com/api/v9/channels/{}/messages/{}", channel_id, message_id); +async fn delete_message( + app_handle: tauri::AppHandle, + token: String, + channel_id: String, + message_id: String, +) -> Result { + let url = format!( + "https://discord.com/api/v9/channels/{}/messages/{}", + channel_id, message_id + ); let client = reqwest::Client::new(); let response = client @@ -119,8 +131,11 @@ async fn delete_message(app_handle: tauri::AppHandle, token: String, channel_id: if !json_path.exists() { // Create the JSON file with initial structure let initial_data = json!({ "deleted_messages": [] }); - fs::write(&json_path, serde_json::to_string_pretty(&initial_data).map_err(|e| e.to_string())?) - .map_err(|e| e.to_string())?; + fs::write( + &json_path, + serde_json::to_string_pretty(&initial_data).map_err(|e| e.to_string())?, + ) + .map_err(|e| e.to_string())?; } // Log deleted message to the JSON file @@ -128,7 +143,8 @@ async fn delete_message(app_handle: tauri::AppHandle, token: String, channel_id: // Read existing entries if let Ok(data) = fs::read_to_string(&json_path) { - let json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?; + let json_data: Value = + serde_json::from_str(&data).map_err(|e| e.to_string())?; if let Some(messages) = json_data["deleted_messages"].as_array() { deleted_messages.extend(messages.clone()); } @@ -142,17 +158,23 @@ async fn delete_message(app_handle: tauri::AppHandle, token: String, channel_id: // Write back to the JSON file let json_output = json!({ "deleted_messages": deleted_messages }); - fs::write(&json_path, serde_json::to_string_pretty(&json_output).map_err(|e| e.to_string())?) - .map_err(|e| e.to_string())?; + fs::write( + &json_path, + serde_json::to_string_pretty(&json_output).map_err(|e| e.to_string())?, + ) + .map_err(|e| e.to_string())?; } - Ok(status_code) // Return the status code - }, - Err(_) => Err("Error deleting the message".into()), // Handle errors + Ok(status_code) // Return the status code + } + Err(_) => Err("Error deleting the message".into()), // Handle errors } } #[tauri::command] -fn read_discord_backup(app_handle: tauri::AppHandle, directory: String) -> Result { +fn read_discord_backup( + app_handle: tauri::AppHandle, + directory: String, +) -> Result { let path = Path::new(&directory); if !path.is_dir() { return Err("Provided directory is not valid".to_string()); @@ -161,15 +183,19 @@ fn read_discord_backup(app_handle: tauri::AppHandle, directory: String) -> Resul // Get the path of the JSON file next to the executable let json_path = get_or_create_deleted_messages_path(&app_handle)?; - // Load deleted messages from JSON file let mut deleted_message_ids = vec![]; if json_path.exists() { let data = fs::read_to_string(&json_path).map_err(|e| e.to_string())?; - let json_data: serde_json::Value = serde_json::from_str(&data).map_err(|e| e.to_string())?; + let json_data: serde_json::Value = + serde_json::from_str(&data).map_err(|e| e.to_string())?; if let Some(messages) = json_data["deleted_messages"].as_array() { - deleted_message_ids.extend(messages.iter().map(|msg| msg["message_id"].as_str().unwrap_or("").to_string())); + deleted_message_ids.extend( + messages + .iter() + .map(|msg| msg["message_id"].as_str().unwrap_or("").to_string()), + ); } } @@ -186,11 +212,13 @@ fn read_discord_backup(app_handle: tauri::AppHandle, directory: String) -> Resul // Read and parse channel.json let channel_data = fs::read_to_string(channel_file).map_err(|e| e.to_string())?; - let channel: Channel = serde_json::from_str(&channel_data).map_err(|e| e.to_string())?; + let channel: Channel = + serde_json::from_str(&channel_data).map_err(|e| e.to_string())?; // Read and parse messages.json let messages_data = fs::read_to_string(messages_file).map_err(|e| e.to_string())?; - let mut messages: Vec = serde_json::from_str(&messages_data).map_err(|e| e.to_string())?; + let mut messages: Vec = + serde_json::from_str(&messages_data).map_err(|e| e.to_string())?; // Filter out deleted messages messages.retain(|msg| !deleted_message_ids.contains(&msg.ID)); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index bf203c1..706caa9 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,32 +1,47 @@ { - "$schema": "https://schema.tauri.app/config/2.0.0", - "productName": "discappear", - "version": "0.1.2", - "identifier": "com.discappear.app", - "build": { - "beforeDevCommand": "pnpm run dev", - "devUrl": "http://localhost:1420", - "beforeBuildCommand": "pnpm run build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "discappear", - "minWidth": 600, - "width": 800, - "minHeight": 600, - "height": 600, - "decorations": false - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": true, - "targets": "all", - "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"] - } -} + "$schema": "https://schema.tauri.app/config/2.0.0", + "productName": "discappear", + "version": "0.1.3", + "identifier": "com.discappear.app", + "build": { + "beforeDevCommand": "pnpm run dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "pnpm run build", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "title": "discappear", + "minWidth": 600, + "width": 800, + "minHeight": 600, + "height": 600, + "decorations": false + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "createUpdaterArtifacts": true, + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + }, + "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDI5RjZEQkVCOTg2NDBBOUIKUldTYkNtU1k2OXYyS1lGclIxQmd5TUdjVk9Fb2wycTMydWVBeDdQcVk0cVNzNytkSlMwY2lMbVMK", + "endpoints": [ + "https://github.com/omznc/discappear/releases/latest/download/latest.json" + ] + } + } +} \ No newline at end of file