diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ceaa822..b73b680 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,14 +26,16 @@ jobs: - name: cargo fmt --check run: cargo fmt --all --check - # clippy and test cover the full workspace including the Tauri GUI crate. - # Tauri 1.x links against `libwebkit2gtk-4.0` + `libsoup2.4`, both of - # which Ubuntu 24.04 (the `ubuntu-latest` image) dropped in favor of -4.1 - # / -3.0. Pin to `ubuntu-22.04` until the GUI migrates to Tauri 2.x — - # ubuntu-22.04 GH runner support extends well past that migration. + # clippy + test cover the full workspace including the Tauri 2.x GUI. + # The migration flipped the system-lib stack from libwebkit2gtk-4.0 + + # libsoup-2.4 (Ubuntu 22.04-only) to libwebkit2gtk-4.1 + libsoup-3.0 + # (native on Ubuntu 24.04), so we're back on the default `ubuntu-latest` + # image. Keep the prefix-key cache isolation in place — it's good + # hygiene regardless of which image we're on, and prevents future + # image-version drift from poisoning caches. clippy: name: clippy - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -41,49 +43,39 @@ jobs: components: clippy - uses: Swatinem/rust-cache@v2 with: - # rust-cache keys on `runner.os` ("Linux") which is shared - # between ubuntu-latest (24.04) and ubuntu-22.04. Without a - # per-image prefix, build-script binaries cached on 24.04 - # (GLIBC 2.39) leak into 22.04 jobs (GLIBC 2.35) and fail with - # `version 'GLIBC_2.39' not found`. The `ImageOS` env var - # (ubuntu22 / ubuntu24 / etc.) gives us proper isolation. prefix-key: "v0-rust-${{ env.ImageOS }}" - - name: install Tauri 1.x system deps + - name: install Tauri 2.x system deps run: | sudo apt-get update sudo apt-get install -y \ - libwebkit2gtk-4.0-dev \ + libwebkit2gtk-4.1-dev \ libgtk-3-dev \ libayatana-appindicator3-dev \ librsvg2-dev \ - libsoup2.4-dev + libsoup-3.0-dev \ + libjavascriptcoregtk-4.1-dev - name: clippy run: cargo clippy --workspace --all-targets -- -D warnings test: name: test (no services) - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: - # rust-cache keys on `runner.os` ("Linux") which is shared - # between ubuntu-latest (24.04) and ubuntu-22.04. Without a - # per-image prefix, build-script binaries cached on 24.04 - # (GLIBC 2.39) leak into 22.04 jobs (GLIBC 2.35) and fail with - # `version 'GLIBC_2.39' not found`. The `ImageOS` env var - # (ubuntu22 / ubuntu24 / etc.) gives us proper isolation. prefix-key: "v0-rust-${{ env.ImageOS }}" - - name: install Tauri 1.x system deps + - name: install Tauri 2.x system deps run: | sudo apt-get update sudo apt-get install -y \ - libwebkit2gtk-4.0-dev \ + libwebkit2gtk-4.1-dev \ libgtk-3-dev \ libayatana-appindicator3-dev \ librsvg2-dev \ - libsoup2.4-dev + libsoup-3.0-dev \ + libjavascriptcoregtk-4.1-dev - name: build run: cargo build --workspace - name: tests @@ -92,9 +84,8 @@ jobs: # Mandatory: any new RUSTSEC vulnerability against a crate in `Cargo.lock` # fails the pipeline. Default cargo-audit behavior treats unmaintained / # unsound / yanked as informational warnings, which is the right balance - # here — the Tauri 1.x dep tree carries some unmaintained transitives that - # we'll clear when we migrate to 2.x; surfacing them as hard errors today - # would block the daemon from shipping for an unrelated reason. + # while a few transitives in our dep tree (notably from the Tauri stack) + # haven't been revived yet. audit: name: cargo audit runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index adc6346..4ed5a7a 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,15 @@ cobertura.xml # are ignored. Generated `.onion` hostnames must never be committed. *.onion /configs/torrc.local + +# ----- Tauri -------------------------------------------------------------- +# `gen/schemas/` is regenerated by `tauri-build` on every compile from the +# capability/permission set. Tracking it would just create churn on every +# Tauri version bump. +torpc-proxy/torpc-proxy-gui/gen/ + +# `cargo tauri icon` regenerates per-platform icon variants for Android + +# iOS by default. We don't ship a mobile GUI; ignore those subdirs so a +# future regen doesn't bloat the tree. +torpc-proxy/torpc-proxy-gui/icons/android/ +torpc-proxy/torpc-proxy-gui/icons/ios/ diff --git a/Cargo.lock b/Cargo.lock index a471688..3ae15a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,26 +150,25 @@ dependencies = [ [[package]] name = "atk" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", - "bitflags 1.3.2", "glib", "libc", ] [[package]] name = "atk-sys" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] @@ -205,7 +204,7 @@ dependencies = [ "http-body-util", "hyper 1.6.0", "hyper-util", - "itoa 1.0.15", + "itoa", "matchit", "memchr", "mime", @@ -289,12 +288,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -307,6 +300,21 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -318,12 +326,9 @@ name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -334,11 +339,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -347,9 +361,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.3" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -389,39 +403,75 @@ name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] [[package]] name = "cairo-rs" -version = "0.15.12" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "cairo-sys-rs", "glib", "libc", + "once_cell", "thiserror 1.0.69", ] [[package]] name = "cairo-sys-rs" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ "glib-sys", "libc", - "system-deps 6.2.2", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", ] [[package]] name = "cargo_toml" -version = "0.15.3" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.7.8", + "toml 0.9.12+spec-1.1.0", ] [[package]] @@ -450,15 +500,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "cfg-expr" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" -dependencies = [ - "smallvec", -] - [[package]] name = "cfg-expr" version = "0.15.8" @@ -536,42 +577,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "cocoa" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.5" @@ -597,12 +602,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.18.1" @@ -623,6 +622,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -631,25 +640,25 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.22.3" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 1.3.2", - "core-foundation", + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] [[package]] name = "core-graphics-types" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 1.3.2", - "core-foundation", + "bitflags 2.9.1", + "core-foundation 0.10.1", "libc", ] @@ -680,25 +689,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -717,19 +707,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", + "itoa", + "phf", "smallvec", - "syn 1.0.109", ] [[package]] @@ -744,14 +730,20 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.9" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" dependencies = [ - "quote", - "syn 2.0.104", + "ctor-proc-macro", + "dtor", ] +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "daemonize" version = "0.5.0" @@ -795,6 +787,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dbus" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + [[package]] name = "deranged" version = "0.5.8" @@ -807,11 +810,19 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.20" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", "proc-macro2", "quote", "rustc_version", @@ -846,17 +857,16 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "dirs" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "cfg-if", - "dirs-sys-next", + "dirs-sys 0.5.0", ] [[package]] @@ -867,26 +877,33 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.4.6", "windows-sys 0.48.0", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "dirs-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", - "redox_users", - "winapi", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.60.2", ] [[package]] -name = "dispatch" -version = "0.2.0" +name = "dispatch2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.9.1", + "block2", + "libc", + "objc2", +] [[package]] name = "displaydoc" @@ -899,12 +916,59 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + [[package]] name = "dotenvy" version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + [[package]] name = "dtoa" version = "1.0.11" @@ -920,6 +984,21 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + [[package]] name = "dunce" version = "1.0.5" @@ -940,16 +1019,16 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "2.5.2" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d506610004cfc74a6f5ee7e8c632b355de5eca1f03ee5e5e0ec11b77d4eb3d61" +checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb" dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.23", + "toml 1.1.2+spec-1.1.0", "vswhom", - "winreg 0.52.0", + "winreg 0.55.0", ] [[package]] @@ -973,6 +1052,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + [[package]] name = "errno" version = "0.3.13" @@ -1008,17 +1098,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "filetime" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" -dependencies = [ - "cfg-if", - "libc", - "libredox", -] - [[package]] name = "flate2" version = "1.1.9" @@ -1038,28 +1117,46 @@ dependencies = [ "num-traits", ] -[[package]] -name = "fluent-uri" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -1068,6 +1165,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1078,20 +1181,10 @@ dependencies = [ ] [[package]] -name = "futf" -version = "0.1.5" +name = "futures-channel" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] @@ -1151,6 +1244,7 @@ dependencies = [ "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -1158,22 +1252,12 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" -version = "0.15.4" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" dependencies = [ - "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -1185,35 +1269,35 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.15.11" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" dependencies = [ - "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", "libc", + "once_cell", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" dependencies = [ "gio-sys", "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gdk-sys" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1223,47 +1307,48 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gdkwayland-sys" -version = "0.15.3" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", "glib-sys", "gobject-sys", "libc", "pkg-config", - "system-deps 6.2.2", + "system-deps", ] [[package]] -name = "gdkx11-sys" -version = "0.15.1" +name = "gdkx11" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" dependencies = [ - "gdk-sys", - "glib-sys", + "gdk", + "gdkx11-sys", + "gio", + "glib", "libc", - "system-deps 6.2.2", "x11", ] [[package]] -name = "generator" -version = "0.7.5" +name = "gdkx11-sys" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ - "cc", + "gdk-sys", + "glib-sys", "libc", - "log", - "rustversion", - "windows 0.48.0", + "system-deps", + "x11", ] [[package]] @@ -1276,17 +1361,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.16" @@ -1318,49 +1392,54 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gio" -version = "0.15.12" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" dependencies = [ - "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", + "futures-util", "gio-sys", "glib", "libc", "once_cell", + "pin-project-lite", + "smallvec", "thiserror 1.0.69", ] [[package]] name = "gio-sys" -version = "0.15.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", "winapi", ] [[package]] name = "glib" -version = "0.15.12" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "futures-channel", "futures-core", "futures-executor", "futures-task", + "futures-util", + "gio-sys", "glib-macros", "glib-sys", "gobject-sys", "libc", + "memchr", "once_cell", "smallvec", "thiserror 1.0.69", @@ -1368,27 +1447,26 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.15.13" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ - "anyhow", "heck 0.4.1", - "proc-macro-crate", + "proc-macro-crate 2.0.2", "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] name = "glib-sys" -version = "0.15.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] @@ -1397,38 +1475,24 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "globset" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - [[package]] name = "gobject-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ "glib-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gtk" -version = "0.15.5" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" dependencies = [ "atk", - "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -1439,16 +1503,15 @@ dependencies = [ "gtk-sys", "gtk3-macros", "libc", - "once_cell", "pango", "pkg-config", ] [[package]] name = "gtk-sys" -version = "0.15.3" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1459,21 +1522,20 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gtk3-macros" -version = "0.15.6" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" dependencies = [ - "anyhow", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] @@ -1488,7 +1550,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.10.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -1507,7 +1569,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.10.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -1522,18 +1584,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "heck" -version = "0.3.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1555,16 +1608,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.26.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ "log", - "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", ] [[package]] @@ -1575,7 +1624,7 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -1586,7 +1635,7 @@ checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -1623,12 +1672,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - [[package]] name = "http-range-header" version = "0.4.2" @@ -1662,7 +1705,7 @@ dependencies = [ "http-body 0.4.6", "httparse", "httpdate", - "itoa 1.0.15", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -1685,7 +1728,7 @@ dependencies = [ "http-body 1.0.1", "httparse", "httpdate", - "itoa 1.0.15", + "itoa", "pin-project-lite", "smallvec", "tokio", @@ -1711,6 +1754,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -1718,7 +1762,9 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1752,12 +1798,12 @@ dependencies = [ [[package]] name = "ico" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -1873,34 +1919,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "ignore" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-traits", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -1914,33 +1932,25 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.17.0", "serde", + "serde_core", ] [[package]] name = "infer" -version = "0.13.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ "cfb", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1953,12 +1963,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.15" @@ -1967,9 +1971,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "javascriptcore-rs" -version = "0.16.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" dependencies = [ "bitflags 1.3.2", "glib", @@ -1978,28 +1982,30 @@ dependencies = [ [[package]] name = "javascriptcore-rs-sys" -version = "0.4.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 5.0.0", + "system-deps", ] [[package]] name = "jni" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -2032,19 +2038,21 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "2.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ "jsonptr", "serde", @@ -2054,11 +2062,10 @@ dependencies = [ [[package]] name = "jsonptr" -version = "0.4.7" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" dependencies = [ - "fluent-uri", "serde", "serde_json", ] @@ -2073,16 +2080,14 @@ dependencies = [ ] [[package]] -name = "kuchikiki" -version = "0.8.2" +name = "keyboard-types" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.3", - "matches", - "selectors", + "bitflags 2.9.1", + "serde", + "unicode-segmentation", ] [[package]] @@ -2093,9 +2098,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libappindicator" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" dependencies = [ "glib", "gtk", @@ -2106,9 +2111,9 @@ dependencies = [ [[package]] name = "libappindicator-sys" -version = "0.7.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", "libloading", @@ -2121,6 +2126,15 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + [[package]] name = "libloading" version = "0.7.4" @@ -2137,10 +2151,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.9.1", "libc", - "plain", - "redox_syscall 0.7.5", ] [[package]] @@ -2171,48 +2182,15 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", ] [[package]] @@ -2224,12 +2202,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.7.3" @@ -2312,6 +2284,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "muda" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae8844f63b5b118e334e205585b8c5c17b984121dbdb179d44aeb087ffad3cb" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.12", + "windows-sys 0.60.2", +] + [[package]] name = "native-tls" version = "0.2.14" @@ -2331,28 +2324,24 @@ dependencies = [ [[package]] name = "ndk" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "jni-sys 0.3.1", + "log", "ndk-sys", "num_enum", + "raw-window-handle", "thiserror 1.0.69", ] -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - [[package]] name = "ndk-sys" -version = "0.3.0" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys 0.3.1", ] @@ -2375,12 +2364,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -2393,7 +2376,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2413,51 +2396,219 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] -name = "objc" -version = "0.2.7" +name = "objc2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ - "malloc_buf", - "objc_exception", + "objc2-encode", + "objc2-exception-helper", ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-app-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "cc", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2", ] [[package]] -name = "objc_id" +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "objc", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", ] [[package]] @@ -2481,16 +2632,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "open" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" -dependencies = [ - "pathdiff", - "windows-sys 0.42.0", -] - [[package]] name = "openssl" version = "0.10.73" @@ -2499,7 +2640,7 @@ checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags 2.9.1", "cfg-if", - "foreign-types", + "foreign-types 0.3.2", "libc", "once_cell", "openssl-macros", @@ -2543,11 +2684,11 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "pango" -version = "0.15.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" dependencies = [ - "bitflags 1.3.2", + "gio", "glib", "libc", "once_cell", @@ -2556,14 +2697,14 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] @@ -2584,17 +2725,11 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.13", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2603,106 +2738,43 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_macros", + "phf_shared", + "serde", ] [[package]] name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", + "phf_generator", + "phf_shared", ] [[package]] name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", + "fastrand", + "phf_shared", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.104", @@ -2710,29 +2782,11 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.3", + "siphasher", ] [[package]] @@ -2773,12 +2827,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "plist" version = "1.9.0" @@ -2786,7 +2834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" dependencies = [ "base64 0.22.1", - "indexmap 2.10.0", + "indexmap 2.14.0", "quick-xml", "serde", "time", @@ -2805,6 +2853,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.9.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -2885,6 +2946,16 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2909,12 +2980,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.95" @@ -2948,20 +3013,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - [[package]] name = "rand" version = "0.8.5" @@ -2983,16 +3034,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -3013,15 +3054,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -3040,29 +3072,11 @@ dependencies = [ "getrandom 0.3.3", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "redox_syscall" @@ -3074,23 +3088,25 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.7.5" +name = "redox_users" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "bitflags 2.9.1", + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", ] [[package]] name = "redox_users" -version = "0.4.6" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] @@ -3148,39 +3164,73 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.7", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-socks", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +dependencies = [ + "base64 0.22.1", "bytes", - "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-tls", - "ipnet", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-util", "js-sys", "log", - "mime", - "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", "serde", "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", + "sync_wrapper 1.0.2", "tokio", - "tokio-native-tls", - "tokio-socks", + "tokio-util", + "tower 0.5.2", + "tower-http 0.6.9", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", - "winreg 0.50.0", ] [[package]] @@ -3214,6 +3264,12 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustc_version" version = "0.4.1" @@ -3275,6 +3331,21 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + [[package]] name = "schemars" version = "0.9.0" @@ -3300,10 +3371,16 @@ dependencies = [ ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "schemars_derive" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.104", +] [[package]] name = "scopeguard" @@ -3336,7 +3413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.9.4", "core-foundation-sys", "libc", "security-framework-sys", @@ -3354,22 +3431,21 @@ dependencies = [ [[package]] name = "selectors" -version = "0.22.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "cssparser", "derive_more", - "fxhash", "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", + "new_debug_unreachable", + "phf", + "phf_codegen", "precomputed-hash", + "rustc-hash", "servo_arc", "smallvec", - "thin-slice", ] [[package]] @@ -3392,6 +3468,18 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -3412,14 +3500,24 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "serde_json" version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.10.0", - "itoa 1.0.15", + "itoa", "memchr", "serde", "serde_core", @@ -3432,7 +3530,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ - "itoa 1.0.15", + "itoa", "serde", ] @@ -3456,6 +3554,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3463,7 +3570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.15", + "itoa", "ryu", "serde", ] @@ -3478,7 +3585,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.10.0", + "indexmap 2.14.0", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -3523,11 +3630,10 @@ dependencies = [ [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" dependencies = [ - "nodrop", "stable_deref_trait", ] @@ -3588,12 +3694,6 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.3" @@ -3623,31 +3723,51 @@ dependencies = [ ] [[package]] -name = "soup2" -version = "0.2.1" +name = "softbuffer" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ - "bitflags 1.3.2", + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", "gio", "glib", "libc", - "once_cell", - "soup2-sys", + "soup3-sys", ] [[package]] -name = "soup2-sys" -version = "0.2.0" +name = "soup3-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" dependencies = [ - "bitflags 1.3.2", "gio-sys", "glib-sys", "gobject-sys", "libc", - "system-deps 5.0.0", + "system-deps", ] [[package]] @@ -3656,36 +3776,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "state" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" -dependencies = [ - "loom", -] - [[package]] name = "string_cache" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.11.3", + "phf_shared", "precomputed-hash", - "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -3696,6 +3806,17 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "syn" version = "1.0.109" @@ -3703,7 +3824,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote", "unicode-ident", ] @@ -3729,6 +3849,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -3748,7 +3871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3762,78 +3885,56 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" -dependencies = [ - "cfg-expr 0.9.1", - "heck 0.3.3", - "pkg-config", - "toml 0.5.11", - "version-compare 0.0.11", -] - [[package]] name = "system-deps" version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr 0.15.8", + "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.23", - "version-compare 0.2.1", + "toml 0.8.2", + "version-compare", ] [[package]] name = "tao" -version = "0.16.11" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf915e6c7112402f7b88a064cfbd264f851052df07fdc3a2abd3038b0cc434a" +checksum = "a33f7f9e486ade65fcf1e45c440f9236c904f5c1002cdc7fc6ae582777345ce4" dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "cc", - "cocoa", - "core-foundation", + "bitflags 2.9.1", + "block2", + "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", - "dirs-next", - "dispatch", - "gdk", - "gdk-pixbuf", - "gdk-sys", + "dbus", + "dispatch2", + "dlopen2", + "dpi", "gdkwayland-sys", "gdkx11-sys", - "gio", - "glib", - "glib-sys", "gtk", - "image", - "instant", "jni", - "lazy_static", - "libappindicator", "libc", "log", "ndk", - "ndk-context", "ndk-sys", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "once_cell", "parking_lot", - "png", + "percent-encoding", "raw-window-handle", - "scopeguard", - "serde", "tao-macros", "unicode-segmentation", - "uuid", - "windows 0.39.0", - "windows-implement 0.39.0", + "url", + "windows", + "windows-core", + "windows-version", "x11-dl", ] @@ -3848,17 +3949,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "tar" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "target-lexicon" version = "0.12.16" @@ -3867,66 +3957,68 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "1.8.3" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae1f57c291a6ab8e1d2e6b8ad0a35ff769c9925deb8a89de85425ff08762d0c" +checksum = "b93bd86d231f0a8138f11a02a584769fe4b703dc36ae133d783228dbc4801405" dependencies = [ "anyhow", - "cocoa", - "dirs-next", + "bytes", + "cookie", + "dirs 6.0.0", "dunce", "embed_plist", - "encoding_rs", - "flate2", - "futures-util", - "getrandom 0.2.16", - "glib", + "getrandom 0.3.3", "glob", "gtk", "heck 0.5.0", - "http 0.2.12", - "ignore", + "http 1.3.1", + "jni", + "libc", "log", - "objc", - "once_cell", - "open", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "percent-encoding", "plist", - "rand 0.8.5", "raw-window-handle", - "regex", - "semver", + "reqwest 0.13.3", "serde", "serde_json", "serde_repr", "serialize-to-javascript", - "state", - "tar", + "swift-rs", + "tauri-build", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", + "tray-icon", "url", - "uuid", "webkit2gtk", "webview2-com", - "windows 0.39.0", + "window-vibrancy", + "windows", ] [[package]] name = "tauri-build" -version = "1.5.6" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db08694eec06f53625cfc6fff3a363e084e5e9a238166d2989996413c346453" +checksum = "3a318b234cc2dea65f575467bafcfb76286bce228ebc3778e337d61d03213007" dependencies = [ "anyhow", "cargo_toml", - "dirs-next", + "dirs 6.0.0", + "glob", "heck 0.5.0", "json-patch", + "schemars 0.8.22", "semver", "serde", "serde_json", @@ -3937,123 +4029,143 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.4.6" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53438d78c4a037ffe5eafa19e447eea599bedfb10844cb08ec53c2471ac3ac3f" +checksum = "6bd11644962add2549a60b7e7c6800f17d7020156e02f516021d8103e80cc528" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "brotli", "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", - "regex", "semver", "serde", "serde_json", "sha2", + "syn 2.0.104", "tauri-utils", - "thiserror 1.0.69", + "thiserror 2.0.12", "time", + "url", "uuid", "walkdir", ] [[package]] name = "tauri-macros" -version = "1.4.7" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233988ac08c1ed3fe794cd65528d48d8f7ed4ab3895ca64cdaa6ad4d00c45c0b" +checksum = "fed9d3742a37a355d2e47c9af924e9fbc112abb76f9835d35d4780e318419502" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-runtime" -version = "0.14.6" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8066855882f00172935e3fa7d945126580c34dcbabab43f5d4f0c2398a67d47b" +checksum = "8fef478ba1d2ac21c2d528740b24d0cb315e1e8b1111aae53fafac34804371fc" dependencies = [ + "cookie", + "dpi", "gtk", - "http 0.2.12", - "http-range", - "rand 0.8.5", + "http 1.3.1", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror 1.0.69", + "thiserror 2.0.12", "url", - "uuid", + "webkit2gtk", "webview2-com", - "windows 0.39.0", + "windows", ] [[package]] name = "tauri-runtime-wry" -version = "0.14.11" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce361fec1e186705371f1c64ae9dd2a3a6768bc530d0a2d5e75a634bb416ad4d" +checksum = "a3989df2ae1c476404fe0a2e8ffc4cfbde97e51efd613c2bb5355fbc9ab52cf0" dependencies = [ - "cocoa", "gtk", + "http 1.3.1", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", "percent-encoding", - "rand 0.8.5", "raw-window-handle", + "softbuffer", + "tao", "tauri-runtime", "tauri-utils", - "uuid", + "url", "webkit2gtk", "webview2-com", - "windows 0.39.0", + "windows", "wry", ] [[package]] name = "tauri-utils" -version = "1.6.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c357952645e679de02cd35007190fcbce869b93ffc61b029f33fe02648453774" +checksum = "d57200389a2f82b4b0a40ae29ca19b6978116e8f4d4e974c3234ce40c0ffbdec" dependencies = [ + "anyhow", "brotli", + "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", - "heck 0.5.0", - "html5ever", + "http 1.3.1", "infer", "json-patch", - "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf", + "plist", "proc-macro2", "quote", + "regex", + "schemars 0.8.22", "semver", "serde", + "serde-untagged", "serde_json", "serde_with", - "thiserror 1.0.69", + "swift-rs", + "thiserror 2.0.12", + "toml 1.1.2+spec-1.1.0", "url", + "urlpattern", + "uuid", "walkdir", - "windows-version", ] [[package]] name = "tauri-winres" -version = "0.1.1" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ + "dunce", "embed-resource", - "toml 0.7.8", + "toml 1.1.2+spec-1.1.0", ] [[package]] @@ -4071,12 +4183,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" dependencies = [ - "futf", - "mac", + "new_debug_unreachable", "utf-8", ] @@ -4086,12 +4197,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.69" @@ -4148,7 +4253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", - "itoa 1.0.15", + "itoa", "num-conv", "powerfmt", "serde_core", @@ -4270,78 +4375,111 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", ] [[package]] name = "toml" -version = "0.7.8" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", ] [[package]] name = "toml" -version = "0.8.23" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.27", + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.2", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.10.0", - "serde", - "serde_spanned", - "toml_datetime", + "indexmap 2.14.0", + "toml_datetime 0.6.3", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.14.0", "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.15", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.2", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_writer" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "torpc" @@ -4357,7 +4495,7 @@ dependencies = [ "nix", "once_cell", "rand 0.8.5", - "reqwest", + "reqwest 0.11.27", "secp256k1", "serde", "serde_json", @@ -4366,7 +4504,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tower 0.4.13", - "tower-http", + "tower-http 0.5.2", "tracing", "tracing-subscriber", "uuid", @@ -4380,6 +4518,7 @@ dependencies = [ "assert_cmd", "clap", "daemonize", + "dirs 5.0.1", "predicates", "tempfile", "tokio", @@ -4407,7 +4546,7 @@ dependencies = [ "tokio", "tokio-socks", "tokio-test", - "toml 0.8.23", + "toml 0.8.2", "tracing", ] @@ -4416,13 +4555,14 @@ name = "torpc-proxy-gui" version = "0.1.0" dependencies = [ "anyhow", - "dirs", + "dirs 5.0.1", "serde", "serde_json", "tauri", "tauri-build", "tokio", "tokio-socks", + "toml 0.8.2", "torpc-proxy-core", "tracing", "tracing-subscriber", @@ -4486,6 +4626,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28f0d049ccfaa566e14e9663d304d8577427b368cb4710a20528690287a738b" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", + "tower 0.5.2", + "tower-layer", + "tower-service", + "url", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -4560,18 +4718,87 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tray-icon" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773" +dependencies = [ + "crossbeam-channel", + "dirs 6.0.0", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.12", + "windows-sys 0.60.2", +] + [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.8.1" @@ -4602,6 +4829,18 @@ dependencies = [ "serde", ] +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -4644,12 +4883,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version-compare" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" - [[package]] name = "version-compare" version = "0.2.1" @@ -4710,12 +4943,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -4733,48 +4960,32 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4782,41 +4993,66 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.104", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "webkit2gtk" -version = "0.18.2" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4832,20 +5068,18 @@ dependencies = [ "javascriptcore-rs", "libc", "once_cell", - "soup2", + "soup3", "webkit2gtk-sys", ] [[package]] name = "webkit2gtk-sys" -version = "0.18.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ - "atk-sys", "bitflags 1.3.2", "cairo-sys-rs", - "gdk-pixbuf-sys", "gdk-sys", "gio-sys", "glib-sys", @@ -4853,48 +5087,45 @@ dependencies = [ "gtk-sys", "javascriptcore-rs-sys", "libc", - "pango-sys", "pkg-config", - "soup2-sys", - "system-deps 6.2.2", + "soup3-sys", + "system-deps", ] [[package]] name = "webview2-com" -version = "0.19.1" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.39.0", - "windows-implement 0.39.0", + "windows", + "windows-core", + "windows-implement", + "windows-interface", ] [[package]] name = "webview2-com-macros" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] name = "webview2-com-sys" -version = "0.19.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "regex", - "serde", - "serde_json", - "thiserror 1.0.69", - "windows 0.39.0", - "windows-bindgen", - "windows-metadata", + "thiserror 2.0.12", + "windows", + "windows-core", ] [[package]] @@ -4935,36 +5166,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.39.0" +name = "window-vibrancy" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "windows-implement 0.39.0", - "windows_aarch64_msvc 0.39.0", - "windows_i686_gnu 0.39.0", - "windows_i686_msvc 0.39.0", - "windows_x86_64_gnu 0.39.0", - "windows_x86_64_msvc 0.39.0", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", ] [[package]] name = "windows" -version = "0.48.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-targets 0.48.5", + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", ] [[package]] -name = "windows-bindgen" -version = "0.39.0" +name = "windows-collections" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-metadata", - "windows-tokens", + "windows-core", ] [[package]] @@ -4973,7 +5208,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.0", + "windows-implement", "windows-interface", "windows-link 0.1.3", "windows-result", @@ -4981,13 +5216,14 @@ dependencies = [ ] [[package]] -name = "windows-implement" -version = "0.39.0" +name = "windows-future" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "syn 1.0.109", - "windows-tokens", + "windows-core", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -5025,10 +5261,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-metadata" -version = "0.39.0" +name = "windows-numerics" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] [[package]] name = "windows-result" @@ -5061,17 +5301,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.42.2", ] [[package]] @@ -5110,6 +5344,30 @@ dependencies = [ "windows-targets 0.53.2", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -5158,10 +5416,13 @@ dependencies = [ ] [[package]] -name = "windows-tokens" -version = "0.39.0" +name = "windows-threading" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] [[package]] name = "windows-version" @@ -5196,12 +5457,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5226,12 +5481,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5268,12 +5517,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5298,12 +5541,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5352,12 +5589,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5396,9 +5627,12 @@ name = "winnow" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" [[package]] name = "winreg" @@ -5412,12 +5646,12 @@ dependencies = [ [[package]] name = "winreg" -version = "0.52.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5437,40 +5671,46 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.24.12" +version = "0.55.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a2a144c3ab5e83e04724bc8e67cea552ffae413185fda459fafdae173fd985d" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" dependencies = [ - "base64 0.13.1", - "block", - "cocoa", - "core-graphics", + "base64 0.22.1", + "block2", + "cookie", "crossbeam-channel", + "dirs 6.0.0", + "dom_query", + "dpi", "dunce", - "gdk", - "gio", - "glib", + "gdkx11", "gtk", - "html5ever", - "http 0.2.12", - "kuchikiki", + "http 1.3.1", + "javascriptcore-rs", + "jni", "libc", - "log", - "objc", - "objc_id", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "once_cell", - "serde", - "serde_json", + "percent-encoding", + "raw-window-handle", "sha2", - "soup2", - "tao", - "thiserror 1.0.69", + "soup3", + "tao-macros", + "thiserror 2.0.12", "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.39.0", - "windows-implement 0.39.0", + "windows", + "windows-core", + "windows-version", + "x11-dl", ] [[package]] @@ -5494,16 +5734,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix", -] - [[package]] name = "yansi" version = "1.0.1" diff --git a/torpc-proxy/torpc-proxy-cli/Cargo.toml b/torpc-proxy/torpc-proxy-cli/Cargo.toml index 018947c..0a3affd 100644 --- a/torpc-proxy/torpc-proxy-cli/Cargo.toml +++ b/torpc-proxy/torpc-proxy-cli/Cargo.toml @@ -28,6 +28,9 @@ anyhow = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } +# Platform-specific config-dir resolution (matches the GUI's path). +dirs = "5.0" + # System integration [target.'cfg(unix)'.dependencies] daemonize = "0.5" diff --git a/torpc-proxy/torpc-proxy-cli/src/main.rs b/torpc-proxy/torpc-proxy-cli/src/main.rs index da70677..94a0b8e 100644 --- a/torpc-proxy/torpc-proxy-cli/src/main.rs +++ b/torpc-proxy/torpc-proxy-cli/src/main.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result}; use clap::{Parser, Subcommand}; use std::net::SocketAddr; use std::path::PathBuf; -use tracing::{error, info}; +use tracing::{debug, error, info}; use tracing_subscriber::EnvFilter; use torpc_proxy_core::{Config, ProxyConfig, TorRpcProxy}; @@ -14,9 +14,12 @@ struct Cli { #[command(subcommand)] command: Option, - /// Configuration file path - #[arg(short, long, default_value = "torpc-proxy.toml")] - config: PathBuf, + /// Configuration file path. When unspecified, the CLI looks at + /// `dirs::config_dir() / torpc-proxy / config.toml` first (shared with + /// the GUI), then falls back to `./torpc-proxy.toml` for backward + /// compatibility with cwd-based setups. + #[arg(short, long)] + config: Option, } #[derive(Subcommand)] @@ -30,18 +33,34 @@ enum Commands { /// Onion endpoint (overrides config) #[arg(short, long)] onion: Option, + + /// Tor SOCKS5 host (overrides config; default 127.0.0.1) + #[arg(long)] + tor_host: Option, + + /// Tor SOCKS5 port (overrides config; default 9050 — Tor Browser uses 9150) + #[arg(long)] + tor_port: Option, }, /// Show the default configuration Config, - /// Test Tor connectivity - Test, + /// Test Tor connectivity. Probes a well-known onion to confirm Tor is + /// reachable, then probes the configured `onion_endpoint` if present. + Test { + /// Tor SOCKS5 host (overrides config; default 127.0.0.1) + #[arg(long)] + tor_host: Option, + + /// Tor SOCKS5 port (overrides config; default 9050) + #[arg(long)] + tor_port: Option, + }, } #[tokio::main] async fn main() -> Result<()> { - // Initialize logging tracing_subscriber::fmt() .with_env_filter( EnvFilter::try_from_default_env() @@ -50,29 +69,56 @@ async fn main() -> Result<()> { .init(); let cli = Cli::parse(); + let config_path = resolve_config_path(cli.config.clone()); - match &cli.command { - Some(Commands::Start { port, onion }) => { - start_proxy(cli.config, *port, onion.clone()).await - } + match cli.command { + Some(Commands::Start { + port, + onion, + tor_host, + tor_port, + }) => start_proxy(config_path, port, onion, tor_host, tor_port).await, Some(Commands::Config) => { show_default_config(); Ok(()) } - Some(Commands::Test) => test_tor_connectivity().await, - None => { - // Default to start if no subcommand - start_proxy(cli.config, None, None).await + Some(Commands::Test { tor_host, tor_port }) => { + test_tor_connectivity(config_path, tor_host, tor_port).await } + None => start_proxy(config_path, None, None, None, None).await, } } +/// Resolve which `Config` file the CLI should read. +/// +/// Priority: +/// 1. `--config` flag (explicit user choice; honour even if missing). +/// 2. `dirs::config_dir() / torpc-proxy / config.toml` (shared with the GUI). +/// 3. `./torpc-proxy.toml` (cwd; backward-compat with operator setups that +/// pre-date the user-config path). +/// +/// The returned path may not exist on disk — `start_proxy` falls back to +/// `Config::default()` in that case. +fn resolve_config_path(explicit: Option) -> PathBuf { + if let Some(path) = explicit { + return path; + } + if let Some(user) = dirs::config_dir().map(|d| d.join("torpc-proxy/config.toml")) { + if user.exists() { + debug!("Using user-config path {:?}", user); + return user; + } + } + PathBuf::from("torpc-proxy.toml") +} + async fn start_proxy( config_path: PathBuf, port_override: Option, onion_override: Option, + tor_host_override: Option, + tor_port_override: Option, ) -> Result<()> { - // Load configuration let mut config = if config_path.exists() { Config::load_from_file(&config_path).context("Failed to load configuration")? } else { @@ -80,43 +126,43 @@ async fn start_proxy( Config::default() }; - // Apply command-line overrides if let Some(port) = port_override { config.port = port; } if let Some(onion) = onion_override { config.onion_endpoint = onion; } + if let Some(host) = tor_host_override { + config.tor_proxy_host = host; + } + if let Some(port) = tor_port_override { + config.tor_proxy_port = port; + } - // Validate configuration if config.onion_endpoint.is_empty() { error!("No onion endpoint specified!"); - error!("Please provide --onion flag or set onion_endpoint in config file"); + error!("Provide --onion or set onion_endpoint in the config file"); std::process::exit(1); } - // Create proxy configuration let proxy_config = ProxyConfig { listen_addr: ([127, 0, 0, 1], config.port).into(), tor_proxy: config.tor_proxy_addr(), onion_endpoint: config.onion_endpoint, }; - // Create and run proxy let proxy = TorRpcProxy::new(proxy_config); info!("Starting ToRPC proxy..."); info!("Wallet RPC URL: http://localhost:{}", config.port); info!("Press Ctrl+C to stop"); - // Handle shutdown gracefully let proxy_handle = tokio::spawn(async move { if let Err(e) = proxy.run().await { error!("Proxy error: {}", e); } }); - // Wait for Ctrl+C tokio::signal::ctrl_c() .await .context("Failed to install signal handler")?; @@ -144,18 +190,42 @@ fn show_default_config() { println!("log_level = \"info\""); } -async fn test_tor_connectivity() -> Result<()> { +/// Probe the local Tor daemon and (if configured) the user's onion endpoint. +/// +/// `tor_host_override` / `tor_port_override` come from `--tor-host` / +/// `--tor-port`. Without overrides we fall back to the values in the +/// configured file (so a Tor Browser user with `tor_proxy_port = 9150` +/// gets the right address tested). Pre-PR-1 the test hardcoded 9050, +/// which produced confusing "Tor not running" errors for those users. +async fn test_tor_connectivity( + config_path: PathBuf, + tor_host_override: Option, + tor_port_override: Option, +) -> Result<()> { use std::time::Duration; use tokio::time::timeout; use tokio_socks::tcp::Socks5Stream; info!("Testing Tor connectivity..."); - // Step 1: confirm Tor itself is reachable by hitting a well-known onion. - // DuckDuckGo's onion is stable and tolerates a single TCP probe. - let tor_addr: SocketAddr = ([127, 0, 0, 1], 9050).into(); + let config = if config_path.exists() { + Config::load_from_file(&config_path).unwrap_or_else(|e| { + info!("Could not load {:?}: {}; using defaults", config_path, e); + Config::default() + }) + } else { + Config::default() + }; + + let tor_host = tor_host_override.unwrap_or(config.tor_proxy_host.clone()); + let tor_port = tor_port_override.unwrap_or(config.tor_proxy_port); + let tor_addr: SocketAddr = format!("{tor_host}:{tor_port}") + .parse() + .with_context(|| format!("Invalid Tor SOCKS5 address: {tor_host}:{tor_port}"))?; info!("Using Tor SOCKS5 proxy at: {}", tor_addr); + // Step 1: confirm Tor itself is reachable by hitting a well-known onion. + // DuckDuckGo's onion is stable and tolerates a single TCP probe. let well_known = "duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion:80"; info!("Step 1: probing Tor reachability via {}", well_known); let probe = Socks5Stream::connect(tor_addr, well_known); @@ -163,7 +233,10 @@ async fn test_tor_connectivity() -> Result<()> { Ok(Ok(_)) => info!("✓ Tor is reachable; SOCKS5 working"), Ok(Err(e)) => { error!("✗ Tor SOCKS5 reach test failed: {}", e); - error!("Make sure Tor is running and listening on port 9050"); + error!( + "Make sure Tor is running and listening on {} (Tor Browser uses 9150)", + tor_addr + ); return Err(e.into()); } Err(_) => { @@ -172,26 +245,17 @@ async fn test_tor_connectivity() -> Result<()> { } } - // Step 2: also probe the user's *configured* onion endpoint, since that's - // the one their wallet will actually use. Tor itself working doesn't - // imply the configured onion is up, and that's the more common failure. - let config_path = PathBuf::from("torpc-proxy.toml"); - let configured = if config_path.exists() { - match Config::load_from_file(&config_path) { - Ok(c) if !c.onion_endpoint.is_empty() => Some(c.onion_endpoint), - _ => None, - } - } else { - None - }; - - if let Some(onion) = configured { - info!("Step 2: probing configured onion {}", onion); - let probe = Socks5Stream::connect(tor_addr, onion.as_str()); + // Step 2: probe the configured onion (the more common failure mode). + if !config.onion_endpoint.is_empty() { + info!("Step 2: probing configured onion {}", config.onion_endpoint); + let probe = Socks5Stream::connect(tor_addr, config.onion_endpoint.as_str()); match timeout(Duration::from_secs(30), probe).await { Ok(Ok(_)) => info!("✓ Configured onion endpoint is reachable"), Ok(Err(e)) => { - error!("✗ Could not reach configured onion {}: {}", onion, e); + error!( + "✗ Could not reach configured onion {}: {}", + config.onion_endpoint, e + ); error!("Confirm the .onion address is correct and the remote service is up"); return Err(e.into()); } @@ -201,7 +265,7 @@ async fn test_tor_connectivity() -> Result<()> { } } } else { - info!("Step 2 skipped: no `onion_endpoint` configured in torpc-proxy.toml"); + info!("Step 2 skipped: no `onion_endpoint` configured"); } Ok(()) diff --git a/torpc-proxy/torpc-proxy-core/src/lib.rs b/torpc-proxy/torpc-proxy-core/src/lib.rs index 0b3a6fd..2bc3ff9 100644 --- a/torpc-proxy/torpc-proxy-core/src/lib.rs +++ b/torpc-proxy/torpc-proxy-core/src/lib.rs @@ -10,8 +10,18 @@ use tracing::{error, info}; pub use config::Config; pub use proxy::{ProxyConfig, TorRpcProxy}; -/// Status of the proxy -#[derive(Debug, Clone, PartialEq)] +/// Status of the proxy. +/// +/// Serializes to a tagged JSON shape so the GUI can pattern-match without +/// regexing against `Debug` output. Examples: +/// +/// ```json +/// { "state": "Stopped" } +/// { "state": "Running" } +/// { "state": "Error", "message": "Tor not reachable" } +/// ``` +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "state", content = "message")] pub enum ProxyStatus { Stopped, Starting, diff --git a/torpc-proxy/torpc-proxy-core/src/proxy.rs b/torpc-proxy/torpc-proxy-core/src/proxy.rs index 3a963e9..bdf06f9 100644 --- a/torpc-proxy/torpc-proxy-core/src/proxy.rs +++ b/torpc-proxy/torpc-proxy-core/src/proxy.rs @@ -165,7 +165,12 @@ impl TorRpcProxy { discovery_port, e ), } - info!("Discovery token (X-Torpc-Token): {}", token); + // Token is already persisted at mode 0600 to ${XDG_RUNTIME_DIR:-/tmp}/ + // torpc-discovery.token; printing it at INFO duplicates that info into + // journal/syslog where any local user with log access can grab it. + // Trusted local clients should read the file. Operators wanting to + // see the token at startup can `RUST_LOG=debug`. + debug!("Discovery token (X-Torpc-Token): {}", token); let token = Arc::new(token); tokio::spawn(async move { diff --git a/torpc-proxy/torpc-proxy-gui/Cargo.toml b/torpc-proxy/torpc-proxy-gui/Cargo.toml index d14874b..4da7a3b 100644 --- a/torpc-proxy/torpc-proxy-gui/Cargo.toml +++ b/torpc-proxy/torpc-proxy-gui/Cargo.toml @@ -7,14 +7,17 @@ license.workspace = true description = "Desktop GUI for ToRPC proxy using Tauri" [build-dependencies] -tauri-build = { version = "1", features = [] } +tauri-build = { version = "2", features = [] } [dependencies] # Core library torpc-proxy-core = { path = "../torpc-proxy-core" } -# Tauri -tauri = { version = "1", features = ["shell-open", "system-tray", "window-close", "window-hide", "window-minimize", "window-set-focus", "window-show"] } +# Tauri 2.x — most features that were behind feature flags in 1.x are now +# either built-in (window/tray APIs) or split into separate plugin crates. +# `tauri-plugin-shell` will be added in PR 3 when we wire the update- +# notification "open releases page" action. +tauri = { version = "2", features = ["tray-icon"] } # Async runtime tokio = { workspace = true } @@ -29,6 +32,7 @@ tracing-subscriber = { workspace = true } # Serialization serde = { workspace = true } serde_json = { workspace = true } +toml = { workspace = true } # Tor support for connection testing tokio-socks = { workspace = true } @@ -37,5 +41,6 @@ tokio-socks = { workspace = true } dirs = "5.0" [features] -# This feature is used for production builds or when `devPath` points to the filesystem -custom-protocol = ["tauri/custom-protocol"] \ No newline at end of file +# This feature is used for production builds or when `frontendDist` points +# to the filesystem (Tauri 2.x renamed `devPath`/`distDir`). +custom-protocol = ["tauri/custom-protocol"] diff --git a/torpc-proxy/torpc-proxy-gui/build.rs b/torpc-proxy/torpc-proxy-gui/build.rs index d860e1e..6abcbe6 100644 --- a/torpc-proxy/torpc-proxy-gui/build.rs +++ b/torpc-proxy/torpc-proxy-gui/build.rs @@ -1,3 +1,10 @@ fn main() { + // tauri-build doesn't watch `frontendDist` (the `ui/` directory) by + // default — `cargo build` after editing app.js / index.html / style.css + // returns "Finished" instantly without re-embedding the assets, leaving + // the running binary serving stale frontend code. Watch the dir + // explicitly so Cargo treats it as a rebuild input. + println!("cargo:rerun-if-changed=ui"); + tauri_build::build() } diff --git a/torpc-proxy/torpc-proxy-gui/capabilities/default.json b/torpc-proxy/torpc-proxy-gui/capabilities/default.json new file mode 100644 index 0000000..9c644dd --- /dev/null +++ b/torpc-proxy/torpc-proxy-gui/capabilities/default.json @@ -0,0 +1,12 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Default capability for the settings window: window management, tray-icon access, and permission to call our custom tauri::commands.", + "windows": ["main"], + "permissions": [ + "core:default", + "core:tray:default", + "core:window:default", + "core:webview:default" + ] +} diff --git a/torpc-proxy/torpc-proxy-gui/icons/128x128.png b/torpc-proxy/torpc-proxy-gui/icons/128x128.png index b471b1d..473278e 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/128x128.png and b/torpc-proxy/torpc-proxy-gui/icons/128x128.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/128x128@2x.png b/torpc-proxy/torpc-proxy-gui/icons/128x128@2x.png index 496d0b7..9dbd00d 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/128x128@2x.png and b/torpc-proxy/torpc-proxy-gui/icons/128x128@2x.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/32x32.png b/torpc-proxy/torpc-proxy-gui/icons/32x32.png index 828cca6..d8edcbb 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/32x32.png and b/torpc-proxy/torpc-proxy-gui/icons/32x32.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/64x64.png b/torpc-proxy/torpc-proxy-gui/icons/64x64.png new file mode 100644 index 0000000..9c412c3 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/64x64.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square107x107Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square107x107Logo.png new file mode 100644 index 0000000..3cec778 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square107x107Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square142x142Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square142x142Logo.png new file mode 100644 index 0000000..930a08e Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square142x142Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square150x150Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square150x150Logo.png new file mode 100644 index 0000000..c29c023 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square150x150Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square284x284Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square284x284Logo.png new file mode 100644 index 0000000..5898a40 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square284x284Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square30x30Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square30x30Logo.png new file mode 100644 index 0000000..ff8110b Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square30x30Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square310x310Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square310x310Logo.png new file mode 100644 index 0000000..3827be4 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square310x310Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square44x44Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square44x44Logo.png new file mode 100644 index 0000000..0e9123a Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square44x44Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square71x71Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square71x71Logo.png new file mode 100644 index 0000000..445fdc1 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square71x71Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/Square89x89Logo.png b/torpc-proxy/torpc-proxy-gui/icons/Square89x89Logo.png new file mode 100644 index 0000000..4ac31c6 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/Square89x89Logo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/StoreLogo.png b/torpc-proxy/torpc-proxy-gui/icons/StoreLogo.png new file mode 100644 index 0000000..c068db5 Binary files /dev/null and b/torpc-proxy/torpc-proxy-gui/icons/StoreLogo.png differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/icon.icns b/torpc-proxy/torpc-proxy-gui/icons/icon.icns index e69de29..d7e4358 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/icon.icns and b/torpc-proxy/torpc-proxy-gui/icons/icon.icns differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/icon.ico b/torpc-proxy/torpc-proxy-gui/icons/icon.ico index fd7c991..ebc80b7 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/icon.ico and b/torpc-proxy/torpc-proxy-gui/icons/icon.ico differ diff --git a/torpc-proxy/torpc-proxy-gui/icons/icon.png b/torpc-proxy/torpc-proxy-gui/icons/icon.png index ecc0fa7..19d11cc 100644 Binary files a/torpc-proxy/torpc-proxy-gui/icons/icon.png and b/torpc-proxy/torpc-proxy-gui/icons/icon.png differ diff --git a/torpc-proxy/torpc-proxy-gui/src/main.rs b/torpc-proxy/torpc-proxy-gui/src/main.rs index 5b51923..e682ce3 100644 --- a/torpc-proxy/torpc-proxy-gui/src/main.rs +++ b/torpc-proxy/torpc-proxy-gui/src/main.rs @@ -1,76 +1,107 @@ +// Hide the console window on Windows release builds. Tauri 1.x and 2.x +// agree on this attribute. #![cfg_attr( all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows" )] +//! ToRPC Proxy desktop GUI. +//! +//! Caffeine-shaped tray app: a small icon in the menu bar, click to open a +//! settings window, close-button hides instead of quits. Wraps +//! `torpc_proxy_core::ProxyController` so the same forwarding logic backs +//! the CLI and the GUI. +//! +//! Migrated to Tauri 2.x. The 1.x `SystemTray` / `SystemTrayMenu` / +//! `SystemTrayEvent` triple is gone; tray-icons + menus are constructed +//! against an `AppHandle` inside `setup` using `TrayIconBuilder` and the +//! new `tauri::menu::*` types. Window APIs renamed +//! `Manager::get_window` → `Manager::get_webview_window`. Allowlist +//! removed, replaced by `capabilities/default.json`. + use anyhow::Result; use std::fs; use std::path::PathBuf; use std::sync::Arc; use tauri::{ - CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, + menu::{Menu, MenuItem, PredefinedMenuItem}, + tray::TrayIconBuilder, + Manager, }; use tokio::sync::Mutex; -use torpc_proxy_core::{ProxyConfig, ProxyController}; +use torpc_proxy_core::{ProxyConfig, ProxyController, ProxyStatus}; use tracing::{error, info}; struct AppState { proxy_controller: Arc>, } -/// Get the configuration directory path -fn get_config_dir() -> Result { - let config_dir = dirs::config_dir() +// ----------------------------------------------------------------------------- +// Configuration persistence +// +// Pre-PR-1 the CLI read TOML and the GUI read JSON, so installing both binaries +// on the same machine would silently fork the configuration. They now agree on +// a single TOML file at `dirs::config_dir() / torpc-proxy / config.toml`. +// ----------------------------------------------------------------------------- + +fn config_dir() -> Result { + let dir = dirs::config_dir() .ok_or_else(|| anyhow::anyhow!("Could not determine config directory"))? .join("torpc-proxy"); - - // Create directory if it doesn't exist - if !config_dir.exists() { - fs::create_dir_all(&config_dir)?; + if !dir.exists() { + fs::create_dir_all(&dir)?; } + Ok(dir) +} - Ok(config_dir) +fn config_file_path() -> Result { + Ok(config_dir()?.join("config.toml")) } -/// Get the configuration file path -fn get_config_file_path() -> Result { - Ok(get_config_dir()?.join("config.json")) +fn default_config() -> ProxyConfig { + // Default `onion_endpoint` is **empty**, not the legacy "placeholder.onion:80" + // sentinel. The settings UI uses an HTML `placeholder=` attr to suggest + // the format; persisting a real-looking placeholder string used to make + // it through `update_config` and trigger the proxy to chase a non-existent + // hidden service. + ProxyConfig { + listen_addr: ([127, 0, 0, 1], 8545).into(), + tor_proxy: ([127, 0, 0, 1], 9050).into(), + onion_endpoint: String::new(), + } } -/// Load configuration from file fn load_config() -> Result { - let config_path = get_config_file_path()?; - - if config_path.exists() { - info!("Loading configuration from {:?}", config_path); - let config_str = fs::read_to_string(&config_path)?; - let config: ProxyConfig = serde_json::from_str(&config_str)?; - Ok(config) + let path = config_file_path()?; + if path.exists() { + info!("Loading configuration from {:?}", path); + let raw = fs::read_to_string(&path)?; + Ok(toml::from_str(&raw)?) } else { info!("No configuration file found, using defaults"); - // Return default config - Ok(ProxyConfig { - listen_addr: ([127, 0, 0, 1], 8545).into(), - tor_proxy: ([127, 0, 0, 1], 9050).into(), - onion_endpoint: "placeholder.onion:80".to_string(), - }) + Ok(default_config()) } } -/// Save configuration to file fn save_config(config: &ProxyConfig) -> Result<()> { - let config_path = get_config_file_path()?; - let config_str = serde_json::to_string_pretty(config)?; - fs::write(&config_path, config_str)?; - info!("Configuration saved to {:?}", config_path); + let path = config_file_path()?; + let raw = toml::to_string_pretty(config)?; + fs::write(&path, raw)?; + info!("Configuration saved to {:?}", path); Ok(()) } +// ----------------------------------------------------------------------------- +// Tauri commands invoked from the settings window's JS +// ----------------------------------------------------------------------------- + +/// Returns the typed `ProxyStatus` (serializes to `{"state":"Running"}` etc.) +/// rather than `Debug`-formatted text. The frontend can pattern-match on +/// `status.state` without parsing strings. #[tauri::command] -async fn get_status(state: tauri::State<'_, AppState>) -> Result { +async fn get_status(state: tauri::State<'_, AppState>) -> Result { let controller = state.proxy_controller.lock().await; - let status = controller.get_status().await; - Ok(format!("{status:?}")) + Ok(controller.get_status().await) } #[tauri::command] @@ -78,18 +109,15 @@ async fn start_proxy(state: tauri::State<'_, AppState>) -> Result<(), String> { info!("start_proxy command called"); let controller = state.proxy_controller.lock().await; - // Reject configurations the user clearly forgot to fill in. The proxy - // would otherwise start, immediately fail to connect to "placeholder.onion", - // and the GUI would show a confusingly successful "Running" status. let config = controller.get_config().await; - if config.onion_endpoint.is_empty() || config.onion_endpoint == "placeholder.onion:80" { + if config.onion_endpoint.trim().is_empty() { let msg = "No onion endpoint configured. Open Settings and enter the .onion address before starting the proxy."; error!("Refusing to start proxy: {}", msg); return Err(msg.to_string()); } match controller.start().await { - Ok(_) => { + Ok(()) => { info!("Proxy started successfully"); Ok(()) } @@ -119,24 +147,32 @@ async fn update_config( ) -> Result<(), String> { let controller = state.proxy_controller.lock().await; - // Update the configuration in the controller controller .update_config(config.clone()) .await .map_err(|e| e.to_string())?; - // Save the configuration to file if let Err(e) = save_config(&config) { + // Don't fail the command if we can't persist — the in-memory + // controller is already updated. The next restart will fall back + // to defaults, which is recoverable. error!("Failed to save configuration to file: {}", e); - // Don't fail the command if we can't save the file, just log the error } Ok(()) } +/// Two-stage connection probe. Stage 1 establishes a SOCKS5 connection +/// through the local Tor daemon to the configured onion endpoint. Stage 2 +/// sends a `web3_clientVersion` JSON-RPC and verifies the response is a +/// well-formed JSON-RPC envelope — without stage 2, "connection successful" +/// passes against any TCP listener happening to live on the configured +/// onion port. The HTTP request is built by hand to avoid pulling hyper +/// in just for the probe. #[tauri::command] async fn test_connection(onion_endpoint: String, tor_proxy: String) -> Result { use std::time::Duration; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio_socks::tcp::Socks5Stream; info!( @@ -144,57 +180,172 @@ async fn test_connection(onion_endpoint: String, tor_proxy: String) -> Result { - info!("Connection test successful"); - Ok("Connection successful! The onion endpoint is reachable.".to_string()) - } + // Stage 1: SOCKS5 connect (15s budget — Tor circuit setup is sometimes slow). + let connect = Socks5Stream::connect(tor_proxy_addr, onion_endpoint.as_str()); + let mut stream = match tokio::time::timeout(Duration::from_secs(15), connect).await { + Ok(Ok(s)) => s, Ok(Err(e)) => { - error!("Connection test failed: {}", e); - if e.to_string().contains("Connection refused") { - Err("Connection refused: The onion service may not be running or the address is incorrect.".to_string()) + let s = e.to_string(); + // Distinguish "Tor not reachable" from "onion offline" so the + // user knows which knob to turn. + return Err(if s.contains("Connection refused") { + "Tor SOCKS proxy refused the connection. Is Tor running on this address?" + .to_string() + } else if s.contains("ttl expired") || s.contains("network unreachable") { + "Onion service unreachable (rendezvous failed). The .onion may be offline." + .to_string() } else { - Err(format!("Connection failed: {e}")) - } + format!("SOCKS5 connect failed: {s}") + }); } Err(_) => { - error!("Connection test timeout"); - Err( - "Connection timeout: Unable to reach the onion endpoint within 30 seconds." - .to_string(), - ) + return Err( + "Connection timeout: SOCKS5 connect didn't complete within 15s.".to_string(), + ); } + }; + + // Stage 2: minimal JSON-RPC handshake. We don't need to handle chunked + // encoding or other HTTP nuances — TorPC's daemon speaks + // Content-Length-framed responses to JSON-RPC POSTs. + let body = r#"{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}"#; + let req = format!( + "POST / HTTP/1.1\r\n\ + Host: {host}\r\n\ + User-Agent: torpc-proxy-gui/{ver}\r\n\ + Content-Type: application/json\r\n\ + Content-Length: {len}\r\n\ + Connection: close\r\n\ + \r\n\ + {body}", + host = onion_endpoint, + ver = env!("CARGO_PKG_VERSION"), + len = body.len(), + body = body + ); + + if let Err(e) = + tokio::time::timeout(Duration::from_secs(15), stream.write_all(req.as_bytes())).await + { + return Err(format!("Failed to send probe request (timeout: {e})")); + } + + let mut buf = Vec::with_capacity(2048); + let read_result = + tokio::time::timeout(Duration::from_secs(15), stream.read_to_end(&mut buf)).await; + match read_result { + Ok(Ok(_)) => {} + Ok(Err(e)) => return Err(format!("Probe read failed: {e}")), + Err(_) => return Err("Probe timed out waiting for a response.".to_string()), + } + + // Parse: status line + headers + body. Cheap manual split is enough + // for HTTP/1.1 with `Connection: close`. + let response = String::from_utf8_lossy(&buf); + let (head, _, payload) = match response.find("\r\n\r\n") { + Some(i) => { + let head = &response[..i]; + let payload = &response[i + 4..]; + (head, "\r\n\r\n", payload) + } + None => return Err("Onion endpoint returned a non-HTTP response.".to_string()), + }; + + let status = head.lines().next().unwrap_or(""); + if !(status.contains(" 2") || status.contains(" 3")) { + return Err(format!("Onion endpoint replied: {status}")); } + + if !(payload.contains("\"jsonrpc\"") && payload.contains("\"2.0\"")) { + return Err("Endpoint reachable but didn't return a JSON-RPC envelope. \ + This may not be a TorPC daemon." + .to_string()); + } + + Ok("Connection successful: reached a TorPC daemon and got a valid JSON-RPC reply.".to_string()) } -fn create_system_tray() -> SystemTray { - let start = CustomMenuItem::new("start".to_string(), "Start Proxy"); - let stop = CustomMenuItem::new("stop".to_string(), "Stop Proxy"); - let settings = CustomMenuItem::new("settings".to_string(), "Settings"); - let quit = CustomMenuItem::new("quit".to_string(), "Quit"); - - let tray_menu = SystemTrayMenu::new() - .add_item(start) - .add_item(stop) - .add_native_item(SystemTrayMenuItem::Separator) - .add_item(settings) - .add_native_item(SystemTrayMenuItem::Separator) - .add_item(quit); - - SystemTray::new().with_menu(tray_menu) +// ----------------------------------------------------------------------------- +// Tray icon construction (Tauri 2.x) +// +// In Tauri 1.x the tray was a top-level builder method. In 2.x we build it +// from inside `setup` because we need an `AppHandle` to construct menu +// items and attach event handlers. +// ----------------------------------------------------------------------------- + +fn build_tray(app: &tauri::AppHandle) -> tauri::Result<()> { + let start = MenuItem::with_id(app, "start", "Start Proxy", true, None::<&str>)?; + let stop = MenuItem::with_id(app, "stop", "Stop Proxy", true, None::<&str>)?; + let settings = MenuItem::with_id(app, "settings", "Settings", true, None::<&str>)?; + let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; + let sep1 = PredefinedMenuItem::separator(app)?; + let sep2 = PredefinedMenuItem::separator(app)?; + + let menu = Menu::with_items(app, &[&start, &stop, &sep1, &settings, &sep2, &quit])?; + + TrayIconBuilder::with_id("main") + .menu(&menu) + .show_menu_on_left_click(true) + .icon(app.default_window_icon().cloned().unwrap()) + .icon_as_template(true) + .on_menu_event(|app, event| { + let id = event.id.as_ref(); + match id { + "start" => spawn_controller(app, |c| async move { + let controller = c.lock().await; + if let Err(e) = controller.start().await { + error!("Failed to start proxy from tray: {}", e); + } + }), + "stop" => spawn_controller(app, |c| async move { + let controller = c.lock().await; + if let Err(e) = controller.stop().await { + error!("Failed to stop proxy from tray: {}", e); + } + }), + "settings" => { + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + let _ = window.unminimize(); + } + } + "quit" => { + spawn_controller(app, |c| async move { + let controller = c.lock().await; + let _ = controller.stop().await; + std::process::exit(0); + }); + } + _ => {} + } + }) + .build(app)?; + + Ok(()) +} + +/// Helper to run a closure that needs the `ProxyController` from app state. +/// Avoids the State extraction + lock dance being repeated in every menu +/// arm above. +fn spawn_controller(app: &tauri::AppHandle, f: F) +where + F: FnOnce(Arc>) -> Fut + Send + 'static, + Fut: std::future::Future + Send, +{ + let app = app.clone(); + tauri::async_runtime::spawn(async move { + let state: tauri::State = app.state(); + let controller = state.proxy_controller.clone(); + f(controller).await; + }); } fn main() { - // Initialize logging tracing_subscriber::fmt() .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() @@ -202,29 +353,18 @@ fn main() { ) .init(); - // The GUI is a trusted local client of the discovery API — opt it in by - // default so the in-app wallet flows work, while leaving the CLI/server - // user-controlled. The token is generated by the proxy at start time and - // persisted to ${XDG_RUNTIME_DIR:-/tmp}/torpc-discovery.token (mode 0600); - // the GUI reads that file and forwards it as `X-Torpc-Token` when - // querying the discovery endpoint from any embedded wallet view. + // The GUI is a trusted local client of the discovery API; opt it in. + // The token persists at `${XDG_RUNTIME_DIR:-/tmp}/torpc-discovery.token` + // (mode 0600). PR 3 will read it from there if/when we add an embedded + // wallet view that needs the discovery endpoint. if std::env::var_os("TORPC_DISCOVERY_ENABLE").is_none() { std::env::set_var("TORPC_DISCOVERY_ENABLE", "true"); } - // Load configuration from file or use defaults - let config = match load_config() { - Ok(config) => config, - Err(e) => { - error!("Failed to load configuration: {}", e); - info!("Using default configuration"); - ProxyConfig { - listen_addr: ([127, 0, 0, 1], 8545).into(), - tor_proxy: ([127, 0, 0, 1], 9050).into(), - onion_endpoint: "placeholder.onion:80".to_string(), - } - } - }; + let config = load_config().unwrap_or_else(|e| { + error!("Failed to load configuration: {}; using defaults", e); + default_config() + }); let proxy_controller = Arc::new(Mutex::new(ProxyController::new(config))); let app_state = AppState { @@ -243,65 +383,20 @@ fn main() { update_config, test_connection ]) - .system_tray(create_system_tray()) - .on_window_event(|event| { - if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() { - // Prevent the window from closing + .setup(|app| { + build_tray(app.handle())?; + Ok(()) + }) + .on_window_event(|window, event| { + // Caffeine semantics: pressing the close button hides the + // window into the tray, doesn't quit the app. Right-click the + // tray → Quit terminates. + if let tauri::WindowEvent::CloseRequested { api, .. } = event { api.prevent_close(); - - // Hide the window instead - let window = event.window(); let _ = window.hide(); - info!("Window hidden to system tray"); } }) - .on_system_tray_event(move |app, event| { - #[allow(clippy::single_match)] - match event { - SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { - "start" => { - let handle = app.app_handle(); - tauri::async_runtime::spawn(async move { - let state: tauri::State = handle.state(); - let controller = state.proxy_controller.lock().await; - if let Err(e) = controller.start().await { - error!("Failed to start proxy: {}", e); - } - }); - } - "stop" => { - let handle = app.app_handle(); - tauri::async_runtime::spawn(async move { - let state: tauri::State = handle.state(); - let controller = state.proxy_controller.lock().await; - if let Err(e) = controller.stop().await { - error!("Failed to stop proxy: {}", e); - } - }); - } - "settings" => { - if let Some(window) = app.get_window("main") { - // Show the window - let _ = window.show(); - let _ = window.set_focus(); - let _ = window.unminimize(); - } - } - "quit" => { - let handle = app.app_handle(); - tauri::async_runtime::spawn(async move { - let state: tauri::State = handle.state(); - let controller = state.proxy_controller.lock().await; - let _ = controller.stop().await; - std::process::exit(0); - }); - } - _ => {} - }, - _ => {} - } - }) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/torpc-proxy/torpc-proxy-gui/tauri.conf.json b/torpc-proxy/torpc-proxy-gui/tauri.conf.json index ac6e9b3..aaf3e6d 100644 --- a/torpc-proxy/torpc-proxy-gui/tauri.conf.json +++ b/torpc-proxy/torpc-proxy-gui/tauri.conf.json @@ -1,90 +1,60 @@ { + "$schema": "https://schema.tauri.app/config/2", + "productName": "ToRPC Proxy", + "version": "0.1.0", + "identifier": "com.torpc.proxy", "build": { - "beforeBuildCommand": "", - "beforeDevCommand": "", - "devPath": "ui", - "distDir": "ui", - "withGlobalTauri": true + "frontendDist": "ui" }, - "package": { - "productName": "ToRPC Proxy", - "version": "0.1.0" - }, - "tauri": { - "allowlist": { - "all": false, - "shell": { - "all": false, - "open": true - }, - "window": { - "all": false, - "close": true, - "hide": true, - "show": true, - "maximize": false, - "minimize": true, - "unmaximize": false, - "unminimize": false, - "setFocus": true - } - }, - "bundle": { - "active": true, - "category": "Utility", - "copyright": "ToRPC Contributors", - "deb": { - "depends": [] - }, - "externalBin": [], - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "identifier": "com.torpc.proxy", - "longDescription": "A system tray application for managing ToRPC proxy connections through Tor", - "macOS": { - "entitlements": null, - "exceptionDomain": "", - "frameworks": [], - "providerShortName": null, - "signingIdentity": null - }, - "resources": [], - "shortDescription": "ToRPC Proxy Manager", - "targets": "all", - "windows": { - "certificateThumbprint": null, - "digestAlgorithm": "sha256", - "timestampUrl": "" - } - }, - "security": { - "csp": "default-src 'self'; connect-src 'self' http://localhost:8081 ws://localhost:* wss://localhost:*; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" - }, - "systemTray": { - "iconPath": "icons/icon.png", - "iconAsTemplate": true - }, - "updater": { - "active": false - }, + "app": { + "withGlobalTauri": true, "windows": [ { - "fullscreen": false, - "height": 700, - "resizable": true, + "label": "main", "title": "ToRPC Proxy Settings", "width": 600, - "visible": true, - "center": true, + "height": 700, "minWidth": 450, "minHeight": 500, + "resizable": true, + "fullscreen": false, + "center": true, + "visible": true, "maximizable": true } - ] + ], + "security": { + "csp": "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost" + }, + "trayIcon": { + "id": "main", + "iconPath": "icons/icon.png", + "iconAsTemplate": true + } + }, + "bundle": { + "active": true, + "category": "Utility", + "copyright": "ToRPC Contributors", + "shortDescription": "ToRPC Proxy Manager", + "longDescription": "A system tray application for managing ToRPC proxy connections through Tor", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "linux": { + "deb": { + "depends": [] + } + }, + "macOS": { + "frameworks": [], + "providerShortName": null, + "signingIdentity": null + }, + "targets": "all" } -} \ No newline at end of file +} diff --git a/torpc-proxy/torpc-proxy-gui/ui/app.js b/torpc-proxy/torpc-proxy-gui/ui/app.js index cf510dc..10bdaef 100644 --- a/torpc-proxy/torpc-proxy-gui/ui/app.js +++ b/torpc-proxy/torpc-proxy-gui/ui/app.js @@ -1,18 +1,21 @@ -// Check if Tauri API is available +// Tauri 2.x global API entry points (enabled by `app.withGlobalTauri: true` +// in tauri.conf.json). The 1.x layout (`window.__TAURI__.tauri.invoke`, +// `window.__TAURI__.window.appWindow`) was reorganized; `core` holds +// `invoke`. The window handle is fetched on-demand by the (currently +// nonexistent) callers that need it; the OS close-button is what hides +// the window into the tray today. if (!window.__TAURI__) { - console.error('Tauri API not available! Make sure you are running this in a Tauri window.'); + console.error('Tauri API not available! Make sure you are running this in a Tauri desktop app.'); alert('Error: This application must be run as a Tauri desktop app.'); } -const { invoke } = window.__TAURI__.tauri; -const { appWindow } = window.__TAURI__.window; +const { invoke } = window.__TAURI__.core; // DOM elements const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); const configForm = document.getElementById('configForm'); -const closeBtn = document.getElementById('closeBtn'); -const message = document.getElementById('message'); +const toastContainer = document.getElementById('toastContainer'); const onionEndpointInput = document.getElementById('onionEndpoint'); const listenPortInput = document.getElementById('listenPort'); const torProxyInput = document.getElementById('torProxy'); @@ -20,56 +23,72 @@ const startBtn = document.getElementById('startBtn'); const stopBtn = document.getElementById('stopBtn'); const proxyInfo = document.getElementById('proxyInfo'); const proxyUrl = document.getElementById('proxyUrl'); -const testBtn = document.getElementById('testBtn'); const walletRpcUrl = document.getElementById('walletRpcUrl'); -// Update status display +// Update status display. +// +// `status` is now structured (per the serde-tagged enum on the Rust side): +// { "state": "Running" } / { "state": "Error", "message": "..." } +// Pre-PR-1 the GUI did `status.includes('Running')` against +// `format!("{:?}")` output — fragile, fragile, fragile. Now we pattern- +// match on `status.state`. async function updateStatus() { try { const status = await invoke('get_status'); const config = await invoke('get_config'); - - // Remove all status classes + statusDot.classList.remove('running', 'stopped', 'starting', 'stopping'); - - if (status.includes('Running')) { - statusDot.classList.add('running'); - statusText.textContent = 'Proxy is running'; - startBtn.style.display = 'none'; - stopBtn.style.display = 'block'; - proxyInfo.style.display = 'block'; - - // Update proxy URL with actual port - const port = config.listen_addr.split(':').pop(); - const url = `http://localhost:${port}`; - proxyUrl.textContent = url; - walletRpcUrl.textContent = url; - } else if (status.includes('Stopped')) { - statusDot.classList.add('stopped'); - statusText.textContent = 'Proxy is stopped'; - startBtn.style.display = 'block'; - stopBtn.style.display = 'none'; - proxyInfo.style.display = 'none'; - } else if (status.includes('Starting')) { - statusDot.classList.add('starting'); - statusText.textContent = 'Starting proxy...'; - startBtn.style.display = 'none'; - stopBtn.style.display = 'none'; - proxyInfo.style.display = 'none'; - } else if (status.includes('Stopping')) { - statusDot.classList.add('stopping'); - statusText.textContent = 'Stopping proxy...'; - startBtn.style.display = 'none'; - stopBtn.style.display = 'none'; - proxyInfo.style.display = 'none'; - } else if (status.includes('Error')) { - statusDot.classList.add('stopped'); - const errorMatch = status.match(/Error\(["'](.+?)["']\)/); - const errorMsg = errorMatch ? errorMatch[1] : 'Unknown error'; - statusText.textContent = `Error: ${errorMsg}`; - startBtn.style.display = 'block'; - stopBtn.style.display = 'none'; - proxyInfo.style.display = 'none'; + + switch (status.state) { + case 'Running': { + statusDot.classList.add('running'); + statusText.textContent = 'Proxy is running'; + startBtn.style.display = 'none'; + stopBtn.style.display = 'block'; + proxyInfo.style.display = 'block'; + const port = config.listen_addr.split(':').pop(); + const url = `http://localhost:${port}`; + proxyUrl.textContent = url; + walletRpcUrl.textContent = url; + break; + } + case 'Stopped': { + statusDot.classList.add('stopped'); + statusText.textContent = 'Proxy is stopped'; + startBtn.style.display = 'block'; + stopBtn.style.display = 'none'; + proxyInfo.style.display = 'none'; + break; + } + case 'Starting': { + statusDot.classList.add('starting'); + statusText.textContent = 'Starting proxy...'; + startBtn.style.display = 'none'; + stopBtn.style.display = 'none'; + proxyInfo.style.display = 'none'; + break; + } + case 'Stopping': { + statusDot.classList.add('stopping'); + statusText.textContent = 'Stopping proxy...'; + startBtn.style.display = 'none'; + stopBtn.style.display = 'none'; + proxyInfo.style.display = 'none'; + break; + } + case 'Error': { + statusDot.classList.add('stopped'); + statusText.textContent = `Error: ${status.message ?? 'Unknown error'}`; + startBtn.style.display = 'block'; + stopBtn.style.display = 'none'; + proxyInfo.style.display = 'none'; + break; + } + default: { + console.warn('Unknown ProxyStatus state:', status); + statusText.textContent = 'Unknown'; + statusDot.classList.add('stopped'); + } } } catch (error) { console.error('Failed to get status:', error); @@ -78,222 +97,296 @@ async function updateStatus() { } } -// Load current configuration async function loadConfig() { try { const config = await invoke('get_config'); - - // Parse listen address + const listenPort = config.listen_addr.split(':').pop(); listenPortInput.value = listenPort; - - // Parse tor proxy address + const torProxyParts = config.tor_proxy.split(':'); if (torProxyParts.length >= 2) { const torProxyPort = torProxyParts[torProxyParts.length - 1]; const torProxyHost = torProxyParts.slice(0, -1).join(':'); torProxyInput.value = `${torProxyHost}:${torProxyPort}`; } - - // Set onion endpoint + + // Empty string is the new default — let the HTML `placeholder` + // attr suggest the format rather than seeding a misleading + // "placeholder.onion:80" the proxy will then chase. onionEndpointInput.value = config.onion_endpoint || ''; } catch (error) { console.error('Failed to load config:', error); - showMessage('Failed to load configuration', 'error'); + showToast('Failed to load configuration', 'error'); } } -// Save configuration +// Tor v3 onion: 56-char base32 (a-z, 2-7) + ".onion", optional ":port". +// Pre-fix this used `.includes('.onion')`, which accepted "example.onion" +// and any other string containing those eight characters. The proxy then +// happily started its TCP listener (status went green) but every wallet +// request failed at the SOCKS5 layer with "invalid address format" — a +// confusing first-run experience for new operators. +const ONION_REGEX = /^[a-z2-7]{56}\.onion(:\d{1,5})?$/i; + async function saveConfig(event) { event.preventDefault(); - - const onionEndpoint = onionEndpointInput.value.trim(); - const listenPort = parseInt(listenPortInput.value); + + const rawOnion = onionEndpointInput.value.trim(); + const listenPort = parseInt(listenPortInput.value, 10); const torProxy = torProxyInput.value.trim(); - - // Validate inputs - if (!onionEndpoint) { - showMessage('Onion endpoint is required', 'error'); + + if (!rawOnion) { + showToast('Onion endpoint is required', 'error'); return; } - - if (!onionEndpoint.includes('.onion')) { - showMessage('Invalid onion endpoint format', 'error'); + + if (!ONION_REGEX.test(rawOnion)) { + showToast( + 'Invalid onion endpoint. Expected 56 base32 characters (a-z, 2-7) ' + + 'followed by ".onion" and an optional ":port" (e.g. ' + + 'pxglb4naobvtpmnnvmsqmqgmfougct7en7xfqdevao6nrkmgmgrzopid.onion:80).', + 'error', + { duration: 8000 } // longer because the message is dense + ); return; } - - // Parse tor proxy address + + // Auto-append :80 if no port specified — Tor's default for HTTP-over-onion. + // tokio_socks rejects address-without-port at SOCKS5 connect time, so we + // can't rely on the proxy to deal with this for us. + const onionEndpoint = rawOnion.includes(':') ? rawOnion : `${rawOnion}:80`; + const torProxyParts = torProxy.split(':'); if (torProxyParts.length < 2) { - showMessage('Invalid Tor proxy format', 'error'); + showToast('Invalid Tor proxy format', 'error'); return; } - - const torProxyPort = parseInt(torProxyParts[torProxyParts.length - 1]); + const torProxyPort = parseInt(torProxyParts[torProxyParts.length - 1], 10); const torProxyHost = torProxyParts.slice(0, -1).join(':') || torProxyParts[0]; - - // Create config object + const config = { listen_addr: `127.0.0.1:${listenPort}`, tor_proxy: `${torProxyHost}:${torProxyPort}`, onion_endpoint: onionEndpoint }; - + + // Save persists + applies the new config to the controller. It does NOT + // start the proxy. The user clicks "Start Proxy" explicitly so the + // "Running" status reflects an intentional action rather than a save + // side-effect — and so they can run Test Connection first if they want + // to verify the endpoint is reachable before going live. try { await invoke('update_config', { config }); - showMessage('Configuration saved successfully', 'success'); - - // Get current status - const status = await invoke('get_status'); - - // If proxy is not running, offer to start it - if (!status.includes('Running')) { - showMessage('Configuration saved. Starting proxy...', 'success'); - try { - await invoke('start_proxy'); - showMessage('Proxy started successfully!', 'success'); - } catch (startError) { - showMessage('Configuration saved but failed to start proxy: ' + startError, 'error'); - } - } else { - showMessage('Configuration updated and proxy restarted', 'success'); - } - - setTimeout(() => { - hideMessage(); - }, 3000); + showToast( + 'Configuration saved. Click "Test Connection" to verify, then "Start Proxy" to begin.', + 'success', + { duration: 6000 } + ); } catch (error) { console.error('Failed to save config:', error); - showMessage('Failed to save configuration: ' + error, 'error'); + showToast('Failed to save configuration: ' + error, 'error'); } } -// Show message -function showMessage(text, type) { - message.textContent = text; - message.className = `message ${type}`; +// ----------------------------------------------------------------------- +// Toasts +// +// Routine feedback (save success, validation errors, test results, +// start/stop) goes to a transient floating notification at the top-right. +// `showToast(text, type, { duration })` returns `{ dismiss }` so callers +// can pop a "in progress…" toast with `duration: 0` and dismiss it +// explicitly when the operation completes. +// ----------------------------------------------------------------------- + +const TOAST_ICON = { success: '✓', error: '✕', info: 'ℹ' }; +const DEFAULT_TOAST_DURATION_MS = 4000; +const TOAST_LEAVE_ANIMATION_MS = 220; // matches `.toast` transition timing + +function showToast(text, type = 'info', { duration = DEFAULT_TOAST_DURATION_MS } = {}) { + const toast = document.createElement('div'); + toast.className = `toast toast-${type}`; + toast.setAttribute('role', type === 'error' ? 'alert' : 'status'); + + const icon = document.createElement('span'); + icon.className = 'toast-icon'; + icon.setAttribute('aria-hidden', 'true'); + icon.textContent = TOAST_ICON[type] ?? 'ℹ'; + + const body = document.createElement('span'); + body.className = 'toast-body'; + body.textContent = text; + + toast.append(icon, body); + toastContainer.appendChild(toast); + + // Force the entry transition by toggling the visible class on the next + // animation frame — without this delay the browser may collapse the + // initial styles + class change into a single frame. + requestAnimationFrame(() => toast.classList.add('toast-visible')); + + let dismissed = false; + const dismiss = () => { + if (dismissed) return; + dismissed = true; + toast.classList.remove('toast-visible'); + toast.classList.add('toast-leaving'); + setTimeout(() => toast.remove(), TOAST_LEAVE_ANIMATION_MS); + }; + + let dismissTimer; + if (duration > 0) { + dismissTimer = setTimeout(dismiss, duration); + } + + toast.addEventListener('click', () => { + if (dismissTimer) clearTimeout(dismissTimer); + dismiss(); + }); + + return { dismiss }; } -// Hide message -function hideMessage() { - message.className = 'message'; - message.textContent = ''; +// Error-modal helpers. Reserved for failures the user MUST acknowledge — +// the inline `.message` banner is easy to miss at the bottom of the form, +// so verification failures and other "your proxy is not running because +// X" errors get a dim-screen modal with a one-time shake animation. +const errorModal = document.getElementById('errorModal'); +const errorModalTitle = document.getElementById('errorModalTitle'); +const errorModalBody = document.getElementById('errorModalBody'); +const errorModalClose = document.getElementById('errorModalClose'); + +function showErrorModal(title, body) { + errorModalTitle.textContent = title; + errorModalBody.textContent = body; + errorModal.hidden = false; + // Re-trigger the shake animation if the modal was already showing. + // (Strictly: removeProperty + reflow + re-add. Cheap.) + const card = errorModal.querySelector('.modal-card'); + if (card) { + card.style.animation = 'none'; + // Force reflow so the next assignment restarts the keyframes. + // eslint-disable-next-line no-unused-expressions + void card.offsetWidth; + card.style.animation = ''; + } + errorModalClose.focus(); +} + +function hideErrorModal() { + errorModal.hidden = true; } -// Start proxy +errorModalClose.addEventListener('click', hideErrorModal); + +// Click outside the card → dismiss. (We intentionally don't dismiss on a +// click *inside* the card so the user doesn't lose the message by accident +// while reading it.) +errorModal.addEventListener('click', (event) => { + if (event.target === errorModal) hideErrorModal(); +}); + +// Esc key → dismiss. Standard accessibility expectation for modal dialogs. +document.addEventListener('keydown', (event) => { + if (event.key === 'Escape' && !errorModal.hidden) { + hideErrorModal(); + } +}); + +// Pre-flight verify before actually flipping the proxy to Running. +// +// Without this, "Start Proxy" used to mean "bind a TCP listener", not "the +// onion is reachable and speaks JSON-RPC". The proxy would happily go +// green on a non-existent .onion (or a real-looking one that's offline), +// and the failure would only surface when the wallet sent its first +// request. That's a confusing first-run. +// +// Verification runs the same probe as the Test Connection button: +// SOCKS5 to the configured Tor proxy, then a `web3_clientVersion` +// JSON-RPC over the tunnel. The listener only comes up if both pass. async function startProxy() { - console.log('Start proxy button clicked'); + const restoreButton = () => { + startBtn.disabled = false; + startBtn.textContent = 'Start Proxy'; + }; try { - // Check if onion endpoint is configured const config = await invoke('get_config'); - console.log('Current config:', config); - if (!config.onion_endpoint || config.onion_endpoint.trim() === '') { - showMessage('Please configure the onion endpoint first', 'error'); + showToast('Please configure the onion endpoint first', 'error'); + return; + } + + startBtn.disabled = true; + startBtn.textContent = 'Verifying…'; + const verifyingToast = showToast( + 'Verifying connection to the onion endpoint (this can take up to 30 seconds)…', + 'info', + { duration: 0 } // sticks until we dismiss it explicitly + ); + + try { + await invoke('test_connection', { + onionEndpoint: config.onion_endpoint, + torProxy: config.tor_proxy + }); + } catch (testError) { + // Verification failure is must-acknowledge — surface in the + // modal, not a corner toast. + verifyingToast.dismiss(); + showErrorModal('Cannot start proxy', String(testError)); + restoreButton(); return; } - - showMessage('Starting proxy...', 'success'); - console.log('Invoking start_proxy command...'); + + verifyingToast.dismiss(); + startBtn.textContent = 'Starting…'; + const startingToast = showToast('Verification passed. Starting proxy…', 'info', { duration: 0 }); await invoke('start_proxy'); - console.log('start_proxy command completed'); - - // Force status update + await updateStatus(); - hideMessage(); + startingToast.dismiss(); + showToast('Proxy is running.', 'success'); + restoreButton(); } catch (error) { console.error('Failed to start proxy:', error); - showMessage('Failed to start proxy: ' + error, 'error'); + showToast('Failed to start proxy: ' + error, 'error'); + restoreButton(); } } -// Stop proxy async function stopProxy() { + const stoppingToast = showToast('Stopping proxy…', 'info', { duration: 0 }); try { - showMessage('Stopping proxy...', 'success'); await invoke('stop_proxy'); - hideMessage(); + stoppingToast.dismiss(); + showToast('Proxy stopped.', 'success'); } catch (error) { console.error('Failed to stop proxy:', error); - showMessage('Failed to stop proxy: ' + error, 'error'); + stoppingToast.dismiss(); + showToast('Failed to stop proxy: ' + error, 'error'); } } -// Close window -closeBtn.addEventListener('click', async () => { - try { - // Since we're now handling close events in Rust to hide the window, - // we can simply close the window and it will be hidden instead - await appWindow.close(); - } catch (error) { - console.error('Error closing window:', error); - // Fallback: try to hide the window directly - try { - await appWindow.hide(); - } catch (hideError) { - console.error('Error hiding window:', hideError); - } - } -}); +// The standalone "Test Connection" button was removed: Start Proxy now +// runs the same probe automatically and surfaces failures via the modal. +// Test/close handlers + the `testConnection` function are gone — the +// `test_connection` Rust command is still alive and called by startProxy. -// Form submission configForm.addEventListener('submit', saveConfig); - -// Test connection -async function testConnection() { - console.log('Test connection button clicked'); - const onionEndpoint = onionEndpointInput.value.trim(); - const torProxy = torProxyInput.value.trim(); - - console.log('Testing connection to:', onionEndpoint, 'via', torProxy); - - if (!onionEndpoint) { - showMessage('Please enter an onion endpoint', 'error'); - return; - } - - // Disable button during test - testBtn.disabled = true; - testBtn.textContent = 'Testing...'; - showMessage('Testing connection to onion endpoint (this may take up to 30 seconds)...', 'success'); - - try { - console.log('Invoking test_connection command...'); - const result = await invoke('test_connection', { - onionEndpoint: onionEndpoint, - torProxy: torProxy - }); - console.log('Test result:', result); - showMessage(result, 'success'); - } catch (error) { - console.error('Test connection error:', error); - showMessage(error, 'error'); - } finally { - testBtn.disabled = false; - testBtn.textContent = 'Test Connection'; - } -} - -// Start/Stop button handlers startBtn.addEventListener('click', startProxy); stopBtn.addEventListener('click', stopProxy); -testBtn.addEventListener('click', testConnection); -// Initialize document.addEventListener('DOMContentLoaded', async () => { - console.log('DOM loaded, initializing ToRPC Proxy GUI...'); - console.log('Tauri API available:', !!window.__TAURI__); - try { await loadConfig(); await updateStatus(); - - // Update status periodically + + // Poll status every 2s. Cheap (it's a local Tauri IPC call against + // an Arc>); refines fast enough that the user sees state + // changes promptly. setInterval(updateStatus, 2000); - - console.log('GUI initialization complete'); } catch (error) { console.error('Failed to initialize GUI:', error); - showMessage('Failed to initialize: ' + error, 'error'); + showToast('Failed to initialize: ' + error, 'error'); } -}); \ No newline at end of file +}); diff --git a/torpc-proxy/torpc-proxy-gui/ui/index.html b/torpc-proxy/torpc-proxy-gui/ui/index.html index 4509f32..b3542ef 100644 --- a/torpc-proxy/torpc-proxy-gui/ui/index.html +++ b/torpc-proxy/torpc-proxy-gui/ui/index.html @@ -29,23 +29,34 @@

