diff --git a/.gitignore b/.gitignore index e37c672..39826fd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ **/**/.idea/* sifir-android/outputs/** sifir-ios/outputs/** +sifir-ios/scripts/custom/**a +# android builds +sifir-android/src/ffi/java_glue.rs +sifir-android/outputs/aar/** +sifir-android/app/tor/src/main/java/com/sifir/** diff --git a/Cargo.lock b/Cargo.lock index f480983..21d9f84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" dependencies = [ "gimli", ] @@ -37,7 +39,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ed09b18365ed295d722d0b5ed59c01b79a826ff2d2a8f73d5ecca8e6fb2f66" dependencies = [ "android_log-sys", - "env_logger 0.8.3", + "env_logger 0.8.4", "lazy_static", "log", ] @@ -53,9 +55,20 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" + +[[package]] +name = "async-trait" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" +dependencies = [ + "proc-macro2 1.0.27", + "quote 1.0.9", + "syn 1.0.73", +] [[package]] name = "atty" @@ -85,13 +98,13 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -119,6 +132,75 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64-compat" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8d4d2746f89841e49230dd26917df1876050f95abafafbe34f47cb534b88d7" +dependencies = [ + "byteorder", +] + +[[package]] +name = "bdk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fffcbebd2cd69f95e6928e21489b0bc277beabe7c2f24c2f0116d91a8b25f3" +dependencies = [ + "async-trait", + "bdk-macros", + "bitcoin", + "electrum-client", + "js-sys", + "log", + "miniscript", + "rand 0.7.3", + "serde", + "serde_json", + "sled", + "tiny-bip39", + "tokio 1.8.0", +] + +[[package]] +name = "bdk-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45570b78250774145859a8f85bfdb6e310663fc82640d7e159a44b1386074a2" +dependencies = [ + "proc-macro2 1.0.27", + "quote 1.0.9", + "syn 1.0.73", +] + +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + +[[package]] +name = "bitcoin" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6742ec672d3f12506f4ac5c0d853926ff1f94e675f60ffd3224039972bf663f1" +dependencies = [ + "base64-compat", + "bech32", + "bitcoin_hashes", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -155,6 +237,18 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "btc" +version = "0.1.0" +dependencies = [ + "anyhow", + "bdk", + "rand 0.8.4", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "bumpalo" version = "3.7.0" @@ -173,16 +267,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - [[package]] name = "bytes" version = "0.5.6" @@ -224,9 +308,9 @@ dependencies = [ [[package]] name = "cbindgen" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744fcfb4c9f64d649756fd972afec5120641eaa8b2ff86a4ae981f68648780b8" +checksum = "97449daf9b8c245bcad10bbc7c9f4a37c06172c18dd5f9fac340deefc309b957" dependencies = [ "clap", "heck", @@ -236,7 +320,7 @@ dependencies = [ "quote 1.0.9", "serde", "serde_json", - "syn 1.0.72", + "syn 1.0.73", "tempfile", "toml", ] @@ -253,12 +337,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -282,9 +360,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.5.2" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e" +checksum = "a2d47c1b11006b87e492b53b313bb699ce60e16613c4dddaa91f8f7c220ab2fa" dependencies = [ "bytes 1.0.1", "memchr", @@ -308,13 +386,45 @@ checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] name = "cpufeatures" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + [[package]] name = "crypto-mac" version = "0.7.0" @@ -325,6 +435,16 @@ dependencies = [ "subtle 1.0.0", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.4", + "subtle 2.4.0", +] + [[package]] name = "curve25519-dalek" version = "3.1.0" @@ -399,13 +519,29 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "electrum-client" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cab4d90cc575a7daab4cfed9e315912a88071bc47462e6be57516a2f01ccc89" +dependencies = [ + "bitcoin", + "log", + "rustls", + "serde", + "serde_json", + "socks", + "webpki", + "webpki-roots", +] + [[package]] name = "encoding_rs" version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -423,9 +559,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime 2.1.0", @@ -482,7 +618,7 @@ dependencies = [ "smallvec", "smol_str", "strum", - "syn 1.0.72", + "syn 1.0.73", "which", ] @@ -518,26 +654,20 @@ dependencies = [ ] [[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "fs2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ - "bitflags", - "fuchsia-zircon-sys", + "libc", + "winapi 0.3.9", ] [[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" +name = "fs_extra" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "futures" @@ -547,7 +677,6 @@ checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -570,36 +699,12 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" -[[package]] -name = "futures-executor" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - [[package]] name = "futures-io" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" -[[package]] -name = "futures-macro" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" -dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2 1.0.27", - "quote 1.0.9", - "syn 1.0.72", -] - [[package]] name = "futures-sink" version = "0.3.15" @@ -619,18 +724,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ "autocfg", - "futures-channel", "futures-core", - "futures-io", - "futures-macro", "futures-sink", "futures-task", - "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", ] [[package]] @@ -658,9 +765,11 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -669,7 +778,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] @@ -682,11 +791,11 @@ checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" [[package]] name = "h2" -version = "0.2.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" dependencies = [ - "bytes 0.5.6", + "bytes 1.0.1", "fnv", "futures-core", "futures-sink", @@ -694,32 +803,31 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 0.2.25", + "tokio 1.8.0", "tokio-util", "tracing", - "tracing-futures", ] [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -736,10 +844,20 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" dependencies = [ - "crypto-mac", + "crypto-mac 0.7.0", "digest 0.8.1", ] +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + [[package]] name = "http" version = "0.2.4" @@ -753,12 +871,13 @@ dependencies = [ [[package]] name = "http-body" -version = "0.3.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" dependencies = [ - "bytes 0.5.6", + "bytes 1.0.1", "http", + "pin-project-lite 0.2.7", ] [[package]] @@ -769,9 +888,9 @@ checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" [[package]] name = "httpdate" -version = "0.3.2" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -790,11 +909,11 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.13.10" +version = "0.14.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" +checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" dependencies = [ - "bytes 0.5.6", + "bytes 1.0.1", "futures-channel", "futures-core", "futures-util", @@ -804,9 +923,9 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project", + "pin-project-lite 0.2.7", "socket2", - "tokio 0.2.25", + "tokio 1.8.0", "tower-service", "tracing", "want", @@ -814,15 +933,15 @@ dependencies = [ [[package]] name = "hyper-tls" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 0.5.6", + "bytes 1.0.1", "hyper", "native-tls", - "tokio 0.2.25", - "tokio-tls", + "tokio 1.8.0", + "tokio-native-tls", ] [[package]] @@ -838,9 +957,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", @@ -852,23 +971,14 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", + "cfg-if", ] [[package]] name = "ipnet" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itoa" @@ -911,16 +1021,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -929,15 +1029,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" [[package]] name = "libtor" -version = "45.8.0+0.4.5.8" +version = "46.6.1+0.4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e98eb97f8ff55703846611ce119308b9e72eb0a30d5d09cb2d857fa865753fa" +checksum = "dab41a0ec51a14dd9c4bb7ed69db84b04dbda91293801ca4e4b235c18a31dfbf" dependencies = [ "libtor-derive", "libtor-sys", @@ -946,20 +1046,20 @@ dependencies = [ [[package]] name = "libtor-derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90450d60feda0caed0cce77534e89804cb05468c491ee97d58fa94b26685844a" +checksum = "177781b25e83853831c5af66320ceaf5e456e1b6d533426fcd9c7544b5543043" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] name = "libtor-sys" -version = "45.8.0+0.4.5.8" +version = "46.7.1+0.4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a70a39d18f86b85b803846a70c9061f7b83a7779e86a833b26bc92624b68035" +checksum = "ded79576f3d5abfba65a7f245acd7e05becb5f080623089eab2fcd31de12157f" dependencies = [ "autotools", "cc", @@ -995,7 +1095,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1012,7 +1112,7 @@ name = "logger" version = "0.1.0" dependencies = [ "android_logger", - "env_logger 0.8.3", + "env_logger 0.8.4", "log", "log-panics", ] @@ -1029,6 +1129,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" @@ -1036,13 +1145,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] -name = "mime_guess" -version = "2.0.3" +name = "miniscript" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +checksum = "71f455be59a359d50370c4f587afbc5739c862e684c5afecae80ab93e7474b4e" dependencies = [ - "mime", - "unicase", + "bitcoin", ] [[package]] @@ -1057,48 +1165,17 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" -dependencies = [ - "libc", - "log", - "miow 0.3.7", + "miow", "ntapi", "winapi 0.3.9", ] -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - [[package]] name = "miow" version = "0.3.7" @@ -1110,9 +1187,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", @@ -1126,17 +1203,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "ntapi" version = "0.3.6" @@ -1158,15 +1224,21 @@ dependencies = [ [[package]] name = "object" -version = "0.24.0" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" +checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +dependencies = [ + "memchr", +] [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +dependencies = [ + "parking_lot", +] [[package]] name = "opaque-debug" @@ -1182,12 +1254,12 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.34" +version = "0.10.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" +checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -1211,9 +1283,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.63" +version = "0.9.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" +checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" dependencies = [ "autocfg", "cc", @@ -1240,7 +1312,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -1248,6 +1320,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac 0.8.0", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1264,26 +1345,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "pin-project" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" -dependencies = [ - "proc-macro2 1.0.27", - "quote 1.0.9", - "syn 1.0.72", -] - [[package]] name = "pin-project-lite" version = "0.1.12" @@ -1292,9 +1353,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -1314,18 +1375,6 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "0.4.30" @@ -1383,14 +1432,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -1405,12 +1454,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -1424,9 +1473,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom 0.2.3", ] @@ -1442,18 +1491,18 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" dependencies = [ "bitflags", ] @@ -1486,12 +1535,12 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.10.10" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" +checksum = "7c4e0a76dc12a116108933f6301b95e83634e0c47b0afbed6abbaa0601e99258" dependencies = [ "base64 0.13.0", - "bytes 0.5.6", + "bytes 1.0.1", "encoding_rs", "futures-core", "futures-util", @@ -1504,15 +1553,15 @@ dependencies = [ "lazy_static", "log", "mime", - "mime_guess", "native-tls", "percent-encoding", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "serde", + "serde_json", "serde_urlencoded", - "tokio 0.2.25", + "tokio 1.8.0", + "tokio-native-tls", "tokio-socks", - "tokio-tls", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -1520,11 +1569,26 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rustc-demangle" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" +checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" [[package]] name = "rustc-hash" @@ -1541,6 +1605,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" +dependencies = [ + "base64 0.10.1", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1572,11 +1649,40 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "827cb7cce42533829c792fc51b82fbf18b125b45a702ef2c8be77fce65463a7b" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" +checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" dependencies = [ "bitflags", "core-foundation", @@ -1587,9 +1693,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339" +checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" dependencies = [ "core-foundation-sys", "libc", @@ -1628,7 +1734,7 @@ checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -1673,7 +1779,7 @@ checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -1701,7 +1807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -1725,6 +1831,7 @@ name = "sifir-android" version = "0.1.0" dependencies = [ "base64 0.13.0", + "btc", "flapigen", "jni", "jni-sys", @@ -1739,10 +1846,12 @@ name = "sifir-ios" version = "0.1.0" dependencies = [ "base64 0.13.0", + "btc", "cargo-lipo", "cbindgen", "libc", "logger", + "reqwest", "serde", "serde_json", "tor", @@ -1759,9 +1868,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" +checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" [[package]] name = "slab" @@ -1769,6 +1878,22 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +[[package]] +name = "sled" +version = "0.34.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0132f3e393bcb7390c60bb45769498cf4550bcb7a21d7f95c02b69f6362cdc" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot", +] + [[package]] name = "smallvec" version = "1.6.1" @@ -1777,17 +1902,16 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "smol_str" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca0f7ce3a29234210f0f4f0b56f8be2e722488b95cb522077943212da3b32eb" +checksum = "b203e79e90905594272c1c97c7af701533d42adaab0beb3859018e477d54a3b0" [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ - "cfg-if 1.0.0", "libc", "winapi 0.3.9", ] @@ -1804,6 +1928,12 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "strsim" version = "0.8.0" @@ -1850,7 +1980,7 @@ dependencies = [ "heck", "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", ] [[package]] @@ -1878,9 +2008,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", @@ -1895,7 +2025,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", "unicode-xid 0.2.2", ] @@ -1905,9 +2035,9 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi 0.3.9", @@ -1933,22 +2063,40 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e44c4759bae7f1032e286a7ef990bd9ed23fe831b7eeba0beb97484c2e59b8" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.5", + "thiserror", + "unicode-normalization", + "zeroize", ] [[package]] @@ -1973,12 +2121,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" dependencies = [ "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "memchr", - "mio 0.6.23", "num_cpus", "pin-project-lite 0.1.12", "slab", @@ -1986,18 +2128,18 @@ dependencies = [ [[package]] name = "tokio" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975" +checksum = "570c2eb13b3ab38208130eccd41be92520388791207fde783bda7c1e8ace28d4" dependencies = [ "autocfg", "bytes 1.0.1", "libc", "memchr", - "mio 0.7.11", + "mio", "num_cpus", "once_cell", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "signal-hook-registry", "winapi 0.3.9", ] @@ -2010,23 +2152,32 @@ checksum = "e7d4237822b7be8fff0a7a27927462fad435dcb6650f95cea9e946bf6bdc7e07" dependencies = [ "bytes 0.5.6", "once_cell", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "tokio 0.2.25", - "tokio 1.6.1", + "tokio 1.8.0", "tokio-stream", ] [[package]] -name = "tokio-socks" +name = "tokio-native-tls" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d611fd5d241872372d52a0a3d309c52d0b95a6a67671a6c8f7ab2c4a37fb2539" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio 1.8.0", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" dependencies = [ - "bytes 0.4.12", "either", - "futures", + "futures-util", "thiserror", - "tokio 0.2.25", + "tokio 1.8.0", ] [[package]] @@ -2036,32 +2187,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8864d706fdb3cc0843a49647ac892720dac98a6eeb818b77190592cf4994066" dependencies = [ "futures-core", - "pin-project-lite 0.2.6", - "tokio 1.6.1", -] - -[[package]] -name = "tokio-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" -dependencies = [ - "native-tls", - "tokio 0.2.25", + "pin-project-lite 0.2.7", + "tokio 1.8.0", ] [[package]] name = "tokio-util" -version = "0.3.1" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ - "bytes 0.5.6", + "bytes 1.0.1", "futures-core", "futures-sink", "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", + "pin-project-lite 0.2.7", + "tokio 1.8.0", ] [[package]] @@ -2090,7 +2231,7 @@ dependencies = [ "serial_test", "socks", "thiserror", - "tokio 1.6.1", + "tokio 1.8.0", "tokio-compat-02", "torut", "utils", @@ -2098,16 +2239,16 @@ dependencies = [ [[package]] name = "torut" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05253df8056cc5830af67e5e86d6bb88bef83221238e698783f2560048584757" +checksum = "5b2cdfcb8b9dccc90fd618101a6f0a5a1f9e23e36956da9a2fe0abee901b04cc" dependencies = [ "base32", "base64 0.10.1", "derive_more", "ed25519-dalek", "hex", - "hmac", + "hmac 0.7.1", "openssl", "rand 0.7.3", "serde", @@ -2115,7 +2256,7 @@ dependencies = [ "sha1", "sha2 0.8.2", "sha3", - "tokio 1.6.1", + "tokio 1.8.0", ] [[package]] @@ -2130,9 +2271,8 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ - "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.6", + "cfg-if", + "pin-project-lite 0.2.7", "tracing-core", ] @@ -2145,16 +2285,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "try-lock" version = "0.2.3" @@ -2167,15 +2297,6 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" -[[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.5" @@ -2187,18 +2308,18 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33717dca7ac877f497014e10d73f3acf948c342bee31b5ca7892faf94ccc6b49" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -2218,6 +2339,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.2.2" @@ -2239,9 +2366,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vec_map" @@ -2294,9 +2421,7 @@ version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ - "cfg-if 1.0.0", - "serde", - "serde_json", + "cfg-if", "wasm-bindgen-macro", ] @@ -2311,7 +2436,7 @@ dependencies = [ "log", "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", "wasm-bindgen-shared", ] @@ -2321,7 +2446,7 @@ version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -2345,7 +2470,7 @@ checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2366,6 +2491,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eff4b7516a57307f9349c64bf34caa34b940b66fed4b2fb3136cb7386e5739" +dependencies = [ + "webpki", +] + [[package]] name = "which" version = "3.1.1" @@ -2454,6 +2598,6 @@ checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.73", "synstructure", ] diff --git a/btc/Cargo.toml b/btc/Cargo.toml new file mode 100644 index 0000000..306e933 --- /dev/null +++ b/btc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "btc" +version = "0.1.0" +authors = ["Gus "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bdk = { version = "0.9.0", features = ['all-keys','key-value-db'] } +rand = "0.8.0" +serde = "1.0.118" +serde_json = "1.0" +anyhow = "1.0" +thiserror = "1.0.24" diff --git a/btc/src/lib.rs b/btc/src/lib.rs new file mode 100644 index 0000000..874a4af --- /dev/null +++ b/btc/src/lib.rs @@ -0,0 +1,530 @@ +pub mod multi_sig; +pub use bdk; +use bdk::bitcoin::consensus::encode::{ + deserialize, serialize, serialize_hex, Error as BitcoinError, +}; +use bdk::bitcoin::util::address::Error as BitcoinAddressError; +pub use bdk::bitcoin::util::bip32::{ + ChildNumber, DerivationPath, Error as Bip32Error, ExtendedPrivKey, ExtendedPubKey, Fingerprint, + IntoDerivationPath, +}; +pub use bdk::bitcoin::{secp256k1, Address, Network, OutPoint, PrivateKey, Script, Txid}; +pub use bdk::blockchain::{log_progress, Blockchain, ElectrumBlockchain, Progress, ProgressData}; +use bdk::blockchain::{AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig}; +pub use bdk::database::{BatchDatabase, MemoryDatabase}; +use bdk::descriptor::IntoWalletDescriptor; +use bdk::electrum_client::Client; +use bdk::keys::bip39::{Language, Mnemonic, MnemonicType}; +use bdk::keys::{ + DerivableKey, DescriptorKey, ExtendedKey, GeneratableKey, GeneratedKey, KeyError, ScriptContext, +}; +use bdk::miniscript::miniscript; +pub use bdk::wallet::AddressIndex; +pub use bdk::{sled, FeeRate, TxBuilder, Wallet}; +use rand::{thread_rng, RngCore}; +use serde::{Deserialize, Serialize}; +use serde_json; + +use bdk::miniscript::descriptor::DescriptorType; +use std::str::FromStr; +use thiserror::Error; + +#[derive(Debug, Serialize, Deserialize)] +// Use that type +pub struct WalletDescriptors { + network: Network, + external: String, + internal: Option, + public: String, +} +#[derive(Debug, Serialize, Deserialize)] +pub struct WalletCfg { + name: String, + descriptors: WalletDescriptors, + address_look_ahead: u32, + db_path: Option, + server_uri: Option, + // TODO IMPLMENT THIS replace server_uri + // blockchain_cfg: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct XprvsWithPaths(ExtendedPrivKey, DerivationPath, Fingerprint); +#[derive(Debug, Serialize, Deserialize)] +pub struct XpubsWithPaths(ExtendedPubKey, DerivationPath, Fingerprint); + +#[derive(Debug, Serialize, Deserialize)] +pub struct DerivedBip39Xprvs { + phrase: String, + master_xprv: ExtendedPrivKey, + xprv_w_paths: Vec, +} + +#[derive(Error, Debug)] +pub enum BtcErrors { + #[error("General BDK:")] + BdkError(#[from] bdk::Error), + #[error("BDK Key Error:")] + BdkKeyError(#[from] bdk::keys::KeyError), + #[error("Bip32 error:")] + Bip32Error(#[from] Bip32Error), + #[error("Io Error:")] + IoError(#[from] std::io::Error), + #[error("Descriptor Error:")] + DescriptorError(#[from] bdk::descriptor::error::Error), + #[error("BitcoinError Error:")] + BitcoinError(#[from] BitcoinError), + #[error("Bitcoin Address Error Error:")] + BitcoinAddressError(#[from] BitcoinAddressError), + #[error("Expected value missing for {:?}",.0)] + EmptyOption(String), + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +#[derive(Debug, Serialize, Deserialize)] +enum FeeType { + Abs, + Rate, +} +#[derive(Debug, Serialize, Deserialize)] +enum SpendChangePolicy { + Yes, + No, + OnlyChange, +} + +/// Txn parameters Easy to serialize into JSON and send across FFI +#[derive(Debug, Serialize, Deserialize)] +pub struct CreateTx { + recipients: Vec<(String, u64)>, + fee_type: FeeType, + fee: f32, + spend_change: SpendChangePolicy, + enable_rbf: bool, +} + +/// Converts a CreateTx struct into a BDK TxnBuilder and finalizes it +impl CreateTx { + pub fn into_wallet_txn( + self, + wallet: &Wallet, + ) -> Result< + ( + bdk::bitcoin::util::psbt::PartiallySignedTransaction, + bdk::TransactionDetails, + ), + BtcErrors, + > { + let mut txn = wallet.build_tx(); + // strings to addresses + let rcpts: Result, BtcErrors> = self + .recipients + .into_iter() + .map(|(addr, amount)| { + let address = Address::from_str(addr.as_str())?.script_pubkey(); + Ok((address, amount)) + }) + .collect(); + + txn.set_recipients(rcpts?); + match self.fee_type { + FeeType::Abs => txn.fee_absolute(self.fee as u64), + FeeType::Rate => txn.fee_rate(FeeRate::from_sat_per_vb(self.fee)), + }; + + match self.spend_change { + SpendChangePolicy::No => { + txn.do_not_spend_change(); + } + SpendChangePolicy::OnlyChange => { + txn.only_spend_change(); + } + _ => (), + }; + + txn.enable_rbf(); + txn.finish().map_err(BtcErrors::BdkError) + } +} +pub type ElectrumMemoryWallet = Wallet; +pub type ElectrumSledWallet = Wallet; + +impl From for ElectrumMemoryWallet { + fn from(cfg: WalletCfg) -> ElectrumMemoryWallet { + let secp = &secp256k1::Secp256k1::new(); + Wallet::new( + cfg.descriptors + .external + .as_str() + .into_wallet_descriptor(&secp, cfg.descriptors.network) + .unwrap(), + match cfg.descriptors.internal { + Some(desc) => Some( + desc.as_str() + .into_wallet_descriptor(&secp, cfg.descriptors.network) + .unwrap(), + ), + None => None, + }, + cfg.descriptors.network, + MemoryDatabase::new(), + match cfg.server_uri { + Some(uri) => ElectrumBlockchain::from(Client::new(&uri).unwrap()), + None => ElectrumBlockchain::from( + Client::new("ssl://electrum.blockstream.info:60002").unwrap(), + ), + }, + ) + .unwrap() + } +} + +impl From for ElectrumSledWallet { + fn from(cfg: WalletCfg) -> ElectrumSledWallet { + let secp = &secp256k1::Secp256k1::new(); + let db = sled::open(cfg.db_path.expect("Missing db path")).unwrap(); + let tree = db.open_tree(cfg.name).unwrap(); + let electrum_config = ElectrumBlockchainConfig { + url: match cfg.server_uri { + Some(uri) => uri, + None => "ssl://electrum.blockstream.info:60002".into(), + } + .into(), + socks5: None, + retry: 7, + timeout: Some(30), + }; + + let client = ElectrumBlockchain::from_config(&electrum_config).unwrap(); + + Wallet::new( + cfg.descriptors + .external + .as_str() + .into_wallet_descriptor(&secp, cfg.descriptors.network) + .unwrap(), + match cfg.descriptors.internal { + Some(desc) => Some( + desc.as_str() + .into_wallet_descriptor(&secp, cfg.descriptors.network) + .unwrap(), + ), + None => None, + }, + cfg.descriptors.network, + tree, + client, + ) + .unwrap() + } +} + +/// Generate a new Bip39 mnemonic seed +/// Derive num_child from provided derive_base +impl DerivedBip39Xprvs { + pub fn new( + derive_base: DerivationPath, + network: Network, + num_child: u32, + password: Option, + seed_phrase: Option, + ) -> Result { + let secp = secp256k1::Secp256k1::new(); + let (master_key, mnemonic_gen): (ExtendedKey, Mnemonic) = + match seed_phrase { + Some(phrase) => { + let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?; + (mnemonic.clone().into_extended_key()?, mnemonic) + } + None => { + let mnemonic: GeneratedKey<_, miniscript::BareCtx> = + Mnemonic::generate((MnemonicType::Words24, Language::English)).unwrap(); + let mnemonic = mnemonic.into_key(); + ((mnemonic.clone(), password).into_extended_key()?, mnemonic) + } + }; + + let xprv_master = master_key + .into_xprv(network) + .ok_or(BtcErrors::EmptyOption("xprv_master was empty".into()))?; + let xprv_w_paths: Result, BtcErrors> = (0..num_child) + .map(|index| ChildNumber::Normal { index }) + .map(|path| derive_base.extend(&[path])) + .map(|full_path| -> Result { + // Path is relative to key, so here derive from master + let extended_priv = xprv_master.derive_priv(&secp, &full_path)?; + Ok(XprvsWithPaths( + extended_priv, + full_path, + xprv_master.fingerprint(&secp), + )) + }) + .collect(); + + Ok(DerivedBip39Xprvs { + master_xprv: xprv_master, + phrase: mnemonic_gen.into_phrase(), + xprv_w_paths: xprv_w_paths?, + }) + } +} + +/// Enum that wraps all DescriptorCfg we can pass as serialized JSON +#[derive(Debug, Serialize, Deserialize)] +pub enum AnyDescriptorCfg { + Wpkh(Vec, Network), + WshMultiSorted(multi_sig::MultiSigCfg), +} + +impl From for WalletDescriptors { + fn from(cfg: AnyDescriptorCfg) -> Self { + match cfg { + AnyDescriptorCfg::Wpkh(xprvs, net) => (xprvs, net).into(), + AnyDescriptorCfg::WshMultiSorted(cfg) => cfg.into(), + } + } +} +impl From<(Vec, Network)> for WalletDescriptors { + fn from((keys, network): (Vec, Network)) -> Self { + let mut descriptors = keys + .iter() + .map(|XprvsWithPaths(key, path, master_fp)| { + let descriptor_key = key + .into_descriptor_key( + Some((*master_fp, path.clone())), + vec![key.child_number].into(), + ) + .unwrap(); + // TODO define the type of descriptor + bdk::descriptor!(wpkh((descriptor_key))).unwrap() + }) + .take(2); + + let (external_desc, ext_keymap, _) = descriptors.next().unwrap(); + let (internal_desc, int_keymap, _) = descriptors.next().unwrap(); + + WalletDescriptors { + external: external_desc.to_string_with_secret(&ext_keymap), + internal: Some(internal_desc.to_string_with_secret(&int_keymap)), + network, + public: external_desc.to_string(), + } + } +} + +impl From<(XprvsWithPaths, Network)> for XpubsWithPaths { + fn from((key, network): (XprvsWithPaths, Network)) -> Self { + let XprvsWithPaths(xprv, path, fp) = key; + let ex_xpub: ExtendedKey = xprv.into_extended_key().unwrap(); + let xpub = ex_xpub.into_xpub(network, &secp256k1::Secp256k1::new()); + XpubsWithPaths(xpub, path, fp) + } +} + +pub fn generate_extended_priv_key(network: Network) -> Result { + let mut entropy = [0u8; secp256k1::constants::SECRET_KEY_SIZE]; + thread_rng().fill_bytes(&mut entropy); + ExtendedPrivKey::new_master(network, &entropy) +} +pub fn generate_wif(network: Network) -> String { + let mut entropy = [0u8; secp256k1::constants::SECRET_KEY_SIZE]; + thread_rng().fill_bytes(&mut entropy); + PrivateKey { + compressed: true, + network, + key: secp256k1::SecretKey::from_slice(&entropy).expect("Error passing"), + } + .to_wif() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn get_a_harcoded_wallet() { + let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/0/*)"; + let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/1/*)"; + let wallet = Wallet::new( + external_descriptor, + Some(internal_descriptor), + Network::Testnet, + MemoryDatabase::new(), + ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002").unwrap()), + ) + .unwrap(); + let address = wallet + .get_address(AddressIndex::New) + .unwrap() + .address_type() + .unwrap(); + assert_eq!(format!("{}", address), "p2wpkh") + } + + #[test] + fn bip44_derive_path_with_bip39() { + let test_mnemonic = + "aim bunker wash balance finish force paper analyst cabin spoon stable organ"; + let num_child = 2; + // segwit/coin/account + let derive_base = "m/44'/0'/0'"; + let network = Network::Bitcoin; + + let wallet_xprvs = DerivedBip39Xprvs::new( + derive_base.into_derivation_path().unwrap(), + network, + num_child, + None, + Some(String::from(test_mnemonic)), + ) + .unwrap(); + + // master m + assert_eq!(wallet_xprvs.master_xprv.depth, 0); + + // from https://iancoleman.io/bip39/ + let expected_xprvs = ["xprvA1Rm2Dm6Zgjc6yLcH1vyS1VuykpPMKCQmymmYFv9kSvpfZ51y8G6wzaZVC6BtphuiDKEXcsENy3RbwLa3Nqwb9VBQvQagEG6J5EK76aTjmh","xprvA1Rm2Dm6Zgjc8zwffxi6Bb9dX5V14mvLRPVo72J3Q8C5BHRyACD7Ywk2L7ovf5fo8WcBQ7Janoba9fQXjXuY5wQaRfzj5ahZkPBZY449suQ"]; + + // derive n childs int/ext m/0'/n' + wallet_xprvs.xprv_w_paths.into_iter().enumerate().for_each( + |(i, XprvsWithPaths(key, path, _))| { + assert_eq!(format!("{}", path), format!("m/44'/0'/0'/{}", i)); + assert_eq!(key.to_string(), expected_xprvs[i]); + assert_eq!(key.depth, 4); + }, + ); + } + + #[test] + fn generate_a_bip39_wallet_with_n_keys_from_path() { + // /coin/account + let derive_base = "m/44'/0'/0'"; + let network = Network::Testnet; + let wallet_xprvs = DerivedBip39Xprvs::new( + derive_base.into_derivation_path().unwrap(), + network, + 2, + Some(String::from("mypass")), + None, + ) + .unwrap(); + + let descriptors: WalletDescriptors = (wallet_xprvs.xprv_w_paths, network).into(); + println!("Descr {:#?}", serde_json::to_string(&descriptors)); + let wallet_cfg = WalletCfg { + name: String::from("my test"), + descriptors, + address_look_ahead: 2, + db_path: None, + server_uri: Some("ssl://electrum.blockstream.info:50002".into()), + }; + let wallet: ElectrumMemoryWallet = wallet_cfg.into(); + let address = wallet.get_address(AddressIndex::New).unwrap(); + assert_eq!(format!("{}", address.address_type().unwrap()), "p2wpkh"); + } + #[test] + fn electrum_sled() { + // segwit/coin/account + let derive_base = "m/44'/0'/0'"; + let network = Network::Testnet; + let wallet_xprvs = DerivedBip39Xprvs::new( + derive_base.into_derivation_path().unwrap(), + network, + 2, + Some(String::from("mypass")), + None, + ) + .unwrap(); + + let descriptors: WalletDescriptors = + AnyDescriptorCfg::Wpkh(wallet_xprvs.xprv_w_paths, network).into(); + let wallet_cfg = WalletCfg { + name: String::from("mytest2"), + descriptors, + address_look_ahead: 2, + db_path: Some(String::from("/tmp/sifir-bdk")), + server_uri: Some("ssl://electrum.blockstream.info:50002".into()), + }; + let wallet: ElectrumSledWallet = wallet_cfg.into(); + let address = wallet.get_address(AddressIndex::New).unwrap(); + assert_eq!(format!("{}", address.address_type().unwrap()), "p2wpkh"); + } + + #[test] + fn txn_from_create_txn_json() { + let rcvr_wallet_cfg:WalletCfg = serde_json::from_str( "{\"name\":\"my test\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wpkh(tprv8e5FKc3Mdn1ByJgZ2GBBA4DFZ2tAzmtquHHPhRtRFmq1M8a3je1DXhRu2Dnx6db3GKmavKbku5sdkcAzWBHwi1KVoNMi4V3oox4vfrvuyNs/0\'/0/*)\",\"internal\":\"wpkh([547f0cd3/0\'/1]tprv8e5FKc3Mdn1C3eHRQ4pBZR13wHTHpX1umHgPpQv9HDjA5MRUKmRQqjWic6gfSAp6CDyM8B3ur3jkayG7E8yG5eNj3ZcCEJnuaKa14Q9Tf9W/0\'/1/*)#63l9gmuk\",\"public\":\"wpkh([547f0cd3/0\'/0/0\']tpubDCYJ5ZRDkRcFtTQZzetaWVS6q52rs3RTAKXYMWEvGCR6Nb1LTFpdwGohYQ4f98aVE6NxYN3tru8kziP9vZhDYZYDd5VDERyFr8U5WeCbGHy/0/*)#knhduycc\"},\"address_look_ahead\":2}").unwrap(); + let sender_wallet_cfg:WalletCfg = serde_json::from_str( "{\"name\":\"my test_2\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wpkh(tprv8dWQe989ftsPNn9NddyKVri3GHs4voe2E4xS75oX9neHeQGCnbn2ru3o1mbxmW2SnNRtpMdaopc6GWftoGMyhKPX3zjCBTKU1Ckw6E6NmQL/0\'/0/*)\",\"internal\":\"wpkh([0776ff86/0\'/1]tprv8dWQe989ftsPRPriFR6w1cG3R2s5FBxXsDscygXe8RiaUQrRkA7J8FFJwTPRBoLia7fqVB8s87SQ5rLnVjbZfDpuorRkBBqrSHKVbhUMYmq/0\'/1/*)#ynv3pma4\",\"public\":\"wpkh([0776ff86/0\'/0/0\']tpubDCmXi7Tx4hixdHtw4WVgnSAsDJ4Q8oR3NSq6DYRmCC46hihokPaHo3RAdaSQza8sWtAU63zt5VgkgYt6tUmZQWqVZio5vptzgrNMmrRwcBF/0/*)#cn8qlh6k\"},\"address_look_ahead\":2}").unwrap(); + + let rcvr_wallet: ElectrumMemoryWallet = rcvr_wallet_cfg.into(); + let sender_wallet: ElectrumMemoryWallet = sender_wallet_cfg.into(); + + let recipients = (1..3) + .map(|i| { + ( + rcvr_wallet + .get_address(AddressIndex::New) + .unwrap() + .to_string(), + 1000 * i, + ) + }) + .collect(); + let txn = CreateTx { + recipients, + fee_type: FeeType::Rate, + fee: 4.0, + spend_change: SpendChangePolicy::Yes, + enable_rbf: true, + }; + + let txn_json = serde_json::to_string(&txn).unwrap(); + println!("txn json {}", txn_json); + let txn: CreateTx = serde_json::from_str(&txn_json).unwrap(); + + let wallet_txn = txn.into_wallet_txn(&sender_wallet).unwrap(); + println!("txn wallet {:?} {:?}", wallet_txn.0, wallet_txn.1); + } + #[test] + #[ignore] + fn can_sync_wallet_and_sign_utxos() { + let rcvr_wallet_cfg:WalletCfg = serde_json::from_str( "{\"name\":\"my test\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wpkh(tprv8e5FKc3Mdn1ByJgZ2GBBA4DFZ2tAzmtquHHPhRtRFmq1M8a3je1DXhRu2Dnx6db3GKmavKbku5sdkcAzWBHwi1KVoNMi4V3oox4vfrvuyNs/0\'/0/*)\",\"internal\":\"wpkh([547f0cd3/0\'/1]tprv8e5FKc3Mdn1C3eHRQ4pBZR13wHTHpX1umHgPpQv9HDjA5MRUKmRQqjWic6gfSAp6CDyM8B3ur3jkayG7E8yG5eNj3ZcCEJnuaKa14Q9Tf9W/0\'/1/*)#63l9gmuk\",\"public\":\"wpkh([547f0cd3/0\'/0/0\']tpubDCYJ5ZRDkRcFtTQZzetaWVS6q52rs3RTAKXYMWEvGCR6Nb1LTFpdwGohYQ4f98aVE6NxYN3tru8kziP9vZhDYZYDd5VDERyFr8U5WeCbGHy/0/*)#knhduycc\"},\"address_look_ahead\":2,\"server_uri\": \"ssl://electrum.blockstream.info:60002\"}").unwrap(); + let sender_wallet_cfg:WalletCfg = serde_json::from_str( "{\"name\":\"my test_2\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wpkh(tprv8dWQe989ftsPNn9NddyKVri3GHs4voe2E4xS75oX9neHeQGCnbn2ru3o1mbxmW2SnNRtpMdaopc6GWftoGMyhKPX3zjCBTKU1Ckw6E6NmQL/0\'/0/*)\",\"internal\":\"wpkh([0776ff86/0\'/1]tprv8dWQe989ftsPRPriFR6w1cG3R2s5FBxXsDscygXe8RiaUQrRkA7J8FFJwTPRBoLia7fqVB8s87SQ5rLnVjbZfDpuorRkBBqrSHKVbhUMYmq/0\'/1/*)#ynv3pma4\",\"public\":\"wpkh([0776ff86/0\'/0/0\']tpubDCmXi7Tx4hixdHtw4WVgnSAsDJ4Q8oR3NSq6DYRmCC46hihokPaHo3RAdaSQza8sWtAU63zt5VgkgYt6tUmZQWqVZio5vptzgrNMmrRwcBF/0/*)#cn8qlh6k\"},\"address_look_ahead\":2},\"server_uri\": \"ssl://electrum.blockstream.info:60002\"}").unwrap(); + + let rcvr_wallet: ElectrumMemoryWallet = rcvr_wallet_cfg.into(); + let sender_wallet: ElectrumMemoryWallet = sender_wallet_cfg.into(); + + println!( + "rcvr add {}", + rcvr_wallet.get_address(AddressIndex::New).unwrap() + ); + struct SifirWallet {} // TODO SifirWallet + impl Progress for SifirWallet { + fn update(&self, progress: f32, message: Option) -> Result<(), bdk::Error> { + println!("progress is {} and message {:?}", progress, message); + Ok(()) + } + } + let sync_result = sender_wallet.sync(SifirWallet {}, Some(100)); + sync_result.unwrap(); + + let balance = sender_wallet.get_balance().unwrap(); + assert!(balance > 100); + let mut txn = sender_wallet.build_tx(); + txn.add_recipient( + rcvr_wallet + .get_address(AddressIndex::New) + .unwrap() + .script_pubkey(), + 1000, + ) + .fee_rate(FeeRate::from_sat_per_vb(5.0)) + .do_not_spend_change() + .enable_rbf(); + + let (mut psbt, _tx_details) = txn.finish().unwrap(); + let ok = sender_wallet.sign(&mut psbt, Default::default()).unwrap(); + assert!(ok); + let _txn_id = sender_wallet.broadcast(psbt.extract_tx()).unwrap(); + } +} diff --git a/btc/src/multi_sig/mod.rs b/btc/src/multi_sig/mod.rs new file mode 100644 index 0000000..e666f54 --- /dev/null +++ b/btc/src/multi_sig/mod.rs @@ -0,0 +1,315 @@ +use crate::bdk::descriptor::IntoWalletDescriptor; +use crate::AnyDescriptorCfg; +use crate::{sled, AddressIndex, Client, ElectrumBlockchain, Wallet}; +use crate::{ + DerivedBip39Xprvs, ElectrumMemoryWallet, ElectrumSledWallet, WalletDescriptors, XprvsWithPaths, + XpubsWithPaths, +}; +pub use bdk::bitcoin::util::bip32::{ + ChildNumber, DerivationPath, Error as Bip32Error, ExtendedPrivKey, ExtendedPubKey, Fingerprint, + IntoDerivationPath, +}; +pub use bdk::bitcoin::{secp256k1, Address, Network, OutPoint, PrivateKey, Script, Txid}; +use bdk::keys::{DerivableKey, DescriptorKey, IntoDescriptorKey}; +use serde::{Deserialize, Serialize}; +use std::iter::Map; +use std::ops::RangeFrom; +use std::str::FromStr; + +#[derive(Debug, Serialize, Deserialize)] +pub enum MultiSigKey { + Xpub(XpubsWithPaths), + Xprv(XprvsWithPaths), +} + +#[derive(Debug, Serialize, Deserialize)] +/// +/// Serializes as: +///{ +/// "descriptors": [ +/// { +/// "Xprv": [ +/// "tprv8hb2jMkXPyzimyaTaQ9tTH2xj7CcQENS3uMdNptCyGmDgSbFA2q7Zfpyjs3kf96Ecmascxp2bRg1ztSXGGY3jhzT1N5chXgHUcRwWAAh7kY", +/// "m/0", +/// "ff31a959" +/// ] +/// }, +/// { +/// "Xpub": [ +/// "tpubDFSuJXy4vxC6vX3o1yNZjmdR7T7qS2FgbtqhHSvjNMjyXLHNJk9XzTqCPbVrbevbYyasY6wnS96s5Er4xkNosm3pcuyFH9LUxPUavJ2EZSC", +/// "m/44'/0'/0'/0", +/// "77306a4c" +/// ] +/// }, +/// { +/// "Xpub": [ +/// "tpubDEYM383BbDXgPSpGmBWcdDCDo5HbREUBPVeUuyypBXpyQsMGykfGA2AURtuHbaN7ktrcbyct665m6VbtyQKsQD17Vp7yavVwdyGQ87659RR", +/// "m/44'/0'/0'/0", +/// "d22d870c" +/// ] +/// } +/// ], +/// "network": "testnet", +/// "quorom": 2 +///} +pub struct MultiSigCfg { + descriptors: Vec, + network: Network, + quorom: i32, +} + +impl From for WalletDescriptors { + fn from( + MultiSigCfg { + descriptors, + quorom, + network, + }: MultiSigCfg, + ) -> Self { + let keys = descriptors + .into_iter() + .map(|key| { + match key { + MultiSigKey::Xpub(xpub_w_paths) => xpub_w_paths + .0 + .into_descriptor_key( + Some((xpub_w_paths.2, xpub_w_paths.1.clone())), + "m/0".into_derivation_path().unwrap(), + ) + .unwrap(), + MultiSigKey::Xprv(xprv_w_paths) => + // Note: here use the path to apply to xprv, not full derivation path + { + (xprv_w_paths.0, xprv_w_paths.1) + .into_descriptor_key() + .unwrap() + } + } + }) + .collect(); + + let (multi_sig_desc, multi_key_map, _) = + // TODO accept input of descriptor type + bdk::descriptor!(wsh(sortedmulti_vec(quorom as usize, keys))).unwrap(); + + WalletDescriptors { + external: multi_sig_desc.to_string_with_secret(&multi_key_map), + internal: None, + network, + public: multi_sig_desc.to_string(), + } + } +} +#[cfg(test)] +mod tests { + use super::*; + use crate::bdk::keys::ExtendedKey; + use crate::bdk::miniscript::miniscript; + use crate::WalletCfg; + use bdk::{FeeRate, SignOptions}; + use std::str::FromStr; + + struct SifirWallet {} // TODO SifirWallet + impl bdk::blockchain::Progress for SifirWallet { + fn update(&self, progress: f32, message: Option) -> Result<(), bdk::Error> { + println!("progress is {} and message {:?}", progress, message); + Ok(()) + } + } + + #[test] + fn gen_multisig_wallets() { + // 1. Make some keys + let derive_base = "m/44'/0'/0'"; + let network = Network::Testnet; + // Returns a tuple of closures that generate an Xpub and Xprv for each key + let mut xpub_xprv_tuple = (1..) + .map(|_| { + let key = DerivedBip39Xprvs::new( + derive_base.into_derivation_path().unwrap(), + network, + 1, + None, + None, + ) + .unwrap(); + key + }) + .map(|key| { + let XprvsWithPaths(key, path, master_fp) = &key.xprv_w_paths[0]; + // TODO is all this cloning necessary to keep compiler happy? Clean this up + let p1 = path.clone(); + let mf = master_fp.clone(); + let mf2 = master_fp.clone(); + let key1 = key.clone(); + let key2 = key.clone(); + ( + move || { + let path = p1.clone(); + let ex_xpub: ExtendedKey = + key1.into_extended_key().unwrap(); + let xpub = + ex_xpub.into_xpub(Network::Testnet, &secp256k1::Secp256k1::new()); + XpubsWithPaths(xpub, path, mf) + }, + move || + // Note to self: Path is relative to xprv (ie from here), which is m/0 here (NOT the full path used to get to this key) + XprvsWithPaths(key2, DerivationPath::from_str("m/0").unwrap(), mf2), + ) + }); + + let (andriana_xpub, andriana_xprv) = xpub_xprv_tuple.next().unwrap(); + let (jose_xpub, jose_xprv) = xpub_xprv_tuple.next().unwrap(); + let (ahmed_xpub, ahmed_xprv) = xpub_xprv_tuple.next().unwrap(); + // 2. Construct some wallet cfg + let adriana_wallet_cfg = WalletCfg { + name: String::from("adriana_wallet"), + db_path: None, + descriptors: AnyDescriptorCfg::WshMultiSorted(MultiSigCfg { + descriptors: vec![ + MultiSigKey::Xprv(andriana_xprv()), + MultiSigKey::Xpub(jose_xpub()), + MultiSigKey::Xpub(ahmed_xpub()), + ], + network: Network::Testnet, + quorom: 2, + }) + .into(), + address_look_ahead: 1, + server_uri: None, + }; + + let jose_wallet_cfg = WalletCfg { + name: String::from("jose_wallet"), + db_path: None, + descriptors: AnyDescriptorCfg::WshMultiSorted(MultiSigCfg { + descriptors: vec![ + MultiSigKey::Xpub(andriana_xpub()), + MultiSigKey::Xprv(jose_xprv()), + MultiSigKey::Xpub(ahmed_xpub()), + ], + network: Network::Testnet, + quorom: 2, + }) + .into(), + address_look_ahead: 1, + server_uri: None, + }; + let ahmed_wallet_cfg = WalletCfg { + name: String::from("ahmed_wallet"), + db_path: None, + descriptors: AnyDescriptorCfg::WshMultiSorted(MultiSigCfg { + descriptors: vec![ + MultiSigKey::Xpub(andriana_xpub()), + MultiSigKey::Xpub(jose_xpub()), + MultiSigKey::Xprv(ahmed_xprv()), + ], + + network: Network::Testnet, + quorom: 2, + }) + .into(), + address_look_ahead: 1, + server_uri: None, + }; + println!( + "{} \r\n {} \r\n {} \r\n", + serde_json::to_string(&adriana_wallet_cfg).unwrap(), + serde_json::to_string(&jose_wallet_cfg).unwrap(), + serde_json::to_string(&ahmed_wallet_cfg).unwrap() + ); + + // 3. Wallet instances and sync + let synced_wallets: Vec<_> = vec![adriana_wallet_cfg, jose_wallet_cfg, ahmed_wallet_cfg] + .into_iter() + .map(ElectrumMemoryWallet::from) + .map(|wallet| { + wallet.sync(SifirWallet {}, Some(100)).unwrap(); + wallet + }) + .collect(); + + // 4. Make sure we generate the same addresses + + let ariana_add = synced_wallets[0] + .get_address(AddressIndex::LastUnused) + .unwrap(); + let jose_add = synced_wallets[1] + .get_address(AddressIndex::LastUnused) + .unwrap(); + let ahmad_add = synced_wallets[2] + .get_address(AddressIndex::LastUnused) + .unwrap(); + assert_eq!(ariana_add, jose_add); + assert_eq!(jose_add, ahmad_add); + // println!("{}", ariana_add); + } + + #[test] + fn deserialize_multsig_and_sign() { + // send back to https://testnet-faucet.mempool.co/ + // let rcvr_address = "mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt"; + let rcvr_address = "tb1qcpvp8fwv23egkee7ld2dt9ndymcyhl58g4fvq479tsr62u5mjakq2r8gke"; + + // Deserialize savde wallets + let adriana_wallet: ElectrumMemoryWallet = serde_json::from_str::("{\"name\":\"adriana_wallet\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wsh(sortedmulti(2,tprv8ip37K5SBQqZcmpaH72wSNfAAXPt5UPUVnWHPTkPqgvQCm5kFRkQL9k8fmXV7xG9nB3eJxi2SKVGtRQspG2NRfkyj5dseVPaznx4saX8KQp/0/*,[011aed20/44'/0'/0'/0]tpubDFZR9wnXt7a1fUVj2jEJw7E37pju124qjEfDDG9efozibH7T5BYtjwbjHtxHDK9q2nqsTYn25CngM2XUpXd1oZWCByWjkCG1YY1wnRvPTb8/0/*,[83488a89/44'/0'/0'/0]tpubDFi8BjbFcmJ3owMcf6SP2ZwZfYFWqi1C9PUv3EdorHCeipRycFrWc5crm7yJSUJiMWpqoXL37ykWgk6Str2yRd519MogoRKoLfkCuRT33oY/0/*))#z6qy6pcq\",\"internal\":null,\"public\":\"wsh(sortedmulti(2,tpubDFW5Fj7gKnXEWErNAkhXqnKGjYupEoaP5674fynhFxio3FLWspZzWeMzquGXpVs1LknsbBvxPVu8XPWXZDwKFFr56kagYiPL8mLCiZ5Wq1K/0/*,[011aed20/44'/0'/0'/0]tpubDFZR9wnXt7a1fUVj2jEJw7E37pju124qjEfDDG9efozibH7T5BYtjwbjHtxHDK9q2nqsTYn25CngM2XUpXd1oZWCByWjkCG1YY1wnRvPTb8/0/*,[83488a89/44'/0'/0'/0]tpubDFi8BjbFcmJ3owMcf6SP2ZwZfYFWqi1C9PUv3EdorHCeipRycFrWc5crm7yJSUJiMWpqoXL37ykWgk6Str2yRd519MogoRKoLfkCuRT33oY/0/*))#6365az6x\"},\"address_look_ahead\":1,\"db_path\":null,\"server_uri\":null} +").unwrap().into(); + let jose_wallet: ElectrumMemoryWallet = serde_json::from_str::(" {\"name\":\"jose_wallet\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wsh(sortedmulti(2,[74d72b43/44'/0'/0'/0]tpubDFW5Fj7gKnXEWErNAkhXqnKGjYupEoaP5674fynhFxio3FLWspZzWeMzquGXpVs1LknsbBvxPVu8XPWXZDwKFFr56kagYiPL8mLCiZ5Wq1K/0/*,tprv8isP1XkHjjtLn1Tw95ZiXhZvYoDxqgsw9w4Rvk7MFYCKknrgSnjJZSys7k4aMx5Fk6vidUv7KWgj5RBRVR1aLqqNzZV6gDgpJS7PMNpza1C/0/*,[83488a89/44'/0'/0'/0]tpubDFi8BjbFcmJ3owMcf6SP2ZwZfYFWqi1C9PUv3EdorHCeipRycFrWc5crm7yJSUJiMWpqoXL37ykWgk6Str2yRd519MogoRKoLfkCuRT33oY/0/*))#yfgnjyt7\",\"internal\":null,\"public\":\"wsh(sortedmulti(2,[74d72b43/44'/0'/0'/0]tpubDFW5Fj7gKnXEWErNAkhXqnKGjYupEoaP5674fynhFxio3FLWspZzWeMzquGXpVs1LknsbBvxPVu8XPWXZDwKFFr56kagYiPL8mLCiZ5Wq1K/0/*,tpubDFZR9wnXt7a1fUVj2jEJw7E37pju124qjEfDDG9efozibH7T5BYtjwbjHtxHDK9q2nqsTYn25CngM2XUpXd1oZWCByWjkCG1YY1wnRvPTb8/0/*,[83488a89/44'/0'/0'/0]tpubDFi8BjbFcmJ3owMcf6SP2ZwZfYFWqi1C9PUv3EdorHCeipRycFrWc5crm7yJSUJiMWpqoXL37ykWgk6Str2yRd519MogoRKoLfkCuRT33oY/0/*))#ulfgmk2l\"},\"address_look_ahead\":1,\"db_path\":null,\"server_uri\":null} +").unwrap().into(); + + let ahmed_wallet: ElectrumMemoryWallet = serde_json::from_str::(" {\"name\":\"ahmed_wallet\",\"descriptors\":{\"network\":\"testnet\",\"external\":\"wsh(sortedmulti(2,[74d72b43/44'/0'/0'/0]tpubDFW5Fj7gKnXEWErNAkhXqnKGjYupEoaP5674fynhFxio3FLWspZzWeMzquGXpVs1LknsbBvxPVu8XPWXZDwKFFr56kagYiPL8mLCiZ5Wq1K/0/*,[011aed20/44'/0'/0'/0]tpubDFZR9wnXt7a1fUVj2jEJw7E37pju124qjEfDDG9efozibH7T5BYtjwbjHtxHDK9q2nqsTYn25CngM2XUpXd1oZWCByWjkCG1YY1wnRvPTb8/0/*,tprv8j263KZ1UPcNvUKpmSmndAHT6WjagNpHa5t8kibWS1QFtLBCys2vRazzayhbAKNj9WdGaAC6gFjga7YibMNhboLeJKgfxS5b7ESy6gTMkAk/0/*))#zzx570uh\",\"internal\":null,\"public\":\"wsh(sortedmulti(2,[74d72b43/44'/0'/0'/0]tpubDFW5Fj7gKnXEWErNAkhXqnKGjYupEoaP5674fynhFxio3FLWspZzWeMzquGXpVs1LknsbBvxPVu8XPWXZDwKFFr56kagYiPL8mLCiZ5Wq1K/0/*,[011aed20/44'/0'/0'/0]tpubDFZR9wnXt7a1fUVj2jEJw7E37pju124qjEfDDG9efozibH7T5BYtjwbjHtxHDK9q2nqsTYn25CngM2XUpXd1oZWCByWjkCG1YY1wnRvPTb8/0/*,tpubDFi8BjbFcmJ3owMcf6SP2ZwZfYFWqi1C9PUv3EdorHCeipRycFrWc5crm7yJSUJiMWpqoXL37ykWgk6Str2yRd519MogoRKoLfkCuRT33oY/0/*))#zskvcukm\"},\"address_look_ahead\":1,\"db_path\":null,\"server_uri\":null} +").unwrap().into(); + + adriana_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + jose_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + ahmed_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + + let adriana_address = adriana_wallet + .get_address(AddressIndex::LastUnused) + .unwrap(); + let jose_address = jose_wallet.get_address(AddressIndex::LastUnused).unwrap(); + let ahmed_addres = ahmed_wallet.get_address(AddressIndex::LastUnused).unwrap(); + + assert_eq!(adriana_address, jose_address); + assert_eq!(jose_address, ahmed_addres); + // + // Send some sats to this scripts address + //println!("next address: {}",adriana_address ); + + adriana_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + jose_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + ahmed_wallet.sync(SifirWallet {}, Some(100)).unwrap(); + + let adoni_balance = adriana_wallet.get_balance().unwrap(); + let janis_balance = jose_wallet.get_balance().unwrap(); + let albert_balance = ahmed_wallet.get_balance().unwrap(); + + //println!( "wallet balance {}", adoni_balance ); + assert!(adoni_balance > 0); + assert_eq!(adoni_balance, janis_balance); + assert_eq!(janis_balance, albert_balance); + + let mut txn = jose_wallet.build_tx(); + txn.set_single_recipient( + Address::from_str(rcvr_address) + .unwrap() + .payload + .script_pubkey(), + ) + .drain_wallet() + .fee_rate(FeeRate::from_sat_per_vb(1.0)) + .enable_rbf(); + + let (mut psbt, _tx_details) = txn.finish().unwrap(); + let finished = jose_wallet.sign(&mut psbt, SignOptions::default()).unwrap(); + assert!(!finished); + let finished = ahmed_wallet + .sign(&mut psbt, SignOptions::default()) + .unwrap(); + assert!(finished); + + //let txn_id = jose_wallet.broadcast(psbt.extract_tx()).unwrap(); + //println!("txnId: {}",txn_id); + //assert_eq!(txn_id.len(),32) + } +} diff --git a/sifir-android/Cargo.toml b/sifir-android/Cargo.toml index 108812c..cbd18fa 100644 --- a/sifir-android/Cargo.toml +++ b/sifir-android/Cargo.toml @@ -4,9 +4,15 @@ version = "0.1.0" authors = ["Gus Abidi "] edition = "2018" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +btc_wallet =["btc"] +tor_daemon =["tor"] + [dependencies] +tor = { path = "../tor", optional = true } +btc= { path = "../btc", optional = true } logger = { path = "../logger" } -tor = { path = "../tor" } jni = "0.18.0" jni-sys = "0.3.0" serde = { version="1.0.117", features = ["derive"]} diff --git a/sifir-android/app/tor/src/main/java/com/sifir/.gitkeep b/sifir-android/app/tor/src/main/java/com/sifir/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/DataObserver.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/DataObserver.java deleted file mode 100644 index a8399c2..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/DataObserver.java +++ /dev/null @@ -1,13 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public interface DataObserver { - - - void onData(String result); - - - void onError(String result); - -} diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/HiddenServiceHandler.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/HiddenServiceHandler.java deleted file mode 100644 index 01f27e8..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/HiddenServiceHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public final class HiddenServiceHandler { - - public HiddenServiceHandler(int dst_port, DataObserver cb) throws Exception { - mNativeObj = init(dst_port, cb); - } - private static native long init(int dst_port, DataObserver cb) throws Exception; - - public synchronized void delete() { - if (mNativeObj != 0) { - do_delete(mNativeObj); - mNativeObj = 0; - } - } - @Override - protected void finalize() throws Throwable { - try { - delete(); - } - finally { - super.finalize(); - } - } - private static native void do_delete(long me); - /*package*/ HiddenServiceHandler(InternalPointerMarker marker, long ptr) { - assert marker == InternalPointerMarker.RAW_PTR; - this.mNativeObj = ptr; - } - /*package*/ long mNativeObj; -} \ No newline at end of file diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/InternalPointerMarker.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/InternalPointerMarker.java deleted file mode 100644 index 641ae4c..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/InternalPointerMarker.java +++ /dev/null @@ -1,7 +0,0 @@ - -// Automatically generated by flapigen -package com.sifir.tor; - -/*package*/ enum InternalPointerMarker { - RAW_PTR; -} diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/JNIReachabilityFence.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/JNIReachabilityFence.java deleted file mode 100644 index 6ae02e4..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/JNIReachabilityFence.java +++ /dev/null @@ -1,14 +0,0 @@ - -// Automatically generated by flapigen -package com.sifir.tor; - -/*package*/ final class JNIReachabilityFence { - private JNIReachabilityFence() {} - /*package*/ static native void reachabilityFence1(Object ref1); - /*package*/ static native void reachabilityFence2(Object ref1, Object ref2); - /*package*/ static native void reachabilityFence3(Object ref1, Object ref2, Object ref3); - /*package*/ static native void reachabilityFence4(Object ref1, Object ref2, Object ref3, Object ref4); - /*package*/ static native void reachabilityFence5(Object ref1, Object ref2, Object ref3, Object ref4, Object ref5); - /*package*/ static native void reachabilityFence6(Object ref1, Object ref2, Object ref3, Object ref4, Object ref5, Object ref6); - /*package*/ static native void reachabilityFence7(Object ref1, Object ref2, Object ref3, Object ref4, Object ref5, Object ref6, Object ref7); - /*package*/ static native void reachabilityFence8(Object ref1, Object ref2, Object ref3, Object ref4, Object ref5, Object ref6, Object ref7, Object ref8);} diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/OwnedTorService.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/OwnedTorService.java deleted file mode 100644 index 35aac07..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/OwnedTorService.java +++ /dev/null @@ -1,69 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public final class OwnedTorService { - - public OwnedTorService(TorServiceParam param) throws Exception { - long a0 = param.mNativeObj; - param.mNativeObj = 0; - - mNativeObj = init(a0); - JNIReachabilityFence.reachabilityFence1(param); - } - private static native long init(long param) throws Exception; - - public final int getSocksPort() { - int ret = do_getSocksPort(mNativeObj); - - return ret; - } - private static native int do_getSocksPort(long self); - - public final void shutdown() throws Exception { - do_shutdown(mNativeObj); - } - private static native void do_shutdown(long self) throws Exception; - - public final String get_status() { - String ret = do_get_status(mNativeObj); - - return ret; - } - private static native String do_get_status(long self); - - public final TorHiddenService create_hidden_service(int dst_port, int hs_port, String secret_key) throws Exception { - long ret = do_create_hidden_service(mNativeObj, dst_port, hs_port, secret_key); - TorHiddenService convRet = new TorHiddenService(InternalPointerMarker.RAW_PTR, ret); - - return convRet; - } - private static native long do_create_hidden_service(long self, int dst_port, int hs_port, String secret_key) throws Exception; - - public final void delete_hidden_service(String onion) throws Exception { - do_delete_hidden_service(mNativeObj, onion); - } - private static native void do_delete_hidden_service(long self, String onion) throws Exception; - - public synchronized void delete() { - if (mNativeObj != 0) { - do_delete(mNativeObj); - mNativeObj = 0; - } - } - @Override - protected void finalize() throws Throwable { - try { - delete(); - } - finally { - super.finalize(); - } - } - private static native void do_delete(long me); - /*package*/ OwnedTorService(InternalPointerMarker marker, long ptr) { - assert marker == InternalPointerMarker.RAW_PTR; - this.mNativeObj = ptr; - } - /*package*/ long mNativeObj; -} \ No newline at end of file diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/TcpSocksStream.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/TcpSocksStream.java deleted file mode 100644 index 0778922..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/TcpSocksStream.java +++ /dev/null @@ -1,43 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public final class TcpSocksStream { - - public TcpSocksStream(String target, String socks_proxy, long timeout_ms) throws Exception { - mNativeObj = init(target, socks_proxy, timeout_ms); - } - private static native long init(String target, String socks_proxy, long timeout_ms) throws Exception; - - public final void on_data(DataObserver cb) throws Exception { - do_on_data(mNativeObj, cb); - } - private static native void do_on_data(long self, DataObserver cb) throws Exception; - - public final void send_data(String msg, long timeout) throws Exception { - do_send_data(mNativeObj, msg, timeout); - } - private static native void do_send_data(long self, String msg, long timeout) throws Exception; - - public synchronized void delete() { - if (mNativeObj != 0) { - do_delete(mNativeObj); - mNativeObj = 0; - } - } - @Override - protected void finalize() throws Throwable { - try { - delete(); - } - finally { - super.finalize(); - } - } - private static native void do_delete(long me); - /*package*/ TcpSocksStream(InternalPointerMarker marker, long ptr) { - assert marker == InternalPointerMarker.RAW_PTR; - this.mNativeObj = ptr; - } - /*package*/ long mNativeObj; -} \ No newline at end of file diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/TorHiddenService.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/TorHiddenService.java deleted file mode 100644 index 79ec18a..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/TorHiddenService.java +++ /dev/null @@ -1,44 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public final class TorHiddenService { - - private TorHiddenService() {} - - public final String get_onion_url() { - String ret = do_get_onion_url(mNativeObj); - - return ret; - } - private static native String do_get_onion_url(long self); - - public final String get_secret_b64() { - String ret = do_get_secret_b64(mNativeObj); - - return ret; - } - private static native String do_get_secret_b64(long self); - - public synchronized void delete() { - if (mNativeObj != 0) { - do_delete(mNativeObj); - mNativeObj = 0; - } - } - @Override - protected void finalize() throws Throwable { - try { - delete(); - } - finally { - super.finalize(); - } - } - private static native void do_delete(long me); - /*package*/ TorHiddenService(InternalPointerMarker marker, long ptr) { - assert marker == InternalPointerMarker.RAW_PTR; - this.mNativeObj = ptr; - } - /*package*/ long mNativeObj; -} \ No newline at end of file diff --git a/sifir-android/app/tor/src/main/java/com/sifir/tor/TorServiceParam.java b/sifir-android/app/tor/src/main/java/com/sifir/tor/TorServiceParam.java deleted file mode 100644 index 4746982..0000000 --- a/sifir-android/app/tor/src/main/java/com/sifir/tor/TorServiceParam.java +++ /dev/null @@ -1,33 +0,0 @@ -// Automatically generated by flapigen -package com.sifir.tor; - - -public final class TorServiceParam { - - public TorServiceParam(String data_dir, int socks_port, long bootstap_timeout_ms) { - mNativeObj = init(data_dir, socks_port, bootstap_timeout_ms); - } - private static native long init(String data_dir, int socks_port, long bootstap_timeout_ms); - - public synchronized void delete() { - if (mNativeObj != 0) { - do_delete(mNativeObj); - mNativeObj = 0; - } - } - @Override - protected void finalize() throws Throwable { - try { - delete(); - } - finally { - super.finalize(); - } - } - private static native void do_delete(long me); - /*package*/ TorServiceParam(InternalPointerMarker marker, long ptr) { - assert marker == InternalPointerMarker.RAW_PTR; - this.mNativeObj = ptr; - } - /*package*/ long mNativeObj; -} \ No newline at end of file diff --git a/sifir-android/app/tor/src/main/jniLibs/arm64-v8a/libsifir_android.so b/sifir-android/app/tor/src/main/jniLibs/arm64-v8a/libsifir_android.so index a31788f..e2f10d2 100755 Binary files a/sifir-android/app/tor/src/main/jniLibs/arm64-v8a/libsifir_android.so and b/sifir-android/app/tor/src/main/jniLibs/arm64-v8a/libsifir_android.so differ diff --git a/sifir-android/app/tor/src/main/jniLibs/arm64/libsifir_android.so b/sifir-android/app/tor/src/main/jniLibs/arm64/libsifir_android.so index a31788f..e2f10d2 100755 Binary files a/sifir-android/app/tor/src/main/jniLibs/arm64/libsifir_android.so and b/sifir-android/app/tor/src/main/jniLibs/arm64/libsifir_android.so differ diff --git a/sifir-android/app/tor/src/main/jniLibs/armeabi-v7a/libsifir_android.so b/sifir-android/app/tor/src/main/jniLibs/armeabi-v7a/libsifir_android.so index 66b43af..7ca194a 100755 Binary files a/sifir-android/app/tor/src/main/jniLibs/armeabi-v7a/libsifir_android.so and b/sifir-android/app/tor/src/main/jniLibs/armeabi-v7a/libsifir_android.so differ diff --git a/sifir-android/app/tor/src/main/jniLibs/x86/libsifir_android.so b/sifir-android/app/tor/src/main/jniLibs/x86/libsifir_android.so index 9886f18..2463357 100755 Binary files a/sifir-android/app/tor/src/main/jniLibs/x86/libsifir_android.so and b/sifir-android/app/tor/src/main/jniLibs/x86/libsifir_android.so differ diff --git a/sifir-android/app/tor/src/main/jniLibs/x86_64/libsifir_android.so b/sifir-android/app/tor/src/main/jniLibs/x86_64/libsifir_android.so index 7147ca3..e46ee8e 100755 Binary files a/sifir-android/app/tor/src/main/jniLibs/x86_64/libsifir_android.so and b/sifir-android/app/tor/src/main/jniLibs/x86_64/libsifir_android.so differ diff --git a/sifir-android/app/tor/src/test/jniLibs/x86_64/libsifir_android.so b/sifir-android/app/tor/src/test/jniLibs/x86_64/libsifir_android.so index dfa0fca..da75569 100755 Binary files a/sifir-android/app/tor/src/test/jniLibs/x86_64/libsifir_android.so and b/sifir-android/app/tor/src/test/jniLibs/x86_64/libsifir_android.so differ diff --git a/sifir-android/build.rs b/sifir-android/build.rs index 0af800f..ed46a29 100644 --- a/sifir-android/build.rs +++ b/sifir-android/build.rs @@ -1,12 +1,62 @@ use flapigen::*; +use std::env; use std::path::Path; fn main() { - setup_java(); + // TODO this comes from env because script creates directory + // Move it all here so we can create and manage all features in one place + // setup_android(); + setup_cpp(); } -fn setup_java() { - println!("Building Java bidingins"); - let in_src = Path::new("src/ffi/").join("java_glue_in.rs"); +fn setup_cpp() { + println!("Generate CPP bindings..."); + let out = env::var("CPP_FFI_OUTPUT_DIR").expect("Missing CPP_FFI_OUTPUT_DIR"); + let out_src = Path::new(".").join(out.as_str()); + + //println!( + // "{:#?}", + // out_src + // .read_dir() + // .unwrap() + // .map(|dir| format!("{:#?}", dir.unwrap())) + // .collect::() + //); + let mut in_src_vec = vec![Path::new("src/ffi_cpp/").join("java_glue_in_common.rs")]; + + #[cfg(feature = "tor_daemon")] + in_src_vec.push(Path::new("src/ffi_cpp/").join("java_glue_in_tor.rs")); + + #[cfg(feature = "btc_wallet")] + in_src_vec.push(Path::new("src/ffi_cpp/").join("java_glue_in_btc.rs")); + + //ANCHOR: config + let swig_gen = flapigen::Generator::new(LanguageConfig::CppConfig( + CppConfig::new(out_src.clone(), "sifir_lib".into()) + .cpp_optional(CppOptional::Boost) + .cpp_variant(CppVariant::Boost) + .cpp_str_view(CppStrView::Boost), + )) + .rustfmt_bindings(true); + //ANCHOR_END: config + swig_gen.expand_many( + "c++-api-for-sifir", + &in_src_vec, + Path::new("src/ffi_cpp/").join("java_glue.rs"), + ); +} +fn setup_android() { + println!("Generate Android bindings..."); + let target = + env::var("SIFIR_ANDROID_JAVA_DIR").expect("Missing SIFIR_ANDROID_JAVA_DIR env for target"); + + let mut in_src_vec = vec![Path::new("src/ffi/").join("java_glue_in_common.rs")]; + + #[cfg(feature = "tor_daemon")] + in_src_vec.push(Path::new("src/ffi/").join("java_glue_in_tor.rs")); + + #[cfg(feature = "btc_wallet")] + in_src_vec.push(Path::new("src/ffi/").join("java_glue_in_btc.rs")); + let out_src = Path::new("src/ffi/").join("java_glue.rs"); //ANCHOR: config let swig_gen = flapigen::Generator::new(LanguageConfig::JavaConfig( @@ -18,12 +68,11 @@ fn setup_java() { .join("java") .join("com") .join("sifir") - .join("tor"), - "com.sifir.tor".into(), + .join(target.clone()), + format!("com.sifir.{}", target), ), // .use_null_annotation_from_package("android.support.annotation".into()), )) .rustfmt_bindings(true); //ANCHOR_END: config - swig_gen.expand("android bindings", &in_src, &out_src); - println!("cargo:rerun-if-changed={}", in_src.display()); + swig_gen.expand_many("android bindings", &in_src_vec, &out_src); } diff --git a/sifir-android/outputs/aar/tor-debug.aar b/sifir-android/outputs/aar/tor-debug.aar deleted file mode 100644 index 88721df..0000000 Binary files a/sifir-android/outputs/aar/tor-debug.aar and /dev/null differ diff --git a/sifir-android/outputs/aar/tor-release.aar b/sifir-android/outputs/aar/tor-release.aar deleted file mode 100644 index ddc7e26..0000000 Binary files a/sifir-android/outputs/aar/tor-release.aar and /dev/null differ diff --git a/sifir-android/scripts/build_aar_from_so.sh b/sifir-android/scripts/build_aar_from_so.sh index fad542a..e6c93ab 100755 --- a/sifir-android/scripts/build_aar_from_so.sh +++ b/sifir-android/scripts/build_aar_from_so.sh @@ -11,7 +11,7 @@ targets=("i686-linux-android" "x86" "armv7-linux-androideabi" "armeabi-v7a" "aa test_targets=("x86_64-unknown-linux-gnu" "x86_64"); libfile="libsifir_android.so"; -# Copy lib targets to respevtive android project directories +# Copy lib targets to respevtive android project directories for ((i=0; i<${#targets[@]}; i+=2)); do libpath="../../target/${targets[i]}/release/$libfile"; if [ ! -f "$libpath" ]; then @@ -43,7 +43,9 @@ done; echo "Copied all binaries..."; # Build AAR -cd ../app && ./gradlew assembleRelease +cd ../app +./gradlew cleanBuildCache +./gradlew assembleRelease --stacktrace [ $retVal -ne 0 ] && echo "[ERROR] Building AAR" && exit 1; cd ../scripts \cp -rf ../app/tor/build/outputs/aar ../outputs/ diff --git a/sifir-android/scripts/build_cpp.sh b/sifir-android/scripts/build_cpp.sh new file mode 100755 index 0000000..3abba47 --- /dev/null +++ b/sifir-android/scripts/build_cpp.sh @@ -0,0 +1,87 @@ +#! /bin/bash +OS=$(uname) +features=$1 +if [ ! "$features" ]; then + echo "Missing features parameter" + exit 1 +fi + +cd .. +# TODO better way to do this +case $features in +"btc_wallet") + aar_dir="btc" + ;; +"tor_daemon") + aar_dir="tor" + ;; +"btc_wallet,tor_daemon") + aar_dir="tor_btc" + ;; +"tor_daemon,btc_wallet") + aar_dir="tor_btc" + ;; +*) + echo "unknown target combo!" + exit 1; +esac + +target_dir="./outputs/cpp/$aar_dir" +export CPP_FFI_OUTPUT_DIR=$target_dir + +read -p "Will build features $features to CPP target dir $target_dir, \r\n Note: This will delete everything in the target_dir parent ! \r\n Press Ctrl-C to abort or any other key to continue..."; + +rm -rf "$target_dir" +mkdir -p "$target_dir" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 + +if [ "$OS" = "Darwin" ]; then + echo "building apple darwin x86_64 lib" + cargo build --target x86_64-apple-darwin -p sifir-android --release --features "$features" + retVal=$? + + [ ! $retVal -eq 0 ] && exit 1 +elif [ "$OS" = "Linux" ]; then + echo "building linux x86_64 lib" + cargo build --target x86_64-unknown-linux-gnu -p sifir-android --release --features "$features" + retVal=$? + [ ! $retVal -eq 0 ] && exit 1 +fi + +cargo ndk --platform 30 --target x86_64-linux-android build --release --features "$features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target aarch64-linux-android build -p sifir-android --release --features "$features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target armv7-linux-androideabi build -p sifir-android --release --features "$features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target i686-linux-android build -p sifir-android --release --features "$features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 + + +echo "--- Compiling Done! --- \r\n" + +# Copy binaries to output dir +targets=("i686-linux-android" "x86" "armv7-linux-androideabi" "armeabi-v7a" "aarch64-linux-android" "arm64" "aarch64-linux-android" "arm64-v8a" "x86_64-linux-android" "x86_64"); +test_targets=("x86_64-unknown-linux-gnu" "x86_64"); +#libfile="libsifir_android.so"; +libfile="libsifir_android"; + +# Copy lib targets to respective android project directories +for ((i=0; i<${#targets[@]}; i+=2)); do + libpath="../target/${targets[i]}/release/$libfile"; + if [ ! -f "$libpath.so" ]; then + echo "[ERROR] $libpath could not be found in targets directory skipping!"; + exit 1; + else + libdir="$target_dir/bin/${targets[i+1]}"; + mkdir -p "$libdir"; + retVal=$?; + [ $retVal -ne 0 ] && echo "[ERROR] Error creating directories $target_dir" && exit 1; + \cp -f "$libpath.d" "$libpath.so" "$libpath.a" "$libdir/"; + fi +done; diff --git a/sifir-android/scripts/build_multi_so.sh b/sifir-android/scripts/build_multi_so.sh index c422272..365ac16 100755 --- a/sifir-android/scripts/build_multi_so.sh +++ b/sifir-android/scripts/build_multi_so.sh @@ -1,31 +1,67 @@ #! /bin/bash cd .. -OS=`uname` -if [ "$OS" = "Darwin" ] -then - echo "building apple darwin x86_64 lib" - cargo build --target x86_64-apple-darwin -p sifir-android --release #--features "java" +OS=$(uname) +features=$1 +if [ ! "$features" ]; then + echo "Missing features parameter" + exit 1 +fi + +# TODO better way to do this +case $features in +"btc_wallet") + aar_dir="btc" + ;; +"tor_daemon") + aar_dir="tor" + ;; +"btc_wallet,tor_daemon") + aar_dir="tor_btc" + ;; +"tor_daemon,btc_wallet") + aar_dir="tor_btc" + ;; +*) + echo "unknown target combo!" + exit 1; +esac + +export SIFIR_ANDROID_JAVA_DIR=$aar_dir +# delete stuff that might already be compiled +target_dir="./app/tor/src/main/java/com/sifir/$SIFIR_ANDROID_JAVA_DIR" + +read -p "Will build features $features to aar target dir $target_dir, \r\n Note: This will delete everything in the target_dir parent ! \r\n Press Ctrl-C to abort or any other key to continue..."; + +rm -rf ./app/tor/src/main/java/com/sifir/* + +mkdir -p "$target_dir" retVal=$? -[ ! $retVal -eq 0 ] && exit 1; -elif [ "$OS" = "Linux" ] -then +[ ! $retVal -eq 0 ] && exit 1 + +if [ "$OS" = "Darwin" ]; then + echo "building apple darwin x86_64 lib" + cargo build --target x86_64-apple-darwin -p sifir-android --release --features "$features" + retVal=$? + + [ ! $retVal -eq 0 ] && exit 1 +elif [ "$OS" = "Linux" ]; then echo "building linux x86_64 lib" - cargo build --target x86_64-unknown-linux-gnu -p sifir-android --release #--features "java" -retVal=$? -[ ! $retVal -eq 0 ] && exit 1; + cargo build --target x86_64-unknown-linux-gnu -p sifir-android --release --features "$features" + retVal=$? + [ ! $retVal -eq 0 ] && exit 1 fi -cargo ndk --platform 30 --target x86_64-linux-android build --release +cargo ndk --platform 30 --target x86_64-linux-android build --release --features "$features" retVal=$? -[ ! $retVal -eq 0 ] && exit 1; -cargo ndk --platform 30 --target aarch64-linux-android build -p sifir-android --release +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target aarch64-linux-android build -p sifir-android --release --features "$features" retVal=$? -[ ! $retVal -eq 0 ] && exit 1; -cargo ndk --platform 30 --target armv7-linux-androideabi build -p sifir-android --release +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target armv7-linux-androideabi build -p sifir-android --release --features "$features" retVal=$? -[ ! $retVal -eq 0 ] && exit 1; -cargo ndk --platform 30 --target i686-linux-android build -p sifir-android --release +[ ! $retVal -eq 0 ] && exit 1 +cargo ndk --platform 30 --target i686-linux-android build -p sifir-android --release --features "$features" retVal=$? -[ ! $retVal -eq 0 ] && exit 1; +[ ! $retVal -eq 0 ] && exit 1 echo "Done!" diff --git a/sifir-android/src/ffi/java_glue.rs b/sifir-android/src/ffi/java_glue.rs deleted file mode 100644 index 9144c32..0000000 --- a/sifir-android/src/ffi/java_glue.rs +++ /dev/null @@ -1,2222 +0,0 @@ -#[allow(dead_code)] -mod internal_aliases { - use super::*; - pub type JStringOptStr = jstring; - pub type JOptionalInt = jobject; - pub type JInteger = jobject; - pub type JByte = jobject; - pub type JShort = jobject; - pub type JFloat = jobject; - pub type JDouble = jobject; - pub type JOptionalDouble = jobject; - pub type JLong = jobject; - pub type JOptionalLong = jobject; - #[repr(transparent)] - pub struct JForeignObjectsArray { - pub(crate) inner: jobjectArray, - pub(crate) _marker: ::std::marker::PhantomData, - } - pub type JStringPath = jstring; - pub type JStringObjectsArray = jobjectArray; -} -#[doc = " Default JNI_VERSION"] -const SWIG_JNI_VERSION: jint = JNI_VERSION_1_6 as jint; -#[doc = " Marker for what to cache in JNI_OnLoad"] -#[allow(unused_macros)] -macro_rules! swig_jni_find_class { - ($ id : ident , $ path : expr) => { - unsafe { $id } - }; - ($ id : ident , $ path : expr ,) => { - unsafe { $id } - }; -} -#[allow(unused_macros)] -macro_rules! swig_jni_get_method_id { - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr) => { - unsafe { $global_id } - }; - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr ,) => { - unsafe { $global_id } - }; -} -#[allow(unused_macros)] -macro_rules! swig_jni_get_static_method_id { - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr) => { - unsafe { $global_id } - }; - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr ,) => { - unsafe { $global_id } - }; -} -#[allow(unused_macros)] -macro_rules! swig_jni_get_field_id { - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr) => { - unsafe { $global_id } - }; - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr ,) => { - unsafe { $global_id } - }; -} -#[allow(unused_macros)] -macro_rules! swig_jni_get_static_field_id { - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr) => { - unsafe { $global_id } - }; - ($ global_id : ident , $ class_id : ident , $ name : expr , $ sig : expr ,) => { - unsafe { $global_id } - }; -} -#[allow(dead_code)] -#[doc = ""] -trait SwigInto { - fn swig_into(self, env: *mut JNIEnv) -> T; -} -#[allow(dead_code)] -#[doc = ""] -trait SwigFrom { - fn swig_from(_: T, env: *mut JNIEnv) -> Self; -} -#[allow(dead_code)] -#[doc = ""] -trait SwigDeref { - type Target: ?Sized; - fn swig_deref(&self) -> &Self::Target; -} -#[allow(dead_code)] -#[doc = ""] -trait SwigDerefMut { - type Target: ?Sized; - fn swig_deref_mut(&mut self) -> &mut Self::Target; -} -#[allow(unused_macros)] -macro_rules! swig_c_str { - ($ lit : expr) => { - concat!($lit, "\0").as_ptr() as *const ::std::os::raw::c_char - }; -} -#[allow(unused_macros)] -macro_rules ! swig_assert_eq_size { ($ x : ty , $ ($ xs : ty) ,+ $ (,) *) => { $ (let _ = :: std :: mem :: transmute ::<$ x , $ xs >;) + } ; } -#[cfg(target_pointer_width = "32")] -pub unsafe fn jlong_to_pointer(val: jlong) -> *mut T { - (val as u32) as *mut T -} -#[cfg(target_pointer_width = "64")] -pub unsafe fn jlong_to_pointer(val: jlong) -> *mut T { - val as *mut T -} -#[allow(dead_code)] -pub trait SwigForeignClass { - type PointedType; - fn jni_class() -> jclass; - fn jni_class_pointer_field() -> jfieldID; - fn box_object(x: Self) -> jlong; - fn unbox_object(x: jlong) -> Self; - fn to_pointer(x: jlong) -> ::std::ptr::NonNull; -} -#[allow(dead_code)] -pub trait SwigForeignCLikeEnum { - fn as_jint(&self) -> jint; - #[doc = " # Panics"] - #[doc = " Panics on error"] - fn from_jint(_: jint) -> Self; -} -#[allow(dead_code)] -pub struct JavaString { - string: jstring, - chars: *const ::std::os::raw::c_char, - env: *mut JNIEnv, -} -#[allow(dead_code)] -impl JavaString { - pub fn new(env: *mut JNIEnv, js: jstring) -> JavaString { - let chars = if !js.is_null() { - unsafe { (**env).GetStringUTFChars.unwrap()(env, js, ::std::ptr::null_mut()) } - } else { - ::std::ptr::null_mut() - }; - JavaString { - string: js, - chars: chars, - env: env, - } - } - pub fn to_str(&self) -> &str { - if !self.chars.is_null() { - let s = unsafe { ::std::ffi::CStr::from_ptr(self.chars) }; - s.to_str().unwrap() - } else { - "" - } - } -} -#[allow(dead_code)] -impl Drop for JavaString { - fn drop(&mut self) { - assert!(!self.env.is_null()); - if !self.string.is_null() { - assert!(!self.chars.is_null()); - unsafe { - (**self.env).ReleaseStringUTFChars.unwrap()(self.env, self.string, self.chars) - }; - self.env = ::std::ptr::null_mut(); - self.chars = ::std::ptr::null_mut(); - } - } -} -#[allow(dead_code)] -struct JavaCallback { - java_vm: *mut JavaVM, - this: jobject, - methods: Vec, -} -#[doc = " According to JNI spec it should be safe to"] -#[doc = " pass pointer to JavaVm and jobject (global) across threads"] -unsafe impl Send for JavaCallback {} -#[allow(dead_code)] -struct JniEnvHolder<'a> { - env: Option<*mut JNIEnv>, - callback: &'a JavaCallback, - need_detach: bool, -} -#[allow(dead_code)] -impl<'a> Drop for JniEnvHolder<'a> { - fn drop(&mut self) { - if self.need_detach { - let res = unsafe { - (**self.callback.java_vm).DetachCurrentThread.unwrap()(self.callback.java_vm) - }; - if res != 0 { - log::error!("JniEnvHolder: DetachCurrentThread failed: {}", res); - } - } - } -} -#[allow(dead_code)] -impl JavaCallback { - fn new(obj: jobject, env: *mut JNIEnv) -> JavaCallback { - let mut java_vm: *mut JavaVM = ::std::ptr::null_mut(); - let ret = unsafe { (**env).GetJavaVM.unwrap()(env, &mut java_vm) }; - assert_eq!(0, ret, "GetJavaVm failed"); - let global_obj = unsafe { (**env).NewGlobalRef.unwrap()(env, obj) }; - assert!(!global_obj.is_null()); - JavaCallback { - java_vm, - this: global_obj, - methods: Vec::new(), - } - } - fn get_jni_env(&self) -> JniEnvHolder { - assert!(!self.java_vm.is_null()); - let mut env: *mut JNIEnv = ::std::ptr::null_mut(); - let res = unsafe { - (**self.java_vm).GetEnv.unwrap()( - self.java_vm, - (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void, - SWIG_JNI_VERSION, - ) - }; - if res == (JNI_OK as jint) { - return JniEnvHolder { - env: Some(env), - callback: self, - need_detach: false, - }; - } - if res != (JNI_EDETACHED as jint) { - panic!("get_jni_env: GetEnv return error `{}`", res); - } - trait ConvertPtr { - fn convert_ptr(self) -> T; - } - impl ConvertPtr<*mut *mut ::std::os::raw::c_void> for *mut *mut JNIEnv { - fn convert_ptr(self) -> *mut *mut ::std::os::raw::c_void { - self as *mut *mut ::std::os::raw::c_void - } - } - impl ConvertPtr<*mut *mut JNIEnv> for *mut *mut JNIEnv { - fn convert_ptr(self) -> *mut *mut JNIEnv { - self - } - } - let res = unsafe { - (**self.java_vm).AttachCurrentThread.unwrap()( - self.java_vm, - (&mut env as *mut *mut JNIEnv).convert_ptr(), - ::std::ptr::null_mut(), - ) - }; - if res != 0 { - log::error!( - "JavaCallback::get_jnienv: AttachCurrentThread failed: {}", - res - ); - JniEnvHolder { - env: None, - callback: self, - need_detach: false, - } - } else { - assert!(!env.is_null()); - JniEnvHolder { - env: Some(env), - callback: self, - need_detach: true, - } - } - } -} -#[allow(dead_code)] -impl Drop for JavaCallback { - fn drop(&mut self) { - let env = self.get_jni_env(); - if let Some(env) = env.env { - assert!(!env.is_null()); - unsafe { (**env).DeleteGlobalRef.unwrap()(env, self.this) }; - } else { - log::error!("JavaCallback::drop failed, can not get JNIEnv"); - } - } -} -#[allow(dead_code)] -fn jni_throw(env: *mut JNIEnv, ex_class: jclass, message: &str) { - let c_message = ::std::ffi::CString::new(message).unwrap(); - let res = unsafe { (**env).ThrowNew.unwrap()(env, ex_class, c_message.as_ptr()) }; - if res != 0 { - log::error!( - "JNI ThrowNew({}) failed for class {:?} failed", - message, - ex_class - ); - } -} -#[allow(dead_code)] -fn jni_throw_exception(env: *mut JNIEnv, message: &str) { - let exception_class = swig_jni_find_class!(JAVA_LANG_EXCEPTION, "java/lang/Exception"); - jni_throw(env, exception_class, message) -} -#[allow(dead_code)] -fn object_to_jobject(env: *mut JNIEnv, obj: T) -> jobject { - let jcls = ::jni_class(); - assert!(!jcls.is_null()); - let field_id = ::jni_class_pointer_field(); - assert!(!field_id.is_null()); - let jobj: jobject = unsafe { (**env).AllocObject.unwrap()(env, jcls) }; - assert!(!jobj.is_null(), "object_to_jobject: AllocObject failed"); - let ret: jlong = ::box_object(obj); - unsafe { - (**env).SetLongField.unwrap()(env, jobj, field_id, ret); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("object_to_jobject: Can not set mNativeObj field: catch exception"); - } - } - jobj -} -#[allow(dead_code)] -fn jobject_array_to_vec_of_objects( - env: *mut JNIEnv, - arr: internal_aliases::JForeignObjectsArray, -) -> Vec { - let field_id = ::jni_class_pointer_field(); - assert!(!field_id.is_null()); - let length = unsafe { (**env).GetArrayLength.unwrap()(env, arr.inner) }; - let len = >::try_from(length) - .expect("invalid jsize, in jsize => usize conversation"); - let mut result = Vec::with_capacity(len); - for i in 0..length { - let native: &mut T = unsafe { - let obj = (**env).GetObjectArrayElement.unwrap()(env, arr.inner, i); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Failed to retrieve element {} from this `jobjectArray'", i); - } - let ptr = (**env).GetLongField.unwrap()(env, obj, field_id); - let native = (jlong_to_pointer(ptr) as *mut T).as_mut().unwrap(); - (**env).DeleteLocalRef.unwrap()(env, obj); - native - }; - result.push(native.clone()); - } - result -} -#[allow(dead_code)] -fn vec_of_objects_to_jobject_array( - env: *mut JNIEnv, - mut arr: Vec, -) -> internal_aliases::JForeignObjectsArray { - let jcls: jclass = ::jni_class(); - assert!(!jcls.is_null()); - let arr_len = >::try_from(arr.len()) - .expect("invalid usize, in usize => to jsize conversation"); - let obj_arr: jobjectArray = - unsafe { (**env).NewObjectArray.unwrap()(env, arr_len, jcls, ::std::ptr::null_mut()) }; - assert!(!obj_arr.is_null()); - let field_id = ::jni_class_pointer_field(); - assert!(!field_id.is_null()); - for (i, r_obj) in arr.drain(..).enumerate() { - let jobj: jobject = unsafe { (**env).AllocObject.unwrap()(env, jcls) }; - assert!(!jobj.is_null()); - let r_obj: jlong = ::box_object(r_obj); - unsafe { - (**env).SetLongField.unwrap()(env, jobj, field_id, r_obj); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Can not mNativeObj field: catch exception"); - } - (**env).SetObjectArrayElement.unwrap()(env, obj_arr, i as jsize, jobj); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("SetObjectArrayElement({}) failed", i); - } - (**env).DeleteLocalRef.unwrap()(env, jobj); - } - } - internal_aliases::JForeignObjectsArray { - inner: obj_arr, - _marker: ::std::marker::PhantomData, - } -} -#[allow(dead_code)] -trait JniInvalidValue { - fn jni_invalid_value() -> Self; -} -impl JniInvalidValue for *const T { - fn jni_invalid_value() -> Self { - ::std::ptr::null() - } -} -impl JniInvalidValue for *mut T { - fn jni_invalid_value() -> Self { - ::std::ptr::null_mut() - } -} -impl JniInvalidValue for () { - fn jni_invalid_value() {} -} -impl JniInvalidValue for internal_aliases::JForeignObjectsArray { - fn jni_invalid_value() -> Self { - Self { - inner: ::std::ptr::null_mut(), - _marker: ::std::marker::PhantomData, - } - } -} -macro_rules ! impl_jni_jni_invalid_value { ($ ($ type : ty) *) => ($ (impl JniInvalidValue for $ type { fn jni_invalid_value () -> Self { <$ type >:: default () } }) *) } -impl_jni_jni_invalid_value! { jbyte jshort jint jlong jfloat jdouble } -#[allow(dead_code)] -pub fn u64_to_jlong_checked(x: u64) -> jlong { - >::try_from(x) - .expect("invalid u64, in u64 => jlong conversation") -} -#[allow(dead_code)] -fn from_std_string_jstring(x: String, env: *mut JNIEnv) -> jstring { - let x = x.into_bytes(); - unsafe { - let x = ::std::ffi::CString::from_vec_unchecked(x); - (**env).NewStringUTF.unwrap()(env, x.as_ptr()) - } -} -#[allow(dead_code)] -fn vec_string_to_jobject_array(mut arr: Vec, env: *mut JNIEnv) -> jobjectArray { - let jcls: jclass = swig_jni_find_class!(JAVA_LANG_STRING, "java/lang/String"); - assert!(!jcls.is_null()); - let obj_arr: jobjectArray = unsafe { - (**env).NewObjectArray.unwrap()(env, arr.len() as jsize, jcls, ::std::ptr::null_mut()) - }; - assert!(!obj_arr.is_null()); - for (i, r_str) in arr.drain(..).enumerate() { - let jstr: jstring = from_std_string_jstring(r_str, env); - assert!(!jstr.is_null()); - unsafe { - (**env).SetObjectArrayElement.unwrap()(env, obj_arr, i as jsize, jstr); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("SetObjectArrayElement({}) failed", i); - } - (**env).DeleteLocalRef.unwrap()(env, jstr); - } - } - obj_arr -} -macro_rules ! define_array_handling_code { ($ ([jni_arr_type = $ jni_arr_type : ident , rust_arr_wrapper = $ rust_arr_wrapper : ident , jni_get_array_elements = $ jni_get_array_elements : ident , jni_elem_type = $ jni_elem_type : ident , rust_elem_type = $ rust_elem_type : ident , jni_release_array_elements = $ jni_release_array_elements : ident , jni_new_array = $ jni_new_array : ident , jni_set_array_region = $ jni_set_array_region : ident]) ,*) => { $ (# [allow (dead_code)] struct $ rust_arr_wrapper { array : $ jni_arr_type , data : * mut $ jni_elem_type , env : * mut JNIEnv , } # [allow (dead_code)] impl $ rust_arr_wrapper { fn new (env : * mut JNIEnv , array : $ jni_arr_type) -> $ rust_arr_wrapper { assert ! (! array . is_null ()) ; let data = unsafe { (** env) .$ jni_get_array_elements . unwrap () (env , array , :: std :: ptr :: null_mut ()) } ; $ rust_arr_wrapper { array , data , env } } fn to_slice (& self) -> & [$ rust_elem_type] { unsafe { let len : jsize = (** self . env) . GetArrayLength . unwrap () (self . env , self . array) ; assert ! ((len as u64) <= (usize :: max_value () as u64)) ; :: std :: slice :: from_raw_parts (self . data , len as usize) } } fn from_slice_to_raw (arr : & [$ rust_elem_type] , env : * mut JNIEnv) -> $ jni_arr_type { assert ! ((arr . len () as u64) <= (jsize :: max_value () as u64)) ; let jarr : $ jni_arr_type = unsafe { (** env) .$ jni_new_array . unwrap () (env , arr . len () as jsize) } ; assert ! (! jarr . is_null ()) ; unsafe { (** env) .$ jni_set_array_region . unwrap () (env , jarr , 0 , arr . len () as jsize , arr . as_ptr ()) ; if (** env) . ExceptionCheck . unwrap () (env) != 0 { panic ! ("{}:{} {} failed" , file ! () , line ! () , stringify ! ($ jni_set_array_region)) ; } } jarr } } # [allow (dead_code)] impl Drop for $ rust_arr_wrapper { fn drop (& mut self) { assert ! (! self . env . is_null ()) ; assert ! (! self . array . is_null ()) ; unsafe { (** self . env) .$ jni_release_array_elements . unwrap () (self . env , self . array , self . data , JNI_ABORT as jint ,) } ; } }) * } } -define_array_handling_code!( - [ - jni_arr_type = jbyteArray, - rust_arr_wrapper = JavaByteArray, - jni_get_array_elements = GetByteArrayElements, - jni_elem_type = jbyte, - rust_elem_type = i8, - jni_release_array_elements = ReleaseByteArrayElements, - jni_new_array = NewByteArray, - jni_set_array_region = SetByteArrayRegion - ], - [ - jni_arr_type = jshortArray, - rust_arr_wrapper = JavaShortArray, - jni_get_array_elements = GetShortArrayElements, - jni_elem_type = jshort, - rust_elem_type = i16, - jni_release_array_elements = ReleaseShortArrayElements, - jni_new_array = NewShortArray, - jni_set_array_region = SetShortArrayRegion - ], - [ - jni_arr_type = jintArray, - rust_arr_wrapper = JavaIntArray, - jni_get_array_elements = GetIntArrayElements, - jni_elem_type = jint, - rust_elem_type = i32, - jni_release_array_elements = ReleaseIntArrayElements, - jni_new_array = NewIntArray, - jni_set_array_region = SetIntArrayRegion - ], - [ - jni_arr_type = jlongArray, - rust_arr_wrapper = JavaLongArray, - jni_get_array_elements = GetLongArrayElements, - jni_elem_type = jlong, - rust_elem_type = i64, - jni_release_array_elements = ReleaseLongArrayElements, - jni_new_array = NewLongArray, - jni_set_array_region = SetLongArrayRegion - ], - [ - jni_arr_type = jfloatArray, - rust_arr_wrapper = JavaFloatArray, - jni_get_array_elements = GetFloatArrayElements, - jni_elem_type = jfloat, - rust_elem_type = f32, - jni_release_array_elements = ReleaseFloatArrayElements, - jni_new_array = NewFloatArray, - jni_set_array_region = SetFloatArrayRegion - ], - [ - jni_arr_type = jdoubleArray, - rust_arr_wrapper = JavaDoubleArray, - jni_get_array_elements = GetDoubleArrayElements, - jni_elem_type = jdouble, - rust_elem_type = f64, - jni_release_array_elements = ReleaseDoubleArrayElements, - jni_new_array = NewDoubleArray, - jni_set_array_region = SetDoubleArrayRegion - ] -); -#[allow(dead_code)] -fn to_java_util_optional_double( - env: *mut JNIEnv, - x: Option, -) -> internal_aliases::JOptionalDouble { - let class: jclass = swig_jni_find_class!(JAVA_UTIL_OPTIONAL_DOUBLE, "java/util/OptionalDouble"); - assert!(!class.is_null(),); - match x { - Some(val) => { - let of_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_DOUBLE_OF, - JAVA_UTIL_OPTIONAL_DOUBLE, - "of", - "(D)Ljava/util/OptionalDouble;" - ); - assert!(!of_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, of_m, val); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalDouble.of failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - None => { - let empty_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_DOUBLE_EMPTY, - JAVA_UTIL_OPTIONAL_DOUBLE, - "empty", - "()Ljava/util/OptionalDouble;" - ); - assert!(!empty_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, empty_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalDouble.empty failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - } -} -#[allow(dead_code)] -fn from_java_lang_double_to_rust(env: *mut JNIEnv, x: internal_aliases::JDouble) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_DOUBLE, "java/lang/Double"); - assert!(!class.is_null()); - let double_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_DOUBLE_DOUBLE_VALUE_METHOD, - JAVA_LANG_DOUBLE, - "doubleValue", - "()D", - ); - assert!(!double_value_m.is_null(),); - let ret: f64 = unsafe { - let ret = (**env).CallDoubleMethod.unwrap()(env, x, double_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Double.doubleValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn from_java_lang_float_to_rust(env: *mut JNIEnv, x: internal_aliases::JFloat) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_FLOAT, "java/lang/Float"); - assert!(!class.is_null()); - let float_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_FLOAT_FLOAT_VALUE, - JAVA_LANG_FLOAT, - "floatValue", - "()F" - ); - assert!(!float_value_m.is_null()); - let ret: f32 = unsafe { - let ret = (**env).CallFloatMethod.unwrap()(env, x, float_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Float.floatValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn to_java_util_optional_long(env: *mut JNIEnv, x: Option) -> internal_aliases::JOptionalLong { - let class: jclass = swig_jni_find_class!(JAVA_UTIL_OPTIONAL_LONG, "java/util/OptionalLong"); - assert!(!class.is_null(),); - match x { - Some(val) => { - let of_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_LONG_OF, - JAVA_UTIL_OPTIONAL_LONG, - "of", - "(J)Ljava/util/OptionalLong;" - ); - assert!(!of_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, of_m, val); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalLong.of failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - None => { - let empty_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_LONG_EMPTY, - JAVA_UTIL_OPTIONAL_LONG, - "empty", - "()Ljava/util/OptionalLong;", - ); - assert!(!empty_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, empty_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalLong.empty failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - } -} -#[allow(dead_code)] -fn from_java_lang_long_to_rust(env: *mut JNIEnv, x: internal_aliases::JLong) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_LONG, "java/lang/Long"); - assert!(!class.is_null()); - let long_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_LONG_LONG_VALUE, - JAVA_LANG_LONG, - "longValue", - "()J" - ); - assert!(!long_value_m.is_null()); - let ret: i64 = unsafe { - let ret = (**env).CallLongMethod.unwrap()(env, x, long_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Long.longValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn from_java_lang_int_to_rust(env: *mut JNIEnv, x: internal_aliases::JInteger) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_INTEGER, "java/lang/Integer"); - assert!(!class.is_null()); - let int_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_INTEGER_INT_VALUE, - JAVA_LANG_INTEGER, - "intValue", - "()I" - ); - assert!(!int_value_m.is_null(),); - let ret: i32 = unsafe { - let ret = (**env).CallIntMethod.unwrap()(env, x, int_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Integer.intValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn from_java_lang_byte_to_rust(env: *mut JNIEnv, x: internal_aliases::JByte) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_BYTE, "java/lang/Byte"); - assert!(!class.is_null()); - let byte_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_BYTE_BYTE_VALUE, - JAVA_LANG_BYTE, - "byteValue", - "()B" - ); - assert!(!byte_value_m.is_null(),); - let ret: i8 = unsafe { - let ret = (**env).CallByteMethod.unwrap()(env, x, byte_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Byte.byteValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn from_java_lang_short_to_rust(env: *mut JNIEnv, x: internal_aliases::JByte) -> Option { - if x.is_null() { - None - } else { - let x = unsafe { (**env).NewLocalRef.unwrap()(env, x) }; - if x.is_null() { - None - } else { - let class: jclass = swig_jni_find_class!(JAVA_LANG_SHORT, "java/lang/Short"); - assert!(!class.is_null()); - let short_value_m: jmethodID = swig_jni_get_method_id!( - JAVA_LANG_SHORT_SHORT_VALUE, - JAVA_LANG_SHORT, - "shortValue", - "()S" - ); - assert!(!short_value_m.is_null()); - let ret: i16 = unsafe { - let ret = (**env).CallShortMethod.unwrap()(env, x, short_value_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("Short.shortValue failed: catch exception"); - } - (**env).DeleteLocalRef.unwrap()(env, x); - ret - }; - Some(ret) - } - } -} -#[allow(dead_code)] -fn to_java_util_optional_int(env: *mut JNIEnv, x: Option) -> jobject { - let class: jclass = swig_jni_find_class!(JAVA_UTIL_OPTIONAL_INT, "java/util/OptionalInt"); - assert!(!class.is_null(),); - match x { - Some(val) => { - let of_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_INT_OF, - JAVA_UTIL_OPTIONAL_INT, - "of", - "(I)Ljava/util/OptionalInt;" - ); - assert!(!of_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, of_m, val); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalInt.of failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - None => { - let empty_m: jmethodID = swig_jni_get_static_method_id!( - JAVA_UTIL_OPTIONAL_INT_EMPTY, - JAVA_UTIL_OPTIONAL_INT, - "empty", - "()Ljava/util/OptionalInt;" - ); - assert!(!empty_m.is_null()); - let ret = unsafe { - let ret = (**env).CallStaticObjectMethod.unwrap()(env, class, empty_m); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - panic!("OptionalInt.empty failed: catch exception"); - } - ret - }; - assert!(!ret.is_null()); - ret - } - } -} -use jni_sys::*; -use logger::{log, Logger}; -use serde::Serialize; -use std::time::Duration; -use tor::{ - hidden_service::{HiddenServiceDataHandler, HiddenServiceHandler}, - tcp_stream::{DataObserver, TcpSocksStream}, - BootstrapPhase, OwnedTorService, OwnedTorServiceBootstrapPhase, TorHiddenService, - TorHiddenServiceParam, TorServiceParam, -}; -unsafe impl Send for Observer {} -unsafe impl Sync for Observer {} -struct Observer { - cb: Box, -} -impl DataObserver for Observer { - fn on_data(&self, data: String) { - self.cb.on_data(data); - } - fn on_error(&self, data: String) { - self.cb.on_error(data); - } -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence1( - _env: *mut JNIEnv, - _: jclass, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence2( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence3( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence4( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence5( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence6( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence7( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, -) { -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_JNIReachabilityFence_reachabilityFence8( - _env: *mut JNIEnv, - _: jclass, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, - _: jobject, -) { -} -impl DataObserver for JavaCallback { - #[allow(unused_mut)] - fn on_data(&self, a0: String) { - swig_assert_eq_size!(::std::os::raw::c_uint, u32); - swig_assert_eq_size!(::std::os::raw::c_int, i32); - let env = self.get_jni_env(); - if let Some(env) = env.env { - let mut a0: jstring = from_std_string_jstring(a0, env); - unsafe { - (**env).CallVoidMethod.unwrap()(env, self.this, self.methods[0usize], a0); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - log::error!(concat!(stringify!(on_data), ": java throw exception")); - (**env).ExceptionDescribe.unwrap()(env); - (**env).ExceptionClear.unwrap()(env); - } - }; - } - } - #[allow(unused_mut)] - fn on_error(&self, a0: String) { - swig_assert_eq_size!(::std::os::raw::c_uint, u32); - swig_assert_eq_size!(::std::os::raw::c_int, i32); - let env = self.get_jni_env(); - if let Some(env) = env.env { - let mut a0: jstring = from_std_string_jstring(a0, env); - unsafe { - (**env).CallVoidMethod.unwrap()(env, self.this, self.methods[1usize], a0); - if (**env).ExceptionCheck.unwrap()(env) != 0 { - log::error!(concat!(stringify!(on_error), ": java throw exception")); - (**env).ExceptionDescribe.unwrap()(env); - (**env).ExceptionClear.unwrap()(env); - } - }; - } - } -} -impl SwigForeignClass for HiddenServiceHandler { - type PointedType = HiddenServiceHandler; - fn jni_class() -> jclass { - swig_jni_find_class!( - FOREIGN_CLASS_HIDDENSERVICEHANDLER, - "com/sifir/tor/HiddenServiceHandler" - ) - } - fn jni_class_pointer_field() -> jfieldID { - swig_jni_get_field_id!( - FOREIGN_CLASS_HIDDENSERVICEHANDLER_MNATIVEOBJ_FIELD, - FOREIGN_CLASS_HIDDENSERVICEHANDLER, - "mNativeObj", - "J" - ) - } - fn box_object(this: Self) -> jlong { - let this: Box = Box::new(this); - let this: *mut HiddenServiceHandler = Box::into_raw(this); - this as jlong - } - fn unbox_object(x: jlong) -> Self { - let x: *mut HiddenServiceHandler = unsafe { - jlong_to_pointer::(x) - .as_mut() - .unwrap() - }; - let x: Box = unsafe { Box::from_raw(x) }; - let x: HiddenServiceHandler = *x; - x - } - fn to_pointer(x: jlong) -> ::std::ptr::NonNull { - let x: *mut HiddenServiceHandler = unsafe { - jlong_to_pointer::(x) - .as_mut() - .unwrap() - }; - ::std::ptr::NonNull::::new(x).unwrap() - } -} -#[doc = ""] -impl SwigFrom for Box { - fn swig_from(this: jobject, env: *mut JNIEnv) -> Self { - let mut cb = JavaCallback::new(this, env); - cb.methods.reserve(2); - let class = unsafe { (**env).GetObjectClass.unwrap()(env, cb.this) }; - assert!( - !class.is_null(), - "GetObjectClass return null class for DataObserver" - ); - let method_id: jmethodID = unsafe { - (**env).GetMethodID.unwrap()( - env, - class, - swig_c_str!("onData"), - swig_c_str!("(Ljava/lang/String;)V"), - ) - }; - assert!(!method_id.is_null(), "Can not find onData id"); - cb.methods.push(method_id); - let method_id: jmethodID = unsafe { - (**env).GetMethodID.unwrap()( - env, - class, - swig_c_str!("onError"), - swig_c_str!("(Ljava/lang/String;)V"), - ) - }; - assert!(!method_id.is_null(), "Can not find onError id"); - cb.methods.push(method_id); - Box::new(cb) - } -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_HiddenServiceHandler_init( - env: *mut JNIEnv, - _: jclass, - dst_port: jint, - cb: jobject, -) -> jlong { - let mut dst_port: u16 = >::try_from(dst_port) - .expect("invalid jint, in jint => u16 conversation"); - let mut cb: Box = >::swig_from(cb, env); - let this: Result = { - let mut lsnr = HiddenServiceHandler::new(dst_port) - .map_err(|e| format!("{:#?}", e)) - .unwrap(); - lsnr.set_data_handler(Observer { cb }) - .map_err(|e| format!("{:#?}", e)) - .unwrap(); - let _ = lsnr.start_http_listener(); - Ok(lsnr) - }; - let mut this: jlong = match this { - Ok(x) => { - let ret: jlong = ::box_object(x); - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return ::jni_invalid_value(); - } - }; - this as jlong -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_HiddenServiceHandler_do_1delete( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) { - let this: *mut HiddenServiceHandler = unsafe { - jlong_to_pointer::(this) - .as_mut() - .unwrap() - }; - let this: Box = unsafe { Box::from_raw(this) }; - drop(this); -} -impl SwigForeignClass for TorHiddenService { - type PointedType = TorHiddenService; - fn jni_class() -> jclass { - swig_jni_find_class!( - FOREIGN_CLASS_TORHIDDENSERVICE, - "com/sifir/tor/TorHiddenService" - ) - } - fn jni_class_pointer_field() -> jfieldID { - swig_jni_get_field_id!( - FOREIGN_CLASS_TORHIDDENSERVICE_MNATIVEOBJ_FIELD, - FOREIGN_CLASS_TORHIDDENSERVICE, - "mNativeObj", - "J" - ) - } - fn box_object(this: Self) -> jlong { - let this: Box = Box::new(this); - let this: *mut TorHiddenService = Box::into_raw(this); - this as jlong - } - fn unbox_object(x: jlong) -> Self { - let x: *mut TorHiddenService = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - let x: Box = unsafe { Box::from_raw(x) }; - let x: TorHiddenService = *x; - x - } - fn to_pointer(x: jlong) -> ::std::ptr::NonNull { - let x: *mut TorHiddenService = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - ::std::ptr::NonNull::::new(x).unwrap() - } -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TorHiddenService_do_1get_1onion_1url( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) -> jstring { - let this: &TorHiddenService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: String = { this.onion_url.to_string() }; - let mut ret: jstring = from_std_string_jstring(ret, env); - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TorHiddenService_do_1get_1secret_1b64( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) -> jstring { - let this: &TorHiddenService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: String = { base64::encode(this.secret_key).into() }; - let mut ret: jstring = from_std_string_jstring(ret, env); - ret -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TorHiddenService_do_1delete( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) { - let this: *mut TorHiddenService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let this: Box = unsafe { Box::from_raw(this) }; - drop(this); -} -impl SwigForeignClass for TorServiceParam { - type PointedType = TorServiceParam; - fn jni_class() -> jclass { - swig_jni_find_class!( - FOREIGN_CLASS_TORSERVICEPARAM, - "com/sifir/tor/TorServiceParam" - ) - } - fn jni_class_pointer_field() -> jfieldID { - swig_jni_get_field_id!( - FOREIGN_CLASS_TORSERVICEPARAM_MNATIVEOBJ_FIELD, - FOREIGN_CLASS_TORSERVICEPARAM, - "mNativeObj", - "J" - ) - } - fn box_object(this: Self) -> jlong { - let this: Box = Box::new(this); - let this: *mut TorServiceParam = Box::into_raw(this); - this as jlong - } - fn unbox_object(x: jlong) -> Self { - let x: *mut TorServiceParam = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - let x: Box = unsafe { Box::from_raw(x) }; - let x: TorServiceParam = *x; - x - } - fn to_pointer(x: jlong) -> ::std::ptr::NonNull { - let x: *mut TorServiceParam = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - ::std::ptr::NonNull::::new(x).unwrap() - } -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TorServiceParam_init( - env: *mut JNIEnv, - _: jclass, - data_dir: jstring, - socks_port: jint, - bootstap_timeout_ms: jlong, -) -> jlong { - let mut data_dir: JavaString = JavaString::new(env, data_dir); - let mut data_dir: &str = data_dir.to_str(); - let mut socks_port: u16 = >::try_from(socks_port) - .expect("invalid jint, in jint => u16 conversation"); - let mut bootstap_timeout_ms: u64 = - >::try_from(bootstap_timeout_ms) - .expect("invalid jlong, in jlong => u64 conversation"); - let this: TorServiceParam = TorServiceParam::new(data_dir, socks_port, bootstap_timeout_ms); - let this: Box = Box::new(this); - let this: *mut TorServiceParam = Box::into_raw(this); - this as jlong -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TorServiceParam_do_1delete( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) { - let this: *mut TorServiceParam = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let this: Box = unsafe { Box::from_raw(this) }; - drop(this); -} -impl SwigForeignClass for OwnedTorService { - type PointedType = OwnedTorService; - fn jni_class() -> jclass { - swig_jni_find_class!( - FOREIGN_CLASS_OWNEDTORSERVICE, - "com/sifir/tor/OwnedTorService" - ) - } - fn jni_class_pointer_field() -> jfieldID { - swig_jni_get_field_id!( - FOREIGN_CLASS_OWNEDTORSERVICE_MNATIVEOBJ_FIELD, - FOREIGN_CLASS_OWNEDTORSERVICE, - "mNativeObj", - "J" - ) - } - fn box_object(this: Self) -> jlong { - let this: Box = Box::new(this); - let this: *mut OwnedTorService = Box::into_raw(this); - this as jlong - } - fn unbox_object(x: jlong) -> Self { - let x: *mut OwnedTorService = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - let x: Box = unsafe { Box::from_raw(x) }; - let x: OwnedTorService = *x; - x - } - fn to_pointer(x: jlong) -> ::std::ptr::NonNull { - let x: *mut OwnedTorService = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - ::std::ptr::NonNull::::new(x).unwrap() - } -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_init( - env: *mut JNIEnv, - _: jclass, - param: jlong, -) -> jlong { - let param: *mut TorServiceParam = - unsafe { jlong_to_pointer::(param).as_mut().unwrap() }; - let param: Box = unsafe { Box::from_raw(param) }; - let param: TorServiceParam = *param; - let this: Result = { - Logger::new(); - OwnedTorService::new(param).map_err(|e| format!("{:#?}", e)) - }; - let mut this: jlong = match this { - Ok(x) => { - let ret: jlong = ::box_object(x); - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return ::jni_invalid_value(); - } - }; - this as jlong -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1getSocksPort( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) -> jint { - let this: &OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: u16 = { this.socks_port }; - let mut ret: jint = jint::from(ret); - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1shutdown( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) -> () { - let this: &mut OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: Result<(), String> = { this.shutdown().map_err(|e| format!("{:#?}", e)) }; - let mut ret: () = match ret { - Ok(x) => { - let mut ret = x; - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return <()>::jni_invalid_value(); - } - }; - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1get_1status( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) -> jstring { - let this: &mut OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: String = { - let node_status = this.get_status(); - match node_status { - Ok(status) => { - let status_string = serde_json::to_string(&status).unwrap(); - status_string - } - Err(e) => e.to_string(), - } - }; - let mut ret: jstring = from_std_string_jstring(ret, env); - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1create_1hidden_1service( - env: *mut JNIEnv, - _: jclass, - this: jlong, - dst_port: jint, - hs_port: jint, - secret_key: jstring, -) -> jlong { - let mut dst_port: u16 = >::try_from(dst_port) - .expect("invalid jint, in jint => u16 conversation"); - let mut hs_port: u16 = >::try_from(hs_port) - .expect("invalid jint, in jint => u16 conversation"); - let mut secret_key: JavaString = JavaString::new(env, secret_key); - let mut secret_key: &str = secret_key.to_str(); - let mut secret_key: String = secret_key.to_string(); - let this: &mut OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: Result = { - let hs_key = match secret_key.len() { - 0 => Ok(None), - _ => { - let mut decoded_buff: [u8; 64] = [0; 64]; - base64::decode_config_slice(secret_key, base64::STANDARD, &mut decoded_buff) - .map(|_| Some(decoded_buff)) - } - }; - match hs_key { - Ok(key) => this - .create_hidden_service(TorHiddenServiceParam { - to_port: dst_port, - hs_port, - secret_key: key, - }) - .map_err(|e| format!("{:#?}", e)), - Err(e) => Err(format!("{:#?}", e)), - } - }; - let mut ret: jlong = match ret { - Ok(x) => { - let ret: jlong = ::box_object(x); - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return ::jni_invalid_value(); - } - }; - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1delete_1hidden_1service( - env: *mut JNIEnv, - _: jclass, - this: jlong, - onion: jstring, -) -> () { - let mut onion: JavaString = JavaString::new(env, onion); - let mut onion: &str = onion.to_str(); - let mut onion: String = onion.to_string(); - let this: &mut OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: Result<(), String> = { - this.delete_hidden_service(onion) - .map_err(|e| format!("{:#?}", e)) - }; - let mut ret: () = match ret { - Ok(x) => { - let mut ret = x; - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return <()>::jni_invalid_value(); - } - }; - ret -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_OwnedTorService_do_1delete( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) { - let this: *mut OwnedTorService = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let this: Box = unsafe { Box::from_raw(this) }; - drop(this); -} -impl SwigForeignClass for TcpSocksStream { - type PointedType = TcpSocksStream; - fn jni_class() -> jclass { - swig_jni_find_class!(FOREIGN_CLASS_TCPSOCKSSTREAM, "com/sifir/tor/TcpSocksStream") - } - fn jni_class_pointer_field() -> jfieldID { - swig_jni_get_field_id!( - FOREIGN_CLASS_TCPSOCKSSTREAM_MNATIVEOBJ_FIELD, - FOREIGN_CLASS_TCPSOCKSSTREAM, - "mNativeObj", - "J" - ) - } - fn box_object(this: Self) -> jlong { - let this: Box = Box::new(this); - let this: *mut TcpSocksStream = Box::into_raw(this); - this as jlong - } - fn unbox_object(x: jlong) -> Self { - let x: *mut TcpSocksStream = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - let x: Box = unsafe { Box::from_raw(x) }; - let x: TcpSocksStream = *x; - x - } - fn to_pointer(x: jlong) -> ::std::ptr::NonNull { - let x: *mut TcpSocksStream = - unsafe { jlong_to_pointer::(x).as_mut().unwrap() }; - ::std::ptr::NonNull::::new(x).unwrap() - } -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TcpSocksStream_init( - env: *mut JNIEnv, - _: jclass, - target: jstring, - socks_proxy: jstring, - timeout_ms: jlong, -) -> jlong { - let mut target: JavaString = JavaString::new(env, target); - let mut target: &str = target.to_str(); - let mut target: String = target.to_string(); - let mut socks_proxy: JavaString = JavaString::new(env, socks_proxy); - let mut socks_proxy: &str = socks_proxy.to_str(); - let mut socks_proxy: String = socks_proxy.to_string(); - let mut timeout_ms: u64 = >::try_from(timeout_ms) - .expect("invalid jlong, in jlong => u64 conversation"); - let this: Result = { - TcpSocksStream::new_timeout(target, socks_proxy, timeout_ms) - .map_err(|e| format!("{:#?}", e)) - }; - let mut this: jlong = match this { - Ok(x) => { - let ret: jlong = ::box_object(x); - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return ::jni_invalid_value(); - } - }; - this as jlong -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TcpSocksStream_do_1on_1data( - env: *mut JNIEnv, - _: jclass, - this: jlong, - cb: jobject, -) -> () { - let mut cb: Box = >::swig_from(cb, env); - let this: &mut TcpSocksStream = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: Result<(), String> = { - this.set_data_handler(Observer { cb }).unwrap(); - this.read_line_async().map_err(|e| format!("{:#?}", e)) - }; - let mut ret: () = match ret { - Ok(x) => { - let mut ret = x; - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return <()>::jni_invalid_value(); - } - }; - ret -} -#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TcpSocksStream_do_1send_1data( - env: *mut JNIEnv, - _: jclass, - this: jlong, - msg: jstring, - timeout: jlong, -) -> () { - let mut msg: JavaString = JavaString::new(env, msg); - let mut msg: &str = msg.to_str(); - let mut msg: String = msg.to_string(); - let mut timeout: u64 = >::try_from(timeout) - .expect("invalid jlong, in jlong => u64 conversation"); - let this: &mut TcpSocksStream = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let mut ret: Result<(), String> = { - this.send_data(msg, Some(Duration::new(timeout, 0))) - .map_err(|e| format!("{:#?}", e)) - }; - let mut ret: () = match ret { - Ok(x) => { - let mut ret = x; - ret - } - Err(msg) => { - jni_throw_exception(env, &msg); - return <()>::jni_invalid_value(); - } - }; - ret -} -#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] -#[no_mangle] -pub extern "C" fn Java_com_sifir_tor_TcpSocksStream_do_1delete( - env: *mut JNIEnv, - _: jclass, - this: jlong, -) { - let this: *mut TcpSocksStream = - unsafe { jlong_to_pointer::(this).as_mut().unwrap() }; - let this: Box = unsafe { Box::from_raw(this) }; - drop(this); -} -static mut JAVA_UTIL_OPTIONAL_INT: jclass = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_INT_OF: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_INT_EMPTY: jmethodID = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TORHIDDENSERVICE: jclass = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TORHIDDENSERVICE_MNATIVEOBJ_FIELD: jfieldID = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TCPSOCKSSTREAM: jclass = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TCPSOCKSSTREAM_MNATIVEOBJ_FIELD: jfieldID = ::std::ptr::null_mut(); -static mut JAVA_LANG_BYTE: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_BYTE_BYTE_VALUE: jmethodID = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_HIDDENSERVICEHANDLER: jclass = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_HIDDENSERVICEHANDLER_MNATIVEOBJ_FIELD: jfieldID = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_DOUBLE: jclass = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_DOUBLE_OF: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_DOUBLE_EMPTY: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_LANG_EXCEPTION: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_INTEGER: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_INTEGER_INT_VALUE: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_LANG_DOUBLE: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_DOUBLE_DOUBLE_VALUE_METHOD: jmethodID = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TORSERVICEPARAM: jclass = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_TORSERVICEPARAM_MNATIVEOBJ_FIELD: jfieldID = ::std::ptr::null_mut(); -static mut JAVA_LANG_STRING: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_LONG: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_LONG_LONG_VALUE: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_LANG_FLOAT: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_FLOAT_FLOAT_VALUE: jmethodID = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_OWNEDTORSERVICE: jclass = ::std::ptr::null_mut(); -static mut FOREIGN_CLASS_OWNEDTORSERVICE_MNATIVEOBJ_FIELD: jfieldID = ::std::ptr::null_mut(); -static mut JAVA_LANG_SHORT: jclass = ::std::ptr::null_mut(); -static mut JAVA_LANG_SHORT_SHORT_VALUE: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_LONG: jclass = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_LONG_OF: jmethodID = ::std::ptr::null_mut(); -static mut JAVA_UTIL_OPTIONAL_LONG_EMPTY: jmethodID = ::std::ptr::null_mut(); -#[no_mangle] -pub extern "system" fn JNI_OnLoad( - java_vm: *mut JavaVM, - _reserved: *mut ::std::os::raw::c_void, -) -> jint { - println!("JNI_OnLoad begin"); - assert!(!java_vm.is_null()); - let mut env: *mut JNIEnv = ::std::ptr::null_mut(); - let res = unsafe { - (**java_vm).GetEnv.unwrap()( - java_vm, - (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void, - SWIG_JNI_VERSION, - ) - }; - if res != (JNI_OK as jint) { - panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res); - } - assert!(!env.is_null()); - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/util/OptionalInt")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/util/OptionalInt") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/util/OptionalInt") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_UTIL_OPTIONAL_INT = class; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("of"), - swig_c_str!("(I)Ljava/util/OptionalInt;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalInt", - " method ", - "of", - " sig ", - "(I)Ljava/util/OptionalInt;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_INT_OF = method_id; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("empty"), - swig_c_str!("()Ljava/util/OptionalInt;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalInt", - " method ", - "empty", - " sig ", - "()Ljava/util/OptionalInt;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_INT_EMPTY = method_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("com/sifir/tor/TorHiddenService")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TorHiddenService") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TorHiddenService") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - FOREIGN_CLASS_TORHIDDENSERVICE = class; - let field_id: jfieldID = - (**env).GetFieldID.unwrap()(env, class, swig_c_str!("mNativeObj"), swig_c_str!("J")); - assert!( - !field_id.is_null(), - concat!( - "GetStaticFieldID for class ", - "com/sifir/tor/TorHiddenService", - " method ", - "mNativeObj", - " sig ", - "J", - " failed" - ) - ); - FOREIGN_CLASS_TORHIDDENSERVICE_MNATIVEOBJ_FIELD = field_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("com/sifir/tor/TcpSocksStream")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TcpSocksStream") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TcpSocksStream") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - FOREIGN_CLASS_TCPSOCKSSTREAM = class; - let field_id: jfieldID = - (**env).GetFieldID.unwrap()(env, class, swig_c_str!("mNativeObj"), swig_c_str!("J")); - assert!( - !field_id.is_null(), - concat!( - "GetStaticFieldID for class ", - "com/sifir/tor/TcpSocksStream", - " method ", - "mNativeObj", - " sig ", - "J", - " failed" - ) - ); - FOREIGN_CLASS_TCPSOCKSSTREAM_MNATIVEOBJ_FIELD = field_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Byte")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Byte") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Byte") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_BYTE = class; - let method_id: jmethodID = - (**env).GetMethodID.unwrap()(env, class, swig_c_str!("byteValue"), swig_c_str!("()B")); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Byte", - " method ", - "byteValue", - " sig ", - "()B", - " failed" - ) - ); - JAVA_LANG_BYTE_BYTE_VALUE = method_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("com/sifir/tor/HiddenServiceHandler")); - assert!( - !class_local_ref.is_null(), - concat!( - "FindClass failed for ", - "com/sifir/tor/HiddenServiceHandler" - ) - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!( - "FindClass failed for ", - "com/sifir/tor/HiddenServiceHandler" - ) - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - FOREIGN_CLASS_HIDDENSERVICEHANDLER = class; - let field_id: jfieldID = - (**env).GetFieldID.unwrap()(env, class, swig_c_str!("mNativeObj"), swig_c_str!("J")); - assert!( - !field_id.is_null(), - concat!( - "GetStaticFieldID for class ", - "com/sifir/tor/HiddenServiceHandler", - " method ", - "mNativeObj", - " sig ", - "J", - " failed" - ) - ); - FOREIGN_CLASS_HIDDENSERVICEHANDLER_MNATIVEOBJ_FIELD = field_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("java/util/OptionalDouble")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/util/OptionalDouble") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/util/OptionalDouble") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_UTIL_OPTIONAL_DOUBLE = class; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("of"), - swig_c_str!("(D)Ljava/util/OptionalDouble;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalDouble", - " method ", - "of", - " sig ", - "(D)Ljava/util/OptionalDouble;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_DOUBLE_OF = method_id; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("empty"), - swig_c_str!("()Ljava/util/OptionalDouble;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalDouble", - " method ", - "empty", - " sig ", - "()Ljava/util/OptionalDouble;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_DOUBLE_EMPTY = method_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Exception")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Exception") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Exception") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_EXCEPTION = class; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Integer")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Integer") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Integer") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_INTEGER = class; - let method_id: jmethodID = - (**env).GetMethodID.unwrap()(env, class, swig_c_str!("intValue"), swig_c_str!("()I")); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Integer", - " method ", - "intValue", - " sig ", - "()I", - " failed" - ) - ); - JAVA_LANG_INTEGER_INT_VALUE = method_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Double")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Double") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Double") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_DOUBLE = class; - let method_id: jmethodID = (**env).GetMethodID.unwrap()( - env, - class, - swig_c_str!("doubleValue"), - swig_c_str!("()D"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Double", - " method ", - "doubleValue", - " sig ", - "()D", - " failed" - ) - ); - JAVA_LANG_DOUBLE_DOUBLE_VALUE_METHOD = method_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("com/sifir/tor/TorServiceParam")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TorServiceParam") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/TorServiceParam") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - FOREIGN_CLASS_TORSERVICEPARAM = class; - let field_id: jfieldID = - (**env).GetFieldID.unwrap()(env, class, swig_c_str!("mNativeObj"), swig_c_str!("J")); - assert!( - !field_id.is_null(), - concat!( - "GetStaticFieldID for class ", - "com/sifir/tor/TorServiceParam", - " method ", - "mNativeObj", - " sig ", - "J", - " failed" - ) - ); - FOREIGN_CLASS_TORSERVICEPARAM_MNATIVEOBJ_FIELD = field_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/String")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/String") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/String") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_STRING = class; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Long")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Long") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Long") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_LONG = class; - let method_id: jmethodID = - (**env).GetMethodID.unwrap()(env, class, swig_c_str!("longValue"), swig_c_str!("()J")); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Long", - " method ", - "longValue", - " sig ", - "()J", - " failed" - ) - ); - JAVA_LANG_LONG_LONG_VALUE = method_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Float")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Float") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Float") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_FLOAT = class; - let method_id: jmethodID = - (**env).GetMethodID.unwrap()(env, class, swig_c_str!("floatValue"), swig_c_str!("()F")); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Float", - " method ", - "floatValue", - " sig ", - "()F", - " failed" - ) - ); - JAVA_LANG_FLOAT_FLOAT_VALUE = method_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("com/sifir/tor/OwnedTorService")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/OwnedTorService") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "com/sifir/tor/OwnedTorService") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - FOREIGN_CLASS_OWNEDTORSERVICE = class; - let field_id: jfieldID = - (**env).GetFieldID.unwrap()(env, class, swig_c_str!("mNativeObj"), swig_c_str!("J")); - assert!( - !field_id.is_null(), - concat!( - "GetStaticFieldID for class ", - "com/sifir/tor/OwnedTorService", - " method ", - "mNativeObj", - " sig ", - "J", - " failed" - ) - ); - FOREIGN_CLASS_OWNEDTORSERVICE_MNATIVEOBJ_FIELD = field_id; - } - unsafe { - let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!("java/lang/Short")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/lang/Short") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/lang/Short") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_LANG_SHORT = class; - let method_id: jmethodID = - (**env).GetMethodID.unwrap()(env, class, swig_c_str!("shortValue"), swig_c_str!("()S")); - assert!( - !method_id.is_null(), - concat!( - "GetMethodID for class ", - "java/lang/Short", - " method ", - "shortValue", - " sig ", - "()S", - " failed" - ) - ); - JAVA_LANG_SHORT_SHORT_VALUE = method_id; - } - unsafe { - let class_local_ref = - (**env).FindClass.unwrap()(env, swig_c_str!("java/util/OptionalLong")); - assert!( - !class_local_ref.is_null(), - concat!("FindClass failed for ", "java/util/OptionalLong") - ); - let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref); - assert!( - !class.is_null(), - concat!("FindClass failed for ", "java/util/OptionalLong") - ); - (**env).DeleteLocalRef.unwrap()(env, class_local_ref); - JAVA_UTIL_OPTIONAL_LONG = class; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("of"), - swig_c_str!("(J)Ljava/util/OptionalLong;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalLong", - " method ", - "of", - " sig ", - "(J)Ljava/util/OptionalLong;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_LONG_OF = method_id; - let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()( - env, - class, - swig_c_str!("empty"), - swig_c_str!("()Ljava/util/OptionalLong;"), - ); - assert!( - !method_id.is_null(), - concat!( - "GetStaticMethodID for class ", - "java/util/OptionalLong", - " method ", - "empty", - " sig ", - "()Ljava/util/OptionalLong;", - " failed" - ) - ); - JAVA_UTIL_OPTIONAL_LONG_EMPTY = method_id; - } - SWIG_JNI_VERSION -} -#[no_mangle] -pub extern "system" fn JNI_OnUnload(java_vm: *mut JavaVM, _reserved: *mut ::std::os::raw::c_void) { - println!("JNI_OnUnLoad begin"); - assert!(!java_vm.is_null()); - let mut env: *mut JNIEnv = ::std::ptr::null_mut(); - let res = unsafe { - (**java_vm).GetEnv.unwrap()( - java_vm, - (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void, - SWIG_JNI_VERSION, - ) - }; - if res != (JNI_OK as jint) { - panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res); - } - assert!(!env.is_null()); - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_UTIL_OPTIONAL_INT); - JAVA_UTIL_OPTIONAL_INT = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, FOREIGN_CLASS_TORHIDDENSERVICE); - FOREIGN_CLASS_TORHIDDENSERVICE = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, FOREIGN_CLASS_TCPSOCKSSTREAM); - FOREIGN_CLASS_TCPSOCKSSTREAM = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_BYTE); - JAVA_LANG_BYTE = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, FOREIGN_CLASS_HIDDENSERVICEHANDLER); - FOREIGN_CLASS_HIDDENSERVICEHANDLER = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_UTIL_OPTIONAL_DOUBLE); - JAVA_UTIL_OPTIONAL_DOUBLE = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_EXCEPTION); - JAVA_LANG_EXCEPTION = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_INTEGER); - JAVA_LANG_INTEGER = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_DOUBLE); - JAVA_LANG_DOUBLE = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, FOREIGN_CLASS_TORSERVICEPARAM); - FOREIGN_CLASS_TORSERVICEPARAM = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_STRING); - JAVA_LANG_STRING = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_LONG); - JAVA_LANG_LONG = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_FLOAT); - JAVA_LANG_FLOAT = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, FOREIGN_CLASS_OWNEDTORSERVICE); - FOREIGN_CLASS_OWNEDTORSERVICE = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_LANG_SHORT); - JAVA_LANG_SHORT = ::std::ptr::null_mut() - } - unsafe { - (**env).DeleteGlobalRef.unwrap()(env, JAVA_UTIL_OPTIONAL_LONG); - JAVA_UTIL_OPTIONAL_LONG = ::std::ptr::null_mut() - } -} diff --git a/sifir-android/src/ffi/java_glue_in_btc.rs b/sifir-android/src/ffi/java_glue_in_btc.rs new file mode 100644 index 0000000..12a837f --- /dev/null +++ b/sifir-android/src/ffi/java_glue_in_btc.rs @@ -0,0 +1,125 @@ +#[cfg(feature = "btc_wallet")] +use btc::*; +use bdk::bitcoin::consensus::encode::{deserialize, serialize}; +use bdk::bitcoin::util::psbt::PartiallySignedTransaction; +use bdk::SignOptions; + +macro_rules! unwrap_err_string { + ($e:expr)=>{ + $e.map_err(|e|{ format!("{:#?}",e)}).unwrap(); + } +} + +// Generate Xprvs +#[cfg(feature = "btc_wallet")] +foreign_class!(class Keys{ + fn derive_xprvs(network: String, derive_path: String, password: String, mnemonic:String, num_child: u32)->Result { + // FIXME this shouold be impl From for Network { + // + // } + let network = match network.as_str() { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + }.unwrap(); + let num_child = match num_child { + x if x >= 2 => x, + _ => 2, + }; + let keys = DerivedBip39Xprvs::new( + derive_path.into_derivation_path().unwrap(), + network, + num_child, + Some(String::from(password)), + match mnemonic.len() { + x if x > 0 => Some(String::from(mnemonic)), + _ => None, + }, + ) + .map_err(|e|{ format!("{:#?}",e)}).unwrap(); + serde_json::to_string(&keys).map_err(|e|{ format!("{:#?}",e)}) + } +fn xprvs_w_paths_to_xpubs_w_paths( + xprvspaths_vector_json_string: String, + network_str: String +) -> Result{ + let network = match network_str.as_str() { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + } + .unwrap(); + let xpubs_with_paths: XpubsWithPaths = ( + unwrap_err_string!(serde_json::from_str::(&xprvspaths_vector_json_string)), + network + ) + .into(); + Ok(unwrap_err_string!(serde_json::to_string(&xpubs_with_paths))) +} + +}); +/// Xprvs To Descriptors +#[cfg(feature = "btc_wallet")] +foreign_class!(class Descriptors{ + fn wallet_descriptors_from_any_descriptor_cfg(any_desc_cfg: String)->Result { + + let wallet_descriptors: WalletDescriptors = + unwrap_err_string!(serde_json::from_str::(&any_desc_cfg)).into(); + // TODO: this should not be unwraped, thus no use of macro + serde_json::to_string(&wallet_descriptors).map_err(|e|{ format!("{:#?}",e)}) +}}); +/// OwnedTorService Android Interface +#[cfg(feature = "btc_wallet")] +foreign_class!(class ElectrumSledWallet { + self_type ElectrumSledWallet; + constructor new(wallet_cfg_json:String)->Result { + let wallet_cfg: WalletCfg = serde_json::from_str(&wallet_cfg_json).map_err(|e| { format!("{:#?}",e)}).unwrap(); + Ok(Into::::into(wallet_cfg)) + } + fn get_balance(&self)-> Result{ + this.get_balance().map_err(|e| { format!("{:#?}",e)}) + } + fn get_new_address(&mut self,index:u32)->Result{ + this.get_address(match index { + 0 => AddressIndex::LastUnused, + 1 => AddressIndex::New, + _ => AddressIndex::Peek(index), + }).map_err(|e| { format!("{:#?}",e)}).map(|address| format!("{}",address)) + } + fn sync(&mut self,max_address_count:u32)-> Result<(),String> { + struct SifirWallet {}; + impl Progress for SifirWallet { + fn update(&self, progress: f32, message: Option) -> Result<(), bdk::Error> { + info!( + "Wallet sync progress is {} and message {:?}, TODO THIS TO OBSERVER", + progress, message + ); + Ok(()) + } + }; + let _ = unwrap_err_string!(this.sync(SifirWallet {}, Some(max_address_count))); + Ok(()) + } + fn create_tx(&mut self,tx: String)-> Result { + let create_txn: CreateTx = unwrap_err_string!(serde_json::from_str(&tx)); + let (psbt, txn) = unwrap_err_string!(create_txn.into_wallet_txn(this)); + Ok(json!({"psbt": base64::encode(serialize(&psbt)), "txnDetails" : txn}).to_string()) + } + fn sign_psbt(&mut self,psbt_base64:String) -> Result{ + let mut psbt = deserialize(&base64::decode(&psbt_base64).unwrap()).unwrap(); + let finished = unwrap_err_string!(this.sign(&mut psbt, SignOptions::default())); + Ok( + json!({"psbt" : base64::encode(serialize(&psbt)).to_string(), "finished": finished}).to_string()) + } + fn broadcast_pbst(&mut self, psbt_base64: String) -> Result{ + let psbt = deserialize::(&base64::decode(&psbt_base64).unwrap()).unwrap(); + let txn_id = this.broadcast(psbt.extract_tx()).unwrap(); + Ok(txn_id.to_string()) + } + +}); +// FIXME +// 1. HERE map_err macro to rest of stuff +// 2. deserialize psbt in a util class as static ? diff --git a/sifir-android/src/ffi/java_glue_in_common.rs b/sifir-android/src/ffi/java_glue_in_common.rs new file mode 100644 index 0000000..5bbc7a2 --- /dev/null +++ b/sifir-android/src/ffi/java_glue_in_common.rs @@ -0,0 +1,11 @@ +use jni_sys::*; +use logger::{log, Logger}; +use log::*; + +use serde_json::json; + +foreign_class!(class Logger { + self_type Logger; + private constructor = empty; + fn Logger::new()->Logger; +}); diff --git a/sifir-android/src/ffi/java_glue_in.rs b/sifir-android/src/ffi/java_glue_in_tor.rs similarity index 95% rename from sifir-android/src/ffi/java_glue_in.rs rename to sifir-android/src/ffi/java_glue_in_tor.rs index 77ca7c1..8cdcfbb 100644 --- a/sifir-android/src/ffi/java_glue_in.rs +++ b/sifir-android/src/ffi/java_glue_in_tor.rs @@ -1,7 +1,5 @@ -use jni_sys::*; -use logger::{log, Logger}; -use serde::Serialize; use std::time::Duration; +#[cfg(feature = "tor_daemon")] use tor::{ hidden_service::{HiddenServiceDataHandler, HiddenServiceHandler}, tcp_stream::{DataObserver, TcpSocksStream}, @@ -18,7 +16,6 @@ foreign_callback!(callback DataObserver { // internally wrap passed the Boxed DataObserver Impl we receive from Java // with Observer so we can Send across threads unsafe impl Send for Observer {} - unsafe impl Sync for Observer {} struct Observer { @@ -35,6 +32,7 @@ impl DataObserver for Observer { } /// Hiden Service Handler +#[cfg(feature = "tor_daemon")] foreign_class!(class HiddenServiceHandler { self_type HiddenServiceHandler; constructor new(dst_port:u16,cb:Box)->Result{ @@ -46,6 +44,7 @@ foreign_class!(class HiddenServiceHandler { }); /// Tor Hidden Service, cannot be constructed directly +#[cfg(feature = "tor_daemon")] foreign_class!(class TorHiddenService { self_type TorHiddenService; private constructor = empty; @@ -58,11 +57,13 @@ foreign_class!(class TorHiddenService { }); /// OwnedTorService Android Interface +#[cfg(feature = "tor_daemon")] foreign_class!(class TorServiceParam { self_type TorServiceParam; constructor TorServiceParam::new(data_dir:&str,socks_port:u16,bootstap_timeout_ms: u64)->TorServiceParam; }); +#[cfg(feature = "tor_daemon")] foreign_class!(class OwnedTorService { self_type OwnedTorService; constructor new(param:TorServiceParam)->Result { @@ -114,6 +115,7 @@ foreign_class!(class OwnedTorService { }); /// TcpStream Android Interface +#[cfg(feature = "tor_daemon")] foreign_class!(class TcpSocksStream { self_type TcpSocksStream; constructor new(target:String,socks_proxy:String,timeout_ms:u64)->Result { diff --git a/sifir-android/src/ffi_cpp/java_glue.rs b/sifir-android/src/ffi_cpp/java_glue.rs new file mode 100644 index 0000000..fee3a92 --- /dev/null +++ b/sifir-android/src/ffi_cpp/java_glue.rs @@ -0,0 +1,916 @@ +#[allow(unused_macros)] +macro_rules! swig_c_str { + ($ lit : expr) => { + concat!($lit, "\0").as_ptr() as *const ::std::os::raw::c_char + }; +} +#[allow(dead_code)] +pub trait SwigForeignClass { + fn c_class_name() -> *const ::std::os::raw::c_char; + fn box_object(x: Self) -> *mut ::std::os::raw::c_void; + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self; +} +#[allow(dead_code)] +pub trait SwigForeignEnum { + fn as_u32(&self) -> u32; + fn from_u32(_: u32) -> Self; +} +#[allow(dead_code)] +#[doc = ""] +trait SwigInto { + fn swig_into(self) -> T; +} +#[allow(dead_code)] +#[doc = ""] +trait SwigFrom { + fn swig_from(_: T) -> Self; +} +#[allow(dead_code)] +#[doc = ""] +trait SwigDeref { + type Target: ?Sized; + fn swig_deref(&self) -> &Self::Target; +} +#[allow(dead_code)] +#[doc = ""] +trait SwigDerefMut { + type Target: ?Sized; + fn swig_deref_mut(&mut self) -> &mut Self::Target; +} +#[allow(dead_code)] +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CRustStrView { + data: *const ::std::os::raw::c_char, + len: usize, +} +#[allow(dead_code)] +impl CRustStrView { + fn from_str(s: &str) -> CRustStrView { + CRustStrView { + data: s.as_ptr() as *const ::std::os::raw::c_char, + len: s.len(), + } + } +} +#[allow(dead_code)] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CRustString { + data: *const ::std::os::raw::c_char, + len: usize, + capacity: usize, +} +#[allow(dead_code)] +impl CRustString { + pub fn from_string(s: String) -> CRustString { + let data = s.as_ptr() as *const ::std::os::raw::c_char; + let len = s.len(); + let capacity = s.capacity(); + ::std::mem::forget(s); + CRustString { + data, + len, + capacity, + } + } +} +#[allow(dead_code)] +#[repr(C)] +pub struct CRustObjectSlice { + data: *const ::std::os::raw::c_void, + len: usize, + step: usize, +} +#[allow(dead_code)] +#[repr(C)] +pub struct CRustObjectMutSlice { + data: *mut ::std::os::raw::c_void, + len: usize, + step: usize, +} +#[allow(dead_code)] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CRustForeignVec { + data: *const ::std::os::raw::c_void, + len: usize, + capacity: usize, + step: usize, +} +#[allow(dead_code)] +impl CRustForeignVec { + pub fn from_vec(mut v: Vec) -> CRustForeignVec { + let data = v.as_mut_ptr() as *const ::std::os::raw::c_void; + let len = v.len(); + let capacity = v.capacity(); + ::std::mem::forget(v); + CRustForeignVec { + data, + len, + capacity, + step: ::std::mem::size_of::(), + } + } +} +#[allow(dead_code)] +#[inline] +fn push_foreign_class_to_vec( + vec: *mut CRustForeignVec, + elem: *mut ::std::os::raw::c_void, +) { + assert!(!vec.is_null()); + let vec: &mut CRustForeignVec = unsafe { &mut *vec }; + assert!(vec.len == 0 || ::std::mem::size_of::() == vec.step); + vec.step = ::std::mem::size_of::(); + let mut v = unsafe { Vec::from_raw_parts(vec.data as *mut T, vec.len, vec.capacity) }; + v.push(T::unbox_object(elem)); + vec.data = v.as_mut_ptr() as *const ::std::os::raw::c_void; + vec.len = v.len(); + vec.capacity = v.capacity(); + ::std::mem::forget(v); +} +#[allow(dead_code)] +#[inline] +fn remove_foreign_class_from_vec( + vec: *mut CRustForeignVec, + index: usize, +) -> *mut ::std::os::raw::c_void { + assert!(!vec.is_null()); + let vec: &mut CRustForeignVec = unsafe { &mut *vec }; + assert_eq!(::std::mem::size_of::(), vec.step); + let mut v = unsafe { Vec::from_raw_parts(vec.data as *mut T, vec.len, vec.capacity) }; + let elem: T = v.remove(index); + vec.data = v.as_mut_ptr() as *const ::std::os::raw::c_void; + vec.len = v.len(); + vec.capacity = v.capacity(); + ::std::mem::forget(v); + T::box_object(elem) +} +#[allow(dead_code)] +#[inline] +fn drop_foreign_class_vec(v: CRustForeignVec) { + assert_eq!(::std::mem::size_of::(), v.step); + let v = unsafe { Vec::from_raw_parts(v.data as *mut T, v.len, v.capacity) }; + drop(v); +} +use jni_sys::*; +use log::*; +use logger::{log, Logger}; +use serde_json::json; +use std::time::Duration; +#[cfg(feature = "tor_daemon")] +use tor::{ + hidden_service::{HiddenServiceDataHandler, HiddenServiceHandler}, + tcp_stream::{DataObserver, TcpSocksStream}, + BootstrapPhase, OwnedTorService, OwnedTorServiceBootstrapPhase, TorHiddenService, + TorHiddenServiceParam, TorServiceParam, +}; +unsafe impl Send for Observer {} +unsafe impl Sync for Observer {} +struct Observer { + cb: Box, +} +impl DataObserver for Observer { + fn on_data(&self, data: String) { + self.cb.on_data(data); + } + fn on_error(&self, data: String) { + self.cb.on_error(data); + } +} +#[allow(non_snake_case)] +#[test] +fn test_CRustStrView_layout() { + #[repr(C)] + struct MyCRustStrView { + data: *const ::std::os::raw::c_char, + len: usize, + } + assert_eq!( + ::std::mem::size_of::(), + ::std::mem::size_of::() + ); + assert_eq!( + ::std::mem::align_of::(), + ::std::mem::align_of::() + ); + let our_s: MyCRustStrView = unsafe { ::std::mem::zeroed() }; + let user_s: CRustStrView = unsafe { ::std::mem::zeroed() }; + #[allow(dead_code)] + fn check_CRustStrView_data_type_fn(s: &CRustStrView) -> &*const ::std::os::raw::c_char { + &s.data + } + let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_char) as usize) + - ((&our_s as *const MyCRustStrView) as usize); + let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_char) as usize) + - ((&user_s as *const CRustStrView) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustStrView_len_type_fn(s: &CRustStrView) -> &usize { + &s.len + } + let offset_our = + ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustStrView) as usize); + let offset_user = + ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustStrView) as usize); + assert_eq!(offset_our, offset_user); +} +#[allow(non_snake_case)] +#[test] +fn test_CRustString_layout() { + #[repr(C)] + struct MyCRustString { + data: *const ::std::os::raw::c_char, + len: usize, + capacity: usize, + } + assert_eq!( + ::std::mem::size_of::(), + ::std::mem::size_of::() + ); + assert_eq!( + ::std::mem::align_of::(), + ::std::mem::align_of::() + ); + let our_s: MyCRustString = unsafe { ::std::mem::zeroed() }; + let user_s: CRustString = unsafe { ::std::mem::zeroed() }; + #[allow(dead_code)] + fn check_CRustString_data_type_fn(s: &CRustString) -> &*const ::std::os::raw::c_char { + &s.data + } + let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_char) as usize) + - ((&our_s as *const MyCRustString) as usize); + let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_char) as usize) + - ((&user_s as *const CRustString) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustString_len_type_fn(s: &CRustString) -> &usize { + &s.len + } + let offset_our = + ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustString) as usize); + let offset_user = + ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustString) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustString_capacity_type_fn(s: &CRustString) -> &usize { + &s.capacity + } + let offset_our = + ((&our_s.capacity as *const usize) as usize) - ((&our_s as *const MyCRustString) as usize); + let offset_user = + ((&user_s.capacity as *const usize) as usize) - ((&user_s as *const CRustString) as usize); + assert_eq!(offset_our, offset_user); +} +#[no_mangle] +pub extern "C" fn crust_string_free(x: CRustString) { + let s = unsafe { String::from_raw_parts(x.data as *mut u8, x.len, x.capacity) }; + drop(s); +} +#[no_mangle] +pub extern "C" fn crust_string_clone(x: CRustString) -> CRustString { + let s = unsafe { String::from_raw_parts(x.data as *mut u8, x.len, x.capacity) }; + let ret = CRustString::from_string(s.clone()); + ::std::mem::forget(s); + ret +} +#[allow(non_snake_case)] +#[test] +fn test_CRustObjectSlice_layout() { + #[repr(C)] + struct MyCRustObjectSlice { + data: *const ::std::os::raw::c_void, + len: usize, + step: usize, + } + assert_eq!( + ::std::mem::size_of::(), + ::std::mem::size_of::() + ); + assert_eq!( + ::std::mem::align_of::(), + ::std::mem::align_of::() + ); + let our_s: MyCRustObjectSlice = unsafe { ::std::mem::zeroed() }; + let user_s: CRustObjectSlice = unsafe { ::std::mem::zeroed() }; + #[allow(dead_code)] + fn check_CRustObjectSlice_data_type_fn(s: &CRustObjectSlice) -> &*const ::std::os::raw::c_void { + &s.data + } + let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) + - ((&our_s as *const MyCRustObjectSlice) as usize); + let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) + - ((&user_s as *const CRustObjectSlice) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustObjectSlice_len_type_fn(s: &CRustObjectSlice) -> &usize { + &s.len + } + let offset_our = + ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustObjectSlice) as usize); + let offset_user = + ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustObjectSlice) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustObjectSlice_step_type_fn(s: &CRustObjectSlice) -> &usize { + &s.step + } + let offset_our = + ((&our_s.step as *const usize) as usize) - ((&our_s as *const MyCRustObjectSlice) as usize); + let offset_user = + ((&user_s.step as *const usize) as usize) - ((&user_s as *const CRustObjectSlice) as usize); + assert_eq!(offset_our, offset_user); +} +#[allow(non_snake_case)] +#[test] +fn test_CRustObjectMutSlice_layout() { + #[repr(C)] + struct MyCRustObjectMutSlice { + data: *mut ::std::os::raw::c_void, + len: usize, + step: usize, + } + assert_eq!( + ::std::mem::size_of::(), + ::std::mem::size_of::() + ); + assert_eq!( + ::std::mem::align_of::(), + ::std::mem::align_of::() + ); + let our_s: MyCRustObjectMutSlice = unsafe { ::std::mem::zeroed() }; + let user_s: CRustObjectMutSlice = unsafe { ::std::mem::zeroed() }; + #[allow(dead_code)] + fn check_CRustObjectMutSlice_data_type_fn( + s: &CRustObjectMutSlice, + ) -> &*mut ::std::os::raw::c_void { + &s.data + } + let offset_our = ((&our_s.data as *const *mut ::std::os::raw::c_void) as usize) + - ((&our_s as *const MyCRustObjectMutSlice) as usize); + let offset_user = ((&user_s.data as *const *mut ::std::os::raw::c_void) as usize) + - ((&user_s as *const CRustObjectMutSlice) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustObjectMutSlice_len_type_fn(s: &CRustObjectMutSlice) -> &usize { + &s.len + } + let offset_our = ((&our_s.len as *const usize) as usize) + - ((&our_s as *const MyCRustObjectMutSlice) as usize); + let offset_user = ((&user_s.len as *const usize) as usize) + - ((&user_s as *const CRustObjectMutSlice) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustObjectMutSlice_step_type_fn(s: &CRustObjectMutSlice) -> &usize { + &s.step + } + let offset_our = ((&our_s.step as *const usize) as usize) + - ((&our_s as *const MyCRustObjectMutSlice) as usize); + let offset_user = ((&user_s.step as *const usize) as usize) + - ((&user_s as *const CRustObjectMutSlice) as usize); + assert_eq!(offset_our, offset_user); +} +#[allow(non_snake_case)] +#[test] +fn test_CRustForeignVec_layout() { + #[repr(C)] + struct MyCRustForeignVec { + data: *const ::std::os::raw::c_void, + len: usize, + capacity: usize, + step: usize, + } + assert_eq!( + ::std::mem::size_of::(), + ::std::mem::size_of::() + ); + assert_eq!( + ::std::mem::align_of::(), + ::std::mem::align_of::() + ); + let our_s: MyCRustForeignVec = unsafe { ::std::mem::zeroed() }; + let user_s: CRustForeignVec = unsafe { ::std::mem::zeroed() }; + #[allow(dead_code)] + fn check_CRustForeignVec_data_type_fn(s: &CRustForeignVec) -> &*const ::std::os::raw::c_void { + &s.data + } + let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) + - ((&our_s as *const MyCRustForeignVec) as usize); + let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) + - ((&user_s as *const CRustForeignVec) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustForeignVec_len_type_fn(s: &CRustForeignVec) -> &usize { + &s.len + } + let offset_our = + ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustForeignVec) as usize); + let offset_user = + ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustForeignVec) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustForeignVec_capacity_type_fn(s: &CRustForeignVec) -> &usize { + &s.capacity + } + let offset_our = ((&our_s.capacity as *const usize) as usize) + - ((&our_s as *const MyCRustForeignVec) as usize); + let offset_user = ((&user_s.capacity as *const usize) as usize) + - ((&user_s as *const CRustForeignVec) as usize); + assert_eq!(offset_our, offset_user); + #[allow(dead_code)] + fn check_CRustForeignVec_step_type_fn(s: &CRustForeignVec) -> &usize { + &s.step + } + let offset_our = + ((&our_s.step as *const usize) as usize) - ((&our_s as *const MyCRustForeignVec) as usize); + let offset_user = + ((&user_s.step as *const usize) as usize) - ((&user_s as *const CRustForeignVec) as usize); + assert_eq!(offset_our, offset_user); +} +impl SwigForeignClass for Logger { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify!(Logger)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box = Box::new(this); + let this: *mut Logger = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut Logger; + let p: Box = unsafe { Box::from_raw(p) }; + let p: Logger = *p; + p + } +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn Logger_new() -> *mut ::std::os::raw::c_void { + let mut ret: Logger = Logger::new(); + let ret: *mut ::std::os::raw::c_void = ::box_object(ret); + ret +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn Logger_delete(this: *mut Logger) { + let this: Box = unsafe { Box::from_raw(this) }; + drop(this); +} +#[repr(C)] +#[derive(Clone)] +#[allow(non_snake_case)] +pub struct C_DataObserver { + opaque: *const ::std::os::raw::c_void, + C_DataObserver_deref: extern "C" fn(_: *const ::std::os::raw::c_void), + onData: extern "C" fn(a0: CRustString, _: *const ::std::os::raw::c_void) -> (), + onError: extern "C" fn(a0: CRustString, _: *const ::std::os::raw::c_void) -> (), +} +#[doc = " It totally depends on ะก++ implementation"] +#[doc = " let's assume it safe"] +unsafe impl Send for C_DataObserver {} +impl DataObserver for C_DataObserver { + #[allow(unused_mut)] + fn on_data(&self, a0: String) -> () { + let mut a0: CRustString = CRustString::from_string(a0); + let ret: () = (self.onData)(a0, self.opaque); + ret + } + #[allow(unused_mut)] + fn on_error(&self, a0: String) -> () { + let mut a0: CRustString = CRustString::from_string(a0); + let ret: () = (self.onError)(a0, self.opaque); + ret + } +} +impl Drop for C_DataObserver { + fn drop(&mut self) { + (self.C_DataObserver_deref)(self.opaque); + } +} +impl SwigForeignClass for Result { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify ! (Result < HiddenServiceHandler , String >)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box> = Box::new(this); + let this: *mut Result = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut Result; + let p: Box> = unsafe { Box::from_raw(p) }; + let p: Result = *p; + p + } +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn HiddenServiceHandler_new( + dst_port: u16, + cb: *const C_DataObserver, +) -> *const ::std::os::raw::c_void { + assert!(!cb.is_null()); + let cb: &C_DataObserver = unsafe { cb.as_ref().unwrap() }; + let cb: Box = Box::new(cb.clone()); + let this: Result = { + let mut lsnr = HiddenServiceHandler::new(dst_port) + .map_err(|e| format!("{:#?}", e)) + .unwrap(); + lsnr.set_data_handler(Observer { cb }) + .map_err(|e| format!("{:#?}", e)) + .unwrap(); + let _ = lsnr.start_http_listener(); + Ok(lsnr) + }; + let this: Box> = Box::new(this); + let this: *mut Result = Box::into_raw(this); + this as *const ::std::os::raw::c_void +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn HiddenServiceHandler_delete(this: *mut Result) { + let this: Box> = unsafe { Box::from_raw(this) }; + drop(this); +} +impl SwigForeignClass for TorHiddenService { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify!(TorHiddenService)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box = Box::new(this); + let this: *mut TorHiddenService = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut TorHiddenService; + let p: Box = unsafe { Box::from_raw(p) }; + let p: TorHiddenService = *p; + p + } +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TorHiddenService_get_onion_url(this: *mut TorHiddenService) -> CRustString { + let this: &TorHiddenService = unsafe { this.as_mut().unwrap() }; + let mut ret: String = { this.onion_url.to_string() }; + let mut ret: CRustString = CRustString::from_string(ret); + ret +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TorHiddenService_get_secret_b64(this: *mut TorHiddenService) -> CRustString { + let this: &TorHiddenService = unsafe { this.as_mut().unwrap() }; + let mut ret: String = { base64::encode(this.secret_key).into() }; + let mut ret: CRustString = CRustString::from_string(ret); + ret +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TorHiddenService_delete(this: *mut TorHiddenService) { + let this: Box = unsafe { Box::from_raw(this) }; + drop(this); +} +impl SwigForeignClass for TorServiceParam { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify!(TorServiceParam)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box = Box::new(this); + let this: *mut TorServiceParam = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut TorServiceParam; + let p: Box = unsafe { Box::from_raw(p) }; + let p: TorServiceParam = *p; + p + } +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TorServiceParam_new( + data_dir: CRustStrView, + socks_port: u16, + bootstap_timeout_ms: u64, +) -> *const ::std::os::raw::c_void { + let mut data_dir: &str = unsafe { + let slice: &[u8] = ::std::slice::from_raw_parts(data_dir.data as *const u8, data_dir.len); + ::std::str::from_utf8_unchecked(slice) + }; + let this: TorServiceParam = TorServiceParam::new(data_dir, socks_port, bootstap_timeout_ms); + let this: Box = Box::new(this); + let this: *mut TorServiceParam = Box::into_raw(this); + this as *const ::std::os::raw::c_void +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TorServiceParam_delete(this: *mut TorServiceParam) { + let this: Box = unsafe { Box::from_raw(this) }; + drop(this); +} +#[repr(C)] +#[derive(Clone, Copy)] +pub union CRustVoidOkResultUnionCRustString { + ok: u8, + err: CRustString, +} +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString, + is_ok: u8, +} +#[repr(C)] +#[derive(Clone, Copy)] +pub union CRustResultUnion4232mut3232c_voidCRustString { + ok: *mut ::std::os::raw::c_void, + err: CRustString, +} +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CRustResult4232mut3232c_voidCRustString { + data: CRustResultUnion4232mut3232c_voidCRustString, + is_ok: u8, +} +impl SwigForeignClass for OwnedTorService { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify!(OwnedTorService)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box = Box::new(this); + let this: *mut OwnedTorService = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut OwnedTorService; + let p: Box = unsafe { Box::from_raw(p) }; + let p: OwnedTorService = *p; + p + } +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_new( + param: *mut ::std::os::raw::c_void, +) -> *const ::std::os::raw::c_void { + assert!(!param.is_null()); + let param: *mut TorServiceParam = param as *mut TorServiceParam; + let param: Box = unsafe { Box::from_raw(param) }; + let param: TorServiceParam = *param; + let this: OwnedTorService = { + Logger::new(); + OwnedTorService::new(param).unwrap() + }; + let this: Box = Box::new(this); + let this: *mut OwnedTorService = Box::into_raw(this); + this as *const ::std::os::raw::c_void +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_getSocksPort(this: *mut OwnedTorService) -> u16 { + let this: &OwnedTorService = unsafe { this.as_mut().unwrap() }; + let mut ret: u16 = { this.socks_port }; + ret +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_shutdown( + this: *mut OwnedTorService, +) -> CRustVoidOkResultCRustString { + let this: &mut OwnedTorService = unsafe { this.as_mut().unwrap() }; + let mut ret: Result<(), String> = { this.shutdown().map_err(|e| format!("{:#?}", e)) }; + let mut ret: CRustVoidOkResultCRustString = match ret { + Ok(()) => CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { ok: 0 }, + is_ok: 1, + }, + Err(err) => { + let mut err: CRustString = CRustString::from_string(err); + CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { err }, + is_ok: 0, + } + } + }; + ret +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_get_status(this: *mut OwnedTorService) -> CRustString { + let this: &mut OwnedTorService = unsafe { this.as_mut().unwrap() }; + let mut ret: String = { + let node_status = this.get_status(); + match node_status { + Ok(status) => { + let status_string = serde_json::to_string(&status).unwrap(); + status_string + } + Err(e) => e.to_string(), + } + }; + let mut ret: CRustString = CRustString::from_string(ret); + ret +} +impl<'a> SwigInto for &'a str { + fn swig_into(self) -> String { + self.into() + } +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_create_hidden_service( + this: *mut OwnedTorService, + dst_port: u16, + hs_port: u16, + secret_key: CRustStrView, +) -> CRustResult4232mut3232c_voidCRustString { + let mut secret_key: &str = unsafe { + let slice: &[u8] = + ::std::slice::from_raw_parts(secret_key.data as *const u8, secret_key.len); + ::std::str::from_utf8_unchecked(slice) + }; + let mut secret_key: String = secret_key.swig_into(); + let this: &mut OwnedTorService = unsafe { this.as_mut().unwrap() }; + let mut ret: Result = { + let hs_key = match secret_key.len() { + 0 => Ok(None), + _ => { + let mut decoded_buff: [u8; 64] = [0; 64]; + base64::decode_config_slice(secret_key, base64::STANDARD, &mut decoded_buff) + .map(|_| Some(decoded_buff)) + } + }; + match hs_key { + Ok(key) => this + .create_hidden_service(TorHiddenServiceParam { + to_port: dst_port, + hs_port, + secret_key: key, + }) + .map_err(|e| format!("{:#?}", e)), + Err(e) => Err(format!("{:#?}", e)), + } + }; + let mut ret: CRustResult4232mut3232c_voidCRustString = match ret { + Ok(mut x) => { + let ok: *mut ::std::os::raw::c_void = ::box_object(x); + CRustResult4232mut3232c_voidCRustString { + data: CRustResultUnion4232mut3232c_voidCRustString { ok }, + is_ok: 1, + } + } + Err(err) => { + let mut err: CRustString = CRustString::from_string(err); + CRustResult4232mut3232c_voidCRustString { + data: CRustResultUnion4232mut3232c_voidCRustString { err }, + is_ok: 0, + } + } + }; + ret +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_delete_hidden_service( + this: *mut OwnedTorService, + onion: CRustStrView, +) -> CRustVoidOkResultCRustString { + let mut onion: &str = unsafe { + let slice: &[u8] = ::std::slice::from_raw_parts(onion.data as *const u8, onion.len); + ::std::str::from_utf8_unchecked(slice) + }; + let mut onion: String = onion.swig_into(); + let this: &mut OwnedTorService = unsafe { this.as_mut().unwrap() }; + let mut ret: Result<(), String> = { + this.delete_hidden_service(onion) + .map_err(|e| format!("{:#?}", e)) + }; + let mut ret: CRustVoidOkResultCRustString = match ret { + Ok(()) => CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { ok: 0 }, + is_ok: 1, + }, + Err(err) => { + let mut err: CRustString = CRustString::from_string(err); + CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { err }, + is_ok: 0, + } + } + }; + ret +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn OwnedTorService_delete(this: *mut OwnedTorService) { + let this: Box = unsafe { Box::from_raw(this) }; + drop(this); +} +impl SwigForeignClass for TcpSocksStream { + fn c_class_name() -> *const ::std::os::raw::c_char { + swig_c_str!(stringify!(TcpSocksStream)) + } + fn box_object(this: Self) -> *mut ::std::os::raw::c_void { + let this: Box = Box::new(this); + let this: *mut TcpSocksStream = Box::into_raw(this); + this as *mut ::std::os::raw::c_void + } + fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self { + let p = p as *mut TcpSocksStream; + let p: Box = unsafe { Box::from_raw(p) }; + let p: TcpSocksStream = *p; + p + } +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TcpSocksStream_new( + target: CRustStrView, + socks_proxy: CRustStrView, + timeout_ms: u64, +) -> *const ::std::os::raw::c_void { + let mut target: &str = unsafe { + let slice: &[u8] = ::std::slice::from_raw_parts(target.data as *const u8, target.len); + ::std::str::from_utf8_unchecked(slice) + }; + let mut target: String = target.swig_into(); + let mut socks_proxy: &str = unsafe { + let slice: &[u8] = + ::std::slice::from_raw_parts(socks_proxy.data as *const u8, socks_proxy.len); + ::std::str::from_utf8_unchecked(slice) + }; + let mut socks_proxy: String = socks_proxy.swig_into(); + let this: TcpSocksStream = + { TcpSocksStream::new_timeout(target, socks_proxy, timeout_ms).unwrap() }; + let this: Box = Box::new(this); + let this: *mut TcpSocksStream = Box::into_raw(this); + this as *const ::std::os::raw::c_void +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TcpSocksStream_on_data( + this: *mut TcpSocksStream, + cb: *const C_DataObserver, +) -> CRustVoidOkResultCRustString { + assert!(!cb.is_null()); + let cb: &C_DataObserver = unsafe { cb.as_ref().unwrap() }; + let cb: Box = Box::new(cb.clone()); + let this: &mut TcpSocksStream = unsafe { this.as_mut().unwrap() }; + let mut ret: Result<(), String> = { + this.set_data_handler(Observer { cb }).unwrap(); + this.read_line_async().map_err(|e| format!("{:#?}", e)) + }; + let mut ret: CRustVoidOkResultCRustString = match ret { + Ok(()) => CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { ok: 0 }, + is_ok: 1, + }, + Err(err) => { + let mut err: CRustString = CRustString::from_string(err); + CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { err }, + is_ok: 0, + } + } + }; + ret +} +#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TcpSocksStream_send_data( + this: *mut TcpSocksStream, + msg: CRustStrView, + timeout: u64, +) -> CRustVoidOkResultCRustString { + let mut msg: &str = unsafe { + let slice: &[u8] = ::std::slice::from_raw_parts(msg.data as *const u8, msg.len); + ::std::str::from_utf8_unchecked(slice) + }; + let mut msg: String = msg.swig_into(); + let this: &mut TcpSocksStream = unsafe { this.as_mut().unwrap() }; + let mut ret: Result<(), String> = { + this.send_data(msg, Some(Duration::new(timeout, 0))) + .map_err(|e| format!("{:#?}", e)) + }; + let mut ret: CRustVoidOkResultCRustString = match ret { + Ok(()) => CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { ok: 0 }, + is_ok: 1, + }, + Err(err) => { + let mut err: CRustString = CRustString::from_string(err); + CRustVoidOkResultCRustString { + data: CRustVoidOkResultUnionCRustString { err }, + is_ok: 0, + } + } + }; + ret +} +#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)] +#[no_mangle] +pub extern "C" fn TcpSocksStream_delete(this: *mut TcpSocksStream) { + let this: Box = unsafe { Box::from_raw(this) }; + drop(this); +} diff --git a/sifir-android/src/ffi_cpp/java_glue_in_btc.rs b/sifir-android/src/ffi_cpp/java_glue_in_btc.rs new file mode 100644 index 0000000..12a837f --- /dev/null +++ b/sifir-android/src/ffi_cpp/java_glue_in_btc.rs @@ -0,0 +1,125 @@ +#[cfg(feature = "btc_wallet")] +use btc::*; +use bdk::bitcoin::consensus::encode::{deserialize, serialize}; +use bdk::bitcoin::util::psbt::PartiallySignedTransaction; +use bdk::SignOptions; + +macro_rules! unwrap_err_string { + ($e:expr)=>{ + $e.map_err(|e|{ format!("{:#?}",e)}).unwrap(); + } +} + +// Generate Xprvs +#[cfg(feature = "btc_wallet")] +foreign_class!(class Keys{ + fn derive_xprvs(network: String, derive_path: String, password: String, mnemonic:String, num_child: u32)->Result { + // FIXME this shouold be impl From for Network { + // + // } + let network = match network.as_str() { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + }.unwrap(); + let num_child = match num_child { + x if x >= 2 => x, + _ => 2, + }; + let keys = DerivedBip39Xprvs::new( + derive_path.into_derivation_path().unwrap(), + network, + num_child, + Some(String::from(password)), + match mnemonic.len() { + x if x > 0 => Some(String::from(mnemonic)), + _ => None, + }, + ) + .map_err(|e|{ format!("{:#?}",e)}).unwrap(); + serde_json::to_string(&keys).map_err(|e|{ format!("{:#?}",e)}) + } +fn xprvs_w_paths_to_xpubs_w_paths( + xprvspaths_vector_json_string: String, + network_str: String +) -> Result{ + let network = match network_str.as_str() { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + } + .unwrap(); + let xpubs_with_paths: XpubsWithPaths = ( + unwrap_err_string!(serde_json::from_str::(&xprvspaths_vector_json_string)), + network + ) + .into(); + Ok(unwrap_err_string!(serde_json::to_string(&xpubs_with_paths))) +} + +}); +/// Xprvs To Descriptors +#[cfg(feature = "btc_wallet")] +foreign_class!(class Descriptors{ + fn wallet_descriptors_from_any_descriptor_cfg(any_desc_cfg: String)->Result { + + let wallet_descriptors: WalletDescriptors = + unwrap_err_string!(serde_json::from_str::(&any_desc_cfg)).into(); + // TODO: this should not be unwraped, thus no use of macro + serde_json::to_string(&wallet_descriptors).map_err(|e|{ format!("{:#?}",e)}) +}}); +/// OwnedTorService Android Interface +#[cfg(feature = "btc_wallet")] +foreign_class!(class ElectrumSledWallet { + self_type ElectrumSledWallet; + constructor new(wallet_cfg_json:String)->Result { + let wallet_cfg: WalletCfg = serde_json::from_str(&wallet_cfg_json).map_err(|e| { format!("{:#?}",e)}).unwrap(); + Ok(Into::::into(wallet_cfg)) + } + fn get_balance(&self)-> Result{ + this.get_balance().map_err(|e| { format!("{:#?}",e)}) + } + fn get_new_address(&mut self,index:u32)->Result{ + this.get_address(match index { + 0 => AddressIndex::LastUnused, + 1 => AddressIndex::New, + _ => AddressIndex::Peek(index), + }).map_err(|e| { format!("{:#?}",e)}).map(|address| format!("{}",address)) + } + fn sync(&mut self,max_address_count:u32)-> Result<(),String> { + struct SifirWallet {}; + impl Progress for SifirWallet { + fn update(&self, progress: f32, message: Option) -> Result<(), bdk::Error> { + info!( + "Wallet sync progress is {} and message {:?}, TODO THIS TO OBSERVER", + progress, message + ); + Ok(()) + } + }; + let _ = unwrap_err_string!(this.sync(SifirWallet {}, Some(max_address_count))); + Ok(()) + } + fn create_tx(&mut self,tx: String)-> Result { + let create_txn: CreateTx = unwrap_err_string!(serde_json::from_str(&tx)); + let (psbt, txn) = unwrap_err_string!(create_txn.into_wallet_txn(this)); + Ok(json!({"psbt": base64::encode(serialize(&psbt)), "txnDetails" : txn}).to_string()) + } + fn sign_psbt(&mut self,psbt_base64:String) -> Result{ + let mut psbt = deserialize(&base64::decode(&psbt_base64).unwrap()).unwrap(); + let finished = unwrap_err_string!(this.sign(&mut psbt, SignOptions::default())); + Ok( + json!({"psbt" : base64::encode(serialize(&psbt)).to_string(), "finished": finished}).to_string()) + } + fn broadcast_pbst(&mut self, psbt_base64: String) -> Result{ + let psbt = deserialize::(&base64::decode(&psbt_base64).unwrap()).unwrap(); + let txn_id = this.broadcast(psbt.extract_tx()).unwrap(); + Ok(txn_id.to_string()) + } + +}); +// FIXME +// 1. HERE map_err macro to rest of stuff +// 2. deserialize psbt in a util class as static ? diff --git a/sifir-android/src/ffi_cpp/java_glue_in_common.rs b/sifir-android/src/ffi_cpp/java_glue_in_common.rs new file mode 100644 index 0000000..5bbc7a2 --- /dev/null +++ b/sifir-android/src/ffi_cpp/java_glue_in_common.rs @@ -0,0 +1,11 @@ +use jni_sys::*; +use logger::{log, Logger}; +use log::*; + +use serde_json::json; + +foreign_class!(class Logger { + self_type Logger; + private constructor = empty; + fn Logger::new()->Logger; +}); diff --git a/sifir-android/src/ffi_cpp/java_glue_in_tor.rs b/sifir-android/src/ffi_cpp/java_glue_in_tor.rs new file mode 100644 index 0000000..fc2a67e --- /dev/null +++ b/sifir-android/src/ffi_cpp/java_glue_in_tor.rs @@ -0,0 +1,138 @@ +use std::time::Duration; +#[cfg(feature = "tor_daemon")] +use tor::{ + hidden_service::{HiddenServiceDataHandler, HiddenServiceHandler}, + tcp_stream::{DataObserver, TcpSocksStream}, + BootstrapPhase, OwnedTorService, OwnedTorServiceBootstrapPhase, TorHiddenService, + TorHiddenServiceParam, TorServiceParam, +}; + +/// Java callback interface for DataObserver callback used in TcpStreams, HiddenService etc.. +foreign_callback!(callback DataObserver { + self_type DataObserver; + onData = DataObserver::on_data(&self,result: String); + onError = DataObserver::on_error(&self,result: String); +}); +// internally wrap passed the Boxed DataObserver Impl we receive from Java +// with Observer so we can Send across threads +unsafe impl Send for Observer {} +unsafe impl Sync for Observer {} + +struct Observer { + cb: Box, +} + +impl DataObserver for Observer { + fn on_data(&self, data: String) { + self.cb.on_data(data); + } + fn on_error(&self, data: String) { + self.cb.on_error(data); + } +} + +/// Hiden Service Handler +#[cfg(feature = "tor_daemon")] +foreign_class!(class HiddenServiceHandler { + self_type HiddenServiceHandler; + constructor new(dst_port:u16,cb:Box)->Result{ + let mut lsnr = HiddenServiceHandler::new(dst_port).map_err(|e| { format!("{:#?}",e) }).unwrap(); + lsnr.set_data_handler(Observer { cb }).map_err(|e| { format!("{:#?}",e) }).unwrap(); + let _ = lsnr.start_http_listener(); + Ok(lsnr) + } +}); + +/// Tor Hidden Service, cannot be constructed directly +#[cfg(feature = "tor_daemon")] +foreign_class!(class TorHiddenService { + self_type TorHiddenService; + private constructor = empty; + fn get_onion_url(&self)->String{ + this.onion_url.to_string() + } + fn get_secret_b64(&self)->String{ + base64::encode(this.secret_key).into() + } +}); + +/// OwnedTorService Android Interface +#[cfg(feature = "tor_daemon")] +foreign_class!(class TorServiceParam { + self_type TorServiceParam; + constructor TorServiceParam::new(data_dir:&str,socks_port:u16,bootstap_timeout_ms: u64)->TorServiceParam; +}); + +#[cfg(feature = "tor_daemon")] +foreign_class!(class OwnedTorService { + self_type OwnedTorService; + // FIXME why result not ok here but ok else where ? look into this + constructor new(param:TorServiceParam)->OwnedTorService { + // constructor new(param:TorServiceParam)->Result { + Logger::new(); + OwnedTorService::new(param).unwrap() + // OwnedTorService::new(param).map_err(|e| { format!("{:#?}",e)}) + } + fn getSocksPort(&self)-> u16{ + this.socks_port + } + fn shutdown(&mut self)->Result<(),String>{ + this.shutdown().map_err(|e| { format!("{:#?}",e) }) + } + fn get_status(&mut self)-> String { + let node_status = this.get_status(); + match node_status { + Ok(status) => { + let status_string = serde_json::to_string(&status).unwrap(); + status_string + } + Err(e) => { e.to_string() } + } + } + fn create_hidden_service(&mut self, dst_port: u16, hs_port: u16, secret_key: String) -> Result { + let hs_key = match secret_key.len() { + 0 => Ok(None), + _ => { + let mut decoded_buff:[u8;64] = [0;64]; + base64::decode_config_slice(secret_key, base64::STANDARD, &mut decoded_buff) + .map( |_| { Some(decoded_buff)}) + } + }; + + match hs_key { + Ok(key) =>{ + this.create_hidden_service(TorHiddenServiceParam { + to_port: dst_port, + hs_port, + secret_key: key + }).map_err(|e| { format! ("{:#?}",e)}) + }, + Err(e)=> { + Err(format!("{:#?}",e)) + } + } + } + fn delete_hidden_service(&mut self, onion: String) -> Result<(),String> { + this.delete_hidden_service(onion).map_err(|e| { format! ("{:#?}",e)}) + } +}); + +/// TcpStream Android Interface +#[cfg(feature = "tor_daemon")] +foreign_class!(class TcpSocksStream { + self_type TcpSocksStream; + constructor new(target:String,socks_proxy:String,timeout_ms:u64)->TcpSocksStream { + // constructor new(target:String,socks_proxy:String,timeout_ms:u64)->Result { + TcpSocksStream::new_timeout(target,socks_proxy,timeout_ms).unwrap() + // TcpSocksStream::new_timeout(target,socks_proxy,timeout_ms).map_err(|e| { format!("{:#?}",e) }) + } + fn on_data(&mut self,cb:Box)->Result<(),String>{ + this.set_data_handler(Observer{ + cb, + }).unwrap(); + this.read_line_async().map_err(|e| { format!("{:#?}",e)}) + } + fn send_data(&mut self, msg:String,timeout:u64)->Result<(),String>{ + this.send_data(msg, Some(Duration::new(timeout, 0))).map_err(|e| { format!("{:#?}",e) }) + } +}); diff --git a/sifir-android/src/ffi_cpp/mod.rs b/sifir-android/src/ffi_cpp/mod.rs new file mode 100644 index 0000000..3f47fda --- /dev/null +++ b/sifir-android/src/ffi_cpp/mod.rs @@ -0,0 +1 @@ +pub mod java_glue; diff --git a/sifir-android/src/lib.rs b/sifir-android/src/lib.rs index bfb0b12..3365e29 100644 --- a/sifir-android/src/lib.rs +++ b/sifir-android/src/lib.rs @@ -1,3 +1,2 @@ -#![allow(non_snake_case)] -pub mod ffi; -pub use ffi::java_glue::*; +pub mod ffi_cpp; +pub use ffi_cpp::*; diff --git a/sifir-ios/Cargo.toml b/sifir-ios/Cargo.toml index 1ea63cc..cdcc336 100644 --- a/sifir-ios/Cargo.toml +++ b/sifir-ios/Cargo.toml @@ -4,18 +4,24 @@ version = "0.1.0" authors = ["Gus Abidi "] edition = "2018" +[features] +btc_wallet =["btc"] +tor_daemon =["tor"] + [dependencies] -tor = { path = "../tor" } +tor = { path = "../tor", optional = true } +btc = { path = "../btc", optional = true } logger = { path = "../logger" } libc = "0.2.80" serde = { version="1.0.117", features = ["derive"]} serde_json = "1.0" base64 = "0.13.0" +reqwest = { version= "0.11.8", features = ["socks"] } [build-dependencies] -cbindgen = "0.17.0" +cbindgen = "0.18.0" cargo-lipo = "3.1.1" [lib] -crate-type = ["staticlib"] -#crate-type = ["cdylib"] +# crate-type = ["staticlib"] +crate-type = ["cdylib"] diff --git a/sifir-ios/build.rs b/sifir-ios/build.rs index 7b1d374..8a7cf20 100644 --- a/sifir-ios/build.rs +++ b/sifir-ios/build.rs @@ -1,12 +1,11 @@ -use cbindgen::Language::C; +// use cbindgen::Language::C; use std::env; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - cbindgen::Builder::new() - .with_crate(crate_dir) - .with_language(C) - .with_include("sifir_typedef.h") - .generate() - .expect("Unable to generate bindings!!") - .write_to_file("./output/sifir-tor.h"); + let outputname = + env::var("SIFIR_CBINDGEN_OUTPUT_FILENAME").unwrap_or(String::from("sifir-tor.h")); + + cbindgen::generate(crate_dir) + .unwrap() + .write_to_file(format!("./output/{}", outputname)); } diff --git a/sifir-ios/cbindgen.toml b/sifir-ios/cbindgen.toml new file mode 100644 index 0000000..fe959d3 --- /dev/null +++ b/sifir-ios/cbindgen.toml @@ -0,0 +1,8 @@ +language="C" +namespace = "libsifir" +includes = ["./sifir-typedef.h"] +cpp_compat = true + +[defines] +"feature = tor_daemon" = "TOR_DAEMON" +"feature = btc_wallet" = "BTC_WALLET" diff --git a/sifir-ios/scripts/build_features_framework_ios.sh b/sifir-ios/scripts/build_features_framework_ios.sh new file mode 100755 index 0000000..3e96a39 --- /dev/null +++ b/sifir-ios/scripts/build_features_framework_ios.sh @@ -0,0 +1,99 @@ +#!/bin/bash +features=$1 +under_scored_features=$(echo "$features" | tr , _) +framework_name="Libsifir_${under_scored_features}"; +bundle_id="${under_scored_features}" +bundle_version="0.1.1" + +export IPHONEOS_DEPLOYMENT_TARGET="11.0" + +echo "---Sifir.io----"; +echo "---------------"; +echo "| |"; +echo "| 0 |"; +echo "| |"; +echo "---------------"; +echo "Will build a universal IOS static and framework:"; +echo "Features: $features" +echo "Framework Name: $framework_name" +echo "---------------"; +echo "---------------"; + +# Build local (+ FFI) +# TODO Seems like this doesn't work for libtor on latest MacOs, something about catalyst ? +# Replicate by running this command and checking config.log for the error +# For now we're iOS focused so it's ok +#SIFIR_CBINDGEN_OUTPUT_FILENAME="$framework_name.h" cargo build -p sifir-ios --release --features "$features"; +#retVal=$? +#[ ! $retVal -eq 0 ] && exit 1; + +SIFIR_CBINDGEN_OUTPUT_FILENAME="$framework_name.h" cargo lipo -p sifir-ios --release --features "$features"; +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +# copy indiviual arch libs for testing +mkdir -p ../output/release/universal/"$under_scored_features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +lib_output_target_dir="../output/release/universal/${under_scored_features}/libsifir_ios.a" + +\cp -f ../../target/universal/release/libsifir_ios.a "$lib_output_target_dir" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +echo "-------- Building Done: ${lib_output_target_dir} ------- " + +working_dir="../output/${framework_name}/target/framework/$framework_name.framework"; + +mkdir -p "$working_dir/Headers"; +mkdir -p "$working_dir/Modules"; +\cp -f "../output/${framework_name}.h" "$working_dir/Headers/$framework_name.h" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +\cp -f "../sifir-typedef.h" "$working_dir/Headers/sifir-typedef.h" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +lipo -create "$lib_output_target_dir" -output "$working_dir/$framework_name" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1; + +cat < "$working_dir/Info.plist" + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $framework_name + CFBundleIdentifier + org.sifir.sifirsdk.$bundle_id + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $framework_name + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $bundle_version + MinimumOSVersion + 11.0 + + +HERE + +cat < "$working_dir/Modules/module.modulemap" +framework module "$framework_name" { + header "$framework_name.h" + header "sifir-typedef.h" + export * +} +HERE +echo "Framework building done: ${working_dir}" +echo "DONE ALL TASKS" + diff --git a/sifir-ios/scripts/build_for_ios.sh b/sifir-ios/scripts/build_for_ios.sh index 44fcb77..c166dc9 100755 --- a/sifir-ios/scripts/build_for_ios.sh +++ b/sifir-ios/scripts/build_for_ios.sh @@ -5,7 +5,7 @@ echo "| |"; echo "| 0 |"; echo "| |"; echo "---------------"; -echo "Will build a universal IOS dylib !!"; +echo "Will build a universal IOS static lib !"; echo "---------------"; echo "---------------"; diff --git a/sifir-ios/scripts/build_for_ios__dylib_DEPRECATED.sh b/sifir-ios/scripts/build_for_ios__dylib_DEPRECATED.sh deleted file mode 100755 index cd09104..0000000 --- a/sifir-ios/scripts/build_for_ios__dylib_DEPRECATED.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -echo "---Sifir.io----"; -echo "---------------"; -echo "| |"; -echo "| 0 |"; -echo "| |"; -echo "---------------"; -echo "Will build a universal IOS dylib !!"; -echo "---------------"; -echo "---------------"; - -# Always build release now since ssl throws error on anything else now -target="release"; -#if [[ "$1" == "release" ]]; then -# target=$1; -# echo "### Building Release ###" -#fi - -# Build local (+ FFI) -cargo build -p sifir-ios --"$target"; - -export IPHONEOS_DEPLOYMENT_TARGET="11.0" - -#cargo +nightly build -p sifir-ios --target x86_64-apple-ios --"$target"; -#cargo +nightly build -p sifir-ios --target aarch64-apple-ios --"$target"; -cargo build -p sifir-ios --target x86_64-apple-ios --"$target"; -retVal=$? -[ ! $retVal -eq 0 ] && exit 1; -cargo build -p sifir-ios --target aarch64-apple-ios --"$target"; -retVal=$? -[ ! $retVal -eq 0 ] && exit 1; - -mkdir -p ../output/"$target"/{universal,aarch64-apple-ios,x86_64-apple-ios}; - -# copy indiviual arch libs for testing -\cp -f ../../target/aarch64-apple-ios/"$target"/libsifir_ios.dylib ../output/"$target"/aarch64-apple-ios/libsifir_ios.dylib -\cp -f ../../target/x86_64-apple-ios/"$target"/libsifir_ios.dylib ../output/"$target"/x86_64-apple-ios/libsifir_ios.dylib - -# create universal lb -lipo -create ../../target/aarch64-apple-ios/"$target"/libsifir_ios.dylib ../../target/x86_64-apple-ios/"$target"/libsifir_ios.dylib -output ../output/"$target"/universal/libsifir_ios.dylib - -[ ! $retVal -eq 0 ] && exit 1; - -# Update dylib rpath -install_name_tool -id "@rpath/libsifir_ios.dylib" ../output/"$target"/universal/libsifir_ios.dylib - -# Output sizes -du -d 1 -h ../output/"$target" - -echo "Done!": - diff --git a/sifir-ios/scripts/build_multi_so.sh b/sifir-ios/scripts/build_multi_so.sh new file mode 100755 index 0000000..b17ef21 --- /dev/null +++ b/sifir-ios/scripts/build_multi_so.sh @@ -0,0 +1,50 @@ +#! /bin/bash +# export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/23.1.7779620 +cd .. + + +OS=$(uname) +features=$1 +if [ ! "$features" ]; then + echo "Missing features parameter" + exit 1 +fi + +# TODO better way to do this +case $features in +"btc_wallet") + aar_dir="btc" + ;; +"tor_daemon") + aar_dir="tor" + ;; +"btc_wallet,tor_daemon") + aar_dir="tor_btc" + ;; +"tor_daemon,btc_wallet") + aar_dir="tor_btc" + ;; +*) + echo "unknown target combo!" + exit 1; +esac + + +if [ "$OS" = "Darwin" ]; then + echo "building apple darwin x86_64 lib" + cargo build --target x86_64-apple-darwin -p sifir-ios --release --features "$features" + retVal=$? + + [ ! $retVal -eq 0 ] && exit 1 +elif [ "$OS" = "Linux" ]; then + echo "building linux x86_64 lib" + cargo build --target x86_64-unknown-linux-gnu -p sifir-ios --release --features "$features" + retVal=$? + [ ! $retVal -eq 0 ] && exit 1 +fi + +cargo ndk --platform 30 --target x86_64-linux-android --target aarch64-linux-android --target armv7-linux-androideabi --target i686-linux-android --output-dir ./output/jniLibs build --release --features "$features" +retVal=$? +[ ! $retVal -eq 0 ] && exit 1 + +echo "Done!" diff --git a/sifir-ios/sifir-typedef.h b/sifir-ios/sifir-typedef.h new file mode 100644 index 0000000..20582b7 --- /dev/null +++ b/sifir-ios/sifir-typedef.h @@ -0,0 +1,4 @@ +typedef struct ElectrumSledWallet ElectrumSledWallet; +typedef struct OwnedTorService OwnedTorService; +typedef struct TcpSocksStream TcpSocksStream; +typedef struct HiddenServiceHandler HiddenServiceHandler; diff --git a/sifir-ios/src/btc_ffi/mod.rs b/sifir-ios/src/btc_ffi/mod.rs new file mode 100644 index 0000000..a5e171b --- /dev/null +++ b/sifir-ios/src/btc_ffi/mod.rs @@ -0,0 +1,282 @@ +use crate::util::*; +use bdk::bitcoin::consensus::encode::{deserialize, serialize}; +use bdk::bitcoin::util::psbt::PartiallySignedTransaction; +use bdk::SignOptions; +use btc::multi_sig::*; +use btc::*; +use libc::c_char; +use serde_json::json; +use std::ffi::{CStr, CString}; +use std::panic::{catch_unwind, AssertUnwindSafe}; + +macro_rules! unwind_into_boxed_result { + ($e:expr) => { + match catch_unwind(|| $e) { + Ok(x) => Box::into_raw(Box::new(BoxedResult { + result: Some(Box::new(x)), + message: ResultMessage::Success, + })), + Err(e) => { + let message = match e.downcast::() { + Ok(msg) => *msg, + Err(_) => String::from("Unknown panic"), + }; + Box::into_raw(Box::new(BoxedResult { + result: None, + message: ResultMessage::Error(CString::new(message).unwrap().into_raw()), + })) + } + } + }; +} + +macro_rules! required_str_from_cchar_ptr { + ($e:expr) => { + unsafe { CStr::from_ptr($e) } + .to_str() + .expect("Could not get str!"); + }; +} + +#[no_mangle] +pub extern "C" fn derive_xprvs( + network: *const c_char, + derive_path: *const c_char, + password: *const c_char, + seed_phrase: *const c_char, + num_child: usize, +) -> *mut BoxedResult<*mut c_char> { + unwind_into_boxed_result!({ + assert!(!network.is_null()); + assert!(!derive_path.is_null()); + assert!(!password.is_null()); + assert!(!seed_phrase.is_null()); + + let network_str = unsafe { CStr::from_ptr(network) } + .to_str() + .expect("Could not get str from network"); + let derive_path_str = unsafe { CStr::from_ptr(derive_path) } + .to_str() + .expect("Could not get str from derive_path"); + let password_srr = unsafe { CStr::from_ptr(password) } + .to_str() + .expect("Could not get str from password_str"); + let mnemonic = unsafe { CStr::from_ptr(seed_phrase) } + .to_str() + .expect("Could not get str from seed_phrase"); + + let network = match network_str { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + } + .unwrap(); + + let num_child: u32 = match num_child { + x if x >= 2 => x as u32, + _ => 2, + }; + + let wallet_desc = DerivedBip39Xprvs::new( + derive_path_str.into_derivation_path().unwrap(), + network, + num_child, + Some(String::from(password_srr)), + match mnemonic.len() { + x if x > 0 => Some(String::from(mnemonic)), + _ => None, + }, + ) + .unwrap(); + + let json = serde_json::to_string(&wallet_desc).unwrap(); + CString::new(json).unwrap().into_raw() + }) +} + +#[no_mangle] +pub extern "C" fn wallet_descriptors_from_any_descriptor_cfg( + any_desc_cfg: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + unwind_into_boxed_result!({ + let any_desc_cfg_str = required_str_from_cchar_ptr!(any_desc_cfg); + let wallet_descriptors: WalletDescriptors = + serde_json::from_str::(any_desc_cfg_str) + .unwrap() + .into(); + let json = serde_json::to_string(&wallet_descriptors).unwrap(); + CString::new(json).unwrap().into_raw() + }) +} + +#[no_mangle] +pub extern "C" fn electrum_wallet_from_wallet_cfg( + wallet_cfg_json: *const c_char, +) -> *mut BoxedResult { + unwind_into_boxed_result!({ + let wallet_cfg_str = required_str_from_cchar_ptr!(wallet_cfg_json); + let wallet_cfg: WalletCfg = serde_json::from_str(wallet_cfg_str).unwrap(); + let wallet: ElectrumSledWallet = wallet_cfg.into(); + wallet + }) +} + +#[no_mangle] +pub extern "C" fn get_electrum_wallet_balance( + electrum_wallet: *mut ElectrumSledWallet, +) -> *mut BoxedResult { + let wallet = unsafe { &mut *electrum_wallet }; + let matcher = AssertUnwindSafe(wallet); + unwind_into_boxed_result!({ matcher.get_balance().unwrap() }) +} + +/// Gets an address from the wallet based on the index provided +/// index = 0 => LastUnused +/// index = 1 => New +/// index > 1 => Peek(index) +#[no_mangle] +pub extern "C" fn get_electrum_wallet_address( + electrum_wallet: *mut ElectrumSledWallet, + index: u32, +) -> *mut BoxedResult<*mut c_char> { + let wallet = unsafe { &mut *electrum_wallet }; + let matcher = AssertUnwindSafe(wallet); + unwind_into_boxed_result!({ + let address = matcher + .get_address(match index { + 0 => AddressIndex::LastUnused, + 1 => AddressIndex::New, + _ => AddressIndex::Peek(index), + }) + .unwrap(); + CString::new(format!("{}", address)).unwrap().into_raw() + }) +} +// TODO accept data observer +struct SifirWallet {} +impl Progress for SifirWallet { + fn update(&self, progress: f32, message: Option) -> Result<(), bdk::Error> { + println!( + "ios ffi sync progress is {} and message {:?}, TODO THIS TO OBSERVER", + progress, message + ); + Ok(()) + } +} + +#[no_mangle] +pub extern "C" fn sync_electrum_wallet( + electrum_wallet: *mut ElectrumSledWallet, + max_address_count: u32, +) -> *mut BoxedResult { + let wallet = unsafe { &mut *electrum_wallet }; + let matcher = AssertUnwindSafe(wallet); + unwind_into_boxed_result!({ + let _ = matcher + .sync(SifirWallet {}, Some(max_address_count)) + .unwrap(); + true + }) +} + +/// Generates a finalized txn from CreateTxn json +/// returns json { psbt: base64, txnDetails: string } +#[no_mangle] +pub extern "C" fn create_tx( + wallet: *mut ElectrumSledWallet, + tx: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + let wallet = unsafe { &mut *wallet }; + let matcher = AssertUnwindSafe(wallet); + unwind_into_boxed_result!({ + let txn_str = required_str_from_cchar_ptr!(tx); + let create_txn: CreateTx = serde_json::from_str(txn_str).unwrap(); + let (psbt, txn) = create_txn.into_wallet_txn(&matcher).unwrap(); + let txn_json = json!({"psbt": base64::encode(serialize(&psbt)), "txnDetails" : txn}); + CString::new(txn_json.to_string()).unwrap().into_raw() + }) +} + +#[no_mangle] +pub extern "C" fn sign_psbt( + electrum_wallet: *mut ElectrumSledWallet, + psbt_base64: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + let psbt_str = required_str_from_cchar_ptr!(psbt_base64); + let wallet = unsafe { &mut *electrum_wallet }; + let matcher = AssertUnwindSafe(wallet); + + unwind_into_boxed_result!({ + let mut psbt = deserialize(&base64::decode(&psbt_str).unwrap()).unwrap(); + let finished = matcher.sign(&mut psbt, SignOptions::default()).unwrap(); + let json = + json!({"psbt" : base64::encode(serialize(&psbt)).to_string(), "finished": finished}); + CString::new(json.to_string()).unwrap().into_raw() + }) +} +#[no_mangle] +pub extern "C" fn broadcast_pbst( + electrum_wallet: *mut ElectrumSledWallet, + psbt_base64: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + let psbt_str = required_str_from_cchar_ptr!(psbt_base64); + let wallet = unsafe { &mut *electrum_wallet }; + let matcher = AssertUnwindSafe(wallet); + + unwind_into_boxed_result!({ + let psbt = + deserialize::(&base64::decode(&psbt_str).unwrap()).unwrap(); + let txn_id = matcher.broadcast(psbt.extract_tx()).unwrap(); + CString::new(txn_id.to_string()).unwrap().into_raw() + }) +} + +/// Convert XprvsWithPaths to XpubsWithPaths +#[no_mangle] +pub extern "C" fn xprvs_w_paths_to_xpubs_w_paths( + vec_xprvs_with_paths_json: *const c_char, + network: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + unwind_into_boxed_result!({ + let xprvspaths_str = required_str_from_cchar_ptr!(vec_xprvs_with_paths_json); + let network_str = required_str_from_cchar_ptr!(network); + let network = match network_str { + "testnet" => Ok(Network::Testnet), + "mainnet" => Ok(Network::Bitcoin), + "bitcoin" => Ok(Network::Bitcoin), + _ => Err("Invalid network passed"), + } + .unwrap(); + let xpubs_with_paths: XpubsWithPaths = ( + serde_json::from_str::(xprvspaths_str).unwrap(), + network, + ) + .into(); + let json = serde_json::to_string(&xpubs_with_paths).unwrap(); + CString::new(json).unwrap().into_raw() + }) +} + +#[no_mangle] +pub unsafe extern "C" fn drop_wallet(wallet: *mut ElectrumSledWallet) { + assert!(!wallet.is_null()); + let _: Box = Box::from_raw(wallet); +} + +#[no_mangle] +///# Safety +/// deserialize consenus encoded base64 PSBT string +// TODO Turn this to a validate function ? is it ours, can we control any of it ? etc.. +pub extern "C" fn consensus_b64_psbt_to_json_string( + psbt: *const c_char, +) -> *mut BoxedResult<*mut c_char> { + let psbt_str = required_str_from_cchar_ptr!(psbt); + + unwind_into_boxed_result!({ + let psbt = + deserialize::(&base64::decode(&psbt_str).unwrap()).unwrap(); + let json = serde_json::to_string(&psbt).unwrap(); + CString::new(json).unwrap().into_raw() + }) +} diff --git a/sifir-ios/src/lib.rs b/sifir-ios/src/lib.rs index 90e1e63..b6680fc 100644 --- a/sifir-ios/src/lib.rs +++ b/sifir-ios/src/lib.rs @@ -1 +1,49 @@ -pub mod tor_ffi; +mod util; + +use libc::{c_char, c_void}; +use log::*; +use logger::{log, Logger}; +use reqwest; +use std::ffi::{CStr, CString}; + +#[cfg(feature = "tor_daemon")] +mod tor_ffi; +use tor::tcp_stream::DataObserver; +use tor::RUNTIME; +use tor_ffi::Observer; + +#[cfg(feature = "btc_wallet")] +mod btc_ffi; + +///# Safety +/// Init the platform's logger +#[no_mangle] +pub extern "C" fn init_logger() { + Logger::new(); +} +pub fn get_proxied_client(socks_port: u16) -> Result { + let proxy = reqwest::Proxy::all( + reqwest::Url::parse(format!("socks5h://127.0.0.1:{}", socks_port).as_str()).unwrap(), + ) + .unwrap(); + reqwest::Client::builder().proxy(proxy).build() +} +#[no_mangle] +///# Safety +pub extern "C" fn get(socks_port: u16, url: *const c_char, observer: Observer) { + let client = get_proxied_client(socks_port).unwrap(); + let get_url: String = unsafe { CStr::from_ptr(url) } + .to_str() + .expect("Could not get str from url") + .to_owned(); + (*RUNTIME).lock().unwrap().spawn(async move { + let resp = client.get(get_url).send().await; + match resp { + Ok(r) => observer.on_data(r.text().await.unwrap()), + Err(e) => { + error!("Error processing request {}", e); + observer.on_error(e.to_string()); + } + } + }); +} diff --git a/sifir-ios/src/tor_ffi/mod.rs b/sifir-ios/src/tor_ffi/mod.rs index f29868b..5246554 100644 --- a/sifir-ios/src/tor_ffi/mod.rs +++ b/sifir-ios/src/tor_ffi/mod.rs @@ -1,5 +1,5 @@ +use crate::util::*; use libc::{c_char, c_void}; -use logger; use serde_json::json; use std::ffi::{CStr, CString}; use std::ops::{Deref, DerefMut}; @@ -22,12 +22,6 @@ pub struct BoxedResult { pub message: ResultMessage, } -#[no_mangle] -/// Starts env logger -pub extern "C" fn start_logger() { - logger::Logger::new(); -} - #[no_mangle] pub extern "C" fn get_owned_TorService( data_dir: *const c_char, @@ -274,12 +268,13 @@ pub extern "C" fn delete_hidden_service( owned_client: *mut OwnedTorService, onion: *const c_char, ) -> *mut ResultMessage { - assert!(!owned_client.is_null()); assert!(!onion.is_null()); let owned = unsafe { &mut *owned_client }; - let onion_str = unsafe { CStr::from_ptr(onion) }.to_str().expect("Could not obtain str from onion"); + let onion_str = unsafe { CStr::from_ptr(onion) } + .to_str() + .expect("Could not obtain str from onion"); match owned.delete_hidden_service(String::from(onion_str)) { Ok(_) => Box::into_raw(Box::new(ResultMessage::Success)), @@ -333,14 +328,6 @@ pub unsafe extern "C" fn tcp_stream_destroy(stream: *mut TcpSocksStream) { let _ = Box::from_raw(stream); } -#[no_mangle] -///# Safety -/// Destroy a cstr -pub unsafe extern "C" fn destroy_cstr(c_str: *mut c_char) { - assert!(!c_str.is_null()); - let _ = Box::from_raw(c_str); -} - // #[no_mangle] ///# Safety diff --git a/sifir-ios/src/util/mod.rs b/sifir-ios/src/util/mod.rs new file mode 100644 index 0000000..4e971f2 --- /dev/null +++ b/sifir-ios/src/util/mod.rs @@ -0,0 +1,27 @@ +use libc::c_char; +use logger; + +#[no_mangle] +/// Starts env logger +pub extern "C" fn start_logger() { + logger::Logger::new(); +} + +#[repr(C)] +pub enum ResultMessage { + Success, + Error(*mut c_char), +} +#[repr(C)] +pub struct BoxedResult { + pub result: Option>, + pub message: ResultMessage, +} + +#[no_mangle] +///# Safety +/// Destroy a cstr +pub unsafe extern "C" fn destroy_cstr(c_str: *mut c_char) { + assert!(!c_str.is_null()); + let _ = Box::from_raw(c_str); +} diff --git a/tor/Cargo.toml b/tor/Cargo.toml index 2f28b85..f03ff37 100644 --- a/tor/Cargo.toml +++ b/tor/Cargo.toml @@ -9,7 +9,8 @@ edition = "2018" [dependencies] tokio = { version= "1.4", features = ["net","rt","process","rt-multi-thread","time","sync"] } logger = { path = "../logger" } -libtor = { version= "45.8.0+0.4.5.8", features=["vendored-openssl"] } +#libtor = { version= "46.5.0+0.4.6.5", features=["vendored-openssl"] } + libtor = { version= "46.6.1+0.4.6.6", features=["vendored-openssl"] } torut = { version = "0.1.9", features=["control","v3","vendored_openssl"] } anyhow = "1.0.33" serde = { version="1.0.117", features = ["derive"]} @@ -27,10 +28,5 @@ httparse = "1.4.1" serial_test = "*" utils = { path = "../utils" } - [[example]] name = "hs_bind" -#required-features = ["cli-utils", "esplora"] -#[lib] -#crate-type = ["staticlib", "cdylib"] -#crate-type = ["lib", "cdylib"] diff --git a/tor/src/lib.rs b/tor/src/lib.rs index 2f10669..5834515 100644 --- a/tor/src/lib.rs +++ b/tor/src/lib.rs @@ -30,13 +30,14 @@ type G = AuthenticatedConn; lazy_static! { pub static ref RUNTIME: Mutex = Mutex::new( tokio::runtime::Builder::new_multi_thread() - .max_blocking_threads(num_cpus::get() / 2) + .max_blocking_threads(if num_cpus::get() > 4 {2} else {1}) .thread_name_fn(|| { static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0); let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst); format!("sifir-thread-pool-{}", id) }) - .on_thread_start(|| { debug!("thread started on {} cpus", num_cpus::get()) }) + .on_thread_start(|| { debug!("thread started")}) + .thread_keep_alive(Duration::from_secs(3)) .on_thread_stop(|| { debug!("thread stopped") }) .enable_all() .build() @@ -186,7 +187,15 @@ impl TryFrom for TorService { .flag(TorFlag::ControlPortAuto) .flag(TorFlag::CookieAuthentication(libtor::TorBool::True)) .flag(TorFlag::ControlPortWriteToFile(ctl_file_path.clone())) - .flag(TorFlag::ControlPortFileGroupReadable(libtor::TorBool::True)); + .flag(TorFlag::ControlPortFileGroupReadable(libtor::TorBool::True)) + .flag(TorFlag::LogTo( + libtor::LogLevel::Debug, + libtor::LogDestination::File(info_log_path), + )) + .flag(TorFlag::LogTo( + libtor::LogLevel::Err, + libtor::LogDestination::File(error_log_path), + )); // // Android logging to android // #[cfg(target_os = "android")] // { @@ -216,7 +225,7 @@ impl TryFrom for TorService { }; let data: Vec<&str> = t.split("PORT=").collect(); control_port = data[1].into(); - info!("success with config port {}!", control_port); + info!("success with control port {}!", control_port); is_ready = true; } Err(e) => { @@ -365,10 +374,7 @@ impl OwnedTorService { .compat(), ) } - pub fn delete_hidden_service( - &mut self, - onion: String, - ) -> Result<(), TorErrors> { + pub fn delete_hidden_service(&mut self, onion: String) -> Result<(), TorErrors> { (*RUNTIME).lock().unwrap().block_on( async { let mut _ctl = self._ctl.borrow_mut(); @@ -377,8 +383,8 @@ impl OwnedTorService { .ok_or(TorErrors::BootStrapError(String::from("Error mut lock")))?; ctl.del_onion(&onion) - .await - .map_err(TorErrors::ControlConnectionError)?; + .await + .map_err(TorErrors::ControlConnectionError)?; info!("Hidden serviec deleted !"); Ok(()) @@ -444,6 +450,7 @@ where .get_info("status/bootstrap-phase") .await .map_err(TorErrors::ControlConnectionError)?; + debug!("wait_bootstrap::{}", input); std::thread::sleep(std::time::Duration::from_millis(300)); } Ok(true) diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 7f8c5e4..2d14e6d 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -7,4 +7,5 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -reqwest = { version= "0.10.8", features = ["socks"] } +reqwest = { version= "0.11.8", features = ["socks"] } +# reqwest = { version= "0.10.8", features = ["socks"] }