From dc88269baf6dead81fee6cf2a4b26ecf2b680463 Mon Sep 17 00:00:00 2001 From: Bonchellon Date: Thu, 9 Jul 2026 17:59:38 +0300 Subject: [PATCH] =?UTF-8?q?0.3.9=20=E2=80=94=20fix=20plugin=20registry=20(?= =?UTF-8?q?backend=20HTTPS,=20CORS),=20fold=20updater=20into=20a=20status-?= =?UTF-8?q?bar=20icon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Plugin catalog/install failed silently: the webview fetch() to Gitea raw is blocked by CORS (no ACAO header). Route registry reads through a new Rust command registry_http_get (host-restricted) — catalog + installs now work. - Updater: removed the floating card that overlapped the Terminal/Log/Updates buttons. Update state now shows as a single status-bar download icon (no text): idle → download glyph, available → accent + dot, checking/downloading → spinner. Co-Authored-By: Claude Opus 4.8 --- package.json | 2 +- src-tauri/Cargo.lock | 211 ++++++++++++++++++++++++++++++++++++-- src-tauri/Cargo.toml | 4 +- src-tauri/src/lib.rs | 20 ++++ src-tauri/tauri.conf.json | 2 +- src/App.css | 6 ++ src/App.tsx | 22 +++- src/Updater.tsx | 118 +++++++-------------- src/i18n.ts | 1 + src/p4.ts | 1 + src/plugins.ts | 14 +-- 11 files changed, 296 insertions(+), 105 deletions(-) diff --git a/package.json b/package.json index 5006242..7b4521c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "exbyte-depot", "private": true, - "version": "0.3.8", + "version": "0.3.9", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5ffc70d..bd60912 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -468,6 +468,23 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.45" @@ -558,6 +575,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -966,9 +992,10 @@ dependencies = [ [[package]] name = "exbyte-depot" -version = "0.3.7" +version = "0.3.8" dependencies = [ "encoding_rs", + "reqwest 0.12.28", "serde", "serde_json", "tauri", @@ -1279,8 +1306,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1302,8 +1331,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] @@ -1572,6 +1604,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -2042,6 +2075,12 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac-notification-sys" version = "0.6.15" @@ -2784,6 +2823,62 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.46" @@ -2812,7 +2907,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -2822,7 +2928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", ] [[package]] @@ -2834,6 +2940,21 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2909,6 +3030,44 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + [[package]] name = "reqwest" version = "0.13.4" @@ -3046,6 +3205,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] @@ -3093,6 +3253,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -3315,6 +3481,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.21.0" @@ -3385,7 +3563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -3709,7 +3887,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest", + "reqwest 0.13.4", "serde", "serde_json", "serde_repr", @@ -3858,7 +4036,7 @@ checksum = "01fc2c5ff41105bd1f7242d8201fdf3efd70749b82fa013a17f2126357d194cc" dependencies = [ "log", "notify-rust", - "rand", + "rand 0.9.4", "serde", "serde_json", "serde_repr", @@ -3917,7 +4095,7 @@ dependencies = [ "minisign-verify", "osakit", "percent-encoding", - "reqwest", + "reqwest 0.13.4", "rustls", "semver", "serde", @@ -4692,6 +4870,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web_atoms" version = "0.2.5" @@ -4757,6 +4945,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.38.2" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index f0b094e..03e1a00 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "exbyte-depot" -version = "0.3.8" +version = "0.3.9" description = "Exbyte Depot — native Perforce client by Exbyte Studios" authors = ["Exbyte Studios"] edition = "2021" @@ -26,6 +26,8 @@ serde_json = "1" tauri-plugin-dialog = "2.7.1" # decode p4 output on non-UTF8 (ANSI/cp1251) systems — Cyrillic paths encoding_rs = "0.8" +# backend-side HTTPS for the plugin registry (webview fetch is blocked by CORS) +reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] } # Auto-updater (desktop only — checks Gitea Releases for a signed new version) [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index d9da2fa..731c08f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2987,6 +2987,25 @@ async fn plugin_write_file(id: String, name: String, content: String) -> Result< Ok(()) } +/// Fetch text from the Exbyte plugin registry over HTTPS on the backend — the +/// webview `fetch()` is blocked by CORS (Gitea raw sends no ACAO header), so the +/// plugin catalog and installs go through here. Restricted to the trusted host. +#[tauri::command] +async fn registry_http_get(url: String) -> Result { + if !url.starts_with("https://gitea.exbytestudios.com/") { + return Err("Only the Exbyte registry host is allowed".into()); + } + let client = reqwest::Client::builder() + .user_agent("ExbyteDepot") + .build() + .map_err(|e| e.to_string())?; + let resp = client.get(&url).send().await.map_err(|e| e.to_string())?; + if !resp.status().is_success() { + return Err(format!("HTTP {}", resp.status().as_u16())); + } + resp.text().await.map_err(|e| e.to_string()) +} + fn copy_dir_recursive(from: &std::path::Path, to: &std::path::Path) -> std::io::Result<()> { std::fs::create_dir_all(to)?; for e in std::fs::read_dir(from)? { @@ -3146,6 +3165,7 @@ pub fn run() { plugin_read_entry, plugin_set_enabled, plugin_write_file, + registry_http_get, plugin_install, plugin_remove, plugins_dir_path, diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index b432be8..fbbbf9f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "https://schema.tauri.app/config/2", "productName": "Exbyte Depot", "mainBinaryName": "Exbyte Depot", - "version": "0.3.8", + "version": "0.3.9", "identifier": "com.bonchellon.exbyte-depot", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/App.css b/src/App.css index 1330339..e7179ae 100644 --- a/src/App.css +++ b/src/App.css @@ -374,6 +374,12 @@ body.resizing{cursor:col-resize!important;user-select:none} color:var(--muted);border-radius:7px;padding:3px 10px;cursor:pointer;font-size:11.5px} .stlog:hover{color:var(--txt);border-color:var(--accent)} .stlog svg{width:13px;height:13px} +.stlog.icon{padding:3px 7px} +.stupd{position:relative} +.stupd.has{color:var(--accent);border-color:var(--accent)} +.stupd.busy{color:var(--accent-2)} +.stupd[disabled]{cursor:default;opacity:.85} +.stupd-dot{position:absolute;top:2px;right:2px;width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px var(--panel)} .logpeek{position:absolute;left:8px;bottom:26px;width:520px;max-width:calc(100vw - 20px);max-height:min(340px,60vh);overflow-y:auto;z-index:250; background:var(--elevated);border:1px solid var(--border);border-radius:11px 11px 0 0;padding:5px;box-shadow:0 -14px 40px -12px rgba(0,0,0,.55)} .logpeek-h{position:sticky;top:0;padding:5px 9px 7px;font-size:10.5px;text-transform:uppercase;letter-spacing:.5px;color:var(--faint); diff --git a/src/App.tsx b/src/App.tsx index a539ee6..ec27d1f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,7 +7,7 @@ import { isPermissionGranted, requestPermission, sendNotification } from "@tauri import { open as openDialog } from "@tauri-apps/plugin-dialog"; import ModelViewer from "./ModelViewer"; import CodeView from "./CodeView"; -import UpdateBanner from "./Updater"; +import { useUpdater } from "./Updater"; import "./App.css"; import { p4, statusOf, splitPath, kindOf, isCodeFile, fmtTime, describeFiles, filelogRevs, humanSize, leaf, saveSession, loadSession, clearSession, saveScope, loadScope, recentScopes, pushRecentScope, fileBytes, getEditor, setEditorPref, P4Info, OpenedFile, Client, Change, Session, Describe, Dir, User, Editor, FileRev, FsEntry, PluginInfo } from "./p4"; import { t, LANG, LANGS, setLangGlobal, Lang } from "./i18n"; @@ -151,7 +151,7 @@ export default function App() { onInfo={setInfo} onSession={(s) => { setSession(s); saveSession(s); }} onDisconnect={() => { p4.disconnect(); clearSession(); setInfo(null); setSession(null); setPhase("connect"); }} />; - return <>{content}; + return content; } /* ---------------- custom styled dropdown (replaces the ugly native