From d371e71466ff3101c5de4a4d54cc3151a47b6175 Mon Sep 17 00:00:00 2001 From: csd113 Date: Fri, 20 Mar 2026 11:41:25 -0700 Subject: [PATCH] replaced dependancy of system installed tor with arti --- .gitignore | 1 + CHANGELOG.md | 103 + Cargo.lock | 5796 ++++++++++++++++++++++++++++++++-- Cargo.toml | 35 +- README.md | 313 +- deny.toml | 78 +- docs/arti-migration-guide.md | 721 +++++ src/.DS_Store | Bin 8196 -> 8196 bytes src/config/defaults.rs | 18 +- src/console/dashboard.rs | 4 +- src/runtime/lifecycle.rs | 13 +- src/runtime/state.rs | 4 +- src/tor/mod.rs | 571 ++-- src/tor/torrc.rs | 77 - 14 files changed, 6862 insertions(+), 872 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 docs/arti-migration-guide.md delete mode 100644 src/tor/torrc.rs diff --git a/.gitignore b/.gitignore index ccc3ffc..1c15a38 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ target dev-check-strict.sh .DS_STORE clippy_reports +src/.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c2119f5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,103 @@ +# Changelog + +All notable changes to RustHost are documented here. +This project adheres to [Semantic Versioning](https://semver.org/). + +--- + +## [0.1.0] — Initial Release + +### HTTP Server + +- Custom HTTP/1.1 static file server built directly on `tokio::net::TcpListener` — no third-party HTTP framework dependency. +- Serves `GET` and `HEAD` requests; all other methods return `400 Bad Request`. +- Percent-decoding of URL paths (e.g. `%20` → space) before file resolution. +- Query string and fragment stripping before path resolution. +- Path traversal protection: every resolved path is verified to be a descendant of the site root via `std::fs::canonicalize`; any attempt to escape (e.g. `/../secret`) is rejected with `HTTP 403 Forbidden`. +- Request header size cap of 8 KiB; oversized requests are rejected immediately. +- `Content-Type`, `Content-Length`, and `Connection: close` headers on every response. +- Configurable index file (default: `index.html`) served for directory requests. +- Optional HTML directory listing for directory requests when no index file is found, with alphabetically sorted entries. +- Built-in "No site found" fallback page (HTTP 200) when the site directory is empty and directory listing is disabled, so the browser always shows a helpful message rather than a connection error. +- Placeholder `index.html` written on first run so the server is immediately functional out of the box. +- Automatic port fallback: if the configured port is in use, the server silently tries the next free port up to 10 times before giving up (configurable via `auto_port_fallback`). +- Configurable bind address; defaults to `127.0.0.1` (loopback only) with a logged warning when set to `0.0.0.0`. +- Per-connection Tokio tasks so concurrent requests never block each other. + +### MIME Types + +- Built-in extension-to-MIME mapping with no external dependency, covering: + - Text: `html`, `htm`, `css`, `js`, `mjs`, `txt`, `csv`, `xml`, `md` + - Data: `json`, `jsonld`, `pdf`, `wasm`, `zip` + - Images: `png`, `jpg`/`jpeg`, `gif`, `webp`, `svg`, `ico`, `bmp`, `avif` + - Fonts: `woff`, `woff2`, `ttf`, `otf` + - Audio: `mp3`, `ogg`, `wav` + - Video: `mp4`, `webm` + - Unknown extensions fall back to `application/octet-stream`. + +### Tor Onion Service (Arti — in-process) + +- Embedded Tor support via [Arti](https://gitlab.torproject.org/tpo/core/arti), the official Rust Tor implementation — no external `tor` binary or `torrc` file required. +- Bootstraps to the Tor network in a background Tokio task; never blocks the HTTP server or console. +- First run downloads approximately 2 MB of directory consensus data (approximately 30 seconds); subsequent runs reuse the cache and start in seconds. +- Stable `.onion` address across restarts: the service keypair is persisted to `rusthost-data/arti_state/`; deleting this directory rotates to a new address. +- Consensus cache stored in `rusthost-data/arti_cache/` for fast startup. +- Onion address encoded in-process using the v3 `.onion` spec (SHA3-256 checksum + base32) — no dependency on Arti's `DisplayRedacted` formatting. +- Each inbound Tor connection is bridged to the local HTTP server via `tokio::io::copy_bidirectional` in its own Tokio task. +- Tor subsystem can be disabled entirely with `[tor] enabled = false`; the dashboard onion section reflects this immediately. +- Graceful shutdown: the `TorClient` is dropped naturally when the Tokio runtime exits, closing all circuits cleanly — no explicit kill step needed. +- `.onion` address displayed in the dashboard and logged in a prominent banner once the service is active. + +### Interactive Terminal Dashboard + +- Full-screen raw-mode terminal UI built with [crossterm](https://github.com/crossterm-rs/crossterm); no external TUI framework. +- Three screens navigable with single-key bindings: + - **Dashboard** (default) — live status overview. + - **Log view** — last 40 log lines, toggled with `[L]`. + - **Help overlay** — key binding reference, toggled with `[H]`; any other key dismisses it. +- Dashboard sections: + - **Status** — local server state (RUNNING with bind address and port, or STARTING) and Tor state (DISABLED / STARTING / READY / FAILED with exit code). + - **Endpoints** — local `http://localhost:` URL and Tor `.onion` URL (or a dim status hint if Tor is not yet ready). + - **Site** — directory path, file count, and total size (auto-scaled to B / KB / MB / GB). + - **Activity** — total request count and error count (errors highlighted in red when non-zero). + - **Key bar** — persistent one-line reminder of available key bindings. +- Dashboard redraws at a configurable interval (default: 500 ms). +- Log view supports optional `HH:MM:SS` timestamp display, toggled via `show_timestamps` in config. +- Customisable instance name shown in the dashboard header (max 32 characters). +- Headless / non-interactive mode: set `[console] interactive = false` for systemd or piped deployments; the server prints a plain `http://…` line to stdout instead. +- Graceful terminal restore on fatal crash: raw mode is disabled and the cursor is shown even if the process exits unexpectedly. + +### Configuration + +- TOML configuration file (`rusthost-data/settings.toml`) with six sections: `[server]`, `[site]`, `[tor]`, `[logging]`, `[console]`, `[identity]`. +- Configuration validated at startup with clear, multi-error messages before any subsystem is started. +- Validated fields include port range, bind IP address format, index file name (no path separators), log level, console refresh rate minimum (100 ms), instance name length (1–32 chars), and absence of control characters in the name. +- Full default config written automatically on first run with inline comments explaining every option. +- Reloading site stats (file count and total size) without restart via `[R]` in the dashboard. + +### Logging + +- Custom `log::Log` implementation; all modules use the standard `log` facade macros (`log::info!`, `log::warn!`, etc.). +- Dual output: log file on disk (append mode, parent directories created automatically) and an in-memory ring buffer. +- Ring buffer holds the most recent 1 000 lines and feeds the console log view without any file I/O on each render tick. +- Log file path configurable relative to `rusthost-data/`; defaults to `logs/rusthost.log`. +- Configurable log level: `trace`, `debug`, `info`, `warn`, `error`. +- Timestamped entries in `[LEVEL] [HH:MM:SS] message` format. +- Logging can be disabled entirely (`[logging] enabled = false`) for minimal-overhead deployments. + +### Lifecycle and Startup + +- **First-run detection**: if `rusthost-data/settings.toml` does not exist, RustHost initialises the data directory (`site/`, `logs/`), writes defaults, drops a placeholder `index.html`, prints a short getting-started guide, and exits cleanly — no daemon started. +- **Normal run** startup sequence: load and validate config → initialise logging → build shared state → scan site directory → bind HTTP server → start Tor (if enabled) → start console → open browser (if configured) → enter event loop. +- Shutdown triggered by `[Q]` keypress or `SIGINT`/`SIGTERM` (via `ctrlc`); sends a watch-channel signal to the HTTP server and console, then waits 300 ms for in-flight connections before exiting. +- Optional browser launch at startup (`open_browser_on_start`); uses `open` (macOS), `explorer` (Windows), or `xdg-open` (Linux/other). +- All subsystems share state through an `Arc>`; hot-path request and error counters use separate `Arc` backed by atomics so the HTTP handler never acquires a lock per request. + +### Project and Build + +- Single binary; no installer, no runtime dependencies beyond the binary itself (Tor included via Arti). +- Data directory co-located with the binary at `./rusthost-data/`; entirely self-contained. +- Minimum supported Rust version: 1.86 (required by `arti-client 0.40`). +- Release profile: `opt-level = 3`, LTO enabled, debug symbols stripped. +- `cargo-deny` configuration (`deny.toml`) enforcing allowed SPDX licenses (MIT, Apache-2.0, Apache-2.0 WITH LLVM-exception, Zlib, Unicode-3.0) and advisory database checks; known transitive duplicate crates (`mio`, `windows-sys`) skipped with comments. +- Advisory `RUSTSEC-2023-0071` (RSA Marvin timing attack) acknowledged and suppressed with a documented rationale: the `rsa` crate is a transitive dependency of `arti-client` used exclusively for RSA *signature verification* on Tor directory consensus documents, not decryption; the attack's threat model does not apply. diff --git a/Cargo.lock b/Cargo.lock index 0d36736..bd9fe3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,88 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "amplify" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f7fb4ac7c881e54a8e7015e399b6112a2a5bc958b6c89ac510840ff20273b31" +dependencies = [ + "amplify_derive", + "amplify_num", + "ascii", + "getrandom 0.2.17", + "getrandom 0.3.4", + "wasm-bindgen", +] + +[[package]] +name = "amplify_derive" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a6309e6b8d89b36b9f959b7a8fa093583b94922a0f6438a24fb08936de4d428" +dependencies = [ + "amplify_syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "amplify_num" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99bcb75a2982047f733547042fc3968c0f460dfcf7d90b90dea3b2744580e9ad" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "amplify_syn" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7736fb8d473c0d83098b5bac44df6a561e20470375cd8bcae30516dc889fd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -11,18 +93,288 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arti-client" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89842cae6e3bda0fd128a5c66eb3392ed412065dc698c77d9fcc4b77e4159f2" +dependencies = [ + "async-trait", + "cfg-if", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "educe", + "fs-mistrust", + "futures", + "hostname-validator", + "humantime", + "humantime-serde", + "libc", + "once_cell", + "postage", + "rand 0.9.2", + "safelog", + "serde", + "thiserror 2.0.18", + "time", + "tor-async-utils", + "tor-basic-utils", + "tor-chanmgr", + "tor-circmgr", + "tor-config", + "tor-config-path", + "tor-dircommon", + "tor-dirmgr", + "tor-error", + "tor-guardmgr", + "tor-hsclient", + "tor-hscrypto", + "tor-hsservice", + "tor-keymgr", + "tor-linkspec", + "tor-llcrypto", + "tor-memquota", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-protover", + "tor-rtcompat", + "tracing", + "void", +] + +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-compression" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" +dependencies = [ + "compression-codecs", + "compression-core", + "futures-io", + "pin-project-lite", +] + +[[package]] +name = "async-native-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" +dependencies = [ + "futures-util", + "native-tls", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async_executors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a982d2f86de6137cc05c9db9a915a19886c97911f9790d04f174cede74be01a5" +dependencies = [ + "blanket", + "futures-core", + "futures-task", + "futures-util", + "pin-project", + "rustc_version", + "tokio", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blanket" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "block2" version = "0.6.2" @@ -32,18 +384,59 @@ dependencies = [ "objc2", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "caret" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beae2cb9f60bc3f21effaaf9c64e51f6627edd54eedc9199ba07f519ef2a2101" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.57" @@ -51,6 +444,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -75,492 +470,4831 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] [[package]] -name = "crossterm" -version = "0.27.0" +name = "ciborium-io" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "ciborium-io", + "half", ] [[package]] -name = "crossterm_winapi" -version = "0.9.1" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "winapi", + "crypto-common", + "inout", + "zeroize", ] [[package]] -name = "ctrlc" -version = "3.5.2" +name = "clap" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ - "dispatch2", - "nix", - "windows-sys 0.61.2", + "clap_builder", ] [[package]] -name = "dispatch2" -version = "0.3.1" +name = "clap_builder" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "bitflags", - "block2", - "libc", - "objc2", + "anstyle", + "clap_lex", ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "clap_lex" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] -name = "errno" -version = "0.3.14" +name = "coarsetime" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "e58eb270476aa4fc7843849f8a35063e8743b4dbcdf6dd0f8ea0886980c204c2" dependencies = [ "libc", - "windows-sys 0.61.2", + "wasix", + "wasm-bindgen", ] [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "compression-codecs" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" +dependencies = [ + "compression-core", + "flate2", + "liblzma", + "zstd", + "zstd-safe", +] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "compression-core" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie-factory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.13.0", + "num-traits", + "oorandom", + "page_size", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-cycles-per-byte" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5396de42a52e9e5d8f67ef0702dae30451f310a9ba1c3094dcf228f0be0e54bc" +dependencies = [ + "cfg-if", + "criterion", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools 0.13.0", +] + +[[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-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.11.0", + "crossterm_winapi", + "libc", + "mio 0.8.11", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctrlc" +version = "3.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" +dependencies = [ + "dispatch2", + "nix", + "windows-sys 0.61.2", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "cookie-factory", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive-deftly" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284db66a66f03c3dafbe17360d959eb76b83f77cfe191677e2a7899c0da291f3" +dependencies = [ + "derive-deftly-macros", + "heck", +] + +[[package]] +name = "derive-deftly-macros" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caef6056a5788d05d173cdc3c562ac28ae093828f851f69378b74e4e3d578e41" +dependencies = [ + "heck", + "indexmap 2.13.0", + "itertools 0.14.0", + "proc-macro-crate", + "proc-macro2", + "quote", + "sha3", + "strum", + "syn 2.0.117", + "void", +] + +[[package]] +name = "derive_builder_core_fork_arti" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c1b715c79be6328caa9a5e1a387a196ea503740f0722ec3dd8f67a9e72314d" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_fork_arti" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eae24d595f4d0ecc90a9a5a6d11c2bd8dafe2375ec4a1ec63250e5ade7d228" +dependencies = [ + "derive_builder_macro_fork_arti", +] + +[[package]] +name = "derive_builder_macro_fork_arti" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69887769a2489cd946bf782eb2b1bb2cb7bc88551440c94a765d4f040c08ebf3" +dependencies = [ + "derive_builder_core_fork_arti", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +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 = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.0", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "merlin", + "rand_core 0.6.4", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "educe" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-ordinalize" +version = "3.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "enumset" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic 0.6.1", + "serde", + "toml 0.8.23", + "uncased", + "version_check", +] + +[[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 = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fluid-let" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749cff877dc1af878a0b31a41dd221a753634401ea0ef2f87b62d3171522485a" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[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", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-mistrust" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189ebb6d350de8d03181999fa9ebe8a021c5ab041004388f29e4dd2c52dc88a2" +dependencies = [ + "derive_builder_fork_arti", + "dirs", + "libc", + "pwd-grp", + "serde", + "thiserror 2.0.18", + "walkdir", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fslock-arti-fork" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21bd626aaab7b904b20bef6d9e06298914a0c8d9fb8b010483766b2e532791" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fslock-guard" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f62cb7d296f7d1fabdce7291281d9f0147b06a6e79afae05e1230eab667d85" +dependencies = [ + "fslock-arti-fork", + "thiserror 2.0.18", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "growable-bloom-filter" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d174ccb4ba660d431329e7f0797870d0a4281e36353ec4b4a3c5eab6c2cfb6f1" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "xxhash-rust", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "hashlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname-validator" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "inotify" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +dependencies = [ + "bitflags 2.11.0", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "inventory" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227" +dependencies = [ + "rustversion", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k12" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dc5fdb62af2f520116927304f15d25b3c2667b4817b90efdc045194c912c54" +dependencies = [ + "digest", + "sha3", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "liblzma" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899" +dependencies = [ + "liblzma-sys", +] + +[[package]] +name = "liblzma-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "bitflags 2.11.0", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4103cffefa72eb8428cb6b47d6627161e51c2739fc5e3b734584157bc642a" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonany" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b8866ec53810a9a4b3d434a29801e78c707430a9ae11c2db4b8b62bb9675a0" + +[[package]] +name = "notify" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" +dependencies = [ + "bitflags 2.11.0", + "inotify", + "kqueue", + "libc", + "log", + "mio 1.1.1", + "notify-types", + "walkdir", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oneshot-fused-workaround" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17b52d0e4a06a4c7eb8d2943c0015fa628cf4ccc409429cebc0f5bed6d33a82" +dependencies = [ + "futures", +] + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "openssl" +version = "0.10.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +dependencies = [ + "memchr", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core 0.6.4", + "sha2", +] + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +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 = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "postage" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3fb618632874fb76937c2361a7f22afd393c982a2165595407edc75b06d3c1" +dependencies = [ + "atomic 0.5.3", + "crossbeam-queue", + "futures", + "parking_lot", + "pin-project", + "static_assertions", + "thiserror 1.0.69", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "priority-queue" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93980406f12d9f8140ed5abe7155acb10bb1e69ea55c88960b9c2f117445ef96" +dependencies = [ + "equivalent", + "indexmap 2.13.0", + "serde", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.5+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pwd-grp" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e2023f41b5fcb7c30eb5300a5733edfaa9e0e0d502d51b586f65633fd39e40c" +dependencies = [ + "derive-deftly", + "libc", + "paste", + "thiserror 2.0.18", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_jitter" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16df48f071248e67b8fc5e866d9448d45c08ad8b672baaaf796e2f15e606ff0" +dependencies = [ + "libc", + "rand_core 0.9.5", + "winapi", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rdrand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "retry-error" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c322ea521636c5a3f13685a6266055b2dda7e54e2be35214d7c2a5d0672a5db" +dependencies = [ + "humantime", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rsqlite-vfs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" +dependencies = [ + "hashbrown 0.16.1", + "thiserror 2.0.18", +] + +[[package]] +name = "rusqlite" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c93dd1c9683b438c392c492109cb702b8090b2bfc8fed6f6e4eb4523f17af3" +dependencies = [ + "bitflags 2.11.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", + "time", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusthost" +version = "0.1.0" +dependencies = [ + "arti-client", + "chrono", + "crossterm", + "ctrlc", + "data-encoding", + "futures", + "log", + "serde", + "sha3", + "tokio", + "toml 0.8.23", + "tor-cell", + "tor-hsservice", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "safelog" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8949ab2810bf603caef654634e5b4cedcbc05c120342a177cf8aaa122ef4bb76" +dependencies = [ + "derive_more", + "educe", + "either", + "fluid-let", + "thiserror 2.0.18", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sanitize-filename" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" +dependencies = [ + "regex", +] + +[[package]] +name = "saturating-time" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63583a1dd0647d1484228529ab4ecaa874048d2956f117362aa5f5826456230" + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_ignored" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shellexpand" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" +dependencies = [ + "bstr", + "dirs", + "os_str_bytes", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio 0.8.11", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "serde", + "version_check", +] + +[[package]] +name = "slotmap-careful" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed92816c1fbb29891a525b92d5fa95757c9dee47044f76c8e06ceb1e052a8d64" +dependencies = [ + "paste", + "serde", + "slotmap", + "thiserror 2.0.18", + "void", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", "wasm-bindgen", - "windows-core", ] [[package]] -name = "iana-time-zone-haiku" +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "cipher", + "ssh-encoding", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2", +] + +[[package]] +name = "ssh-key" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" +dependencies = [ + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core 0.6.4", + "rsa", + "sec1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sysinfo" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "js-sys", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio 1.1.1", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +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.0.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 1.0.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.0", +] + +[[package]] +name = "toml_parser" +version = "1.0.10+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" +dependencies = [ + "winnow 1.0.0", +] + +[[package]] +name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.0.7+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d" + +[[package]] +name = "tor-async-utils" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "895c61a46909134501c6815eceeb66c9c80fc494ee89429821b0f05ccf34b4f5" dependencies = [ - "cc", + "derive-deftly", + "educe", + "futures", + "oneshot-fused-workaround", + "pin-project", + "postage", + "thiserror 2.0.18", + "void", ] [[package]] -name = "indexmap" -version = "2.13.0" +name = "tor-basic-utils" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "fac6e4d7e131b7d69bc85558383cd4ac61e46b4dd0d4ed51632f28fac98cac0c" dependencies = [ - "equivalent", - "hashbrown", + "derive_more", + "hex", + "itertools 0.14.0", + "libc", + "paste", + "rand 0.9.2", + "rand_chacha 0.9.0", + "serde", + "slab", + "smallvec", + "thiserror 2.0.18", + "weak-table", ] [[package]] -name = "js-sys" -version = "0.3.91" +name = "tor-bytes" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "64454947258e49f238a5f06a06250a0c54598a1c7409898b5c79505e6a99e7af" +dependencies = [ + "bytes", + "derive-deftly", + "digest", + "educe", + "getrandom 0.4.2", + "safelog", + "thiserror 2.0.18", + "tor-error", + "tor-llcrypto", + "zeroize", +] + +[[package]] +name = "tor-cell" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab0c79bc92a957e85959cf397a2d8f9c8294c35fa4f65247a9393b20ac95551" +dependencies = [ + "amplify", + "bitflags 2.11.0", + "bytes", + "caret", + "derive-deftly", + "derive_more", + "educe", + "itertools 0.14.0", + "paste", + "rand 0.9.2", + "smallvec", + "thiserror 2.0.18", + "tor-basic-utils", + "tor-bytes", + "tor-cert", + "tor-error", + "tor-hscrypto", + "tor-linkspec", + "tor-llcrypto", + "tor-memquota", + "tor-protover", + "tor-units", + "void", +] + +[[package]] +name = "tor-cert" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debc911738298ee801fce4577c36a50c55295b0bb9c5519461b83cc486a1f86e" +dependencies = [ + "caret", + "derive_builder_fork_arti", + "derive_more", + "digest", + "thiserror 2.0.18", + "tor-bytes", + "tor-checkable", + "tor-error", + "tor-llcrypto", +] + +[[package]] +name = "tor-chanmgr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af5b7c2f1e16d1304b5185fcbc91ca5c8df991c21be00702f925f055573eea1" +dependencies = [ + "async-trait", + "caret", + "cfg-if", + "derive-deftly", + "derive_more", + "educe", + "futures", + "oneshot-fused-workaround", + "percent-encoding", + "postage", + "rand 0.9.2", + "safelog", + "serde", + "serde_with", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-cell", + "tor-config", + "tor-error", + "tor-keymgr", + "tor-linkspec", + "tor-llcrypto", + "tor-memquota", + "tor-netdir", + "tor-proto", + "tor-rtcompat", + "tor-socksproto", + "tor-units", + "tracing", + "url", + "void", +] + +[[package]] +name = "tor-checkable" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b13a5b50bb55037f2e81b25dde42f420d57c75154216b8ef989006cea3ebee" +dependencies = [ + "humantime", + "signature", + "thiserror 2.0.18", + "tor-llcrypto", +] + +[[package]] +name = "tor-circmgr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b878f3f7c6be0c7f130d90b347ada2e7c46519dfbdde8273eae2e5d1792caa87" dependencies = [ + "amplify", + "async-trait", + "cfg-if", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "downcast-rs", + "dyn-clone", + "educe", + "futures", + "humantime-serde", + "itertools 0.14.0", "once_cell", - "wasm-bindgen", + "oneshot-fused-workaround", + "pin-project", + "rand 0.9.2", + "retry-error", + "safelog", + "serde", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-cell", + "tor-chanmgr", + "tor-config", + "tor-dircommon", + "tor-error", + "tor-guardmgr", + "tor-linkspec", + "tor-memquota", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-protover", + "tor-relay-selection", + "tor-rtcompat", + "tor-units", + "tracing", + "void", + "weak-table", ] [[package]] -name = "libc" -version = "0.2.183" +name = "tor-config" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "3cbc74a00ab15bb986e3747c6969e40a58a63065d6f99077e7ee2f4657bb8b03" +dependencies = [ + "amplify", + "cfg-if", + "derive-deftly", + "derive_builder_fork_arti", + "educe", + "either", + "figment", + "fs-mistrust", + "futures", + "humantime-serde", + "itertools 0.14.0", + "notify", + "paste", + "postage", + "regex", + "serde", + "serde-value", + "serde_ignored", + "strum", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "tor-basic-utils", + "tor-error", + "tor-rtcompat", + "tracing", + "void", +] [[package]] -name = "lock_api" -version = "0.4.14" +name = "tor-config-path" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "3005ab7b9a26a7271e5adf3dfb4ae18c09a943e32aeccc4f6d1c53a60de74b8d" +dependencies = [ + "directories", + "serde", + "shellexpand", + "thiserror 2.0.18", + "tor-error", + "tor-general-addr", +] + +[[package]] +name = "tor-consdiff" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bfa2b7b71c72830f61c48da4bb3e13191e0c0e1404b9c5168c795e4f5feb4a8" +dependencies = [ + "digest", + "hex", + "thiserror 2.0.18", + "tor-llcrypto", +] + +[[package]] +name = "tor-dirclient" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccd6fac844ac77c33ccdfcb56bf23ff40ebbb821ea708be79a481ec30e8c39c" +dependencies = [ + "async-compression", + "base64ct", + "derive_more", + "futures", + "hex", + "http", + "httparse", + "httpdate", + "itertools 0.14.0", + "memchr", + "thiserror 2.0.18", + "tor-circmgr", + "tor-error", + "tor-hscrypto", + "tor-linkspec", + "tor-llcrypto", + "tor-netdoc", + "tor-proto", + "tor-rtcompat", + "tracing", +] + +[[package]] +name = "tor-dircommon" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cf39a3c30321d145a4d60753ae7ef5bb58a66a00ac9e2bfc30bd823faf2a4" dependencies = [ + "base64ct", + "derive-deftly", + "getset", + "humantime", + "humantime-serde", + "serde", + "tor-basic-utils", + "tor-checkable", + "tor-config", + "tor-linkspec", + "tor-llcrypto", + "tor-netdoc", + "tracing", +] + +[[package]] +name = "tor-dirmgr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52919aa9dbb82a354c5b904bef82e91beb702b9f8ad14e6eac4237d6128bf67" +dependencies = [ + "async-trait", + "base64ct", + "derive_builder_fork_arti", + "derive_more", + "digest", + "educe", + "event-listener", + "fs-mistrust", + "fslock", + "futures", + "hex", + "humantime", + "humantime-serde", + "itertools 0.14.0", + "memmap2", + "oneshot-fused-workaround", + "paste", + "postage", + "rand 0.9.2", + "rusqlite", + "safelog", "scopeguard", + "serde", + "serde_json", + "signature", + "static_assertions", + "strum", + "thiserror 2.0.18", + "time", + "tor-async-utils", + "tor-basic-utils", + "tor-checkable", + "tor-circmgr", + "tor-config", + "tor-consdiff", + "tor-dirclient", + "tor-dircommon", + "tor-error", + "tor-guardmgr", + "tor-llcrypto", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-protover", + "tor-rtcompat", + "tracing", ] [[package]] -name = "log" -version = "0.4.29" +name = "tor-error" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "595b005e6f571ac3890a34a00f361200aab781fd0218f2c528c86fc7af088df5" +dependencies = [ + "derive_more", + "futures", + "paste", + "retry-error", + "static_assertions", + "strum", + "thiserror 2.0.18", + "tracing", + "void", +] [[package]] -name = "memchr" -version = "2.8.0" +name = "tor-general-addr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727b8c8bc01c1587486055edab5c2cd0d5c960f5bb3fac796fc9911872b8b397" +dependencies = [ + "derive_more", + "thiserror 2.0.18", + "void", +] + +[[package]] +name = "tor-guardmgr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d337f465a477c0fb3b2faafa4654d70ff9df3590e57d22707591dddb4e4450c1" +dependencies = [ + "amplify", + "base64ct", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "dyn-clone", + "educe", + "futures", + "humantime", + "humantime-serde", + "itertools 0.14.0", + "num_enum", + "oneshot-fused-workaround", + "pin-project", + "postage", + "rand 0.9.2", + "safelog", + "serde", + "strum", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-config", + "tor-dircommon", + "tor-error", + "tor-linkspec", + "tor-llcrypto", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-relay-selection", + "tor-rtcompat", + "tor-units", + "tracing", +] + +[[package]] +name = "tor-hsclient" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c701ef4eccab73f23d619ef5650c886239d1215e6d4aa0c3dec6342072a8178" +dependencies = [ + "async-trait", + "derive-deftly", + "derive_more", + "educe", + "either", + "futures", + "itertools 0.14.0", + "oneshot-fused-workaround", + "postage", + "rand 0.9.2", + "retry-error", + "safelog", + "slotmap-careful", + "strum", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-bytes", + "tor-cell", + "tor-checkable", + "tor-circmgr", + "tor-config", + "tor-dirclient", + "tor-error", + "tor-hscrypto", + "tor-keymgr", + "tor-linkspec", + "tor-llcrypto", + "tor-memquota", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-protover", + "tor-rtcompat", + "tracing", +] + +[[package]] +name = "tor-hscrypto" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3693cd43f05cd01ac0aaa060dae5c5e53c4364f89e0d769e33cd629a2fd3118" +dependencies = [ + "cipher", + "data-encoding", + "derive-deftly", + "derive_more", + "digest", + "hex", + "humantime", + "itertools 0.14.0", + "paste", + "rand 0.9.2", + "safelog", + "serde", + "signature", + "subtle", + "thiserror 2.0.18", + "tor-basic-utils", + "tor-bytes", + "tor-error", + "tor-key-forge", + "tor-llcrypto", + "tor-memquota", + "tor-units", + "void", + "zeroize", +] + +[[package]] +name = "tor-hsservice" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2d6a533ffd01b6764bfa59526f12883d6025fd64fdc73e219033ec29936aa3" +dependencies = [ + "amplify", + "async-trait", + "base64ct", + "cfg-if", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "digest", + "educe", + "fs-mistrust", + "futures", + "growable-bloom-filter", + "hex", + "humantime", + "itertools 0.14.0", + "k12", + "once_cell", + "oneshot-fused-workaround", + "postage", + "rand 0.9.2", + "rand_core 0.9.5", + "retry-error", + "safelog", + "serde", + "serde_with", + "strum", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-bytes", + "tor-cell", + "tor-circmgr", + "tor-config", + "tor-config-path", + "tor-dirclient", + "tor-error", + "tor-hscrypto", + "tor-keymgr", + "tor-linkspec", + "tor-llcrypto", + "tor-log-ratelim", + "tor-netdir", + "tor-netdoc", + "tor-persist", + "tor-proto", + "tor-protover", + "tor-relay-selection", + "tor-rtcompat", + "tracing", + "void", +] + +[[package]] +name = "tor-key-forge" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ade9065ae49cfe2ab020ca9ca9f2b3c5c9b5fc0d8980fa681d8b3a0668e042f" +dependencies = [ + "derive-deftly", + "derive_more", + "downcast-rs", + "paste", + "rand 0.9.2", + "rsa", + "signature", + "ssh-key", + "thiserror 2.0.18", + "tor-bytes", + "tor-cert", + "tor-checkable", + "tor-error", + "tor-llcrypto", +] + +[[package]] +name = "tor-keymgr" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243c3163d376c4723cd67271fcd6e5d6b498a6865c6b98299640e1be01c38826" +dependencies = [ + "amplify", + "arrayvec", + "cfg-if", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "downcast-rs", + "dyn-clone", + "fs-mistrust", + "glob-match", + "humantime", + "inventory", + "itertools 0.14.0", + "rand 0.9.2", + "safelog", + "serde", + "signature", + "ssh-key", + "thiserror 2.0.18", + "tor-basic-utils", + "tor-bytes", + "tor-config", + "tor-config-path", + "tor-error", + "tor-hscrypto", + "tor-key-forge", + "tor-llcrypto", + "tor-persist", + "tracing", + "visibility", + "walkdir", + "zeroize", +] + +[[package]] +name = "tor-linkspec" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f1ea8786900d6fbe4c9f775d341b1ba01bbd1f750d89bd63be78b6b01e1836" +dependencies = [ + "base64ct", + "by_address", + "caret", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "hex", + "itertools 0.14.0", + "safelog", + "serde", + "serde_with", + "strum", + "thiserror 2.0.18", + "tor-basic-utils", + "tor-bytes", + "tor-config", + "tor-llcrypto", + "tor-memquota", + "tor-protover", +] + +[[package]] +name = "tor-llcrypto" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6989a1c6d06ffd6835e2917edaae4aeef544f8e5fdd68b54cc365f2af523de" +dependencies = [ + "aes", + "base64ct", + "ctr", + "curve25519-dalek", + "der-parser", + "derive-deftly", + "derive_more", + "digest", + "ed25519-dalek", + "educe", + "getrandom 0.4.2", + "hex", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_core 0.6.4", + "rand_core 0.9.5", + "rand_jitter", + "rdrand", + "rsa", + "safelog", + "serde", + "sha1", + "sha2", + "sha3", + "signature", + "subtle", + "thiserror 2.0.18", + "tor-error", + "tor-memquota-cost", + "visibility", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "tor-log-ratelim" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1cd642180923d12e3fab5996b4aa2189718da7f465df6eb196ce2b9c70e293" +dependencies = [ + "futures", + "humantime", + "thiserror 2.0.18", + "tor-error", + "tor-rtcompat", + "tracing", + "weak-table", +] + +[[package]] +name = "tor-memquota" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "599daea60fd3272eb72a795d1c593b45bbe15343cbc702340a81db124c06eed5" +dependencies = [ + "cfg-if", + "derive-deftly", + "derive_more", + "dyn-clone", + "educe", + "futures", + "itertools 0.14.0", + "paste", + "pin-project", + "serde", + "slotmap-careful", + "static_assertions", + "sysinfo", + "thiserror 2.0.18", + "tor-async-utils", + "tor-basic-utils", + "tor-config", + "tor-error", + "tor-log-ratelim", + "tor-memquota-cost", + "tor-rtcompat", + "tracing", + "void", +] [[package]] -name = "mio" -version = "0.8.11" +name = "tor-memquota-cost" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "dd92b07c0fc24e6d8166a5ff45e5b8654e68d89743c46d01889a16ab74c0b578" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", + "derive-deftly", + "itertools 0.14.0", + "paste", + "void", ] [[package]] -name = "mio" -version = "1.1.1" +name = "tor-netdir" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "41be8f47f521fc95206d2ba5facac8fb1a5b5b82169bd41ebeecdf46d1e77246" dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", + "async-trait", + "bitflags 2.11.0", + "derive_more", + "digest", + "futures", + "hex", + "humantime", + "itertools 0.14.0", + "num_enum", + "rand 0.9.2", + "serde", + "strum", + "thiserror 2.0.18", + "time", + "tor-basic-utils", + "tor-error", + "tor-hscrypto", + "tor-linkspec", + "tor-llcrypto", + "tor-netdoc", + "tor-protover", + "tor-units", + "tracing", + "typed-index-collections", ] [[package]] -name = "nix" -version = "0.31.2" +name = "tor-netdoc" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +checksum = "ea8bce73d2c78bd78a2a927336ca639cf6bd5d8ad092ebcd0b3fdeaa47dcc77e" dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", + "amplify", + "base64ct", + "cipher", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "digest", + "educe", + "enumset", + "hex", + "humantime", + "itertools 0.14.0", + "memchr", + "paste", + "phf", + "rand 0.9.2", + "saturating-time", + "serde", + "serde_with", + "signature", + "smallvec", + "strum", + "subtle", + "thiserror 2.0.18", + "time", + "tinystr", + "tor-basic-utils", + "tor-bytes", + "tor-cell", + "tor-cert", + "tor-checkable", + "tor-error", + "tor-hscrypto", + "tor-linkspec", + "tor-llcrypto", + "tor-protover", + "tor-units", + "void", + "zeroize", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "tor-persist" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "507ab4b6a3d59ed0df5804eeed66dcacde75e3be13d3694216cdfdb666bce625" dependencies = [ - "autocfg", + "amplify", + "derive-deftly", + "derive_more", + "filetime", + "fs-mistrust", + "fslock", + "fslock-guard", + "futures", + "itertools 0.14.0", + "oneshot-fused-workaround", + "paste", + "sanitize-filename", + "serde", + "serde_json", + "thiserror 2.0.18", + "time", + "tor-async-utils", + "tor-basic-utils", + "tor-error", + "tracing", + "void", ] [[package]] -name = "objc2" -version = "0.6.4" +name = "tor-proto" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "bbfc552d535d36539d5782bb02028590bc472d219e49da51a96810725e80ff56" dependencies = [ - "objc2-encode", + "amplify", + "async-trait", + "asynchronous-codec", + "bitvec", + "bytes", + "caret", + "cfg-if", + "cipher", + "coarsetime", + "criterion-cycles-per-byte", + "derive-deftly", + "derive_builder_fork_arti", + "derive_more", + "digest", + "educe", + "enum_dispatch", + "futures", + "futures-util", + "hkdf", + "hmac", + "itertools 0.14.0", + "nonany", + "oneshot-fused-workaround", + "pin-project", + "postage", + "rand 0.9.2", + "rand_core 0.9.5", + "safelog", + "slotmap-careful", + "smallvec", + "static_assertions", + "subtle", + "sync_wrapper", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tor-async-utils", + "tor-basic-utils", + "tor-bytes", + "tor-cell", + "tor-cert", + "tor-checkable", + "tor-config", + "tor-error", + "tor-hscrypto", + "tor-linkspec", + "tor-llcrypto", + "tor-log-ratelim", + "tor-memquota", + "tor-protover", + "tor-relay-crypto", + "tor-rtcompat", + "tor-rtmock", + "tor-units", + "tracing", + "typenum", + "visibility", + "void", + "zeroize", ] [[package]] -name = "objc2-encode" -version = "4.1.0" +name = "tor-protover" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +checksum = "aed88527d070c4b7ea4e55a36d2d56d0500e30ca66298b5264f047f7f2f89cfa" +dependencies = [ + "caret", + "paste", + "serde_with", + "thiserror 2.0.18", + "tor-basic-utils", + "tor-bytes", +] [[package]] -name = "once_cell" -version = "1.21.4" +name = "tor-relay-crypto" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "f7e57e9f71b22ae1df63dbccc8e428cb07feec0abd654735109fa563c10bbb90" +dependencies = [ + "derive-deftly", + "derive_more", + "humantime", + "tor-cert", + "tor-checkable", + "tor-error", + "tor-key-forge", + "tor-keymgr", + "tor-llcrypto", + "tor-persist", +] [[package]] -name = "parking_lot" -version = "0.12.5" +name = "tor-relay-selection" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "a372072ac9dea7d17e49693cc3f3ae77b3abf8125630516c9f2d622239b1920a" dependencies = [ - "lock_api", - "parking_lot_core", + "rand 0.9.2", + "serde", + "tor-basic-utils", + "tor-linkspec", + "tor-netdir", + "tor-netdoc", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "tor-rtcompat" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "14428b930e59003e801c0c32697c0aeb9b0495ad33ecbe8c6753bdb596233270" dependencies = [ + "async-native-tls", + "async-trait", + "async_executors", + "asynchronous-codec", "cfg-if", + "coarsetime", + "derive_more", + "dyn-clone", + "educe", + "futures", + "hex", "libc", - "redox_syscall", - "smallvec", - "windows-link", + "native-tls", + "paste", + "pin-project", + "socket2", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tor-error", + "tor-general-addr", + "tracing", + "void", + "zeroize", ] [[package]] -name = "pin-project-lite" -version = "0.2.17" +name = "tor-rtmock" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "d2da91a432cdaee8a93e0bb21b02f3e9c7667832ccbb4b54e00d9c1214638e70" +dependencies = [ + "amplify", + "assert_matches", + "async-trait", + "derive-deftly", + "derive_more", + "educe", + "futures", + "humantime", + "itertools 0.14.0", + "oneshot-fused-workaround", + "pin-project", + "priority-queue", + "slotmap-careful", + "strum", + "thiserror 2.0.18", + "tor-error", + "tor-general-addr", + "tor-rtcompat", + "tracing", + "tracing-test", + "void", +] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "tor-socksproto" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "adbc9115a2f506d9bb86ae4446f0ca70eb523dc2f5e900a33582e7c39decc23a" dependencies = [ - "unicode-ident", + "amplify", + "caret", + "derive-deftly", + "educe", + "safelog", + "subtle", + "thiserror 2.0.18", + "tor-bytes", + "tor-error", ] [[package]] -name = "quote" -version = "1.0.45" +name = "tor-units" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "da90e93b4b4aa4ec356ecbe9e19aced36fdd655e94ca459d1915120d873363f0" dependencies = [ - "proc-macro2", + "derive-deftly", + "derive_more", + "serde", + "thiserror 2.0.18", + "tor-memquota", ] [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "tracing" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "bitflags", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "rusthost" -version = "0.1.0" +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ - "chrono", - "crossterm", - "ctrlc", - "log", - "serde", - "tokio", - "toml", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "rustversion" -version = "1.0.22" +name = "tracing-core" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] [[package]] -name = "serde" -version = "1.0.228" +name = "tracing-subscriber" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ - "serde_core", - "serde_derive", + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] -name = "serde_core" -version = "1.0.228" +name = "tracing-test" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "19a4c448db514d4f24c5ddb9f73f2ee71bfb24c526cf0c570ba142d1119e0051" dependencies = [ - "serde_derive", + "tracing-core", + "tracing-subscriber", + "tracing-test-macro", ] [[package]] -name = "serde_derive" -version = "1.0.228" +name = "tracing-test-macro" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "ad06847b7afb65c7866a36664b75c40b895e318cea4f71299f013fb22965329d" dependencies = [ - "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] -name = "serde_spanned" -version = "0.6.9" +name = "typed-index-collections" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" dependencies = [ + "bincode", "serde", ] [[package]] -name = "shlex" -version = "1.3.0" +name = "typenum" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] -name = "signal-hook" -version = "0.3.18" +name = "uncased" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" dependencies = [ - "libc", - "signal-hook-registry", + "version_check", ] [[package]] -name = "signal-hook-mio" -version = "0.2.5" +name = "unicode-ident" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" -dependencies = [ - "libc", - "mio 0.8.11", - "signal-hook", -] +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "signal-hook-registry" -version = "1.4.8" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] -name = "smallvec" -version = "1.15.1" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "socket2" -version = "0.6.3" +name = "unty" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] -name = "syn" -version = "2.0.117" +name = "url" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "form_urlencoded", + "idna", + "percent-encoding", + "serde", ] [[package]] -name = "tokio" -version = "1.50.0" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" -dependencies = [ - "bytes", - "libc", - "mio 1.1.1", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "tokio-macros" -version = "2.6.1" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] -name = "toml" -version = "0.8.23" +name = "void" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] -name = "toml_datetime" -version = "0.6.11" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "serde", + "same-file", + "winapi-util", ] [[package]] -name = "toml_edit" -version = "0.22.27" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow", -] +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "toml_write" -version = "0.1.2" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "unicode-ident" -version = "1.0.24" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +name = "wasix" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "1757e0d1f8456693c7e5c6c629bdb54884e032aa0bb53c155f6a39f94440d332" +dependencies = [ + "wasi", +] [[package]] name = "wasm-bindgen" @@ -594,7 +5328,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -602,9 +5336,59 @@ dependencies = [ name = "wasm-bindgen-shared" version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", +] + +[[package]] +name = "weak-table" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ - "unicode-ident", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -623,12 +5407,56 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -637,9 +5465,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -650,7 +5489,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -661,22 +5500,56 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -685,7 +5558,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -694,7 +5567,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", ] [[package]] @@ -703,7 +5585,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -712,13 +5594,39 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -727,42 +5635,90 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" version = "0.7.15" @@ -771,3 +5727,285 @@ checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] + +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index ce7dba4..7e01afa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,19 +2,50 @@ name = "rusthost" version = "0.1.0" edition = "2021" -rust-version = "1.85" +# Bumped from 1.86 → 1.90 to match the highest MSRV in the transitive dep tree: +# arti-client 0.40 and most tor-* crates require 1.89 +# typed-index-collections 3.5 (via tor-netdir) requires 1.90 +rust-version = "1.90" description = "Single-binary, zero-setup static site hosting appliance with Tor support" license = "MIT" authors = [] [[bin]] -name = "rusthost" +name = "rusthost-cli" path = "src/main.rs" [dependencies] # Async runtime — drives the server, console, and all I/O tokio = { version = "1", features = ["full"] } +# ─── Arti (in-process Tor) ──────────────────────────────────────────────────── +# +# arti-client — the high-level Tor client API (bootstrap, launch onion service) +# tokio — use Tokio as the async runtime (default, required) +# native-tls — TLS backend for connecting to Tor relays (default) +# onion-service-service — enables hosting (serving) onion services +# +# tor-hsservice — lower-level onion service types: +# handle_rend_requests, OnionServiceConfigBuilder, StreamRequest +# +# futures — StreamExt trait for iterating over the stream of StreamRequests + +arti-client = { version = "0.40", features = [ + "tokio", + "native-tls", + "onion-service-service", +] } +tor-hsservice = { version = "0.40" } +# tor-cell: needed to construct the Connected message passed to StreamRequest::accept() +tor-cell = { version = "0.40" } +futures = "0.3" + +# Onion-address encoding (used by the tor module to format HsId → ${base32}.onion) +# sha3: provides SHA3-256 for the v3 address checksum +# data-encoding: provides RFC 4648 base32 (no-padding, uppercase/lowercase) +sha3 = "0.10" +data-encoding = "2" + # Configuration — TOML parsing and typed deserialization serde = { version = "1", features = ["derive"] } toml = "0.8" diff --git a/README.md b/README.md index 24e8f6f..fba9d64 100644 --- a/README.md +++ b/README.md @@ -1,199 +1,232 @@ -# RustHost +``` +██████╗ ██╗ ██╗███████╗████████╗██╗ ██╗ ██████╗ ███████╗████████╗ +██╔══██╗██║ ██║██╔════╝╚══██╔══╝██║ ██║██╔═══██╗██╔════╝╚══██╔══╝ +██████╔╝██║ ██║███████╗ ██║ ███████║██║ ██║███████╗ ██║ +██╔══██╗██║ ██║╚════██║ ██║ ██╔══██║██║ ██║╚════██║ ██║ +██║ ██║╚██████╔╝███████║ ██║ ██║ ██║╚██████╔╝███████║ ██║ +╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ +``` + +
-A single-binary, zero-setup static-site hosting appliance written in Rust. +**A self-contained static file server with first-class Tor onion service support — no binaries, no `torrc`, no compromise.** -Serve a local website on `localhost` **and** expose it as a `.onion` address -over the Tor network — no configuration, no external services, no fuss. +[![Rust](https://img.shields.io/badge/rust-1.86%2B-orange?style=flat-square&logo=rust)](https://www.rust-lang.org/) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE) +[![Tor: Arti](https://img.shields.io/badge/tor-arti%20in--process-7d4698?style=flat-square)](https://gitlab.torproject.org/tpo/core/arti) +[![Async: Tokio](https://img.shields.io/badge/async-tokio-49a?style=flat-square)](https://tokio.rs/) +[![Security: cargo-deny](https://img.shields.io/badge/security-cargo--deny-red?style=flat-square)](https://embarkstudios.github.io/cargo-deny/) + +
--- -## Quick start +## What is RustHost? -```sh -# 1. Download or build the binary -cargo build --release -cp target/release/rusthost . +RustHost is a single-binary static file server that brings your content to the clearnet **and** the Tor network simultaneously — with zero external dependencies. Tor is embedded directly into the process via [Arti](https://gitlab.torproject.org/tpo/core/arti), the official Rust Tor implementation. No `tor` daemon, no `torrc`, no system configuration required. -# 2. First run — creates ./data/ and writes default config -./rusthost +Drop the binary next to your site files, run it once, and you get: -# 3. Drop your site into the data directory -cp -r my-site/* data/site/ +- A local HTTP server ready for immediate use +- A stable `.onion` v3 address that survives restarts +- A live terminal dashboard showing you everything at a glance -# 4. Run again — local + onion live immediately -./rusthost +``` +┌─ RustHost ─────────────────────────────────────────────────────────┐ +│ │ +│ STATUS ● RUNNING 127.0.0.1:8080 │ +│ TOR ● READY │ +│ │ +│ ENDPOINTS http://localhost:8080 │ +│ abcdef1234567890abcdef1234567890abcdef12.onion │ +│ │ +│ SITE ./rusthost-data/site · 12 files · 4.2 MB │ +│ ACTIVITY 847 requests · 0 errors │ +│ │ +│ [L] Logs [R] Reload [H] Help [Q] Quit │ +└──────────────────────────────────────────────────────────────────────┘ ``` --- -## Requirements - -| Requirement | Notes | -|---|---| -| **Rust 1.75+** | For building from source | -| **Tor** | Only needed when `[tor] enabled = true` (the default). Install via your package manager: `apt install tor`, `brew install tor`, etc. RustHost detects if Tor is missing and warns you at launch. | - -RustHost itself has **no other runtime dependencies**. The binary is -self-contained; it generates all config files and directories automatically. +## Features + +### 🌐 HTTP Server +- Built directly on `tokio::net::TcpListener` — no HTTP framework dependency +- Handles `GET` and `HEAD` requests; concurrent connections via per-task Tokio workers +- Percent-decoded URL paths, query string & fragment stripping +- **Path traversal protection** — every path verified as a descendant of the site root via `canonicalize`; escapes rejected with `403 Forbidden` +- Configurable index file, optional HTML directory listings, and a built-in fallback page +- Automatic port selection if the configured port is busy (up to 10 attempts) +- Request header cap at 8 KiB; `Content-Type`, `Content-Length`, and `Connection: close` on every response + +### 🧅 Tor Onion Service *(fully working)* +- Embedded via [Arti](https://gitlab.torproject.org/tpo/core/arti) — the official Rust Tor client — in-process, no external daemon +- Bootstraps to the Tor network in the background; never blocks your server or dashboard +- **Stable address**: the v3 service keypair is persisted to `rusthost-data/arti_state/`. Delete the directory to rotate to a new address +- First run fetches ~2 MB of directory data (~30 s); subsequent starts reuse the cache and are up in seconds +- Onion address computed fully in-process using the v3 spec (SHA3-256 + base32) +- Each inbound Tor connection is bridged to the local HTTP listener via `tokio::io::copy_bidirectional` +- Can be disabled entirely with `[tor] enabled = false` + +### 🖥️ Interactive Terminal Dashboard +- Full-screen raw-mode TUI built with [crossterm](https://github.com/crossterm-rs/crossterm) — no TUI framework +- Three screens, all keyboard-navigable: + + | Key | Screen | + |-----|--------| + | *(default)* | **Dashboard** — live status, endpoints, site stats, request/error counters | + | `L` | **Log view** — last 40 log lines with optional timestamps | + | `H` | **Help overlay** — key binding reference | + | `R` | Reload site file count & size without restart | + | `Q` | Graceful shutdown | + +- Configurable refresh rate (default 500 ms); headless mode available for `systemd` / piped deployments + +### ⚙️ Configuration +- TOML file at `rusthost-data/settings.toml`, auto-generated with inline comments on first run +- Six sections: `[server]`, `[site]`, `[tor]`, `[logging]`, `[console]`, `[identity]` +- Startup validation with clear, multi-error messages — nothing starts until config is clean + +### 📝 Logging +- Custom `log::Log` implementation; dual output — append-mode log file + in-memory ring buffer (1 000 lines) +- Ring buffer feeds the dashboard log view with zero file I/O per render tick +- Configurable level (`trace` → `error`) and optional full disable for minimal-overhead deployments --- -## Directory layout +## Quick Start -After first run, RustHost creates the following structure next to the binary: +### 1. Build +```bash +git clone https://github.com/yourname/rusthost +cd rusthost +cargo build --release ``` -rusthost ← the binary -data/ - settings.toml ← full commented config (edit freely) - site/ ← drop your HTML / CSS / JS here - index.html ← placeholder, replace with your content - tor/ - torrc ← auto-generated on every run (do not edit) - data/ ← Tor's internal state (keys, routing cache) - hidden_service/ ← written by Tor: hostname + private_key - logs/ - rusthost.log ← append-only log file -``` - -> **Important:** `data/tor/hidden_service/` is created and owned by the `tor` -> process. Deleting it generates a new `.onion` address permanently. ---- +> **Minimum Rust version: 1.86** (required by `arti-client 0.40`) -## Configuration +### 2. First run — initialise your data directory -`data/settings.toml` is generated on first run with every field present and -documented. Edit it freely; press **R** in the dashboard to reload. +```bash +./target/release/rusthost +``` -### Key settings +On first run, RustHost detects that `rusthost-data/settings.toml` is missing, scaffolds the data directory, writes a default config and a placeholder `index.html`, prints a getting-started guide, and exits. Nothing is daemonised yet. -```toml -[tor] -# Master on/off switch — disable if you only need local serving -enabled = true +``` +rusthost-data/ +├── settings.toml ← your config (edit freely) +├── site/ +│ └── index.html ← placeholder, replace with your files +├── logs/ +│ └── rusthost.log +├── arti_cache/ ← Tor directory consensus (auto-managed) +└── arti_state/ ← your stable .onion keypair (back this up!) +``` -[server] -# Increment automatically if the port is busy -auto_port_fallback = true +### 3. Serve -[console] -# Set to false for headless / systemd use -interactive = true +```bash +./target/release/rusthost ``` ---- +The dashboard appears. Your site is live on `http://localhost:8080`. Tor bootstraps in the background — your `.onion` address appears in the **Endpoints** panel once ready (~30 s on first run). -## Dashboard +--- -``` -──────────────────────────────── - RustHost -──────────────────────────────── - -Status - Local Server : RUNNING (127.0.0.1:8080) - Tor : READY - -Endpoints - Local : http://localhost:8080 - Onion : http://abc123xyz456.onion - -Site - Directory : ./data/site - Files : 12 - Size : 1.4 MB - -Activity - Requests : 42 - Errors : 0 - -──────────────────────────────── -[H] Help [R] Reload [T] Restart Tor [O] Open [L] Logs [Q] Quit -──────────────────────────────── -``` +## Configuration Reference -### Key bindings +```toml +[server] +port = 8080 +bind = "127.0.0.1" # set "0.0.0.0" to expose on LAN (logs a warning) +index_file = "index.html" +directory_listing = false +auto_port_fallback = true -| Key | Action | -|---|---| -| `H` | Show key-binding help overlay | -| `R` | Rescan `./data/site/` and update file stats | -| `T` | Restart the Tor subprocess | -| `O` | Open local URL in system browser | -| `L` | Toggle log view | -| `Q` | Graceful shutdown | +[site] +root = "rusthost-data/site" ---- +[tor] +enabled = true # set false to skip Tor entirely -## Building +[logging] +enabled = true +level = "info" # trace | debug | info | warn | error +path = "logs/rusthost.log" -```sh -# Debug build -cargo build +[console] +interactive = true # false for systemd / piped deployments +refresh_ms = 500 # minimum 100 +show_timestamps = false +open_browser_on_start = false -# Optimised release build (with LTO + strip) -cargo build --release +[identity] +name = "RustHost" # 1–32 chars, shown in dashboard header ``` --- -## Headless / systemd - -Set `[console] interactive = false` in `settings.toml` to disable the -interactive dashboard. RustHost will print a single startup line and run -silently, suitable for use as a `systemd` service or in a container. - -Example `systemd` unit: +## Built-in MIME Types -```ini -[Unit] -Description=RustHost static site server -After=network.target +No external dependency. RustHost ships with a handwritten extension map covering: -[Service] -ExecStart=/opt/rusthost/rusthost -WorkingDirectory=/opt/rusthost -Restart=on-failure +| Category | Extensions | +|----------|-----------| +| Text | `html` `htm` `css` `js` `mjs` `txt` `csv` `xml` `md` | +| Data | `json` `jsonld` `pdf` `wasm` `zip` | +| Images | `png` `jpg/jpeg` `gif` `webp` `svg` `ico` `bmp` `avif` | +| Fonts | `woff` `woff2` `ttf` `otf` | +| Audio | `mp3` `ogg` `wav` | +| Video | `mp4` `webm` | -[Install] -WantedBy=multi-user.target -``` +Unknown extensions fall back to `application/octet-stream`. --- -## Tor not found? - -If you see this at launch: +## Architecture ``` - ⚠ Tor not detected. - `tor` was not found in your PATH. - Install Tor and restart, or set [tor] enabled = false. + ┌─────────────────────────────────────┐ + │ RustHost Process │ + │ │ + Browser ──────┤──► tokio TcpListener (HTTP) │ + │ │ │ + Tor Network ──┤──► Arti (in-process) ──► bridge ────►┤ + │ task │ + │ │ │ + │ Arc Arc │ + │ │ │ + │ crossterm TUI (raw mode) │ + └─────────────────────────────────────┘ ``` -Either install Tor for your platform: +All subsystems share state through `Arc>`. Hot-path request and error counters use a separate `Arc` backed by atomics — the HTTP handler **never acquires a lock per request**. -```sh -# Debian / Ubuntu -sudo apt install tor +Shutdown is coordinated via a `watch` channel: `[Q]`, `SIGINT`, or `SIGTERM` signals all subsystems simultaneously, waits 300 ms for in-flight connections, then exits. The Tor client is dropped naturally with the Tokio runtime — no explicit kill step needed. -# macOS -brew install tor +--- -# Arch -sudo pacman -S tor -``` +## Security -…or disable Tor entirely in `settings.toml`: - -```toml -[tor] -enabled = false -``` +| Concern | Mitigation | +|---------|-----------| +| Path traversal | `std::fs::canonicalize` + descendant check; returns `403` on escape | +| Header overflow | 8 KiB hard cap; oversized requests rejected immediately | +| Bind exposure | Defaults to loopback (`127.0.0.1`); warns loudly on `0.0.0.0` | +| License compliance | `cargo-deny` enforces SPDX allowlist at CI time | +| [RUSTSEC-2023-0071](https://rustsec.org/advisories/RUSTSEC-2023-0071) | Suppressed with rationale: the `rsa` crate is a transitive dep of `arti-client` used **only** for signature *verification* on Tor directory documents — the Marvin timing attack's threat model (decryption oracle) does not apply | --- ## License -MIT +MIT — see [LICENSE](LICENSE). + +--- + +
+Built with Rust 🦀 · Powered by Tokio · Tor via Arti +
diff --git a/deny.toml b/deny.toml index ac497c4..daa8e54 100644 --- a/deny.toml +++ b/deny.toml @@ -13,6 +13,24 @@ allow = [ "Apache-2.0 WITH LLVM-exception", "Zlib", "Unicode-3.0", + # BSD family — pulled in by cryptography crates in the Arti/dalek stack + # (curve25519-dalek, ed25519-dalek, x25519-dalek, subtle, coarsetime) + "BSD-2-Clause", + "BSD-3-Clause", + # ISC — pulled in by inotify, inotify-sys, rdrand (Linux file-watch / RNG) + "ISC", + # CC0-1.0 — pulled in by notify (file-system watcher used by arti-client) + "CC0-1.0", + # MPL-2.0 — pulled in by option-ext (dirs-sys dependency of arti-client) + "MPL-2.0", + # LGPL-3.0-or-later — pulled in by priority-queue (arti circuit scheduler) + # priority-queue is dual-licensed LGPL-3.0-or-later OR MPL-2.0; cargo-deny + # requires both sides of an OR expression to be in the allow list. + "LGPL-3.0-or-later", + # BSL-1.0 (Boost) — pulled in by xxhash-rust (arti hashing utilities) + "BSL-1.0", + # Unlicense — pulled in by async_executors (arti async runtime abstraction) + "Unlicense", ] confidence-threshold = 0.8 @@ -23,8 +41,42 @@ deny = [] skip = [ # crossterm 0.27 still pulls mio 0.8.x; tokio requires mio 1.x { name = "mio" }, - # Various crates in the tokio/crossterm tree pin different windows-sys generations + # Various crates in the tokio/crossterm/arti tree pin different windows-sys generations { name = "windows-sys" }, + # Arti 0.40 dependency tree spans multiple generations of these crates; + # none of the duplicates are under our direct control. + { name = "atomic" }, + { name = "bitflags" }, + { name = "darling" }, + { name = "darling_core" }, + { name = "darling_macro" }, + { name = "getrandom" }, + { name = "itertools" }, + { name = "r-efi" }, + { name = "rand" }, + { name = "rand_chacha" }, + { name = "rand_core" }, + { name = "serde_spanned" }, + { name = "strsim" }, + { name = "syn" }, + { name = "thiserror" }, + { name = "thiserror-impl" }, + { name = "toml" }, + { name = "toml_datetime" }, + { name = "toml_edit" }, + { name = "windows-core" }, + { name = "windows-link" }, + { name = "windows-result" }, + { name = "windows-strings" }, + { name = "windows-targets" }, + { name = "windows_aarch64_gnullvm" }, + { name = "windows_aarch64_msvc" }, + { name = "windows_i686_gnu" }, + { name = "windows_i686_msvc" }, + { name = "windows_x86_64_gnu" }, + { name = "windows_x86_64_gnullvm" }, + { name = "windows_x86_64_msvc" }, + { name = "winnow" }, ] # ─── Advisories ─────────────────────────────────────────────────────────────── @@ -32,6 +84,30 @@ skip = [ # Security advisory checks are now controlled via `[advisories]` alone. [advisories] db-urls = ["https://github.com/rustsec/advisory-db"] +ignore = [ + # rsa 0.9.x — Marvin attack: timing side-channel on decryption + # (RUSTSEC-2023-0071, https://rustsec.org/advisories/RUSTSEC-2023-0071). + # + # No patched release of the `rsa` crate exists. `rsa` is pulled in + # transitively by `arti-client` for parsing X.509 certificates in Tor + # directory consensus documents — it is used only for RSA *signature + # verification*, never for decryption. The Marvin attack requires an + # adversary to make thousands of adaptive chosen-ciphertext queries and + # measure decryption timing; that threat model does not apply here. + # + # Revisit when arti upgrades past rsa 0.9.x or a fixed version ships. + { id = "RUSTSEC-2023-0071", reason = "rsa used only for signature verification in arti-client, not decryption; no fixed version available" }, + + # bincode 2.0.1 — unmaintained (RUSTSEC-2025-0141). + # Pulled in transitively by typed-index-collections → tor-netdir → arti-client. + # Not a direct dependency; no action we can take until arti upgrades. + { id = "RUSTSEC-2025-0141", reason = "transitive dep via arti-client/tor-netdir; no direct upgrade path available" }, + + # paste 1.0.15 — unmaintained (RUSTSEC-2024-0436). + # Pulled in transitively by tor-rtcompat → arti-client. + # Not a direct dependency; no action we can take until arti upgrades. + { id = "RUSTSEC-2024-0436", reason = "transitive dep via arti-client/tor-rtcompat; no direct upgrade path available" }, +] # ─── Sources ────────────────────────────────────────────────────────────────── [sources] diff --git a/docs/arti-migration-guide.md b/docs/arti-migration-guide.md new file mode 100644 index 0000000..83ba213 --- /dev/null +++ b/docs/arti-migration-guide.md @@ -0,0 +1,721 @@ +# Migrating from C Tor Subprocess to Arti (In-Process Tor) + +This document describes exactly how a Rust project was migrated from +spawning the system C Tor binary as a subprocess to running Arti, the +official Tor Project Rust implementation, fully in-process. Use this as a +step-by-step reference for applying the same migration to other projects. + +> **Tested against:** `arti-client 0.40`, `tor-hsservice 0.40`, `tor-cell 0.40` +> on Rust 1.86 (macOS arm64 + x86, Linux x86_64). + +--- + +## Background: What the Old System Did + +The original approach (common in many Rust projects) worked like this: + +1. **Binary search** — scan a hardcoded list of filesystem paths plus `PATH` + for the `tor` executable at runtime. +2. **Directory setup** — create `tor_data/` and `tor_hidden_service/` with + `chmod 0700` (C Tor refuses to start if it doesn't own those dirs). +3. **torrc generation** — write a `torrc` file to disk with `SocksPort 0` + (disables the SOCKS proxy to avoid conflict with any system Tor daemon), + `DataDirectory`, `HiddenServiceDir`, and `HiddenServicePort`. +4. **Process spawn** — `Command::new(tor_bin).arg("-f").arg(&torrc_path).spawn()` +5. **stderr collection** — pipe stderr into a background thread for diagnostics. +6. **Panic hook** — register a panic hook to kill the child if the process crashes. +7. **Hostname polling** — spin a background thread checking for + `tor_hidden_service/hostname` every 500 ms for up to 120 seconds. +8. **Shutdown** — `child.kill()` + `child.wait()` in a `kill()` function called + during graceful shutdown. + +This required the user to have Tor installed (`brew install tor`, +`apt-get install tor`, etc.) and produced two runtime artifacts on disk: +`torrc` and `tor_hidden_service/hostname`. + +--- + +## Why Arti Replaces This Cleanly + +Arti is the Tor Project's own Rust rewrite of the C Tor client. As of the +2.x release series (February 2026), it supports onion service *hosting* +(not just connecting). Because it is a Rust crate, it compiles directly into +your binary — no external binary, no torrc, no hostname file polling. + +The `arti-client` crate provides a high-level async API. The `tor-hsservice` +crate provides the onion service types. Both are first-party from the Tor +Project and versioned together. + +--- + +## Step 1 — Cargo.toml Changes + +### MSRV + +Arti 0.40+ requires Rust **1.86**. If your project targets 1.85 or lower, +bump it: + +```toml +# Before +rust-version = "1.85" + +# After +rust-version = "1.86" +``` + +### Add dependencies + +Add these six entries to `[dependencies]`: + +```toml +# arti-client: high-level Tor client. Features needed for onion service hosting: +# tokio — Tokio async runtime backend (required) +# native-tls — TLS for connecting to Tor relays (required) +# onion-service-service — enables *hosting* onion services +arti-client = { version = "0.40", features = [ + "tokio", + "native-tls", + "onion-service-service", +] } + +# tor-hsservice: lower-level onion service types used directly: +# OnionServiceConfigBuilder, handle_rend_requests, HsId, StreamRequest +tor-hsservice = { version = "0.40" } + +# tor-cell: needed to construct the Connected message passed to +# StreamRequest::accept(Connected) — see the stream proxying section +tor-cell = { version = "0.40" } + +# futures: StreamExt::next() for iterating the stream of incoming connections +futures = "0.3" + +# sha3 + data-encoding: used to encode HsId → "${base32}.onion" manually. +# HsId does not implement std::fmt::Display in arti-client 0.40 — see the +# "Getting the onion address" section for the full explanation. +sha3 = "0.10" +data-encoding = "2" +``` + +### Remove nothing from existing deps + +`tokio`, `log`, `serde`, etc. are unchanged. No existing dep needs to be +removed. + +--- + +## Step 2 — Delete `src/tor/torrc.rs` + +If your project has a separate module for generating `torrc` files, delete it. +There is no torrc concept with Arti — configuration is built in Rust code. + +If it was declared as `mod torrc;` anywhere, remove that declaration too. + +--- + +## Step 3 — Rewrite `src/tor/mod.rs` + +This is the entire migration. Everything else in the project stays the same. + +### Imports + +```rust +// Old imports — remove all of these +use std::{ + path::{Path, PathBuf}, + process::{Command, Stdio}, + sync::{Arc, Mutex, OnceLock}, +}; + +// New imports +use std::path::PathBuf; + +use arti_client::config::TorClientConfigBuilder; +use arti_client::TorClient; +use futures::StreamExt; +use tokio::net::TcpStream; +use tor_cell::relaycell::msg::Connected; +use tor_hsservice::{config::OnionServiceConfigBuilder, handle_rend_requests, HsId, StreamRequest}; +``` + +Notes on the import changes: +- `TorClientConfig` is **not** imported — it is not used directly. The builder is accessed via `TorClientConfigBuilder` instead (see the config section below). +- `HsId` is imported from `tor_hsservice`, **not** from `arti_client`. In arti 0.40, the re-export in `arti_client` is gated behind `feature = "onion-service-client"` and `feature = "experimental-api"` — neither of which is enabled in this setup. `tor_hsservice::HsId` is the ungated path. + +--- + +### `init()` — public signature unchanged + +The public API surface stays identical so nothing that calls `tor::init()` +needs to change. The only internal difference is switching from +`std::thread::spawn` to `tokio::spawn`, since the work is now async: + +```rust +// Old +pub fn init(data_dir: PathBuf, bind_port: u16, state: SharedState) { + std::thread::spawn(move || { + run_sync(data_dir, bind_port, state); + }); +} + +// New +pub fn init(data_dir: PathBuf, bind_port: u16, state: SharedState) { + tokio::spawn(async move { + if let Err(e) = run(data_dir, bind_port, state.clone()).await { + log::error!("Tor: fatal error: {e}"); + set_status(&state, TorStatus::Failed(None)).await; + } + }); +} +``` + +--- + +### `kill()` — becomes a no-op + +```rust +// Old — had to kill and reap the subprocess +pub fn kill() { + if let Some(child) = TOR_CHILD.get() { + if let Ok(mut c) = child.lock() { + let _ = c.kill(); + let _ = c.wait(); + } + } +} + +// New — nothing to do; TorClient drops with the task +pub fn kill() {} +``` + +The call site in your shutdown sequence does not need to change. The +`TorClient` is owned by the `tokio::spawn` task. When the Tokio runtime +shuts down, the task is dropped, which drops `TorClient`, which closes all +circuits cleanly. + +--- + +### The `OnceLock>>` static — remove entirely + +```rust +// Old — remove this +static TOR_CHILD: OnceLock>> = OnceLock::new(); +``` + +There is no process handle to track. Delete it along with the panic hook +that referenced it. + +--- + +### Building `TorClientConfig` — the CfgPath pitfall + +> ⚠️ **This is the most common compile error when migrating.** + +The `StorageConfigBuilder` methods `.cache_dir()` and `.state_dir()` take +`Into`, and `CfgPath` does **not** implement `From`. If you +try to pass a `PathBuf` directly you get: + +``` +error[E0277]: the trait bound `CfgPath: From` is not satisfied +``` + +**Do not use** `.storage().cache_dir().state_dir()`. Instead use +`TorClientConfigBuilder::from_directories`, which takes `AsRef` and +handles the conversion internally. + +> ⚠️ **A second pitfall:** `from_directories` is an *associated function*, not +> a method — it cannot be chained off `.builder()`. Doing so produces: +> ``` +> error[E0599]: no method named `from_directories` found for struct `TorClientConfigBuilder` +> note: found the following associated functions; to be used as methods, +> functions must have a `self` parameter +> ``` + +```rust +// Wrong — does not compile (CfgPath conversion fails) +let config = { + let mut b = TorClientConfig::builder(); + b.storage() + .cache_dir(data_dir.join("arti_cache")) // ← E0277 + .state_dir(data_dir.join("arti_state")); // ← E0277 + b.build()? +}; + +// Wrong — also does not compile (from_directories has no `self`, cannot chain) +let config = TorClientConfig::builder() + .from_directories( // ← E0599 + data_dir.join("arti_state"), + data_dir.join("arti_cache"), + ) + .build()?; + +// Correct — call from_directories directly on TorClientConfigBuilder +let config = TorClientConfigBuilder::from_directories( + data_dir.join("arti_state"), + data_dir.join("arti_cache"), +) +.build()?; +``` + +Note the argument order is `(state_dir, cache_dir)` — state first, cache second. + +Two directories are created automatically on first run: +- `arti_state/` — service keypair. **Determines your `.onion` address.** + Keep it to preserve the address across restarts. Delete it to rotate. +- `arti_cache/` — consensus cache. Safe to delete; re-downloaded on next run. + +Without setting these paths explicitly, Arti defaults to platform-specific +user directories. Always set them explicitly so everything lives inside your +project's data directory. + +--- + +### Bootstrap + +```rust +// Old +let child = Command::new(tor_bin) + .arg("-f").arg(&torrc_path) + .stdout(Stdio::null()) + .stderr(Stdio::piped()) + .spawn(); + +// New +let tor_client = TorClient::create_bootstrapped(config).await?; +``` + +`create_bootstrapped` async-blocks until Tor has downloaded enough directory +information to open circuits. First run takes ~30 seconds (~2 MB download). +Subsequent runs complete in a few seconds using the cached consensus. + +The old stderr collection thread and panic hook are deleted entirely — there +is no subprocess stderr to collect and no child process to kill on panic. + +--- + +### Getting the onion address — Display is not implemented on HsId + +> ⚠️ **Three separate pitfalls here, not two.** + +**Pitfall 1:** `onion_name()` is deprecated. Use `onion_address()` instead. + +**Pitfall 2:** `HsId` does **not** implement `std::fmt::Display` in +`arti-client 0.40`. Neither `format!("{}", hsid)` nor `.to_string()` compile, +regardless of whether you got the `HsId` from `onion_name()` or +`onion_address()`: + +``` +error[E0599]: `HsId` doesn't implement `std::fmt::Display` +``` + +`HsId` implements `DisplayRedacted` from the `safelog` crate instead, which +intentionally opts out of `std::fmt::Display` to prevent accidental logging of +sensitive identifiers. `format!("{}", ...)` and `.to_string()` both require +`Display` — neither works. + +**Pitfall 3:** `HsId` in `arti_client` is gated behind two features +(`onion-service-client` and `experimental-api`). If you try +`arti_client::HsId` without enabling those features: + +``` +error[E0425]: cannot find type `HsId` in crate `arti_client` +note: found an item that was configured out +note: the item is gated behind the `onion-service-client` feature +``` + +Import `HsId` from `tor_hsservice` instead — it is ungated there. + +**The correct pattern** — encode the address manually from the raw key bytes: + +```rust +// Wrong — deprecated +let onion_name = onion_service.onion_name()?.to_string(); // ← deprecated + E0599 + +// Wrong — onion_address() returns HsId, which still has no Display in 0.40 +let onion_name = format!( + "{}", + onion_service.onion_address().ok_or("...")? // ← E0599 +); + +// Wrong — same problem, HsId::to_string() doesn't exist +let onion_name = onion_service.onion_address().ok_or("?")?.to_string(); // ← E0599 + +// Correct — encode the address ourselves using the v3 onion address spec +let hsid = onion_service + .onion_address() + .ok_or("Tor: onion address not yet available")?; +let onion_name = hsid_to_onion_address(hsid); +``` + +Where `hsid_to_onion_address` is: + +```rust +fn hsid_to_onion_address(hsid: HsId) -> String { + use sha3::{Digest, Sha3_256}; + + let pubkey: &[u8; 32] = hsid.as_ref(); // HsId: AsRef<[u8; 32]> is stable + let version: u8 = 3; + + // CHECKSUM = SHA3-256(".onion checksum" || PUBKEY || VERSION) truncated to 2 bytes + let mut hasher = Sha3_256::new(); + hasher.update(b".onion checksum"); + hasher.update(pubkey); + hasher.update([version]); + let hash = hasher.finalize(); + + // ADDRESS_BYTES = PUBKEY (32) || CHECKSUM (2) || VERSION (1) = 35 bytes + let mut address_bytes = [0u8; 35]; + address_bytes[..32].copy_from_slice(pubkey); + address_bytes[32..34].copy_from_slice(&hash[..2]); + address_bytes[34] = version; + + // RFC 4648 base32, no padding, lowercase → 56 characters + let encoded = data_encoding::BASE32_NOPAD + .encode(&address_bytes) + .to_ascii_lowercase(); + + format!("{}.onion", encoded) +} +``` + +This implements the [v3 onion address spec](https://spec.torproject.org/rend-spec/overview.html) +directly. `HsId: AsRef<[u8; 32]>` is stable across arti 0.40+, so it will +keep working regardless of whether `Display` is ever added to `HsId`. + +The address is available immediately when `launch_onion_service` returns — +no polling required. + +--- + +### Incoming connections — replacing `HiddenServicePort` and accepting streams + +> ⚠️ **`StreamRequest::accept()` requires a `Connected` argument.** + +In the old torrc, `HiddenServicePort 80 127.0.0.1:{port}` told C Tor to +forward incoming connections to your local server automatically. With Arti +you handle this yourself. + +**`handle_rend_requests`** takes the `Stream` from +`launch_onion_service`, auto-accepts each Tor rendezvous handshake, and +yields a `StreamRequest` for every fully-established inbound connection. + +**`stream_req.accept(Connected)`** sends a `RELAY_CONNECTED` cell back to +the Tor client (confirming the connection succeeded) and returns the +`DataStream` you can read and write. It requires a `Connected` argument — +calling it with no arguments fails to compile: + +``` +error[E0061]: this method takes 1 argument but 0 arguments were supplied + --> src/tor/mod.rs:194:37 + | + | let mut tor_stream = stream_req.accept().await?; + | ^^^^^^-- argument #1 of type + | `tor_cell::relaycell::msg::Connected` is missing +``` + +For hidden services, use `Connected::new_empty()`. This is correct because +you are the service — there is no exit IP to report to the client: + +```rust +// Wrong — missing argument +let mut tor_stream = stream_req.accept().await?; + +// Correct +let mut tor_stream = stream_req.accept(Connected::new_empty()).await?; +``` + +The full stream loop: + +```rust +let mut stream_requests = handle_rend_requests(rend_requests); + +while let Some(stream_req) = stream_requests.next().await { + let local_addr = format!("127.0.0.1:{bind_port}"); + tokio::spawn(async move { + if let Err(e) = proxy_stream(stream_req, &local_addr).await { + log::debug!("Tor: stream closed: {e}"); + } + }); +} +``` + +```rust +async fn proxy_stream( + stream_req: StreamRequest, + local_addr: &str, +) -> Result<(), Box> { + let mut tor_stream = stream_req.accept(Connected::new_empty()).await?; + let mut local = TcpStream::connect(local_addr).await?; + tokio::io::copy_bidirectional(&mut tor_stream, &mut local).await?; + Ok(()) +} +``` + +`DataStream` implements `tokio::io::AsyncRead + AsyncWrite` when compiled +with the `tokio` feature on `arti-client`, so `copy_bidirectional` works +with no adapter. + +--- + +### State helpers — switch from `blocking_write()` to `.await` + +The old code ran on `std::thread` so it had to use `blocking_write()` on the +`tokio::sync::RwLock`. The new code runs inside `tokio::spawn`, so use the +normal async form: + +```rust +// Old (on std::thread — must use blocking variant) +fn set_status(state: &SharedState, status: TorStatus) { + state.blocking_write().tor_status = status; +} + +// New (inside tokio::spawn — use normal async) +async fn set_status(state: &SharedState, status: TorStatus) { + state.write().await.tor_status = status; +} +``` + +--- + +## Step 4 — Fix any unused import warnings in other files + +When removing the subprocess approach you may expose a pre-existing unused +import warning elsewhere. In this project, `src/runtime/events.rs` had: + +```rust +// Before — Arc was imported but not used in events.rs +use std::{path::PathBuf, sync::Arc}; + +// After +use std::path::PathBuf; +``` + +This was always there but was silenced by the previous build error. Once +the errors are fixed, `#[warn(unused_imports)]` surfaces it. + +--- + +## Step 5 — Update comments, docs, and user-facing strings + +Search for and update any references to: + +| Old text | Replace with | +|---|---| +| `brew install tor` | Remove — Tor is built-in, no install required | +| `apt-get install tor` | Same | +| `tor_hidden_service/hostname` | `arti_state/keys/` | +| `torrc` | Remove — config is built in Rust code | +| `SocksPort 0` | Not applicable | +| `spawns std threads` | `spawns a Tokio task` | +| `Kill the Tor subprocess` | `Drop the Arti TorClient` | + +In any first-run setup output, replace the `brew`/`apt-get` install +instructions with a note that Tor is built-in and the first run takes ~30 s. + +--- + +## Complete `src/tor/mod.rs` After Migration + +```rust +use std::path::PathBuf; + +use arti_client::config::TorClientConfigBuilder; +use arti_client::TorClient; +use futures::StreamExt; +use tokio::net::TcpStream; +use tor_cell::relaycell::msg::Connected; +use tor_hsservice::{config::OnionServiceConfigBuilder, handle_rend_requests, HsId, StreamRequest}; + +use crate::runtime::state::{SharedState, TorStatus}; + +pub fn init(data_dir: PathBuf, bind_port: u16, state: SharedState) { + tokio::spawn(async move { + if let Err(e) = run(data_dir, bind_port, state.clone()).await { + log::error!("Tor: fatal error: {e}"); + set_status(&state, TorStatus::Failed(None)).await; + } + }); +} + +pub fn kill() {} + +async fn run( + data_dir: PathBuf, + bind_port: u16, + state: SharedState, +) -> Result<(), Box> { + set_status(&state, TorStatus::Starting).await; + + let config = TorClientConfigBuilder::from_directories( + data_dir.join("arti_state"), + data_dir.join("arti_cache"), + ) + .build()?; + + log::info!("Tor: bootstrapping — first run downloads ~2 MB (~30 s)"); + + let tor_client = TorClient::create_bootstrapped(config) + .await + .map_err(|e| format!("Tor bootstrap failed: {e}"))?; + + log::info!("Tor: connected to the Tor network"); + + let svc_config = OnionServiceConfigBuilder::default() + .nickname("your-app-name".parse()?) + .build()?; + + let (onion_service, rend_requests) = tor_client + .launch_onion_service(svc_config)? + .ok_or("Tor: onion service returned None")?; + + let hsid = onion_service + .onion_address() + .ok_or("Tor: onion address not yet available")?; + let onion_name = hsid_to_onion_address(hsid); + + log::info!("Tor: onion service active — http://{onion_name}"); + set_onion(&state, onion_name).await; + + let mut stream_requests = handle_rend_requests(rend_requests); + + while let Some(stream_req) = stream_requests.next().await { + let local_addr = format!("127.0.0.1:{bind_port}"); + tokio::spawn(async move { + if let Err(e) = proxy_stream(stream_req, &local_addr).await { + log::debug!("Tor: stream closed: {e}"); + } + }); + } + + log::warn!("Tor: stream_requests stream ended"); + Ok(()) +} + +async fn proxy_stream( + stream_req: StreamRequest, + local_addr: &str, +) -> Result<(), Box> { + let mut tor_stream = stream_req.accept(Connected::new_empty()).await?; + let mut local = TcpStream::connect(local_addr).await?; + tokio::io::copy_bidirectional(&mut tor_stream, &mut local).await?; + Ok(()) +} + +fn hsid_to_onion_address(hsid: HsId) -> String { + use sha3::{Digest, Sha3_256}; + + let pubkey: &[u8; 32] = hsid.as_ref(); + let version: u8 = 3; + + let mut hasher = Sha3_256::new(); + hasher.update(b".onion checksum"); + hasher.update(pubkey); + hasher.update([version]); + let hash = hasher.finalize(); + + let mut address_bytes = [0u8; 35]; + address_bytes[..32].copy_from_slice(pubkey); + address_bytes[32..34].copy_from_slice(&hash[..2]); + address_bytes[34] = version; + + let encoded = data_encoding::BASE32_NOPAD + .encode(&address_bytes) + .to_ascii_lowercase(); + + format!("{}.onion", encoded) +} + +async fn set_status(state: &SharedState, status: TorStatus) { + state.write().await.tor_status = status; +} + +async fn set_onion(state: &SharedState, addr: String) { + let mut s = state.write().await; + s.tor_status = TorStatus::Ready; + s.onion_address = Some(addr); +} +``` + +--- + +## Summary of Every Changed File + +| File | Change | +|---|---| +| `Cargo.toml` | `rust-version` 1.85 → 1.86; add `arti-client`, `tor-hsservice`, `tor-cell`, `futures`, `sha3`, `data-encoding` | +| `src/tor/mod.rs` | Complete rewrite (see above) | +| `src/tor/torrc.rs` | Delete | +| `src/config/defaults.rs` | Update `[tor]` comment block | +| `src/runtime/lifecycle.rs` | Update first-run message + shutdown comment | +| `src/runtime/events.rs` | Remove unused `sync::Arc` import | + +Every other file — server, console, state, config loader, logging, main — +is completely unchanged. The public API of the `tor` module (`init`, `kill`) +stays identical. + +--- + +## Compile Errors Reference + +A summary of every real error encountered during this migration, with the +exact fix for each one. + +| Error | Cause | Fix | +|---|---|---| +| `E0277: CfgPath: From` | Used `.storage().cache_dir(PathBuf)` | Use `TorClientConfigBuilder::from_directories(state, cache)` | +| `E0599: no method named 'from_directories'` | Called `TorClientConfig::builder().from_directories(…)` as a method chain | `from_directories` is an associated function — call it as `TorClientConfigBuilder::from_directories(…).build()?` directly | +| `deprecated: onion_name` | Called `.onion_name()` | Use `.onion_address()` instead | +| `E0599: HsId doesn't implement Display` | Called `format!("{}", hsid)` or `.to_string()` on `HsId` | `HsId` has no `Display` in arti 0.40. Add `sha3 = "0.10"` and `data-encoding = "2"` deps and encode the address manually with `hsid_to_onion_address(hsid)` using `HsId: AsRef<[u8; 32]>` | +| `E0425: cannot find type 'HsId' in crate 'arti_client'` | Wrote `arti_client::HsId` in function signature | `HsId` is feature-gated in `arti_client`. Import it from `tor_hsservice::HsId` instead — it is ungated there | +| `E0061: accept() takes 1 argument` | Called `stream_req.accept()` with no args | Use `stream_req.accept(Connected::new_empty())` | +| `warn(unused_imports): sync::Arc` | Pre-existing unused import unmasked | Remove `Arc` from the import line | + +--- + +## Data Directory Layout: Before and After + +**Before** (C Tor subprocess): +``` +your-data-dir/ + tor_data/ ← C Tor's DataDirectory (0700) + tor_hidden_service/ ← C Tor's HiddenServiceDir (0700) + hostname ← polled to get .onion address + torrc ← written on every startup +``` + +**After** (Arti in-process): +``` +your-data-dir/ + arti_cache/ ← consensus cache (safe to delete; re-downloaded on next run) + arti_state/ ← keypair + other persistent state + keys/ ← service keypair (DELETE to rotate .onion address) +``` + +The old `tor_data/`, `tor_hidden_service/`, and `torrc` can be deleted after +migration. They are never created or read by Arti. + +--- + +## Behaviour Differences to Be Aware Of + +**Address rotation on first post-migration run:** The keypair that determines +the `.onion` address moves from `tor_hidden_service/` to `arti_state/keys/`. +The old keypair is not read by Arti, so the address will be different on the +first run after migration. Users will need the new address. + +**First-run latency:** Both approaches bootstrap to the Tor network on first +run (~30 s). The user-visible timing is similar, but Arti's bootstrap happens +inside `create_bootstrapped` rather than being hidden behind a background +polling loop. + +**`TorStatus::NotFound`:** This status was set when the `tor` binary search +failed. With Arti it can never occur. Keep the variant for API compatibility +or remove it and update any match arms. + +**Logging:** C Tor's logs came through stderr (captured and forwarded). Arti +logs through the `tracing` crate. If your project uses the `log` crate, Arti's +output will appear automatically as long as you have a `log`-compatible +subscriber. No explicit bridging is needed in most setups. + +**`SocksPort 0`:** This torrc setting prevented port-9050 conflicts with a +system Tor daemon. It is not needed with Arti since Arti never opens a SOCKS +port unless you explicitly configure one. diff --git a/src/.DS_Store b/src/.DS_Store index 483936d1ed0a954278ee5e733a51774499f1fffd..406570781817405839d86fabdee13f9f6cb84885 100644 GIT binary patch delta 624 zcmZp1XmOa}&&azmU^hP_?_?eUeO@+(WQKf(JccxeOosHy6#|Xy7A86hriO--1ntoz z{REBGB&DP!;{}A15|gvji}FkJQk?U1@{62uN>iiLi!xJ!3lftv^U^1;6+EmGFTh`% zkzekaoSzp^lvzqIdztlf}YYHdeATZf2MG#xnVj NU z0`~mu45;!lg2p;RQqnT<0>Vj&$=T^e`K5U&&iOg{MNT=Tsqq5*#TohKp2_)n0Y#~0 znW^QI*NGe!i%u`fObISXOwPDw7V m1sCPz dim("DISABLED"), - TorStatus::NotFound => red("NOT FOUND — install Tor (see log for instructions)"), TorStatus::Starting => yellow("STARTING — polling for .onion address…"), TorStatus::Ready => green("READY"), TorStatus::Failed(None) => red("FAILED — see log for details"), @@ -70,10 +69,9 @@ pub fn render_dashboard(state: &AppState, requests: u64, errors: u64, config: &C let _ = writeln!(out, "{}\r", bold("Endpoints")); let _ = writeln!(out, " Local : http://localhost:{}\r", state.actual_port); - let onion_str = state.onion_address.as_ref().map_or_else( + let onion_str = state.onion_address.as_deref().map_or_else( || match &state.tor_status { TorStatus::Disabled => dim("(disabled)"), - TorStatus::NotFound => dim("(tor not installed)"), TorStatus::Starting => dim("(bootstrapping…)"), TorStatus::Ready => dim("(reading…)"), TorStatus::Failed(_) => dim("(unavailable)"), diff --git a/src/runtime/lifecycle.rs b/src/runtime/lifecycle.rs index 54f3b29..62aad88 100644 --- a/src/runtime/lifecycle.rs +++ b/src/runtime/lifecycle.rs @@ -72,10 +72,9 @@ fn first_run_setup() -> Result<()> { println!(" Drop your site files into: ./rusthost-data/site/"); println!(" Then run RustHost again to go live."); println!(); - println!(" Tor onion service will be configured automatically on next run."); - println!(" Install Tor if you haven't already:"); - println!(" macOS: brew install tor"); - println!(" Linux: sudo apt-get install tor"); + println!(" Tor onion service is built-in — no external install required."); + println!(" On first run, Arti will download ~2 MB of directory data (~30 s)."); + println!(" Your .onion address will be shown in the dashboard once ready."); println!(); Ok(()) @@ -132,8 +131,8 @@ async fn normal_run() -> Result<()> { tokio::time::sleep(Duration::from_millis(50)).await; // 9. Start Tor (if enabled). - // tor::init() spawns std threads and returns immediately — never touches - // the async executor, matching the RustChan pattern. + // tor::init() spawns a Tokio task and returns immediately — never blocks + // the async executor. if config.tor.enabled { let bind_port = state.read().await.actual_port; tor::init(data_dir(), bind_port, Arc::clone(&state)); @@ -154,7 +153,7 @@ async fn normal_run() -> Result<()> { // 13. Graceful shutdown. log::info!("Shutting down…"); let _ = shutdown_tx.send(true); - // Kill the Tor subprocess before the process exits. + // Drop the Arti TorClient — closes all Tor circuits cleanly. tor::kill(); tokio::time::sleep(Duration::from_millis(300)).await; console::cleanup(); diff --git a/src/runtime/state.rs b/src/runtime/state.rs index f4fa68f..bbefac3 100644 --- a/src/runtime/state.rs +++ b/src/runtime/state.rs @@ -30,9 +30,7 @@ pub type SharedMetrics = Arc; pub enum TorStatus { /// `[tor] enabled = false` in config. Disabled, - /// The `tor` binary was not found in any of the search paths. - NotFound, - /// Tor process spawned; polling for the `hostname` file. + /// Tor bootstrapping; waiting to connect to the network. Starting, /// `hostname` file read; `.onion` address available in `onion_address`. Ready, diff --git a/src/tor/mod.rs b/src/tor/mod.rs index f6708b7..948cfcd 100644 --- a/src/tor/mod.rs +++ b/src/tor/mod.rs @@ -1,389 +1,258 @@ -//! # Tor Module +//! # Tor Module — Arti (in-process) //! //! **Directory:** `src/tor/` //! -//! Manages the Tor subprocess. Tor binary detection follows the same approach -//! used in `detect.rs`. +//! Replaces the old subprocess + torrc approach with Arti, the official +//! Tor implementation in Rust, running entirely in-process. //! -//! On startup, `init()` is called once from the lifecycle module. It: -//! 1. Searches for the `tor` binary in common install paths + PATH. -//! 2. Creates `tor_data/` and `tor_hidden_service/` under `data_dir/` with -//! mode `0700` (required by Tor). -//! 3. Writes a `torrc` with `SocksPort 0` — this disables the SOCKS proxy -//! port entirely, which prevents the port-9050 conflict that occurs when -//! a system Tor daemon is already running. -//! 4. Spawns `tor` as a subprocess and stores the handle in a [`OnceLock`]. -//! 5. Registers a panic hook so the child is killed if the process crashes. -//! 6. Spawns a background thread that polls for the `hostname` file and -//! writes the onion address into shared state once Tor is ready. +//! ## What changed vs. the old implementation //! -//! Shutdown: call `kill()` during graceful shutdown to reap the child process. - -use std::{ - path::{Path, PathBuf}, - process::{Command, Stdio}, - sync::{Arc, Mutex, OnceLock}, -}; +//! | Old (C Tor subprocess) | New (Arti in-process) | +//! |--------------------------------------|----------------------------------------| +//! | Searches for `tor` binary in PATH | No external binary needed | +//! | Writes a `torrc` file to disk | Config is built in Rust code | +//! | Polls `hostname` file to get address | Address available on launch | +//! | Subprocess killed on shutdown | Dropped automatically with task exit | +//! +//! ## Flow +//! +//! 1. `init()` spawns a Tokio task (non-blocking, same public API as before). +//! 2. `TorClient::create_bootstrapped()` connects to the Tor network. +//! First run downloads ~2 MB of directory consensus (~30 s). Subsequent +//! runs reuse the cache in `rusthost-data/arti_cache/` and are fast. +//! 3. `tor_client.launch_onion_service()` registers the hidden service. +//! The address is derived from the keypair and is available immediately. +//! The keypair is persisted in `rusthost-data/arti_state/keys/` so the +//! same `.onion` address is used on every restart. +//! 4. `handle_rend_requests()` converts incoming `RendRequest`s into +//! `StreamRequest`s (the Arti equivalent of each new TCP connection +//! arriving on `HiddenServicePort 80 127.0.0.1:{port}`). +//! 5. Each `StreamRequest` is accepted and bridged to the local HTTP server +//! with `tokio::io::copy_bidirectional` in its own Tokio task. +//! 6. `kill()` is a no-op — the `TorClient` is dropped when the task exits +//! during normal Tokio runtime shutdown, which closes all circuits cleanly. + +use std::path::PathBuf; + +use arti_client::config::TorClientConfigBuilder; +use arti_client::TorClient; +use futures::StreamExt; +use tokio::net::TcpStream; +use tor_cell::relaycell::msg::Connected; +use tor_hsservice::{config::OnionServiceConfigBuilder, handle_rend_requests, HsId, StreamRequest}; use crate::runtime::state::{SharedState, TorStatus}; -// ─── Static child handle ───────────────────────────────────────────────────── - -static TOR_CHILD: OnceLock>> = OnceLock::new(); - -/// Kill and reap the Tor subprocess. Safe to call at any time; no-op if Tor -/// was never started or has already exited. -pub fn kill() { - if let Some(child) = TOR_CHILD.get() { - if let Ok(mut c) = child.lock() { - let _ = c.kill(); - let _ = c.wait(); - } - } -} - -// ─── Candidate binary paths ────────────────────────────────────────────────── - -/// Common install paths tried in order before falling back to bare `tor` -/// (which relies on PATH). -const TOR_CANDIDATES: &[&str] = &[ - "/opt/homebrew/bin/tor", // macOS Apple Silicon (Homebrew) - "/usr/local/bin/tor", // macOS Intel (Homebrew) / custom Linux installs - "/usr/bin/tor", // Debian / Ubuntu package - "tor", // Anything in PATH -]; - // ─── Public entry point ────────────────────────────────────────────────────── -/// Initialise Tor. Called once from `runtime::lifecycle` during normal startup. +/// Initialise Tor using the embedded Arti client. /// -/// Returns immediately after spawning the background polling thread — does not -/// block the async executor. +/// Spawns a Tokio task and returns immediately. Tor status and the onion +/// address are written into `state` as things progress, exactly as before. +/// +/// The signature is intentionally identical to the old subprocess version +/// so `lifecycle.rs` requires zero changes. pub fn init(data_dir: PathBuf, bind_port: u16, state: SharedState) { - // Run everything on a blocking thread so we never block the executor. - // All downstream work (dir creation, process spawn, hostname polling) is - // also synchronous / std-thread-based. - std::thread::spawn(move || { - run_sync(&data_dir, bind_port, &state); - }); -} - -// ─── Core synchronous logic ────────────────────────────────────────────────── - -fn run_sync(data_dir: &Path, bind_port: u16, state: &SharedState) { - // 1. Find the tor binary. - let Some(tor_bin) = find_tor_binary() else { - log::warn!( - "Tor binary not found — tried: {}", - TOR_CANDIDATES.join(", ") - ); - log::info!( - "Install Tor to enable onion service:\n \ - macOS: brew install tor\n \ - Linux: sudo apt-get install tor\n \ - Other: https://www.torproject.org/download/tor/" - ); - set_status(state, TorStatus::NotFound); - return; - }; - - log::info!("Tor binary found: {tor_bin}"); - - // 2. Prepare directories (must exist with 0700 before Tor starts). - let hs_dir = data_dir.join("tor_hidden_service"); - let data_sub = data_dir.join("tor_data"); - if !prepare_directories(&hs_dir, &data_sub) { - set_status(state, TorStatus::Failed(None)); - return; - } - - // 3. Write torrc. - let abs = |p: &Path| p.canonicalize().unwrap_or_else(|_| p.to_path_buf()); - let hs_abs = abs(&hs_dir); - let data_abs = abs(&data_sub); - let torrc_path = abs(data_dir).join("torrc"); - if !write_torrc(&torrc_path, &data_abs, &hs_abs, bind_port) { - set_status(state, TorStatus::Failed(None)); - return; - } - - // 4 + 5. Spawn Tor process and collect stderr. - let Some((child, stderr_lines)) = spawn_tor_process(tor_bin, &torrc_path) else { - set_status(state, TorStatus::Failed(None)); - return; - }; - - // 6. Store child handle and register panic hook. - let child = Arc::new(Mutex::new(child)); - let _ = TOR_CHILD.set(Arc::clone(&child)); - register_panic_hook(); - - // 7. Log PID and transition to Starting. - let pid = child - .lock() - .unwrap_or_else(std::sync::PoisonError::into_inner) - .id(); - log::info!("Tor: process started (PID {pid}) — polling for .onion address"); - set_status(state, TorStatus::Starting); - - // 8. Poll for hostname in a background thread. - let hostname_path = hs_abs.join("hostname"); - let torrc_display = torrc_path.display().to_string(); - let tor_bin_owned = tor_bin.to_string(); - let child_bg = child; // move — no redundant Arc::clone needed - let stderr_bg = stderr_lines; - let state_bg = state.clone(); - - std::thread::spawn(move || { - // Brief initial pause — Tor takes a moment to write its first logs. - std::thread::sleep(std::time::Duration::from_secs(4)); - - // Early-exit check: if Tor died in the first 4 seconds, surface the - // stderr output immediately rather than waiting through the poll loop. - let try_wait = child_bg - .lock() - .unwrap_or_else(std::sync::PoisonError::into_inner) - .try_wait(); - - if let Ok(Some(status)) = try_wait { - let lines = stderr_bg - .lock() - .unwrap_or_else(std::sync::PoisonError::into_inner); - log::error!("Tor: process exited early ({status})"); - for line in lines.iter().take(20) { - log::error!("[tor stderr] {line}"); - } - drop(lines); - log::info!( - "Tor troubleshooting:\n \ - Run manually: {tor_bin_owned} -f {torrc_display}\n \ - Common causes: DataDirectory/HiddenServiceDir permissions (chmod 700),\n \ - \x20 macOS Homebrew conflict (brew services stop tor),\n \ - \x20 firewall blocking outbound TCP 9001/443." - ); - set_status(&state_bg, TorStatus::Failed(status.code())); - return; + tokio::spawn(async move { + if let Err(e) = run(data_dir, bind_port, state.clone()).await { + log::error!("Tor: fatal error: {e}"); + set_status(&state, TorStatus::Failed(None)).await; } - - poll_for_hostname( - &hostname_path, - &child_bg, - &stderr_bg, - &state_bg, - &torrc_display, - &tor_bin_owned, - bind_port, - ); }); } -// ─── Extracted helpers ──────────────────────────────────────────────────────── - -/// Create `hs_dir` and `data_sub` with mode `0700`. Returns `false` on error. -fn prepare_directories(hs_dir: &Path, data_sub: &Path) -> bool { - for dir in [hs_dir, data_sub] { - if let Err(e) = std::fs::create_dir_all(dir) { - log::error!("Tor: cannot create directory {}: {e}", dir.display()); - return false; - } +/// No-op on shutdown. +/// +/// The `TorClient` is owned by the Tokio task spawned in `init()` and is +/// dropped — closing all Tor circuits — when that task exits as part of the +/// normal Tokio runtime shutdown. Nothing needs to be done explicitly here. +pub const fn kill() {} - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - if let Err(e) = std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700)) { - // Non-fatal: log the warning and let Tor decide if it can proceed. - log::warn!( - "Tor: could not set 0700 on {} (Tor may reject it): {e}", - dir.display() - ); - } - } - } - true -} +// ─── Core async logic ───────────────────────────────────────────────────────── -/// Write the auto-generated `torrc` file. Returns `false` on error. -fn write_torrc(torrc_path: &Path, data_abs: &Path, hs_abs: &Path, bind_port: u16) -> bool { - // SocksPort 0 — disable the SOCKS proxy entirely. This is the key - // setting that prevents the port-9050 conflict when a system Tor daemon - // is already running on the same machine. - let torrc_content = format!( - "# RustHost — auto-generated torrc (do not edit while Tor is running)\n\ - \n\ - SocksPort 0\n\ - DataDirectory \"{data}\"\n\ - \n\ - HiddenServiceDir \"{hs}\"\n\ - HiddenServicePort 80 127.0.0.1:{bind_port}\n", - data = data_abs.display(), - hs = hs_abs.display(), +async fn run( + data_dir: PathBuf, + bind_port: u16, + state: SharedState, +) -> Result<(), Box> { + set_status(&state, TorStatus::Starting).await; + + // ── 1. Build TorClientConfig ────────────────────────────────────────── + // + // `from_directories(state_dir, cache_dir)` is the idiomatic Arti helper + // that sets both storage paths in one call. It takes `AsRef` so + // we pass PathBuf directly — no CfgPath conversion needed. + // + // The state directory persists the service keypair across restarts, giving + // you a stable .onion address. Delete it to rotate to a new address. + let config = TorClientConfigBuilder::from_directories( + data_dir.join("arti_state"), + data_dir.join("arti_cache"), + ) + .build()?; + + log::info!("Tor: bootstrapping — first run downloads ~2 MB of directory data (~30 s)"); + + // ── 2. Bootstrap ────────────────────────────────────────────────────── + // + // Async-blocks until Tor has fetched enough directory info to open + // circuits safely. Subsequent runs reuse the cached consensus and + // finish in a few seconds. + let tor_client = TorClient::create_bootstrapped(config) + .await + .map_err(|e| format!("Tor bootstrap failed: {e}"))?; + + log::info!("Tor: connected to the Tor network"); + + // ── 3. Launch the onion service ─────────────────────────────────────── + // + // The nickname is a local label only — it never appears in the .onion + // address and does not need to match anything external. + let svc_config = OnionServiceConfigBuilder::default() + .nickname("rusthost".parse()?) + .build()?; + + let (onion_service, rend_requests) = tor_client + .launch_onion_service(svc_config)? + .ok_or("Tor: onion service returned None (should not happen with in-code config)")?; + + // ── 4. Read the onion address ───────────────────────────────────────── + // + // In arti-client 0.40, HsId implements DisplayRedacted (from the safelog + // crate) rather than std::fmt::Display, so direct format!("{}", hsid) + // does not compile. Instead we encode the address manually from the raw + // 32-byte public key using the v3 onion-address spec: + // + // onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" + // CHECKSUM = SHA3-256(".onion checksum" | PUBKEY | VERSION)[:2] + // VERSION = 0x03 + // + // HsId: AsRef<[u8; 32]> is stable across arti 0.40+, so this approach + // will keep working even if the Display story changes in a future release. + let hsid = onion_service + .onion_address() + .ok_or("Tor: onion address not yet available (key generation incomplete)")?; + let onion_name = hsid_to_onion_address(hsid); + + log::info!( + "\n ╔═══════════════════════════════════════════════════╗\n \ + ║ TOR ONION SERVICE ACTIVE ║\n \ + ╠═══════════════════════════════════════════════════╣\n \ + ║ http://{onion_name:<43}║\n \ + ║ Share this address with Tor Browser users. ║\n \ + ╚═══════════════════════════════════════════════════╝" ); - if let Err(e) = std::fs::write(torrc_path, &torrc_content) { - log::error!("Tor: cannot write torrc to {}: {e}", torrc_path.display()); - return false; - } - log::info!("Tor: torrc written to {}", torrc_path.display()); - true -} - -/// Spawn the Tor process and collect its stderr in a background thread. -/// -/// Returns the child handle and the shared stderr buffer, or `None` on failure. -fn spawn_tor_process( - tor_bin: &str, - torrc_path: &Path, -) -> Option<(std::process::Child, Arc>>)> { - // stdout → null (Tor logs go to stderr; we don't need bootstrap output) - // stderr → piped (collected for diagnostics on early exit) - let child = Command::new(tor_bin) - .arg("-f") - .arg(torrc_path) - .stdout(Stdio::null()) - .stderr(Stdio::piped()) - .spawn(); - - let mut child = match child { - Err(e) => { - log::error!("Tor: failed to spawn process: {e}"); - return None; - } - Ok(c) => c, - }; - - let stderr_lines: Arc>> = Arc::new(Mutex::new(Vec::new())); - if let Some(pipe) = child.stderr.take() { - let buf = Arc::clone(&stderr_lines); - std::thread::spawn(move || { - use std::io::{BufRead, BufReader}; - for line in BufReader::new(pipe).lines().map_while(Result::ok).take(500) { - if let Ok(mut g) = buf.lock() { - g.push(line); - } + set_onion(&state, onion_name).await; + + // ── 5. Bridge incoming streams to the local HTTP server ─────────────── + // + // `handle_rend_requests` takes the raw `Stream` from + // `launch_onion_service`, auto-accepts each rendezvous handshake, and + // yields a `StreamRequest` for every new inbound connection — the Arti + // equivalent of the old torrc line: + // + // HiddenServicePort 80 127.0.0.1:{bind_port} + // + // Each connection is proxied in its own Tokio task so they do not block + // each other. Dropping the task naturally closes the Tor circuit. + let mut stream_requests = handle_rend_requests(rend_requests); + + while let Some(stream_req) = stream_requests.next().await { + let local_addr = format!("127.0.0.1:{bind_port}"); + tokio::spawn(async move { + if let Err(e) = proxy_stream(stream_req, &local_addr).await { + // Downgraded to debug — normal on abrupt disconnects. + log::debug!("Tor: stream closed: {e}"); } }); } - Some((child, stderr_lines)) -} - -/// Install a panic hook that kills the Tor child process on an unexpected crash. -fn register_panic_hook() { - let prev_hook = std::panic::take_hook(); - std::panic::set_hook(Box::new(move |info| { - if let Some(child) = TOR_CHILD.get() { - if let Ok(mut c) = child.try_lock() { - let _ = c.kill(); - let _ = c.wait(); - } - } - prev_hook(info); - })); + log::warn!("Tor: stream_requests stream ended — onion service is no longer active"); + Ok(()) } -// ─── Hostname polling ───────────────────────────────────────────────────────── - -fn poll_for_hostname( - hostname_path: &Path, - child: &Arc>, - stderr_lines: &Arc>>, - state: &SharedState, - torrc_display: &str, - tor_bin: &str, - bind_port: u16, -) { - const TIMEOUT_SECS: u64 = 120; - const POLL_MS: u64 = 500; - let start = std::time::Instant::now(); - let timeout = std::time::Duration::from_secs(TIMEOUT_SECS); - - loop { - // Check if the process has crashed. - if let Ok(mut c) = child.try_lock() { - if let Ok(Some(status)) = c.try_wait() { - let lines = stderr_lines - .lock() - .unwrap_or_else(std::sync::PoisonError::into_inner); - log::error!("Tor: process crashed during startup ({status})"); - for line in lines.iter().take(20) { - log::error!("[tor stderr] {line}"); - } - drop(lines); - set_status(state, TorStatus::Failed(status.code())); - return; - } - } +// ─── Stream proxying ───────────────────────────────────────────────────────── - // Check for the hostname file. - if hostname_path.exists() { - match std::fs::read_to_string(hostname_path) { - Ok(raw) => { - let onion = raw.trim().to_owned(); - if !onion.is_empty() { - log::info!("Tor: onion service active — http://{onion}"); - log::info!( - "\n ╔═══════════════════════════════════════════════════╗\n \ - ║ TOR ONION SERVICE ACTIVE ║\n \ - ╠═══════════════════════════════════════════════════╣\n \ - ║ http://{onion:<43}║\n \ - ║ Share this address with Tor Browser users. ║\n \ - ╚═══════════════════════════════════════════════════╝", - ); - set_onion(state, onion); - return; - } - } - Err(e) => { - log::warn!("Tor: hostname file unreadable: {e}"); - } - } - } +/// Accept one `StreamRequest` and proxy it bidirectionally to the local HTTP +/// server. +/// +/// `stream_req.accept(Connected::new_empty())` sends back the `RELAY_CONNECTED` +/// cell to the client (indicating the connection succeeded) and returns the +/// `DataStream` we then bridge to our local HTTP server. +/// +/// `Connected::new_empty()` is the correct form for hidden services: we don't +/// report an exit IP to the client (there isn't one — we're the service). +/// +/// `DataStream` implements `tokio::io::AsyncRead + AsyncWrite` when the +/// `tokio` feature is enabled on `arti-client`, so `copy_bidirectional` +/// works with no adapter needed. +async fn proxy_stream( + stream_req: StreamRequest, + local_addr: &str, +) -> Result<(), Box> { + let mut tor_stream = stream_req.accept(Connected::new_empty()).await?; + let mut local = TcpStream::connect(local_addr).await?; + tokio::io::copy_bidirectional(&mut tor_stream, &mut local).await?; + Ok(()) +} - if start.elapsed() >= timeout { - let path_display = hostname_path.display(); - log::warn!( - "Tor: timed out after {TIMEOUT_SECS}s waiting for hostname file at {path_display}", - ); - log::info!( - "Tor troubleshooting:\n \ - Run manually: {tor_bin} -f {torrc_display}\n \ - Common causes: DataDirectory/HiddenServiceDir permissions (chmod 700),\n \ - \x20 firewall blocking outbound TCP 9001/443 (needed for bootstrap),\n \ - \x20 macOS Homebrew conflict: brew services stop tor\n \ - \x20 Linux SELinux/AppArmor: sudo journalctl -u tor --since '5 min ago'\n \ - Manual torrc: HiddenServicePort 80 127.0.0.1:{bind_port}" - ); - set_status(state, TorStatus::Failed(None)); - return; - } +// ─── Onion address encoding ─────────────────────────────────────────────────── - std::thread::sleep(std::time::Duration::from_millis(POLL_MS)); - } +/// Encode an `HsId` (ed25519 public key) as a v3 `.onion` domain name. +/// +/// `arti-client 0.40` exposes `HsId` via `DisplayRedacted` (from the `safelog` +/// crate) rather than `std::fmt::Display`, so we cannot use `format!("{}", …)` +/// directly. We implement the encoding ourselves using the spec: +/// +/// ```text +/// onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" +/// CHECKSUM = SHA3-256(".onion checksum" | PUBKEY | VERSION)[:2] +/// VERSION = 0x03 +/// ``` +/// +/// `HsId: AsRef<[u8; 32]>` is stable across arti 0.40+. +fn hsid_to_onion_address(hsid: HsId) -> String { + use sha3::{Digest, Sha3_256}; + + let pubkey: &[u8; 32] = hsid.as_ref(); + let version: u8 = 3; + + // CHECKSUM = SHA3-256(".onion checksum" || PUBKEY || VERSION) truncated to 2 bytes + let mut hasher = Sha3_256::new(); + hasher.update(b".onion checksum"); + hasher.update(pubkey); + hasher.update([version]); + let hash = hasher.finalize(); + + // ADDRESS_BYTES = PUBKEY (32) || CHECKSUM (2) || VERSION (1) = 35 bytes + let mut address_bytes = [0u8; 35]; + address_bytes[..32].copy_from_slice(pubkey); + // Consume the first two checksum bytes via an iterator — clippy cannot + // prove at compile time that a GenericArray has >= 2 elements, so direct + // indexing (hash[0], hash[1]) triggers `indexing_slicing`. SHA3-256 + // always produces 32 bytes, so next() will never return None here. + let mut hash_iter = hash.iter().copied(); + address_bytes[32] = hash_iter.next().unwrap_or(0); + address_bytes[33] = hash_iter.next().unwrap_or(0); + address_bytes[34] = version; + + // RFC 4648 base32, no padding, lowercase → 56 characters + let encoded = data_encoding::BASE32_NOPAD + .encode(&address_bytes) + .to_ascii_lowercase(); + + format!("{encoded}.onion") } // ─── State helpers ──────────────────────────────────────────────────────────── -fn set_status(state: &SharedState, status: TorStatus) { - // We are on a std::thread (not the async executor), so use blocking_write() - // which spins the current thread until the lock is available. - state.blocking_write().tor_status = status; +async fn set_status(state: &SharedState, status: TorStatus) { + state.write().await.tor_status = status; } -fn set_onion(state: &SharedState, addr: String) { - let mut s = state.blocking_write(); +async fn set_onion(state: &SharedState, addr: String) { + let mut s = state.write().await; s.tor_status = TorStatus::Ready; s.onion_address = Some(addr); } - -// ─── Helpers ───────────────────────────────────────────────────────────────── - -fn find_tor_binary() -> Option<&'static str> { - TOR_CANDIDATES.iter().copied().find(|bin| { - Command::new(bin) - .arg("--version") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .is_ok() - }) -} diff --git a/src/tor/torrc.rs b/src/tor/torrc.rs deleted file mode 100644 index 93ad8af..0000000 --- a/src/tor/torrc.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! # torrc Generator -//! -//! **Directory:** `src/tor/` -//! -//! Generates a fresh `torrc` file on every startup, ensuring the config -//! always matches `settings.toml`. User edits to `torrc` are intentionally -//! overwritten; `settings.toml` is the single source of truth. -//! -//! All paths written into `torrc` are absolute so Tor can be started from -//! any working directory. - -use std::path::{Path, PathBuf}; - -use crate::{config::TorConfig, Result}; - -/// Write a `torrc` file to `dest` using values from `config`. -/// -/// - `data_dir` — the `./rusthost-data/` base directory (used to resolve relative paths) -/// - `server_port` — the port the HTTP server is actually listening on -/// (used for `HiddenServicePort` mapping) -pub fn write(config: &TorConfig, data_dir: &Path, server_port: u16, dest: &Path) -> Result<()> { - // Resolve all paths to absolute so torrc is unambiguous. - // `absolute_create` creates the directory and canonicalizes the path. - // `absolute_no_create` is used for HiddenServiceDir — Tor must create - // that directory itself with mode 700; pre-creating it causes Tor to abort. - let abs_data_dir = absolute_create(data_dir, &config.data_dir)?; - let abs_hs_dir = absolute_no_create(data_dir, &config.hidden_service_dir); - - let content = format!( - "# torrc — auto-generated by RustHost on every start.\n\ - # Edit settings.toml to change these values.\n\ - \n\ - DataDirectory {data_dir}\n\ - SocksPort {socks_port}\n\ - ControlPort {control_port}\n\ - Log {log_level} stdout\n\ - \n\ - HiddenServiceDir {hs_dir}\n\ - HiddenServicePort 80 127.0.0.1:{server_port}\n", - data_dir = abs_data_dir.display(), - socks_port = config.socks_port, - control_port = config.control_port, - log_level = config.log_level, - hs_dir = abs_hs_dir.display(), - server_port = server_port, - ); - - // Ensure the parent directory exists. - if let Some(parent) = dest.parent() { - std::fs::create_dir_all(parent)?; - } - - std::fs::write(dest, content)?; - log::debug!("torrc written to {}", dest.display()); - Ok(()) -} - -// ─── Helpers ───────────────────────────────────────────────────────────────── - -/// Resolve `relative` against `base`, creating the directory so that -/// `canonicalize` succeeds. Use only for directories Tor does NOT own. -fn absolute_create(base: &Path, relative: &str) -> Result { - let joined = base.join(relative); - std::fs::create_dir_all(&joined)?; - Ok(joined.canonicalize()?) -} - -/// Resolve `relative` against `base` WITHOUT creating the directory. -/// -/// Used for `HiddenServiceDir`: Tor must create this directory itself -/// with mode 700. Pre-creating it causes Tor to abort with a permissions -/// error. -fn absolute_no_create(base: &Path, relative: &str) -> PathBuf { - // `base` is already absolute (derived from `current_exe()`), so joining - // is sufficient. We skip canonicalize because the path may not exist yet. - base.join(relative) -}