From a803f3c76e21c2ffe1e13ba2ed826346f945da52 Mon Sep 17 00:00:00 2001 From: DanGould Date: Mon, 27 Nov 2023 11:37:55 -0500 Subject: [PATCH] [Draft] Swap rouille for hyper --- payjoin-cli/Cargo.lock | 762 ++++++++++++++++++---------------------- payjoin-cli/Cargo.toml | 10 +- payjoin-cli/src/app.rs | 384 ++++++++++---------- payjoin-cli/src/main.rs | 7 +- 4 files changed, 548 insertions(+), 615 deletions(-) diff --git a/payjoin-cli/Cargo.lock b/payjoin-cli/Cargo.lock index f568c469..fdb8ac67 100644 --- a/payjoin-cli/Cargo.lock +++ b/payjoin-cli/Cargo.lock @@ -17,12 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "ahash" version = "0.7.6" @@ -43,97 +37,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" -dependencies = [ - "anstyle", - "windows-sys", -] - [[package]] name = "anyhow" version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - [[package]] name = "async-trait" version = "0.1.72" @@ -142,7 +51,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -268,12 +177,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" - [[package]] name = "block-buffer" version = "0.10.4" @@ -283,37 +186,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" version = "3.13.0" @@ -328,9 +200,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -341,56 +213,44 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "winapi", -] - -[[package]] -name = "chunked_transfer" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca491388666e04d7248af3f60f0c40cfb0991c72205595d7c396e3510207d1a" - [[package]] name = "clap" -version = "4.3.19" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "clap_builder", + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", ] [[package]] -name = "clap_builder" -version = "4.3.19" +name = "clap_derive" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "colorchoice" -version = "1.0.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] [[package]] name = "config" @@ -436,15 +296,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -455,16 +306,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", - "gzip-header", -] - [[package]] name = "digest" version = "0.10.7" @@ -526,20 +367,11 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" - -[[package]] -name = "filetime" -version = "0.2.22" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys", + "instant", ] [[package]] @@ -647,15 +479,6 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -[[package]] -name = "gzip-header" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" -dependencies = [ - "crc32fast", -] - [[package]] name = "h2" version = "0.3.20" @@ -684,6 +507,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -769,6 +598,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "log", + "rustls 0.21.9", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -782,29 +627,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[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 = "idna" version = "0.4.0" @@ -826,22 +648,31 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.8.0" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] [[package]] -name = "is-terminal" -version = "0.4.9" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.2", - "rustix", + "libc", "windows-sys", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "itoa" version = "1.0.9" @@ -887,9 +718,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linked-hash-map" @@ -899,21 +730,31 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" -version = "0.4.19" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -921,16 +762,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -957,24 +788,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", -] - [[package]] name = "native-tls" version = "0.2.11" @@ -1003,15 +816,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - [[package]] name = "num_cpus" version = "1.16.0" @@ -1022,15 +826,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "object" version = "0.31.1" @@ -1052,7 +847,7 @@ version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -1069,7 +864,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -1110,6 +905,35 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -1137,12 +961,16 @@ dependencies = [ "clap", "config", "env_logger", + "hyper", + "hyper-rustls", "log", "payjoin", "rcgen", "reqwest", - "rouille", + "rustls 0.20.8", "serde", + "tokio", + "url", ] [[package]] @@ -1197,7 +1025,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -1235,6 +1063,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.66" @@ -1244,12 +1096,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.32" @@ -1296,7 +1142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4954fbc00dcd4d8282c987710e50ba513d351400dbdd00e803a05172a90d8976" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] @@ -1307,14 +1153,23 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.3.2", + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", ] [[package]] name = "regex" -version = "1.9.3" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", @@ -1324,9 +1179,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", @@ -1335,9 +1190,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" @@ -1385,45 +1240,35 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] [[package]] -name = "ron" -version = "0.7.1" +name = "ring" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "serde", + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", ] [[package]] -name = "rouille" -version = "3.6.2" +name = "ron" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3716fbf57fc1084d7a706adf4e445298d123e4a44294c4e8213caf1b85fcc921" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" dependencies = [ "base64 0.13.1", - "brotli", - "chrono", - "deflate", - "filetime", - "multipart", - "percent-encoding", - "rand", + "bitflags", "serde", - "serde_derive", - "serde_json", - "sha1_smol", - "threadpool", - "time", - "tiny_http", - "url", ] [[package]] @@ -1444,28 +1289,78 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.7" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ - "bitflags 2.3.3", + "bitflags", "errno", + "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", ] [[package]] -name = "ryu" -version = "1.0.15" +name = "rustls" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +dependencies = [ + "log", + "ring 0.17.5", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.2", +] [[package]] -name = "safemem" -version = "0.3.3" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schannel" @@ -1476,6 +1371,22 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + [[package]] name = "secp256k1" version = "0.27.0" @@ -1503,7 +1414,7 @@ version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -1537,7 +1448,7 @@ checksum = "6f4c2c6ea4bc09b5c419012eafcdb0fcef1d9119d626c8f3a0708a5b92d38a70" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -1563,12 +1474,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" version = "0.10.7" @@ -1580,6 +1485,15 @@ dependencies = [ "digest", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.8" @@ -1589,6 +1503,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + [[package]] name = "socket2" version = "0.4.9" @@ -1605,12 +1525,29 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[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.28" @@ -1624,13 +1561,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys", ] @@ -1644,6 +1582,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.44" @@ -1661,16 +1605,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", + "syn 2.0.28", ] [[package]] @@ -1679,8 +1614,6 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ - "libc", - "num_threads", "serde", "time-core", ] @@ -1691,20 +1624,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" -[[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", - "openssl", - "zeroize", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -1732,11 +1651,25 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys", ] +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -1747,6 +1680,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.9", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.8" @@ -1802,15 +1745,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - [[package]] name = "typenum" version = "1.16.0" @@ -1823,15 +1757,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -1859,6 +1784,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.0" @@ -1870,12 +1801,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "vcpkg" version = "0.2.15" @@ -1924,7 +1849,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -1958,7 +1883,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1979,6 +1904,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" +dependencies = [ + "ring 0.16.20", + "untrusted 0.7.1", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2010,15 +1945,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -2111,9 +2037,3 @@ checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ "time", ] - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/payjoin-cli/Cargo.toml b/payjoin-cli/Cargo.toml index c16e50d1..b8af3366 100644 --- a/payjoin-cli/Cargo.toml +++ b/payjoin-cli/Cargo.toml @@ -14,18 +14,22 @@ path = "src/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] native-tls-vendored = ["reqwest/native-tls-vendored"] -local-https = ["rcgen", "rouille/ssl"] +local-https = ["rcgen", "rustls", "hyper-rustls"] [dependencies] anyhow = "1.0.70" bip21 = "0.3.1" bitcoincore-rpc = "0.17.0" -clap = "4.1.4" +clap = { version = "3.2.22", features = ["derive"] } config = "0.13.3" env_logger = "0.9.0" +hyper = { version = "0.14", features = ["full"] } +hyper-rustls = { version = "0.24", optional = true } log = "0.4.7" payjoin = { path = "../payjoin", features = ["send", "receive", "base64"] } reqwest = { version = "0.11.4", features = ["blocking"] } rcgen = { version = "0.11.1", optional = true } -rouille = "3.6.2" +rustls = { version = "0.20", optional = true } serde = { version = "1.0.160", features = ["derive"] } +tokio = { version = "1.12.0", features = ["full"] } +url = "2.2.1" diff --git a/payjoin-cli/src/app.rs b/payjoin-cli/src/app.rs index 731e7b8b..0dad93c7 100644 --- a/payjoin-cli/src/app.rs +++ b/payjoin-cli/src/app.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; +use std::net::SocketAddr; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -9,39 +10,44 @@ use bitcoincore_rpc::jsonrpc::serde_json; use bitcoincore_rpc::RpcApi; use clap::ArgMatches; use config::{Config, File, FileFormat}; +use hyper::server::conn::AddrIncoming; +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Method, Request, Response, Server, StatusCode}; use payjoin::bitcoin; use payjoin::bitcoin::psbt::Psbt; use payjoin::receive::{Error, ProvisionalProposal}; -use rouille::{Request, Response}; use serde::{Deserialize, Serialize}; +#[derive(Clone)] pub(crate) struct App { config: AppConfig, - bitcoind: bitcoincore_rpc::Client, seen_inputs: Arc>, } impl App { pub fn new(config: AppConfig) -> Result { - let bitcoind = match &config.bitcoind_cookie { + let seen_inputs = Arc::new(Mutex::new(SeenInputs::new()?)); + Ok(Self { config, seen_inputs }) + } + + pub fn bitcoind(&self) -> Result { + match &self.config.bitcoind_cookie { Some(cookie) => bitcoincore_rpc::Client::new( - &config.bitcoind_rpchost, + &self.config.bitcoind_rpchost, bitcoincore_rpc::Auth::CookieFile(cookie.into()), ), None => bitcoincore_rpc::Client::new( - &config.bitcoind_rpchost, + &self.config.bitcoind_rpchost, bitcoincore_rpc::Auth::UserPass( - config.bitcoind_rpcuser.clone(), - config.bitcoind_rpcpass.clone(), + self.config.bitcoind_rpcuser.clone(), + self.config.bitcoind_rpcpass.clone(), ), ), } - .context("Failed to connect to bitcoind")?; - let seen_inputs = Arc::new(Mutex::new(SeenInputs::new()?)); - Ok(Self { config, bitcoind, seen_inputs }) + .with_context(|| "Failed to connect to bitcoind") } - pub fn send_payjoin(&self, bip21: &str, fee_rate: &f32) -> Result<()> { + pub async fn send_payjoin(&self, bip21: &str, fee_rate: &f32) -> Result<()> { let uri = payjoin::Uri::try_from(bip21) .map_err(|e| anyhow!("Failed to create URI from BIP21: {}", e))? .assume_checked(); @@ -64,7 +70,7 @@ impl App { ..Default::default() }; let psbt = self - .bitcoind + .bitcoind()? .wallet_create_funded_psbt( &[], // inputs &outputs, @@ -75,7 +81,7 @@ impl App { .context("Failed to create PSBT")? .psbt; let psbt = self - .bitcoind + .bitcoind()? .wallet_process_psbt(&psbt, None, None, None) .with_context(|| "Failed to process PSBT")? .psbt; @@ -87,43 +93,45 @@ impl App { .build_recommended(fee_rate) .with_context(|| "Failed to build payjoin request")?; - let client = reqwest::blocking::Client::builder() + let client = reqwest::Client::builder() .danger_accept_invalid_certs(self.config.danger_accept_invalid_certs) .build() .with_context(|| "Failed to build reqwest http client")?; - let mut response = client + let response = client .post(req.url) .body(req.body) .header("Content-Type", "text/plain") .send() + .await .with_context(|| "HTTP request failed")?; + let mut response = std::io::Cursor::new(response.text().await?); // TODO display well-known errors and log::debug the rest let psbt = ctx.process_response(&mut response).with_context(|| "Failed to process response")?; log::debug!("Proposed psbt: {:#?}", psbt); let psbt = self - .bitcoind + .bitcoind()? .wallet_process_psbt(&serialize_psbt(&psbt), None, None, None) .with_context(|| "Failed to process PSBT")? .psbt; let tx = self - .bitcoind + .bitcoind()? .finalize_psbt(&psbt, Some(true)) .with_context(|| "Failed to finalize PSBT")? .hex .ok_or_else(|| anyhow!("Incomplete PSBT"))?; let txid = self - .bitcoind + .bitcoind()? .send_raw_transaction(&tx) .with_context(|| "Failed to send raw transaction")?; log::info!("Transaction sent: {}", txid); Ok(()) } - pub fn receive_payjoin(self, amount_arg: &str) -> Result<()> { + pub async fn receive_payjoin(self, amount_arg: &str) -> Result<()> { use payjoin::Uri; - let pj_receiver_address = self.bitcoind.get_new_address(None, None)?.assume_checked(); + let pj_receiver_address = self.bitcoind()?.get_new_address(None, None)?.assume_checked(); let amount = Amount::from_sat(amount_arg.parse()?); let pj_uri_string = format!( "{}?amount={}&pj={}", @@ -135,7 +143,7 @@ impl App { let _pj_uri = Uri::from_str(&pj_uri_string) .map_err(|e| anyhow!("Constructed a bad URI string from args: {}", e))? .assume_checked(); - + let bind_addr: SocketAddr = self.config.pj_host.parse()?; println!( "Listening at {}. Configured to accept payjoin at BIP 21 Payjoin Uri:", self.config.pj_host @@ -144,113 +152,122 @@ impl App { #[cfg(feature = "local-https")] let server = { - let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()])?; - let cert_ser = cert.serialize_pem()?; - let skey_ser = cert.serialize_private_key_pem().into_bytes(); - rouille::Server::new_ssl( - self.config.pj_host.clone(), - move |req| self.handle_web_request(req), - cert_ser.into_bytes(), - skey_ser, - ) - .map_err(|e| anyhow!("Failed to create HTTPS server: {}", e))? + use rustls::{Certificate, PrivateKey}; + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?; + let key = PrivateKey(cert.serialize_private_key_der()); + let certs = vec![Certificate(cert.serialize_der()?)]; + let incoming = AddrIncoming::bind(&bind_addr.into())?; + let acceptor = hyper_rustls::TlsAcceptor::builder() + .with_single_cert(certs, key) + .map_err(|e| anyhow::anyhow!("TLS error: {}", e))? + .with_all_versions_alpn() + .with_incoming(incoming); + Server::builder(acceptor) }; #[cfg(not(feature = "local-https"))] - let server = { - rouille::Server::new(self.config.pj_host.clone(), move |req| { - self.handle_web_request(req) - }) - .map_err(|e| anyhow!("Failed to create HTTP server: {}", e))? - }; + let server = hyper::Server::bind(&bind_addr); - server.run(); + let make_svc = make_service_fn(|_| { + let app = self.clone(); + async move { + let handler = move |req| handle_web_request(req, app.clone()); + Ok::<_, hyper::Error>(service_fn(handler)) + } + }); + server.serve(make_svc).await?; + // let server = server.serve(make_svc); + // Ok(server.await?) Ok(()) } + fn insert_input_seen_before(&self, input: bitcoin::OutPoint) -> Result { + self.seen_inputs.lock().expect("mutex lock failed").insert(input) + } +} - fn handle_web_request(&self, req: &Request) -> Response { - log::debug!("Received request: {:?}", req); - match (req.method(), req.url().as_ref()) { - ("GET", "/bip21") => { - log::debug!("{:?}, {:?}", req.method(), req.raw_query_string()); - let amount = req.get_param("amount").map(|amt| { - Amount::from_btc(amt.parse().expect("Failed to parse amount")).unwrap() - }); - self.handle_get_bip21(amount) - .map_err(|e| { - log::error!("Error handling request: {}", e); - Response::text(e.to_string()).with_status_code(500) - }) - .unwrap_or_else(|err_resp| err_resp) - } - ("POST", _) => self - .handle_payjoin_post(req) - .map_err(|e| match e { - Error::BadRequest(e) => { - log::error!("Error handling request: {}", e); - Response::text(e.to_string()).with_status_code(400) - } - e => { - log::error!("Error handling request: {}", e); - Response::text(e.to_string()).with_status_code(500) - } +async fn handle_web_request(req: Request, app: App) -> Result> { + log::debug!("Received request: {:?}", req); + let mut response = match (req.method(), req.uri().path()) { + (&Method::GET, "/bip21") => { + let query_string = req.uri().query().unwrap_or(""); + log::debug!("{:?}, {:?}", req.method(), query_string); + let query_params: HashMap<_, _> = + url::form_urlencoded::parse(query_string.as_bytes()).into_owned().collect(); + let amount = query_params + .get("amount") + .map(|amt| Amount::from_btc(amt.parse().expect("Failed to parse amount")).unwrap()); + handle_get_bip21(amount, &app) + .map_err(|e| { + log::error!("Error handling request: {}", e); + Response::builder().status(500).body(Body::from(e.to_string())).unwrap() }) - .unwrap_or_else(|err_resp| err_resp), - _ => Response::empty_404(), + .unwrap_or_else(|err_resp| err_resp) } - .with_additional_header("Access-Control-Allow-Origin", "*") - } + (&Method::POST, _) => handle_payjoin_post(req, &app) + .await + .map_err(|e| match e { + Error::BadRequest(e) => { + log::error!("Error handling request: {}", e); + Response::builder().status(400).body(Body::from(e.to_string())).unwrap() + } + e => { + log::error!("Error handling request: {}", e); + Response::builder().status(500).body(Body::from(e.to_string())).unwrap() + } + }) + .unwrap_or_else(|err_resp| err_resp), + _ => + Response::builder().status(StatusCode::NOT_FOUND).body(Body::from("Not found")).unwrap(), + }; + response + .headers_mut() + .insert("Access-Control-Allow-Origin", hyper::header::HeaderValue::from_static("*")); + Ok(response) +} - fn handle_get_bip21(&self, amount: Option) -> Result { - let address = self - .bitcoind - .get_new_address(None, None) - .map_err(|e| Error::Server(e.into()))? - .assume_checked(); - let uri_string = if let Some(amount) = amount { - format!( - "{}?amount={}&pj={}", - address.to_qr_uri(), - amount.to_btc(), - self.config.pj_endpoint - ) - } else { - format!("{}?pj={}", address.to_qr_uri(), self.config.pj_endpoint) - }; - let uri = payjoin::Uri::try_from(uri_string.clone()) - .map_err(|_| Error::Server(anyhow!("Could not parse payjoin URI string.").into()))?; - let _ = uri.assume_checked(); // we just got it from bitcoind above +fn handle_get_bip21(amount: Option, app: &App) -> Result, Error> { + let address = app + .bitcoind() + .map_err(|e| Error::Server(e.into()))? + .get_new_address(None, None) + .map_err(|e| Error::Server(e.into()))? + .assume_checked(); + let uri_string = if let Some(amount) = amount { + format!("{}?amount={}&pj={}", address.to_qr_uri(), amount.to_btc(), app.config.pj_endpoint) + } else { + format!("{}?pj={}", address.to_qr_uri(), app.config.pj_endpoint) + }; + let uri = payjoin::Uri::try_from(uri_string.clone()) + .map_err(|_| Error::Server(anyhow!("Could not parse payjoin URI string.").into()))?; + let _ = uri.assume_checked(); // we just got it from bitcoind above - Ok(Response::text(uri_string)) - } + Ok(Response::new(Body::from(uri_string))) +} + +async fn handle_payjoin_post(req: Request, app: &App) -> Result, Error> { + let (parts, body) = req.into_parts(); + let headers = Headers(&parts.headers); + let query_string = parts.uri.query().unwrap_or(""); + let body = std::io::Cursor::new(hyper::body::to_bytes(body).await.unwrap().to_vec()); + let proposal = payjoin::receive::UncheckedProposal::from_request(body, query_string, headers)?; + + let bitcoind = app.bitcoind().map_err(|e| Error::Server(e.into()))?; - fn handle_payjoin_post(&self, req: &Request) -> Result { - let headers = Headers(req.headers()); - let proposal = payjoin::receive::UncheckedProposal::from_request( - req.data().context("Failed to read request body").map_err(|e| { - log::warn!("Failed to read request body: {}", e); - Error::Server(e.into()) - })?, - req.raw_query_string(), - headers, - )?; - - // in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx - let _to_broadcast_in_failure_case = proposal.extract_tx_to_schedule_broadcast(); - - // The network is used for checks later - let network = - self.bitcoind.get_blockchain_info().map_err(|e| Error::Server(e.into())).and_then( - |info| bitcoin::Network::from_str(&info.chain).map_err(|e| Error::Server(e.into())), - )?; - - // Receive Check 1: Can Broadcast - let proposal = proposal.check_can_broadcast(|tx| { + // in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx + let _to_broadcast_in_failure_case = proposal.extract_tx_to_schedule_broadcast(); + + // The network is used for checks later + let network = + bitcoind.get_blockchain_info().map_err(|e| Error::Server(e.into())).and_then(|info| { + bitcoin::Network::from_str(&info.chain).map_err(|e| Error::Server(e.into())) + })?; + + // Receive Check 1: Can Broadcast + let proposal = + proposal.check_can_broadcast(|tx| { let raw_tx = bitcoin::consensus::encode::serialize_hex(&tx); - let mempool_results = self - .bitcoind - .test_mempool_accept(&[raw_tx]) - .map_err(|e| Error::Server(e.into()))?; + let mempool_results = + bitcoind.test_mempool_accept(&[raw_tx]).map_err(|e| Error::Server(e.into()))?; match mempool_results.first() { Some(result) => Ok(result.allowed), None => Err(Error::Server( @@ -258,79 +275,71 @@ impl App { )), } })?; - log::trace!("check1"); - - // Receive Check 2: receiver can't sign for proposal inputs - let proposal = proposal.check_inputs_not_owned(|input| { - if let Ok(address) = bitcoin::Address::from_script(input, network) { - self.bitcoind - .get_address_info(&address) - .map(|info| info.is_mine.unwrap_or(false)) - .map_err(|e| Error::Server(e.into())) - } else { - Ok(false) - } - })?; - log::trace!("check2"); - // Receive Check 3: receiver can't sign for proposal inputs - let proposal = proposal.check_no_mixed_input_scripts()?; - log::trace!("check3"); - - // Receive Check 4: have we seen this input before? More of a check for non-interactive i.e. payment processor receivers. - let payjoin = proposal.check_no_inputs_seen_before(|input| { - Ok(!self.insert_input_seen_before(*input).map_err(|e| Error::Server(e.into()))?) - })?; - log::trace!("check4"); - - let mut provisional_payjoin = payjoin.identify_receiver_outputs(|output_script| { - if let Ok(address) = bitcoin::Address::from_script(output_script, network) { - self.bitcoind - .get_address_info(&address) - .map(|info| info.is_mine.unwrap_or(false)) - .map_err(|e| Error::Server(e.into())) - } else { - Ok(false) - } - })?; - - if !self.config.sub_only { - // Select receiver payjoin inputs. - _ = try_contributing_inputs(&mut provisional_payjoin, &self.bitcoind) - .map_err(|e| log::warn!("Failed to contribute inputs: {}", e)); + log::trace!("check1"); + + // Receive Check 2: receiver can't sign for proposal inputs + let proposal = proposal.check_inputs_not_owned(|input| { + if let Ok(address) = bitcoin::Address::from_script(input, network) { + bitcoind + .get_address_info(&address) + .map(|info| info.is_mine.unwrap_or(false)) + .map_err(|e| Error::Server(e.into())) + } else { + Ok(false) } + })?; + log::trace!("check2"); + // Receive Check 3: receiver can't sign for proposal inputs + let proposal = proposal.check_no_mixed_input_scripts()?; + log::trace!("check3"); + + // Receive Check 4: have we seen this input before? More of a check for non-interactive i.e. payment processor receivers. + let payjoin = proposal.check_no_inputs_seen_before(|input| { + Ok(!app.insert_input_seen_before(*input).map_err(|e| Error::Server(e.into()))?) + })?; + log::trace!("check4"); + + let mut provisional_payjoin = payjoin.identify_receiver_outputs(|output_script| { + if let Ok(address) = bitcoin::Address::from_script(output_script, network) { + bitcoind + .get_address_info(&address) + .map(|info| info.is_mine.unwrap_or(false)) + .map_err(|e| Error::Server(e.into())) + } else { + Ok(false) + } + })?; - let receiver_substitute_address = self - .bitcoind - .get_new_address(None, None) - .map_err(|e| Error::Server(e.into()))? - .assume_checked(); - provisional_payjoin.substitute_output_address(receiver_substitute_address); - - let payjoi_proposal = provisional_payjoin.finalize_proposal( - |psbt: &Psbt| { - self.bitcoind - .wallet_process_psbt( - &payjoin::base64::encode(psbt.serialize()), - None, - None, - Some(false), - ) - .map(|res| Psbt::from_str(&res.psbt).map_err(|e| Error::Server(e.into()))) - .map_err(|e| Error::Server(e.into()))? - }, - Some(bitcoin::FeeRate::MIN), - )?; - let payjoin_proposal_psbt = payjoi_proposal.psbt(); - log::debug!("Receiver's Payjoin proposal PSBT Rsponse: {:#?}", payjoin_proposal_psbt); - - let payload = payjoin::base64::encode(&payjoin_proposal_psbt.serialize()); - log::info!("successful response"); - Ok(Response::text(payload)) + if !app.config.sub_only { + // Select receiver payjoin inputs. + _ = try_contributing_inputs(&mut provisional_payjoin, &bitcoind) + .map_err(|e| log::warn!("Failed to contribute inputs: {}", e)); } - fn insert_input_seen_before(&self, input: bitcoin::OutPoint) -> Result { - self.seen_inputs.lock().expect("mutex lock failed").insert(input) - } + let receiver_substitute_address = + bitcoind.get_new_address(None, None).map_err(|e| Error::Server(e.into()))?.assume_checked(); + provisional_payjoin.substitute_output_address(receiver_substitute_address); + + let payjoi_proposal = provisional_payjoin.finalize_proposal( + |psbt: &Psbt| { + bitcoind + .wallet_process_psbt( + &payjoin::base64::encode(psbt.serialize()), + None, + None, + Some(false), + ) + .map(|res| Psbt::from_str(&res.psbt).map_err(|e| Error::Server(e.into()))) + .map_err(|e| Error::Server(e.into()))? + }, + Some(bitcoin::FeeRate::MIN), + )?; + let payjoin_proposal_psbt = payjoi_proposal.psbt(); + log::debug!("Receiver's Payjoin proposal PSBT Rsponse: {:#?}", payjoin_proposal_psbt); + + let payload = payjoin::base64::encode(&payjoin_proposal_psbt.serialize()); + log::info!("successful response"); + Ok(Response::new(Body::from(payload))) } struct SeenInputs { @@ -366,7 +375,7 @@ impl OutPointSet { fn insert(&mut self, input: bitcoin::OutPoint) -> bool { self.0.insert(input) } } -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] pub(crate) struct AppConfig { pub bitcoind_rpchost: String, pub bitcoind_cookie: Option, @@ -466,11 +475,10 @@ fn try_contributing_inputs( Ok(()) } -struct Headers<'a>(rouille::HeadersIter<'a>); +struct Headers<'a>(&'a hyper::HeaderMap); impl payjoin::receive::Headers for Headers<'_> { fn get_header(&self, key: &str) -> Option<&str> { - let mut copy = self.0.clone(); // lol - copy.find(|(k, _)| k.eq_ignore_ascii_case(key)).map(|(_, v)| v) + self.0.get(key).map(|v| v.to_str()).transpose().ok().flatten() } } diff --git a/payjoin-cli/src/main.rs b/payjoin-cli/src/main.rs index 75f18f6c..6ec5f474 100644 --- a/payjoin-cli/src/main.rs +++ b/payjoin-cli/src/main.rs @@ -4,7 +4,8 @@ use clap::{arg, value_parser, Arg, ArgMatches, Command}; mod app; use app::{App, AppConfig}; -fn main() -> Result<()> { +#[tokio::main] +async fn main() -> Result<()> { env_logger::init(); let matches = cli(); @@ -16,12 +17,12 @@ fn main() -> Result<()> { let bip21 = sub_matches.get_one::("BIP21").context("Missing BIP21 argument")?; let fee_rate_sat_per_vb = sub_matches.get_one::("fee_rate").context("Missing --fee-rate argument")?; - app.send_payjoin(bip21, fee_rate_sat_per_vb)?; + app.send_payjoin(bip21, fee_rate_sat_per_vb).await?; } Some(("receive", sub_matches)) => { let amount = sub_matches.get_one::("AMOUNT").context("Missing AMOUNT argument")?; - app.receive_payjoin(amount)?; + app.receive_payjoin(amount).await?; } _ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!() }