feat(asb, cli): Listen on onion address, dial onion addresses (#203)

This pull requests
- Adds rust native support for the `asb` to listen on an onion service. Previously we were depedent on a seperately running `torc` client. Instead we now use [arti](https://tpo.pages.torproject.net/core/arti/), a rust implementation of the tor protocol.
- Removes the `tor.control_port` and `tor.socks5_port` property from the config of the `asb`
- Adds a new `tor.register_hidden_service` boolean property to the config of the `asb` which when enabled automatically runs a hidden service at startup
- Adds a new `tor.hidden_service_num_intro_points` config property to specify how many introduction points to register the onion service at
- Adds support for the `cli` to dial onion addresses

This is dependent on https://github.com/umgefahren/libp2p-tor/pull/24

Closes https://github.com/UnstoppableSwap/core/issues/16
This commit is contained in:
binarybaron 2024-12-03 21:24:33 +01:00 committed by GitHub
parent 45a4cf4fb7
commit d53c12d64e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 427 additions and 387 deletions

View file

@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- GUI: Changed terminology from "swap providers" to "makers" - GUI: Changed terminology from "swap providers" to "makers"
- GUI: For each maker, we now display a unique deterministically generated avatar derived from the maker's public key - GUI: For each maker, we now display a unique deterministically generated avatar derived from the maker's public key
- ASB (experimental): We now listen on an onion address by default using an internal Tor client. You do not need to run a Tor daemon on your own anymore. The `tor.control_port` and `tor.socks5_port` properties in the config file have been removed. A new `tor.register_hidden_service` property has been added which when set to `true` will run a hidden service on which connections will be accepted. You can configure the number of introduction points to use by setting the `tor.hidden_service_num_intro_points` (3 - 20) property in the config file. The onion address will be advertised to all rendezvous points without having to be added to `network.external_addresses`. For now, this feature is experimental and may be unstable. We recommend you use it in combination with a clearnet address. This feature is powered by [arti](https://tpo.pages.torproject.net/core/arti/), an implementation of the Tor protocol in Rust by the Tor Project.
- CLI + GUI: We can now dial makers over `/onion3/****` addresses using the integrated Tor client.
## [1.0.0-rc.6] - 2024-11-21 ## [1.0.0-rc.6] - 2024-11-21

374
Cargo.lock generated
View file

@ -299,6 +299,9 @@ dependencies = [
"tor-dirmgr", "tor-dirmgr",
"tor-error", "tor-error",
"tor-guardmgr", "tor-guardmgr",
"tor-hsclient",
"tor-hscrypto",
"tor-hsservice",
"tor-keymgr", "tor-keymgr",
"tor-linkspec", "tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
@ -331,7 +334,7 @@ dependencies = [
"num-traits", "num-traits",
"rusticata-macros", "rusticata-macros",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -347,7 +350,7 @@ dependencies = [
"num-traits", "num-traits",
"rusticata-macros", "rusticata-macros",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -755,12 +758,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
[[package]] [[package]]
name = "base58-monero" name = "base58-monero"
version = "0.3.2" version = "0.3.2"
@ -925,7 +922,7 @@ dependencies = [
"bitcoincore-rpc-json", "bitcoincore-rpc-json",
"futures", "futures",
"hex", "hex",
"hmac 0.12.1", "hmac",
"jsonrpc_client", "jsonrpc_client",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest",
@ -1018,7 +1015,6 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [ dependencies = [
"block-padding",
"generic-array", "generic-array",
] ]
@ -1031,12 +1027,6 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]] [[package]]
name = "block2" name = "block2"
version = "0.5.1" version = "0.5.1"
@ -1640,7 +1630,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [ dependencies = [
"time 0.3.36", "time 0.3.37",
"version_check", "version_check",
] ]
@ -1863,16 +1853,6 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "crypto-mac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e"
dependencies = [
"generic-array",
"subtle",
]
[[package]] [[package]]
name = "cssparser" name = "cssparser"
version = "0.27.2" version = "0.27.2"
@ -2176,7 +2156,7 @@ dependencies = [
"proc-macro-crate 3.2.0", "proc-macro-crate 3.2.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"sha3 0.10.8", "sha3",
"strum", "strum",
"syn 2.0.90", "syn 2.0.90",
"void", "void",
@ -2889,9 +2869,9 @@ dependencies = [
[[package]] [[package]]
name = "fs-mistrust" name = "fs-mistrust"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12a327e6e1ee5595f66105852c644a2d65dfbc62c30c90f53a2783d270002de" checksum = "050503efe568c5c90c13ef9b6a47fd5b657fb9605d6230a179aa190d004b65db"
dependencies = [ dependencies = [
"derive_builder_fork_arti", "derive_builder_fork_arti",
"dirs", "dirs",
@ -2899,7 +2879,7 @@ dependencies = [
"once_cell", "once_cell",
"pwd-grp", "pwd-grp",
"serde", "serde",
"thiserror 1.0.69", "thiserror 2.0.4",
"walkdir", "walkdir",
] ]
@ -2923,6 +2903,27 @@ dependencies = [
"winapi", "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.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f261f25f1e94963fe8f72863f4da841b280fa3b5a573990b425a26b585a54578"
dependencies = [
"fslock-arti-fork",
"thiserror 2.0.4",
"winapi",
]
[[package]] [[package]]
name = "funty" name = "funty"
version = "2.0.0" version = "2.0.0"
@ -3416,6 +3417,18 @@ dependencies = [
"subtle", "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]] [[package]]
name = "gtk" name = "gtk"
version = "0.18.1" version = "0.18.1"
@ -3679,17 +3692,7 @@ version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
dependencies = [ dependencies = [
"hmac 0.12.1", "hmac",
]
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"digest 0.9.0",
] ]
[[package]] [[package]]
@ -4548,6 +4551,16 @@ dependencies = [
"jsonrpsee-types", "jsonrpsee-types",
] ]
[[package]]
name = "k12"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dc5fdb62af2f520116927304f15d25b3c2667b4817b90efdc045194c912c54"
dependencies = [
"digest 0.10.7",
"sha3",
]
[[package]] [[package]]
name = "keccak" name = "keccak"
version = "0.1.5" version = "0.1.5"
@ -4730,13 +4743,19 @@ dependencies = [
[[package]] [[package]]
name = "libp2p-community-tor" name = "libp2p-community-tor"
version = "0.4.1" version = "0.5.0"
source = "git+https://github.com/UnstoppableSwap/libp2p-tor?branch=main#b7e67aeb551ba2e72634be33837a00428286da38" source = "git+https://github.com/UnstoppableSwap/libp2p-tor?branch=fix/announce-address-immed#3b227a639fb2169662a0b6fba8fd116560ed0adf"
dependencies = [ dependencies = [
"anyhow",
"arti-client", "arti-client",
"data-encoding",
"futures", "futures",
"libp2p", "libp2p",
"thiserror 1.0.69",
"tokio", "tokio",
"tor-cell",
"tor-hsservice",
"tor-proto",
"tor-rtcompat", "tor-rtcompat",
"tracing", "tracing",
] ]
@ -6646,7 +6665,7 @@ dependencies = [
"indexmap 2.7.0", "indexmap 2.7.0",
"quick-xml", "quick-xml",
"serde", "serde",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -6981,7 +7000,7 @@ dependencies = [
"rustc-hash 2.1.0", "rustc-hash 2.1.0",
"rustls 0.23.19", "rustls 0.23.19",
"socket2", "socket2",
"thiserror 2.0.3", "thiserror 2.0.4",
"tokio", "tokio",
"tracing", "tracing",
] ]
@ -7000,7 +7019,7 @@ dependencies = [
"rustls 0.23.19", "rustls 0.23.19",
"rustls-pki-types", "rustls-pki-types",
"slab", "slab",
"thiserror 2.0.3", "thiserror 2.0.4",
"tinyvec", "tinyvec",
"tracing", "tracing",
"web-time", "web-time",
@ -7159,7 +7178,7 @@ checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6"
dependencies = [ dependencies = [
"pem", "pem",
"ring 0.16.20", "ring 0.16.20",
"time 0.3.36", "time 0.3.37",
"yasna", "yasna",
] ]
@ -7312,9 +7331,9 @@ dependencies = [
[[package]] [[package]]
name = "retry-error" name = "retry-error"
version = "0.6.0" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ef93545b13f6dd83a9f98c8a656ccbd7bc2b95a747844346c70f7e6f5a5932" checksum = "424b17c3ab6f4584c2a079c282ada3b63c660551749c9d814da23a07c9a3dd08"
[[package]] [[package]]
name = "rfc6979" name = "rfc6979"
@ -7322,7 +7341,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [ dependencies = [
"hmac 0.12.1", "hmac",
"subtle", "subtle",
] ]
@ -7436,7 +7455,7 @@ dependencies = [
"hashlink", "hashlink",
"libsqlite3-sys", "libsqlite3-sys",
"smallvec", "smallvec",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -7681,15 +7700,15 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "safelog" name = "safelog"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00c331d3dad51d67db003b70b4e1ab8408c5b89f5830af4d282e612a75a84f3" checksum = "5738eff432cfb1f861b0d7d2cfc7c3fabef53b8585840f16ce2eb980c782133b"
dependencies = [ dependencies = [
"derive_more 1.0.0", "derive_more 1.0.0",
"educe", "educe",
"either", "either",
"fluid-let", "fluid-let",
"thiserror 1.0.69", "thiserror 2.0.4",
] ]
[[package]] [[package]]
@ -7984,6 +8003,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_bytes"
version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_cbor" name = "serde_cbor"
version = "0.11.2" version = "0.11.2"
@ -8094,7 +8122,7 @@ dependencies = [
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"serde_with_macros 3.11.0", "serde_with_macros 3.11.0",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -8226,18 +8254,6 @@ dependencies = [
"digest 0.10.7", "digest 0.10.7",
] ]
[[package]]
name = "sha3"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
dependencies = [
"block-buffer 0.9.0",
"digest 0.9.0",
"keccak",
"opaque-debug",
]
[[package]] [[package]]
name = "sha3" name = "sha3"
version = "0.10.8" version = "0.10.8"
@ -8390,14 +8406,14 @@ dependencies = [
[[package]] [[package]]
name = "slotmap-careful" name = "slotmap-careful"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0521c412b8940cf10d63e88faa7b63839ced20547e6d49d86417d90d0c1af8ad" checksum = "b0a59a806f2fa2def01b97bba3a7947cf47daac2ddf6a1b0701063aeafe5b129"
dependencies = [ dependencies = [
"paste", "paste",
"serde", "serde",
"slotmap", "slotmap",
"thiserror 1.0.69", "thiserror 2.0.4",
"void", "void",
] ]
@ -8652,7 +8668,7 @@ dependencies = [
"generic-array", "generic-array",
"hex", "hex",
"hkdf", "hkdf",
"hmac 0.12.1", "hmac",
"itoa 1.0.14", "itoa 1.0.14",
"log", "log",
"md-5", "md-5",
@ -8691,7 +8707,7 @@ dependencies = [
"futures-util", "futures-util",
"hex", "hex",
"hkdf", "hkdf",
"hmac 0.12.1", "hmac",
"home", "home",
"itoa 1.0.14", "itoa 1.0.14",
"log", "log",
@ -8960,14 +8976,13 @@ dependencies = [
"tempfile", "tempfile",
"testcontainers", "testcontainers",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
"tokio", "tokio",
"tokio-tar", "tokio-tar",
"tokio-tungstenite", "tokio-tungstenite",
"tokio-util", "tokio-util",
"toml 0.8.19", "toml 0.8.19",
"tor-rtcompat", "tor-rtcompat",
"torut",
"tower", "tower",
"tower-http", "tower-http",
"tracing", "tracing",
@ -9207,7 +9222,7 @@ dependencies = [
"tauri-runtime", "tauri-runtime",
"tauri-runtime-wry", "tauri-runtime-wry",
"tauri-utils", "tauri-utils",
"thiserror 2.0.3", "thiserror 2.0.4",
"tokio", "tokio",
"tray-icon", "tray-icon",
"url", "url",
@ -9260,8 +9275,8 @@ dependencies = [
"sha2 0.10.8", "sha2 0.10.8",
"syn 2.0.90", "syn 2.0.90",
"tauri-utils", "tauri-utils",
"thiserror 2.0.3", "thiserror 2.0.4",
"time 0.3.36", "time 0.3.37",
"url", "url",
"uuid", "uuid",
"walkdir", "walkdir",
@ -9368,7 +9383,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tauri", "tauri",
"thiserror 2.0.3", "thiserror 2.0.4",
"tracing", "tracing",
"windows-sys 0.59.0", "windows-sys 0.59.0",
"zbus", "zbus",
@ -9412,8 +9427,8 @@ dependencies = [
"tauri", "tauri",
"tauri-plugin", "tauri-plugin",
"tempfile", "tempfile",
"thiserror 2.0.3", "thiserror 2.0.4",
"time 0.3.36", "time 0.3.37",
"tokio", "tokio",
"url", "url",
"windows-sys 0.59.0", "windows-sys 0.59.0",
@ -9434,7 +9449,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tauri-utils", "tauri-utils",
"thiserror 2.0.3", "thiserror 2.0.4",
"url", "url",
"windows 0.58.0", "windows 0.58.0",
] ]
@ -9495,7 +9510,7 @@ dependencies = [
"serde_json", "serde_json",
"serde_with 3.11.0", "serde_with 3.11.0",
"swift-rs", "swift-rs",
"thiserror 2.0.3", "thiserror 2.0.4",
"toml 0.8.19", "toml 0.8.19",
"url", "url",
"urlpattern", "urlpattern",
@ -9546,7 +9561,7 @@ dependencies = [
"bollard-stubs", "bollard-stubs",
"futures", "futures",
"hex", "hex",
"hmac 0.12.1", "hmac",
"log", "log",
"rand 0.8.5", "rand 0.8.5",
"serde", "serde",
@ -9580,11 +9595,11 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.3" version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490"
dependencies = [ dependencies = [
"thiserror-impl 2.0.3", "thiserror-impl 2.0.4",
] ]
[[package]] [[package]]
@ -9600,9 +9615,9 @@ dependencies = [
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "2.0.3" version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -9643,9 +9658,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.36" version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa 1.0.14", "itoa 1.0.14",
@ -9666,9 +9681,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.18" version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",
@ -9710,9 +9725,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.41.1" version = "1.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -9982,6 +9997,7 @@ dependencies = [
"tor-bytes", "tor-bytes",
"tor-cert", "tor-cert",
"tor-error", "tor-error",
"tor-hscrypto",
"tor-linkspec", "tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
"tor-memquota", "tor-memquota",
@ -9996,6 +10012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b8eaa55aa20a3cab77943e176ed48f34c90d9ba0dc98c64adef6c15aef0bc8" checksum = "16b8eaa55aa20a3cab77943e176ed48f34c90d9ba0dc98c64adef6c15aef0bc8"
dependencies = [ dependencies = [
"caret", "caret",
"derive_builder_fork_arti",
"derive_more 1.0.0", "derive_more 1.0.0",
"digest 0.10.7", "digest 0.10.7",
"thiserror 1.0.69", "thiserror 1.0.69",
@ -10179,6 +10196,7 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
"tor-circmgr", "tor-circmgr",
"tor-error", "tor-error",
"tor-hscrypto",
"tor-linkspec", "tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
"tor-netdoc", "tor-netdoc",
@ -10220,7 +10238,7 @@ dependencies = [
"signature 2.2.0", "signature 2.2.0",
"strum", "strum",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
"tor-async-utils", "tor-async-utils",
"tor-basic-utils", "tor-basic-utils",
"tor-checkable", "tor-checkable",
@ -10310,13 +10328,58 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tor-hsclient"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ac236cd5ea5e96590e10adaf71cb0f48678d24da59b724b9cc7cfa552a14ba0"
dependencies = [
"async-trait",
"derive-deftly",
"derive_more 1.0.0",
"educe",
"either",
"futures",
"itertools",
"oneshot-fused-workaround",
"postage",
"rand 0.8.5",
"retry-error",
"safelog",
"slotmap-careful",
"strum",
"thiserror 1.0.69",
"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-rtcompat",
"tracing",
]
[[package]] [[package]]
name = "tor-hscrypto" name = "tor-hscrypto"
version = "0.24.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00099189e52d3376082b58139759249f16a53119d3d4f5f023168881c87d0a0" checksum = "f00099189e52d3376082b58139759249f16a53119d3d4f5f023168881c87d0a0"
dependencies = [ dependencies = [
"cipher",
"data-encoding", "data-encoding",
"derive-deftly",
"derive_more 1.0.0", "derive_more 1.0.0",
"digest 0.10.7", "digest 0.10.7",
"itertools", "itertools",
@ -10330,8 +10393,67 @@ dependencies = [
"tor-bytes", "tor-bytes",
"tor-error", "tor-error",
"tor-llcrypto", "tor-llcrypto",
"tor-memquota",
"tor-units", "tor-units",
"void", "void",
"zeroize",
]
[[package]]
name = "tor-hsservice"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eaf9ac91fff7b5e009da2a4c88b34db4ee8d6416a8cd2907659e715641169bd"
dependencies = [
"amplify",
"async-trait",
"base64ct",
"cfg-if",
"derive-deftly",
"derive_builder_fork_arti",
"derive_more 1.0.0",
"digest 0.10.7",
"educe",
"fs-mistrust",
"futures",
"growable-bloom-filter",
"hex",
"humantime",
"itertools",
"k12",
"once_cell",
"oneshot-fused-workaround",
"postage",
"rand 0.8.5",
"rand_core 0.6.4",
"retry-error",
"safelog",
"serde",
"serde_with 3.11.0",
"strum",
"thiserror 1.0.69",
"tor-async-utils",
"tor-basic-utils",
"tor-bytes",
"tor-cell",
"tor-circmgr",
"tor-config",
"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]] [[package]]
@ -10440,7 +10562,7 @@ dependencies = [
"serde", "serde",
"sha1", "sha1",
"sha2 0.10.8", "sha2 0.10.8",
"sha3 0.10.8", "sha3",
"signature 2.2.0", "signature 2.2.0",
"subtle", "subtle",
"thiserror 1.0.69", "thiserror 1.0.69",
@ -10502,7 +10624,9 @@ checksum = "68a99ad35659954aa280e678c3af2ab68934caaf55b94b947e2fb6f850598b5a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"derive_more 1.0.0", "derive_more 1.0.0",
"digest 0.10.7",
"futures", "futures",
"hex",
"humantime", "humantime",
"itertools", "itertools",
"num_enum", "num_enum",
@ -10511,8 +10635,10 @@ dependencies = [
"static_assertions", "static_assertions",
"strum", "strum",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.37",
"tor-basic-utils", "tor-basic-utils",
"tor-error", "tor-error",
"tor-hscrypto",
"tor-linkspec", "tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
"tor-netdoc", "tor-netdoc",
@ -10541,13 +10667,14 @@ dependencies = [
"itertools", "itertools",
"once_cell", "once_cell",
"phf 0.11.2", "phf 0.11.2",
"rand 0.8.5",
"serde", "serde",
"serde_with 3.11.0", "serde_with 3.11.0",
"signature 2.2.0", "signature 2.2.0",
"smallvec", "smallvec",
"subtle", "subtle",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
"tinystr", "tinystr",
"tor-basic-utils", "tor-basic-utils",
"tor-bytes", "tor-bytes",
@ -10555,8 +10682,11 @@ dependencies = [
"tor-cert", "tor-cert",
"tor-checkable", "tor-checkable",
"tor-error", "tor-error",
"tor-hscrypto",
"tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
"tor-protover", "tor-protover",
"tor-units",
"void", "void",
"weak-table", "weak-table",
"zeroize", "zeroize",
@ -10568,11 +10698,13 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b035192b529f6316c77d969f1e3be9f85d61ca1e1f946c91a96f987fdaba5e" checksum = "69b035192b529f6316c77d969f1e3be9f85d61ca1e1f946c91a96f987fdaba5e"
dependencies = [ dependencies = [
"amplify",
"derive-deftly", "derive-deftly",
"derive_more 1.0.0", "derive_more 1.0.0",
"filetime", "filetime",
"fs-mistrust", "fs-mistrust",
"fslock", "fslock",
"fslock-guard",
"futures", "futures",
"itertools", "itertools",
"oneshot-fused-workaround", "oneshot-fused-workaround",
@ -10606,7 +10738,7 @@ dependencies = [
"educe", "educe",
"futures", "futures",
"hkdf", "hkdf",
"hmac 0.12.1", "hmac",
"oneshot-fused-workaround", "oneshot-fused-workaround",
"pin-project", "pin-project",
"rand 0.8.5", "rand 0.8.5",
@ -10624,6 +10756,7 @@ dependencies = [
"tor-checkable", "tor-checkable",
"tor-config", "tor-config",
"tor-error", "tor-error",
"tor-hscrypto",
"tor-linkspec", "tor-linkspec",
"tor-llcrypto", "tor-llcrypto",
"tor-log-ratelim", "tor-log-ratelim",
@ -10633,6 +10766,7 @@ dependencies = [
"tor-units", "tor-units",
"tracing", "tracing",
"typenum", "typenum",
"visibility",
"void", "void",
"zeroize", "zeroize",
] ]
@ -10745,24 +10879,6 @@ dependencies = [
"tor-memquota", "tor-memquota",
] ]
[[package]]
name = "torut"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99febc413f26cf855b3a309c5872edff5c31e0ffe9c2fce5681868761df36f69"
dependencies = [
"base32",
"base64 0.13.1",
"derive_more 0.99.18",
"ed25519-dalek 1.0.1",
"hex",
"hmac 0.11.0",
"rand 0.7.3",
"sha2 0.9.9",
"sha3 0.9.1",
"tokio",
]
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.4.13" version = "0.4.13"
@ -10846,7 +10962,7 @@ checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -10908,7 +11024,7 @@ dependencies = [
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"time 0.3.36", "time 0.3.37",
"tracing", "tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
@ -11323,7 +11439,7 @@ dependencies = [
"cfg-if", "cfg-if",
"git2", "git2",
"rustversion", "rustversion",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -12295,7 +12411,7 @@ dependencies = [
"oid-registry 0.6.1", "oid-registry 0.6.1",
"rusticata-macros", "rusticata-macros",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -12312,7 +12428,7 @@ dependencies = [
"oid-registry 0.7.1", "oid-registry 0.7.1",
"rusticata-macros", "rusticata-macros",
"thiserror 1.0.69", "thiserror 1.0.69",
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -12348,9 +12464,9 @@ dependencies = [
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.8.23" version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432"
[[package]] [[package]]
name = "xmltree" name = "xmltree"
@ -12361,6 +12477,12 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "xxhash-rust"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984"
[[package]] [[package]]
name = "yamux" name = "yamux"
version = "0.12.1" version = "0.12.1"
@ -12398,7 +12520,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
dependencies = [ dependencies = [
"time 0.3.36", "time 0.3.37",
] ]
[[package]] [[package]]
@ -12597,7 +12719,7 @@ dependencies = [
"displaydoc", "displaydoc",
"indexmap 2.7.0", "indexmap 2.7.0",
"memchr", "memchr",
"thiserror 2.0.3", "thiserror 2.0.4",
] ]
[[package]] [[package]]

View file

@ -275,8 +275,14 @@ async fn initialize_context(
.to_string_lossy() .to_string_lossy()
.starts_with("monero-wallet-rpc") .starts_with("monero-wallet-rpc")
{ {
println!("Killing monero-wallet-rpc process with pid: {}", pid); #[cfg(not(debug_assertions))]
process.kill(); {
println!("Killing monero-wallet-rpc process with pid: {}", pid);
process.kill();
}
#[cfg(debug_assertions)]
println!("Would kill monero-wallet-rpc process with pid: {}", pid);
} }
} }

View file

@ -42,7 +42,7 @@ hex = "0.4"
jsonrpsee = { version = "0.16.2", features = [ "server" ] } jsonrpsee = { version = "0.16.2", features = [ "server" ] }
jsonrpsee-core = "0.16.2" jsonrpsee-core = "0.16.2"
libp2p = { version = "0.53.2", features = [ "tcp", "yamux", "dns", "noise", "request-response", "ping", "rendezvous", "identify", "macros", "cbor", "json", "tokio", "serde", "rsa" ] } libp2p = { version = "0.53.2", features = [ "tcp", "yamux", "dns", "noise", "request-response", "ping", "rendezvous", "identify", "macros", "cbor", "json", "tokio", "serde", "rsa" ] }
libp2p-community-tor = { git = "https://github.com/UnstoppableSwap/libp2p-tor", branch = "main" } libp2p-community-tor = { git = "https://github.com/UnstoppableSwap/libp2p-tor", branch = "fix/announce-address-immed", features = [ "listen-onion-service" ] }
monero = { version = "0.12", features = [ "serde_support" ] } monero = { version = "0.12", features = [ "serde_support" ] }
monero-rpc = { path = "../monero-rpc" } monero-rpc = { path = "../monero-rpc" }
once_cell = "1.19" once_cell = "1.19"
@ -96,10 +96,6 @@ tokio-tungstenite = { version = "0.15", features = [ "rustls-tls" ] }
tokio-util = { version = "0.7", features = [ "io", "codec" ] } tokio-util = { version = "0.7", features = [ "io", "codec" ] }
toml = "0.8" toml = "0.8"
tor-rtcompat = "0.24.0" tor-rtcompat = "0.24.0"
torut = { version = "0.2", default-features = false, features = [
"v3",
"control",
] }
tower = { version = "0.4.13", features = [ "full" ] } tower = { version = "0.4.13", features = [ "full" ] }
tower-http = { version = "0.3.4", features = [ "full" ] } tower-http = { version = "0.3.4", features = [ "full" ] }
tracing = { version = "0.1", features = [ "attributes" ] } tracing = { version = "0.1", features = [ "attributes" ] }

View file

@ -1,10 +1,9 @@
use crate::env::{Mainnet, Testnet}; use crate::env::{Mainnet, Testnet};
use crate::fs::{ensure_directory_exists, system_config_dir, system_data_dir}; use crate::fs::{ensure_directory_exists, system_config_dir, system_data_dir};
use crate::tor::{DEFAULT_CONTROL_PORT, DEFAULT_SOCKS5_PORT};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use config::ConfigError; use config::ConfigError;
use dialoguer::theme::ColorfulTheme; use dialoguer::theme::ColorfulTheme;
use dialoguer::Input; use dialoguer::{Input, Select};
use libp2p::core::Multiaddr; use libp2p::core::Multiaddr;
use rust_decimal::prelude::FromPrimitive; use rust_decimal::prelude::FromPrimitive;
use rust_decimal::Decimal; use rust_decimal::Decimal;
@ -200,8 +199,8 @@ pub struct Monero {
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct TorConf { pub struct TorConf {
pub control_port: u16, pub register_hidden_service: bool,
pub socks5_port: u16, pub hidden_service_num_intro_points: u8,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
@ -219,8 +218,8 @@ pub struct Maker {
impl Default for TorConf { impl Default for TorConf {
fn default() -> Self { fn default() -> Self {
Self { Self {
control_port: DEFAULT_CONTROL_PORT, register_hidden_service: true,
socks5_port: DEFAULT_SOCKS5_PORT, hidden_service_num_intro_points: 5,
} }
} }
} }
@ -313,15 +312,12 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
.default(defaults.monero_wallet_rpc_url) .default(defaults.monero_wallet_rpc_url)
.interact_text()?; .interact_text()?;
let tor_control_port = Input::with_theme(&ColorfulTheme::default()) let register_hidden_service = Select::with_theme(&ColorfulTheme::default())
.with_prompt("Enter Tor control port or hit enter to use default. If Tor is not running on your machine, no hidden service will be created.") .with_prompt("Do you want a Tor hidden service to be created? This will allow you to run from behind a firewall without opening ports, and hide your IP address. You do not have to run a Tor daemon yourself. We recommend this for most users. (y/n)")
.default(DEFAULT_CONTROL_PORT.to_owned()) .items(&["yes", "no"])
.interact_text()?; .default(0)
.interact()?
let tor_socks5_port = Input::with_theme(&ColorfulTheme::default()) == 0;
.with_prompt("Enter Tor socks5 port or hit enter to use default")
.default(DEFAULT_SOCKS5_PORT.to_owned())
.interact_text()?;
let min_buy = Input::with_theme(&ColorfulTheme::default()) let min_buy = Input::with_theme(&ColorfulTheme::default())
.with_prompt("Enter minimum Bitcoin amount you are willing to accept per swap or hit enter to use default.") .with_prompt("Enter minimum Bitcoin amount you are willing to accept per swap or hit enter to use default.")
@ -387,8 +383,8 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
network: monero_network, network: monero_network,
}, },
tor: TorConf { tor: TorConf {
control_port: tor_control_port, register_hidden_service,
socks5_port: tor_socks5_port, ..Default::default()
}, },
maker: Maker { maker: Maker {
min_buy_btc: min_buy, min_buy_btc: min_buy,

View file

@ -490,7 +490,7 @@ where
) )
})?; })?;
tracing::debug!(%ask_price, %xmr_balance, %max_bitcoin_for_monero, "Computed quote"); tracing::trace!(%ask_price, %xmr_balance, %max_bitcoin_for_monero, "Computed quote");
if min_buy > max_bitcoin_for_monero { if min_buy > max_bitcoin_for_monero {
tracing::trace!( tracing::trace!(

View file

@ -22,16 +22,81 @@ use std::time::Duration;
use uuid::Uuid; use uuid::Uuid;
pub mod transport { pub mod transport {
use libp2p::{dns, identity, tcp, Transport}; use std::sync::Arc;
use arti_client::{config::onion_service::OnionServiceConfigBuilder, TorClient};
use libp2p::{core::transport::OptionalTransport, dns, identity, tcp, Transport};
use libp2p_community_tor::AddressConversion;
use tor_rtcompat::tokio::TokioRustlsRuntime;
use super::*; use super::*;
static ASB_ONION_SERVICE_NICKNAME: &str = "asb";
static ASB_ONION_SERVICE_PORT: u16 = 9939;
type OnionTransportWithAddresses = (Boxed<(PeerId, StreamMuxerBox)>, Vec<Multiaddr>);
/// Creates the libp2p transport for the ASB. /// Creates the libp2p transport for the ASB.
pub fn new(identity: &identity::Keypair) -> Result<Boxed<(PeerId, StreamMuxerBox)>> { ///
let tcp = tcp::tokio::Transport::new(tcp::Config::new().nodelay(true)); /// If you pass in a `None` for `maybe_tor_client`, the ASB will not use Tor at all.
///
/// If you pass in a `Some(tor_client)`, the ASB will listen on an onion service and return
/// the onion address. If it fails to listen on the onion address, it will only use tor for
/// dialing and not listening.
pub fn new(
identity: &identity::Keypair,
maybe_tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
num_intro_points: u8,
register_hidden_service: bool,
) -> Result<OnionTransportWithAddresses> {
let (maybe_tor_transport, onion_addresses) = if let Some(tor_client) = maybe_tor_client {
let mut tor_transport = libp2p_community_tor::TorTransport::from_client(
tor_client,
AddressConversion::DnsOnly,
);
let addresses = if register_hidden_service {
let onion_service_config = OnionServiceConfigBuilder::default()
.nickname(
ASB_ONION_SERVICE_NICKNAME
.parse()
.expect("Static nickname to be valid"),
)
.num_intro_points(num_intro_points)
.build()
.expect("We specified a valid nickname");
match tor_transport.add_onion_service(onion_service_config, ASB_ONION_SERVICE_PORT)
{
Ok(addr) => {
tracing::debug!(
%addr,
"Setting up onion service for libp2p to listen on"
);
vec![addr]
}
Err(err) => {
tracing::warn!(error=%err, "Failed to listen on onion address");
vec![]
}
}
} else {
vec![]
};
(OptionalTransport::some(tor_transport), addresses)
} else {
(OptionalTransport::none(), vec![])
};
let tcp = maybe_tor_transport
.or_transport(tcp::tokio::Transport::new(tcp::Config::new().nodelay(true)));
let tcp_with_dns = dns::tokio::Transport::system(tcp)?; let tcp_with_dns = dns::tokio::Transport::system(tcp)?;
authenticate_and_multiplex(tcp_with_dns.boxed(), identity) Ok((
authenticate_and_multiplex(tcp_with_dns.boxed(), identity)?,
onion_addresses,
))
} }
} }

View file

@ -14,12 +14,9 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use comfy_table::Table; use comfy_table::Table;
use libp2p::core::multiaddr::Protocol;
use libp2p::core::Multiaddr;
use libp2p::Swarm; use libp2p::Swarm;
use std::convert::TryInto; use std::convert::TryInto;
use std::env; use std::env;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc; use std::sync::Arc;
use structopt::clap; use structopt::clap;
use structopt::clap::ErrorKind; use structopt::clap::ErrorKind;
@ -28,6 +25,7 @@ use swap::asb::config::{
initial_setup, query_user_for_initial_config, read_config, Config, ConfigNotInitialized, initial_setup, query_user_for_initial_config, read_config, Config, ConfigNotInitialized,
}; };
use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, Finality, KrakenRate}; use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, Finality, KrakenRate};
use swap::common::tor::init_tor_client;
use swap::common::tracing_util::Format; use swap::common::tracing_util::Format;
use swap::common::{self, get_logs, warn_if_outdated}; use swap::common::{self, get_logs, warn_if_outdated};
use swap::database::{open_db, AccessMode}; use swap::database::{open_db, AccessMode};
@ -35,8 +33,7 @@ use swap::network::rendezvous::XmrBtcNamespace;
use swap::network::swarm; use swap::network::swarm;
use swap::protocol::alice::{run, AliceState}; use swap::protocol::alice::{run, AliceState};
use swap::seed::Seed; use swap::seed::Seed;
use swap::tor::AuthenticatedClient; use swap::{bitcoin, kraken, monero};
use swap::{bitcoin, kraken, monero, tor};
use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::filter::LevelFilter;
const DEFAULT_WALLET_NAME: &str = "asb-wallet"; const DEFAULT_WALLET_NAME: &str = "asb-wallet";
@ -149,29 +146,16 @@ pub async fn main() -> Result<()> {
let bitcoin_balance = bitcoin_wallet.balance().await?; let bitcoin_balance = bitcoin_wallet.balance().await?;
tracing::info!(%bitcoin_balance, "Bitcoin wallet balance"); tracing::info!(%bitcoin_balance, "Bitcoin wallet balance");
// Connect to Kraken
let kraken_price_updates = kraken::connect(config.maker.price_ticker_ws_url.clone())?; let kraken_price_updates = kraken::connect(config.maker.price_ticker_ws_url.clone())?;
// Setup Tor hidden services
let tor_client =
tor::Client::new(config.tor.socks5_port).with_control_port(config.tor.control_port);
let _ac = match tor_client.assert_tor_running().await {
Ok(_) => {
tracing::info!("Setting up Tor hidden service");
let ac =
register_tor_services(config.network.clone().listen, tor_client, &seed)
.await?;
Some(ac)
}
Err(_) => {
tracing::warn!("Tor not found. Running on clear net");
None
}
};
let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates); let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates);
let namespace = XmrBtcNamespace::from_is_testnet(testnet); let namespace = XmrBtcNamespace::from_is_testnet(testnet);
let mut swarm = swarm::asb( // Initialize Tor client
let tor_client = init_tor_client(&config.data.dir).await?.into();
let (mut swarm, onion_addresses) = swarm::asb(
&seed, &seed,
config.maker.min_buy_btc, config.maker.min_buy_btc,
config.maker.max_buy_btc, config.maker.max_buy_btc,
@ -180,6 +164,8 @@ pub async fn main() -> Result<()> {
env_config, env_config,
namespace, namespace,
&rendezvous_addrs, &rendezvous_addrs,
tor_client,
config.tor,
)?; )?;
for listen in config.network.listen.clone() { for listen in config.network.listen.clone() {
@ -188,10 +174,25 @@ pub async fn main() -> Result<()> {
} }
} }
for onion_address in onion_addresses {
match swarm.listen_on(onion_address.clone()) {
Err(e) => {
tracing::warn!(
"Failed to listen on onion address {}: {}",
onion_address,
e
);
}
_ => {
swarm.add_external_address(onion_address);
}
}
}
tracing::info!(peer_id = %swarm.local_peer_id(), "Network layer initialized"); tracing::info!(peer_id = %swarm.local_peer_id(), "Network layer initialized");
for external_address in config.network.external_addresses { for external_address in config.network.external_addresses {
Swarm::add_external_address(&mut swarm, external_address); swarm.add_external_address(external_address);
} }
let (event_loop, mut swap_receiver) = EventLoop::new( let (event_loop, mut swap_receiver) = EventLoop::new(
@ -391,46 +392,3 @@ async fn init_monero_wallet(
Ok(wallet) Ok(wallet)
} }
/// Registers a hidden service for each network.
/// Note: Once ac goes out of scope, the services will be de-registered.
async fn register_tor_services(
networks: Vec<Multiaddr>,
tor_client: tor::Client,
seed: &Seed,
) -> Result<AuthenticatedClient> {
let mut ac = tor_client.into_authenticated_client().await?;
let hidden_services_details = networks
.iter()
.flat_map(|network| {
network.iter().map(|protocol| match protocol {
Protocol::Tcp(port) => Some((
port,
SocketAddr::new(IpAddr::from(Ipv4Addr::new(127, 0, 0, 1)), port),
)),
_ => {
// We only care for Tcp for now.
None
}
})
})
.flatten()
.collect::<Vec<_>>();
let key = seed.derive_torv3_key();
ac.add_services(&hidden_services_details, &key).await?;
let onion_address = key
.public()
.get_onion_address()
.get_address_without_dot_onion();
hidden_services_details.iter().for_each(|(port, _)| {
let onion_address = format!("/onion3/{}:{}", onion_address, port);
tracing::info!(%onion_address, "Successfully created hidden service");
});
Ok(ac)
}

View file

@ -4,7 +4,6 @@ pub mod cancel_and_refund;
pub mod command; pub mod command;
mod event_loop; mod event_loop;
mod list_sellers; mod list_sellers;
mod tor;
pub mod transport; pub mod transport;
pub mod watcher; pub mod watcher;

View file

@ -2,6 +2,7 @@ pub mod request;
pub mod tauri_bindings; pub mod tauri_bindings;
use crate::cli::command::{Bitcoin, Monero}; use crate::cli::command::{Bitcoin, Monero};
use crate::common::tor::init_tor_client;
use crate::common::tracing_util::Format; use crate::common::tracing_util::Format;
use crate::database::{open_db, AccessMode}; use crate::database::{open_db, AccessMode};
use crate::env::{Config as EnvConfig, GetConfig, Mainnet, Testnet}; use crate::env::{Config as EnvConfig, GetConfig, Mainnet, Testnet};
@ -29,7 +30,6 @@ use tracing::Level;
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
use super::tor::init_tor_client;
use super::watcher::Watcher; use super::watcher::Watcher;
static START: Once = Once::new(); static START: Once = Once::new();

View file

@ -1,3 +1,4 @@
pub mod tor;
pub mod tracing_util; pub mod tracing_util;
use anyhow::anyhow; use anyhow::anyhow;

View file

@ -21,6 +21,8 @@ pub async fn init_tor_client(data_dir: &Path) -> Result<Arc<TorClient<TokioRustl
// It uses cached information when possible.) // It uses cached information when possible.)
let runtime = TokioRustlsRuntime::current().expect("We are always running with tokio"); let runtime = TokioRustlsRuntime::current().expect("We are always running with tokio");
tracing::debug!("Bootstrapping Tor client");
let tor_client = TorClient::with_runtime(runtime) let tor_client = TorClient::with_runtime(runtime)
.config(config) .config(config)
.create_bootstrapped() .create_bootstrapped()

View file

@ -31,9 +31,19 @@ pub fn init(
dir: impl AsRef<Path>, dir: impl AsRef<Path>,
tauri_handle: Option<TauriHandle>, tauri_handle: Option<TauriHandle>,
) -> Result<()> { ) -> Result<()> {
// file logger will always write in JSON format and with timestamps let ALL_CRATES: Vec<&str> = vec![
"swap",
"asb",
"libp2p_community_tor",
"unstoppableswap-gui-rs",
"arti",
];
let OUR_CRATES: Vec<&str> = vec!["swap", "asb"];
// General log file for non-verbose logs
let file_appender: RollingFileAppender = tracing_appender::rolling::never(&dir, "swap-all.log"); let file_appender: RollingFileAppender = tracing_appender::rolling::never(&dir, "swap-all.log");
// Verbose log file, rotated hourly, with a maximum of 24 files
let tracing_file_appender: RollingFileAppender = RollingFileAppender::builder() let tracing_file_appender: RollingFileAppender = RollingFileAppender::builder()
.rotation(Rotation::HOURLY) .rotation(Rotation::HOURLY)
.filename_prefix("tracing") .filename_prefix("tracing")
@ -42,24 +52,31 @@ pub fn init(
.build(&dir) .build(&dir)
.expect("initializing rolling file appender failed"); .expect("initializing rolling file appender failed");
// Log to file // Layer for writing to the general log file
// Crates: swap, asb
// Level: Passed in
let file_layer = fmt::layer() let file_layer = fmt::layer()
.with_writer(file_appender) .with_writer(file_appender)
.with_ansi(false) .with_ansi(false)
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(false) .with_target(false)
.json() .json()
.with_filter(env_filter(level_filter)?); .with_filter(env_filter(level_filter, OUR_CRATES.clone())?);
// Layer for writing to the verbose log file
// Crates: swap, asb, libp2p_community_tor, unstoppableswap-gui-rs, arti (all relevant crates)
// Level: TRACE
let tracing_file_layer = fmt::layer() let tracing_file_layer = fmt::layer()
.with_writer(tracing_file_appender) .with_writer(tracing_file_appender)
.with_ansi(false) .with_ansi(false)
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(false) .with_target(false)
.json() .json()
.with_filter(env_filter(LevelFilter::TRACE)?); .with_filter(env_filter(LevelFilter::TRACE, ALL_CRATES.clone())?);
// Log to stdout // Layer for writing to the terminal
// Crates: swap, asb
// Level: Passed in
let is_terminal = atty::is(atty::Stream::Stderr); let is_terminal = atty::is(atty::Stream::Stderr);
let terminal_layer = fmt::layer() let terminal_layer = fmt::layer()
.with_writer(std::io::stdout) .with_writer(std::io::stdout)
@ -67,17 +84,23 @@ pub fn init(
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(false); .with_target(false);
// Forwards logs to the tauri guest // Layer for writing to the Tauri guest. This will be displayed in the GUI.
// Crates: swap, asb, libp2p_community_tor, unstoppableswap-gui-rs, arti
// Level: Passed in
let tauri_layer = fmt::layer() let tauri_layer = fmt::layer()
.with_writer(TauriWriter::new(tauri_handle)) .with_writer(TauriWriter::new(tauri_handle))
.with_ansi(false) .with_ansi(false)
.with_timer(UtcTime::rfc_3339()) .with_timer(UtcTime::rfc_3339())
.with_target(true) .with_target(true)
.json() .json()
.with_filter(env_filter(level_filter)?); .with_filter(env_filter(level_filter, ALL_CRATES.clone())?);
let env_filtered = env_filter(level_filter)?; // We only log the bare minimum to the terminal
// Crates: swap, asb
// Level: Passed in
let env_filtered = env_filter(level_filter, OUR_CRATES.clone())?;
// Apply the environment filter and box the layer for the terminal
let final_terminal_layer = match format { let final_terminal_layer = match format {
Format::Json => terminal_layer.json().with_filter(env_filtered).boxed(), Format::Json => terminal_layer.json().with_filter(env_filtered).boxed(),
Format::Raw => terminal_layer.with_filter(env_filtered).boxed(), Format::Raw => terminal_layer.with_filter(env_filtered).boxed(),
@ -97,19 +120,18 @@ pub fn init(
} }
/// This function controls which crate's logs actually get logged and from which level. /// This function controls which crate's logs actually get logged and from which level.
fn env_filter(level_filter: LevelFilter) -> Result<EnvFilter> { fn env_filter(level_filter: LevelFilter, crates: Vec<&str>) -> Result<EnvFilter> {
Ok(EnvFilter::from_default_env() let mut filter = EnvFilter::from_default_env();
.add_directive(Directive::from_str(&format!("asb={}", &level_filter))?)
.add_directive(Directive::from_str(&format!("swap={}", &level_filter))?) // Add directives for each crate in the provided list
.add_directive(Directive::from_str(&format!("arti={}", &level_filter))?) for crate_name in crates {
.add_directive(Directive::from_str(&format!( filter = filter.add_directive(Directive::from_str(&format!(
"libp2p_community_tor={}", "{}={}",
&level_filter crate_name, &level_filter
))?) ))?);
.add_directive(Directive::from_str(&format!( }
"unstoppableswap-gui-rs={}",
&level_filter Ok(filter)
))?))
} }
/// A writer that forwards tracing log messages to the tauri guest. /// A writer that forwards tracing log messages to the tauri guest.

View file

@ -31,7 +31,6 @@ pub mod network;
pub mod protocol; pub mod protocol;
pub mod rpc; pub mod rpc;
pub mod seed; pub mod seed;
pub mod tor;
pub mod tracing_ext; pub mod tracing_ext;
#[cfg(test)] #[cfg(test)]

View file

@ -1,3 +1,4 @@
use crate::asb::config::TorConf;
use crate::asb::{LatestRate, RendezvousNode}; use crate::asb::{LatestRate, RendezvousNode};
use crate::libp2p_ext::MultiAddrExt; use crate::libp2p_ext::MultiAddrExt;
use crate::network::rendezvous::XmrBtcNamespace; use crate::network::rendezvous::XmrBtcNamespace;
@ -23,7 +24,9 @@ pub fn asb<LR>(
env_config: env::Config, env_config: env::Config,
namespace: XmrBtcNamespace, namespace: XmrBtcNamespace,
rendezvous_addrs: &[Multiaddr], rendezvous_addrs: &[Multiaddr],
) -> Result<Swarm<asb::Behaviour<LR>>> maybe_tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
tor_conf: TorConf,
) -> Result<(Swarm<asb::Behaviour<LR>>, Vec<Multiaddr>)>
where where
LR: LatestRate + Send + 'static + Debug + Clone, LR: LatestRate + Send + 'static + Debug + Clone,
{ {
@ -50,7 +53,12 @@ where
rendezvous_nodes, rendezvous_nodes,
); );
let transport = asb::transport::new(&identity)?; let (transport, onion_addresses) = asb::transport::new(
&identity,
maybe_tor_client,
tor_conf.hidden_service_num_intro_points,
tor_conf.register_hidden_service,
)?;
let swarm = SwarmBuilder::with_existing_identity(identity) let swarm = SwarmBuilder::with_existing_identity(identity)
.with_tokio() .with_tokio()
@ -59,7 +67,7 @@ where
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::MAX)) .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::MAX))
.build(); .build();
Ok(swarm) Ok((swarm, onion_addresses))
} }
pub async fn cli<T>( pub async fn cli<T>(

View file

@ -12,7 +12,6 @@ use std::fmt;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use torut::onion::TorSecretKeyV3;
pub const SEED_LENGTH: usize = 32; pub const SEED_LENGTH: usize = 32;
@ -47,14 +46,6 @@ impl Seed {
identity::Keypair::ed25519_from_bytes(bytes).expect("we always pass 32 bytes") identity::Keypair::ed25519_from_bytes(bytes).expect("we always pass 32 bytes")
} }
pub fn derive_torv3_key(&self) -> TorSecretKeyV3 {
let bytes = self.derive(b"TOR").bytes();
let sk = ed25519_dalek::SecretKey::from_bytes(&bytes)
.expect("Failed to create a new extended secret key for Tor.");
let esk = ed25519_dalek::ExpandedSecretKey::from(&sk);
esk.to_bytes().into()
}
pub fn from_file_or_generate(data_dir: &Path) -> Result<Self, Error> { pub fn from_file_or_generate(data_dir: &Path) -> Result<Self, Error> {
let file_path_buf = data_dir.join("seed.pem"); let file_path_buf = data_dir.join("seed.pem");
let file_path = Path::new(&file_path_buf); let file_path = Path::new(&file_path_buf);

View file

@ -1,128 +0,0 @@
use anyhow::{bail, Context, Result};
use std::future::Future;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use tokio::net::TcpStream;
use torut::control::{AsyncEvent, AuthenticatedConn, ConnError, UnauthenticatedConn};
use torut::onion::TorSecretKeyV3;
pub const DEFAULT_SOCKS5_PORT: u16 = 9050;
pub const DEFAULT_CONTROL_PORT: u16 = 9051;
#[derive(Debug, Clone, Copy)]
pub struct Client {
socks5_address: SocketAddrV4,
control_port_address: SocketAddr,
}
impl Default for Client {
fn default() -> Self {
Self {
socks5_address: SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_SOCKS5_PORT),
control_port_address: SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::LOCALHOST,
DEFAULT_CONTROL_PORT,
)),
}
}
}
impl Client {
pub fn new(socks5_port: u16) -> Self {
Self {
socks5_address: SocketAddrV4::new(Ipv4Addr::LOCALHOST, socks5_port),
control_port_address: SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::LOCALHOST,
DEFAULT_CONTROL_PORT,
)),
}
}
pub fn with_control_port(self, control_port: u16) -> Self {
Self {
control_port_address: SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::LOCALHOST,
control_port,
)),
..self
}
}
/// checks if tor is running
pub async fn assert_tor_running(&self) -> Result<()> {
// Make sure you are running tor and this is your socks port
let proxy = reqwest::Proxy::all(format!("socks5h://{}", self.socks5_address).as_str())
.context("Failed to construct Tor proxy URL")?;
let client = reqwest::Client::builder().proxy(proxy).build()?;
let res = client.get("https://check.torproject.org").send().await?;
let text = res.text().await?;
if !text.contains("Congratulations. This browser is configured to use Tor.") {
bail!("Tor is currently not running")
}
Ok(())
}
async fn init_unauthenticated_connection(&self) -> Result<UnauthenticatedConn<TcpStream>> {
// Connect to local tor service via control port
let sock = TcpStream::connect(self.control_port_address).await?;
let uc = UnauthenticatedConn::new(sock);
Ok(uc)
}
/// Create a new authenticated connection to your local Tor service
pub async fn into_authenticated_client(self) -> Result<AuthenticatedClient> {
self.assert_tor_running().await?;
let mut uc = self
.init_unauthenticated_connection()
.await
.context("Failed to connect to Tor")?;
let tor_info = uc
.load_protocol_info()
.await
.context("Failed to load protocol info from Tor")?;
let tor_auth_data = tor_info
.make_auth_data()?
.context("Failed to make Tor auth data")?;
// Get an authenticated connection to the Tor via the Tor Controller protocol.
uc.authenticate(&tor_auth_data)
.await
.context("Failed to authenticate with Tor")?;
Ok(AuthenticatedClient {
inner: uc.into_authenticated().await,
})
}
pub fn tor_proxy_port(&self) -> u16 {
self.socks5_address.port()
}
}
type Handler = fn(AsyncEvent<'_>) -> Box<dyn Future<Output = Result<(), ConnError>> + Unpin>;
#[allow(missing_debug_implementations)]
pub struct AuthenticatedClient {
inner: AuthenticatedConn<TcpStream, Handler>,
}
impl AuthenticatedClient {
/// Add an ephemeral tor service on localhost with the provided key
/// `service_port` and `onion_port` can be different but don't have to as
/// they are on different networks.
pub async fn add_services(
&mut self,
services: &[(u16, SocketAddr)],
tor_key: &TorSecretKeyV3,
) -> Result<()> {
let mut listeners = services.iter();
self.inner
.add_onion_v3(tor_key, false, false, false, None, &mut listeners)
.await
.context("Failed to add onion service")
}
}

View file

@ -243,7 +243,7 @@ async fn start_alice(
let latest_rate = FixedRate::default(); let latest_rate = FixedRate::default();
let resume_only = false; let resume_only = false;
let mut swarm = swarm::asb( let (mut swarm, _) = swarm::asb(
seed, seed,
min_buy, min_buy,
max_buy, max_buy,
@ -252,6 +252,7 @@ async fn start_alice(
env_config, env_config,
XmrBtcNamespace::Testnet, XmrBtcNamespace::Testnet,
&[], &[],
None,
) )
.unwrap(); .unwrap();
swarm.listen_on(listen_address).unwrap(); swarm.listen_on(listen_address).unwrap();