Proxy Status

+ +
- - The .onion address of your ToRPC server + v3 onion: 56 base32 chars (a-z, 2-7) + .onion, optional :port (default 80). Save persists; click Start Proxy to actually run.
@@ -74,14 +85,42 @@

Proxy Status

Tor SOCKS5 proxy address
-
- - - -
+
-
+ + + +
+ + + diff --git a/torpc-proxy/torpc-proxy-gui/ui/style.css b/torpc-proxy/torpc-proxy-gui/ui/style.css index 967d86b..926bd9c 100644 --- a/torpc-proxy/torpc-proxy-gui/ui/style.css +++ b/torpc-proxy/torpc-proxy-gui/ui/style.css @@ -513,4 +513,191 @@ small { form { padding: 20px; } -} \ No newline at end of file +} +/* ----------------------------------------------------------------------- + Error modal + ----------------------------------------------------------------------- + Used for failures the user must explicitly acknowledge — most notably, + the Start Proxy pre-flight verification failure. The inline `.message` + banner sits at the bottom of the form and is easy to miss; this modal + dims the rest of the UI, slides in from above, and shakes once on + appearance to draw the eye. Close on backdrop click, the X button, + or the Esc key (handled in JS). +*/ + +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(8, 8, 18, 0.72); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + animation: modalFadeIn 0.18s ease-out; +} + +.modal-overlay[hidden] { + display: none; +} + +.modal-card { + background: linear-gradient(180deg, #1a1a2e 0%, #2a1a3e 100%); + border: 1px solid rgba(239, 68, 68, 0.35); + border-radius: 12px; + padding: 28px 32px; + max-width: 440px; + width: 90%; + box-shadow: + 0 24px 64px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(255, 255, 255, 0.04) inset, + 0 0 32px rgba(239, 68, 68, 0.18); + animation: modalShake 0.45s cubic-bezier(.36,.07,.19,.97); +} + +.modal-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 16px; +} + +.modal-icon { + font-size: 30px; + line-height: 1; + /* Subtle pulse so the eye lands on the warning glyph first. */ + animation: iconPulse 1.6s ease-in-out infinite; +} + +.modal-card h3 { + font-size: 20px; + font-weight: 600; + color: var(--danger); + margin: 0; +} + +.modal-body { + font-size: 15px; + line-height: 1.55; + color: var(--text-primary); + margin-bottom: 22px; + word-break: break-word; +} + +.modal-close { + width: 100%; + background: var(--danger); + border: none; +} + +.modal-close:hover { + background: #dc2626; +} + +@keyframes modalFadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes modalShake { + 0%, 100% { transform: translateX(0); } + 10% { transform: translateX(-8px); } + 20% { transform: translateX(8px); } + 30% { transform: translateX(-6px); } + 40% { transform: translateX(6px); } + 50% { transform: translateX(-4px); } + 60% { transform: translateX(4px); } + 70% { transform: translateX(-2px); } + 80% { transform: translateX(2px); } + 90% { transform: translateX(0); } +} + +@keyframes iconPulse { + 0%, 100% { transform: scale(1); opacity: 1; } + 50% { transform: scale(1.1); opacity: 0.85; } +} + +/* ----------------------------------------------------------------------- + Toasts + ----------------------------------------------------------------------- + Top-right floating notifications for routine feedback. Auto-dismiss + for transient messages; persistent (`duration: 0`) for in-progress + operations that the caller dismisses explicitly when done. + + Stacking: toasts append to `.toast-container`, which is a flex column + with a gap. New toasts slide in from the right; older toasts shift down + smoothly via the parent's flex layout. +*/ + +.toast-container { + position: fixed; + top: 20px; + right: 20px; + display: flex; + flex-direction: column; + gap: 10px; + z-index: 1100; + pointer-events: none; /* container is transparent to clicks */ + max-width: 420px; + width: calc(100% - 40px); +} + +.toast { + pointer-events: auto; + display: flex; + align-items: flex-start; + gap: 12px; + padding: 14px 16px; + background: linear-gradient(180deg, #1a1a2e 0%, #251a35 100%); + border-left: 4px solid var(--text-muted); + border-radius: 8px; + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45), + 0 0 0 1px rgba(255, 255, 255, 0.04) inset; + color: var(--text-primary); + font-size: 14px; + line-height: 1.5; + transform: translateX(110%); + opacity: 0; + transition: transform 0.22s cubic-bezier(.22,.61,.36,1), + opacity 0.22s ease; + cursor: pointer; + word-break: break-word; +} + +.toast.toast-visible { + transform: translateX(0); + opacity: 1; +} + +.toast.toast-leaving { + transform: translateX(110%); + opacity: 0; +} + +.toast-icon { + flex: 0 0 auto; + font-size: 18px; + line-height: 1.2; + margin-top: 1px; +} + +.toast-body { + flex: 1 1 auto; +} + +/* Type variants — left border + icon color shift, otherwise consistent. */ +.toast-success { + border-left-color: var(--success); +} +.toast-success .toast-icon { color: var(--success); } + +.toast-error { + border-left-color: var(--danger); +} +.toast-error .toast-icon { color: var(--danger); } + +.toast-info { + border-left-color: var(--eth-blue); +} +.toast-info .toast-icon { color: var(--eth-blue); } diff --git a/torpc-proxy/torpc-proxy.example.toml b/torpc-proxy/torpc-proxy.example.toml index 9ab1de7..8a1516d 100644 --- a/torpc-proxy/torpc-proxy.example.toml +++ b/torpc-proxy/torpc-proxy.example.toml @@ -1,16 +1,23 @@ # ToRPC Proxy Configuration Example -# Copy this file to torpc-proxy.toml and modify as needed +# +# Copy this file to torpc-proxy.toml in the working directory, or to +# `dirs::config_dir() / torpc-proxy / config.toml` (e.g. +# ~/Library/Application Support/torpc-proxy/config.toml on macOS, +# ~/.config/torpc-proxy/config.toml on Linux). The CLI looks at the +# user-config path first, then falls back to cwd. -# Port for wallet connections (default: 8545) -port = 9000 +# Port for wallet connections (default: 8545 — wallets expect this) +port = 8545 # Tor SOCKS5 proxy settings tor_proxy_host = "127.0.0.1" tor_proxy_port = 9050 # Your .onion RPC endpoint -# Replace with your actual onion address -onion_endpoint = "pxglb4naobvtpmnnvmsqmqgmfougct7en7xfqdevao6nrkmgmgrzopid.onion:80" +# Replace with the operator's actual onion address — leaving the example +# value here causes confusing failures (the proxy chases a non-existent +# hidden service and the wallet just sees timeouts). +onion_endpoint = "" # Logging level (trace, debug, info, warn, error) -log_level = "trace" +log_level = "info"