diff options
| -rw-r--r-- | Cargo.lock | 932 | ||||
| -rw-r--r-- | plugins/warp/Cargo.toml | 3 | ||||
| -rw-r--r-- | plugins/warp/src/container.rs | 4 | ||||
| -rw-r--r-- | plugins/warp/src/container/network.rs | 110 | ||||
| -rw-r--r-- | plugins/warp/src/container/network/client.rs | 386 | ||||
| -rw-r--r-- | plugins/warp/src/plugin.rs | 92 |
6 files changed, 286 insertions, 1241 deletions
@@ -150,12 +150,6 @@ dependencies = [ ] [[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -310,12 +304,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -486,22 +474,6 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] name = "cpp_demangle" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -694,17 +666,6 @@ dependencies = [ ] [[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "dwarf_export" version = "0.1.0" dependencies = [ @@ -860,30 +821,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1035,25 +972,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] -name = "h2" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] name = "half" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1091,210 +1009,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] name = "idb-rs" version = "0.1.12" source = "git+https://github.com/Vector35/idb-rs?tag=0.1.12#54c50ebb35724e1470ac28d259df8c98ad5fa3b0" @@ -1327,27 +1041,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] name = "image" version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1383,33 +1076,6 @@ dependencies = [ ] [[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1519,12 +1185,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] name = "lock_api" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1556,22 +1216,6 @@ dependencies = [ ] [[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] name = "minidump" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1648,40 +1292,12 @@ dependencies = [ ] [[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] name = "msp430-asm" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91c22f111c205b788cc10e2a58aed039d5dd5554d3a9236be3d413a912ff3cb" [[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1856,50 +1472,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2030,15 +1602,6 @@ dependencies = [ ] [[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2228,63 +1791,6 @@ dependencies = [ ] [[package]] -name = "reqwest" -version = "0.12.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "mime_guess", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] name = "riscv-dis" version = "0.1.0" dependencies = [ @@ -2375,39 +1881,6 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.23.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2458,15 +1931,6 @@ dependencies = [ ] [[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2505,29 +1969,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" [[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2566,15 +2007,14 @@ dependencies = [ ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serde_qs" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", + "percent-encoding", "serde", + "thiserror 2.0.12", ] [[package]] @@ -2650,16 +2090,6 @@ dependencies = [ ] [[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2678,12 +2108,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] name = "svd-parser" version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2742,47 +2166,6 @@ dependencies = [ ] [[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2888,16 +2271,6 @@ dependencies = [ ] [[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2908,56 +2281,6 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "pin-project-lite", - "slab", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2975,51 +2298,6 @@ dependencies = [ ] [[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags 2.9.1", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3052,12 +2330,6 @@ dependencies = [ ] [[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] name = "twox-hash" version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3068,41 +2340,12 @@ dependencies = [ ] [[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3122,12 +2365,6 @@ dependencies = [ ] [[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3144,15 +2381,6 @@ dependencies = [ ] [[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] name = "warp" version = "1.0.0" source = "git+https://github.com/Vector35/warp/?tag=1.0.0#57dcb5abea59a611466be9550ba25b36c5399ce6" @@ -3170,6 +2398,7 @@ version = "0.1.0" dependencies = [ "ar", "arboard", + "base64", "binaryninja", "binaryninjacore-sys", "compact_str", @@ -3183,9 +2412,9 @@ dependencies = [ "minijinja-embed", "rayon", "regex", - "reqwest", "serde", "serde_json", + "serde_qs", "tempdir", "thiserror 2.0.12", "uuid", @@ -3235,19 +2464,6 @@ dependencies = [ ] [[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3327,50 +2543,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3605,12 +2777,6 @@ dependencies = [ ] [[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] name = "x11rb" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3628,30 +2794,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] name = "zerocopy" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3672,66 +2814,6 @@ dependencies = [ ] [[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "zstd" version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/plugins/warp/Cargo.toml b/plugins/warp/Cargo.toml index 702c500a..ccdd0fc5 100644 --- a/plugins/warp/Cargo.toml +++ b/plugins/warp/Cargo.toml @@ -24,9 +24,10 @@ thiserror = "2.0" ar = { git = "https://github.com/mdsteele/rust-ar" } tempdir = "0.3.7" regex = "1.11" -reqwest = { version = "0.12", features = ["blocking", "json", "multipart"] } directories = "6.0" compact_str = { version = "0.9.0", features = ["serde"] } +base64 = "0.22" +serde_qs = "0.15" # For reports minijinja = "2.10.2" diff --git a/plugins/warp/src/container.rs b/plugins/warp/src/container.rs index 8c76bc8f..b5e92bc7 100644 --- a/plugins/warp/src/container.rs +++ b/plugins/warp/src/container.rs @@ -35,6 +35,10 @@ pub enum ContainerError { FailedIO(io::ErrorKind), #[error("source {0} does not have an available path")] SourcePathUnavailable(SourceId), + #[error("search failed: {0}")] + SearchFailed(String), + #[error("failed to commit source '{0}': {1}")] + CommitFailed(SourceId, String), } /// Represents the ID for a single container source. diff --git a/plugins/warp/src/container/network.rs b/plugins/warp/src/container/network.rs index 21ccf05f..d0ccd3ea 100644 --- a/plugins/warp/src/container/network.rs +++ b/plugins/warp/src/container/network.rs @@ -115,26 +115,33 @@ impl NetworkContainer { let mut result: HashMap<SourceId, Vec<FunctionGUID>> = HashMap::new(); // Only query server for unknown guids if we have any. if !unknown.is_empty() { - if let Some(queried_results) = - self.client + let queried_results = + match self + .client .query_functions_source(Some(target_id), tags, &unknown) - { - // Cache the new results, this means we will not try and contact the server for that guids source. - // NOTE: Here we do not just simply list the queried results because we also - // want to cache function guids which have no source, this is important so that we never - // attempt to contact the server for that guid. - for guid in &unknown { - let sources = queried_results - .keys() - .filter(|source_id| queried_results[source_id].contains(guid)) - .copied() - .collect(); - self.known_function_sources.insert(*guid, sources); - } + { + Ok(queried_results) => queried_results, + Err(e) => { + log::error!("Failed to query functions source: {}", e); + return result; + } + }; - for (source_id, guids) in queried_results { - result.entry(source_id).or_default().extend(guids); - } + // Cache the new results, this means we will not try and contact the server for that guids source. + // NOTE: Here we do not just simply list the queried results because we also + // want to cache function guids which have no source, this is important so that we never + // attempt to contact the server for that guid. + for guid in &unknown { + let sources = queried_results + .keys() + .filter(|source_id| queried_results[source_id].contains(guid)) + .copied() + .collect(); + self.known_function_sources.insert(*guid, sources); + } + + for (source_id, guids) in queried_results { + result.entry(source_id).or_default().extend(guids); } } @@ -157,34 +164,40 @@ impl NetworkContainer { functions: &[FunctionGUID], ) { let target_id = self.get_target_id(target); - if let Some(file) = self + let file = match self .client .query_functions(target_id, Some(*source), functions) { - log::debug!("Got {} chunks from server", file.chunks.len()); - for chunk in &file.chunks { - match &chunk.kind { - ChunkKind::Signature(sc) => { - let functions: Vec<_> = sc.functions().collect(); - // Probe the source before attempting to access it, as it might not exist locally. - self.probe_source(*source); - match self.cache.add_functions(target, source, &functions) { - Ok(_) => log::debug!( - "Added {} functions into cached source '{}'", - functions.len(), - source - ), - Err(err) => log::error!( - "Failed to add {} function into cached source '{}': {}", - functions.len(), - source, - err - ), - } + Ok(file) => file, + Err(e) => { + log::error!("Failed to query functions: {}", e); + return; + } + }; + + log::debug!("Got {} chunks from server", file.chunks.len()); + for chunk in &file.chunks { + match &chunk.kind { + ChunkKind::Signature(sc) => { + let functions: Vec<_> = sc.functions().collect(); + // Probe the source before attempting to access it, as it might not exist locally. + self.probe_source(*source); + match self.cache.add_functions(target, source, &functions) { + Ok(_) => log::debug!( + "Added {} functions into cached source '{}'", + functions.len(), + source + ), + Err(err) => log::error!( + "Failed to add {} function into cached source '{}': {}", + functions.len(), + source, + err + ), } - // TODO; Probably want to pull type in with this. - ChunkKind::Type(_) => {} } + // TODO; Probably want to pull type in with this. + ChunkKind::Type(_) => {} } } } @@ -192,10 +205,10 @@ impl NetworkContainer { /// Push a file to the network source. /// /// **This is blocking** - pub fn push_file(&mut self, source_id: SourceId, file: &WarpFile) { + pub fn push_file(&mut self, source_id: SourceId, file: &WarpFile) -> Result<i32, String> { // TODO: We need a better name for the commit. I would like to derive it automatically from // TODO: something instead of having the user give it TBH. - self.client.push_file(source_id, file, "commit"); + self.client.push_file(source_id, file, "commit") } /// Probe the source to make sure it exists in the cache. Retrieving the name from the server. @@ -261,10 +274,14 @@ impl Container for NetworkContainer { .added_chunks .remove(source) .ok_or(ContainerError::SourceNotFound(source.clone()))?; + if chunks.is_empty() { + return Ok(false); + } // Because each add operation is its own chunk, we should merge them into larger chunks before sending. let merged_chunks = Chunk::merge(&chunks, CompressionType::Zstd); let file = WarpFile::new(WarpFileHeader::new(), merged_chunks); - self.push_file(*source, &file); + self.push_file(*source, &file) + .map_err(|e| ContainerError::CommitFailed(*source, e))?; Ok(true) } @@ -407,12 +424,9 @@ impl Container for NetworkContainer { } fn search(&self, query: &ContainerSearchQuery) -> ContainerResult<ContainerSearchResponse> { - // TODO: Give this an actual network error. self.client .search(query) - .ok_or(ContainerError::CorruptedData( - "search query failed to validate", - )) + .map_err(|e| ContainerError::SearchFailed(e.to_string())) } } diff --git a/plugins/warp/src/container/network/client.rs b/plugins/warp/src/container/network/client.rs index 39e7640a..d2217bce 100644 --- a/plugins/warp/src/container/network/client.rs +++ b/plugins/warp/src/container/network/client.rs @@ -3,9 +3,8 @@ use crate::container::{ ContainerSearchItem, ContainerSearchItemKind, ContainerSearchQuery, ContainerSearchResponse, SourceId, SourcePath, SourceTag, }; -use reqwest::blocking::Client; -use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION}; -use reqwest::StatusCode; +use base64::Engine; +use binaryninja::download::DownloadProvider; use serde::Deserialize; use serde_json::json; use std::collections::HashMap; @@ -23,42 +22,23 @@ use warp::WarpFile; /// NOTE: **All requests are blocking**. #[derive(Clone, Debug)] pub struct NetworkClient { - client: Client, + provider: DownloadProvider, + headers: Vec<(String, String)>, pub server_url: String, } impl NetworkClient { - pub fn new( - server_url: String, - server_token: Option<String>, - https_proxy: Option<String>, - ) -> reqwest::Result<Self> { - let version_info = binaryninja::version_info(); - // TODO: IIRC we had a user agent format already for some other thing. - let client_agent = format!( - "Binary Ninja/{}.{}.{}", - version_info.major, version_info.minor, version_info.build - ); + pub fn new(server_url: String, server_token: Option<String>) -> Self { // TODO: This might want to be kept for the request header? - let mut headers = HeaderMap::new(); + let mut headers: Vec<(String, String)> = vec![]; if let Some(token) = &server_token { - headers.insert( - AUTHORIZATION, - HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(), - ); + headers.push(("authorization".to_string(), format!("Bearer {}", token))); } - // TODO: Configurable timeout? - let mut client_builder = Client::builder() - .connect_timeout(std::time::Duration::from_secs(10)) - .default_headers(headers) - .user_agent(client_agent); - if let Some(https_proxy) = https_proxy { - client_builder = client_builder.proxy(reqwest::Proxy::all(&https_proxy)?); - } - Ok(Self { - client: client_builder.build()?, + Self { + provider: DownloadProvider::try_default().unwrap(), + headers, server_url, - }) + } } /// Check to see the status of the server. @@ -67,10 +47,14 @@ impl NetworkClient { /// server that is unresponsive. /// /// Route: `api/v1/status` - pub fn status(&self) -> reqwest::Result<StatusCode> { + pub fn status(&self) -> Result<(), String> { let status_url = format!("{}/api/v1/status", self.server_url); - let resp = self.client.get(&status_url).send()?; - Ok(resp.status()) + let mut inst = self.provider.create_instance().unwrap(); + let resp = inst.get(&status_url, self.headers.clone())?; + match resp.is_success() { + true => Ok(()), + false => Err(format!("Server returned an error: {}", resp.status_code)), + } } /// Query the logged in user. @@ -78,8 +62,9 @@ impl NetworkClient { /// NOTE: **THIS IS BLOCKING** /// /// Route: `api/v1/users/me` (TODO: Comment about the query) - pub fn current_user(&self) -> reqwest::Result<(i32, String)> { + pub fn current_user(&self) -> Result<(i32, String), String> { let current_user_url = format!("{}/api/v1/users/me", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); #[derive(Deserialize)] struct CurrentUser { @@ -87,12 +72,14 @@ impl NetworkClient { id: i32, } - let resp = self - .client - .get(¤t_user_url) - .send()? - .error_for_status()?; - let user: CurrentUser = resp.json()?; + let resp = inst.get(¤t_user_url, self.headers.clone())?; + if !resp.is_success() { + return Err(format!( + "'{}' returned {}", + current_user_url, resp.status_code + )); + } + let user: CurrentUser = resp.json().map_err(|e| e.to_string())?; Ok((user.id, user.username)) } @@ -101,16 +88,20 @@ impl NetworkClient { /// NOTE: **THIS IS BLOCKING** /// /// Route: `api/v1/users/me` (TODO: Comment about the query) - pub fn source_name(&self, id: SourceId) -> reqwest::Result<String> { + pub fn source_name(&self, id: SourceId) -> Result<String, String> { let source_url = format!("{}/api/v1/sources/{}", self.server_url, id); + let mut inst = self.provider.create_instance().unwrap(); #[derive(Deserialize)] struct Source { name: String, } - let resp = self.client.get(&source_url).send()?.error_for_status()?; - let src: Source = resp.json()?; + let resp = inst.get(&source_url, self.headers.clone())?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", source_url, resp.status_code)); + } + let src: Source = resp.json().map_err(|e| e.to_string())?; Ok(src.name) } @@ -123,8 +114,9 @@ impl NetworkClient { /// NOTE: **THIS IS BLOCKING** /// /// Route: `api/v1/sources/` - pub fn create_source(&self, name: &str) -> reqwest::Result<SourceId> { + pub fn create_source(&self, name: &str) -> Result<SourceId, String> { let source_url = format!("{}/api/v1/sources", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); let body = json!({ "name": name, @@ -137,14 +129,11 @@ impl NetworkClient { id: Uuid, } - let resp = self - .client - .post(&source_url) - .json(&body) - .send()? - .error_for_status()?; - - let parsed: CreateSourceResponse = resp.json()?; + let resp = inst.post_json(&source_url, self.headers.clone(), &body)?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", source_url, resp.status_code)); + } + let parsed: CreateSourceResponse = resp.json().map_err(|e| e.to_string())?; Ok(SourceId(parsed.id)) } @@ -153,8 +142,9 @@ impl NetworkClient { /// NOTE: **THIS IS BLOCKING** /// /// Route: `api/v1/sources/query` (TODO: Comment about the query) - pub fn query_sources(&self, user_id: Option<i32>) -> reqwest::Result<Vec<SourceId>> { + pub fn query_sources(&self, user_id: Option<i32>) -> Result<Vec<SourceId>, String> { let sources_url = format!("{}/api/v1/sources/query", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); #[derive(Deserialize)] struct SourceItem { @@ -170,16 +160,12 @@ impl NetworkClient { if let Some(user_id) = user_id { query.insert("user_id", user_id); } - let query_str = json!(query).to_string(); - let resp = self - .client - .post(&sources_url) - .body(query_str) - .header("Content-Type", "application/json") - .send()? - .error_for_status()?; - let parsed: SourcesQueryResponse = resp.json()?; + let resp = inst.post_json(&sources_url, self.headers.clone(), &json!(query))?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", sources_url, resp.status_code)); + } + let parsed: SourcesQueryResponse = resp.json().map_err(|e| e.to_string())?; Ok(parsed.items.into_iter().map(|it| SourceId(it.id)).collect()) } @@ -190,6 +176,12 @@ impl NetworkClient { /// Route: `api/v1/targets/query` (TODO: Comment about the query) pub fn query_target_id(&self, target: &Target) -> Option<NetworkTargetId> { let query_target_url = format!("{}/api/v1/targets/query", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); + + #[derive(Deserialize)] + struct TargetQueryResponse { + id: NetworkTargetId, + } let mut query = HashMap::new(); if let Some(platform) = &target.platform { @@ -198,25 +190,13 @@ impl NetworkClient { if let Some(architecture) = &target.architecture { query.insert("arch", architecture); } - let query_str = json!(query).to_string(); - - #[derive(Deserialize)] - struct TargetQueryResponse { - id: NetworkTargetId, - } - // NOTE: This is blocking. - let response = self - .client - .post(query_target_url) - .body(query_str) - .header("Content-Type", "application/json") - .send() + let resp = inst + .post_json(&query_target_url, self.headers.clone(), &json!(query)) .ok()?; - // Assuming the first response is the one we want. // TODO: Handle multiple responses, or error out. - let json_response: Vec<TargetQueryResponse> = response.json().ok()?; + let json_response: Vec<TargetQueryResponse> = resp.json().ok()?; let first_response = json_response.first()?; Some(first_response.id) @@ -257,27 +237,22 @@ impl NetworkClient { target: Option<NetworkTargetId>, source: Option<SourceId>, guids: &[FunctionGUID], - ) -> Option<WarpFile<'static>> { + ) -> Result<WarpFile<'static>, String> { let query_functions_url = format!("{}/api/v1/functions/query", self.server_url); // TODO: Allow for source tags? We really only need this in query_functions_source as that // TODO: is what prevents a undesired source from being "known" to the container. let payload = Self::query_functions_body(target, source, &[], guids); + let mut inst = self.provider.create_instance().unwrap(); - // Make the POST request - let response = self - .client - .post(&query_functions_url) - .json(&payload) - .send() - .ok()?; - if !response.status().is_success() { - log::error!("Failed to query functions: {}", response.status()); - return None; + let resp = inst.post_json(&query_functions_url, self.headers.clone(), &payload)?; + if !resp.is_success() { + return Err(format!( + "'{}' returned {}", + query_functions_url, resp.status_code + )); } - // Get response bytes and convert to WarpFile - let bytes = response.bytes().ok()?; - WarpFile::from_owned_bytes(bytes.to_vec()) + WarpFile::from_owned_bytes(resp.data).ok_or("Failed to parse WARP data".to_string()) } /// Query the functions, returning the sources and the corresponding function guids. @@ -290,25 +265,21 @@ impl NetworkClient { target: Option<NetworkTargetId>, tags: &[SourceTag], guids: &[FunctionGUID], - ) -> Option<HashMap<SourceId, Vec<FunctionGUID>>> { + ) -> Result<HashMap<SourceId, Vec<FunctionGUID>>, String> { let query_functions_source_url = format!("{}/api/v1/functions/query/source", self.server_url); let payload = Self::query_functions_body(target, None, tags, guids); + let mut inst = self.provider.create_instance().unwrap(); - // Make the POST request - let response = self - .client - .post(&query_functions_source_url) - .json(&payload) - .send() - .ok()?; - if !response.status().is_success() { - log::error!("Failed to query functions source: {}", response.status()); - return None; + let resp = inst.post_json(&query_functions_source_url, self.headers.clone(), &payload)?; + if !resp.is_success() { + return Err(format!( + "'{}' returned {}", + query_functions_source_url, resp.status_code + )); } - // Mapping of source id to function guids - let json_response: HashMap<String, Vec<String>> = response.json().ok()?; + let json_response: HashMap<String, Vec<String>> = resp.json().map_err(|e| e.to_string())?; let mapped_function_guids = json_response .into_iter() .filter_map(|(source_str, guid_strs)| { @@ -321,85 +292,79 @@ impl NetworkClient { }) .collect(); - Some(mapped_function_guids) + Ok(mapped_function_guids) } - /// Pushes the file to the remote source. + /// Pushes the file to the remote source, returning the commit id. /// /// NOTE: **THIS IS BLOCKING** /// - /// Route: `api/v1/files/{source}` - pub fn push_file(&self, source_id: SourceId, file: &WarpFile, name: &str) -> bool { - let push_file_url = format!("{}/api/v1/files", self.server_url); - - // Convert WarpFile to bytes - let file_bytes = file.to_bytes(); + /// Route: `api/v1/files/json` + pub fn push_file( + &self, + source_id: SourceId, + file: &WarpFile, + name: &str, + ) -> Result<i32, String> { + let push_file_url = format!("{}/api/v1/files/json", self.server_url); + // Convert WarpFile to base64 encoded bytes + let file_bytes_base64 = base64::engine::general_purpose::STANDARD.encode(&file.to_bytes()); + let mut inst = self.provider.create_instance().unwrap(); - let Ok(file_part) = reqwest::blocking::multipart::Part::bytes(file_bytes) - .file_name("data.warp") - .mime_str("application/octet-stream") - else { - log::error!("Failed to create file part"); - return false; - }; + #[derive(Deserialize)] + struct UploadResponse { + commit_id: i32, + } - let form = reqwest::blocking::multipart::Form::new() - .part("file", file_part) - .text("name", name.to_string()) - .text("source", source_id.to_string()); + let body = json!({ + "file": file_bytes_base64, + "name": name, + "source": source_id.to_string(), + "description": serde_json::Value::Null, + }); - // Send the request - match self.client.post(&push_file_url).multipart(form).send() { - Ok(response) => { - if response.status().is_success() { - true - } else { - log::error!("Failed to push file: {}", response.status()); - false - } - } - Err(e) => { - log::error!("Failed to send push request: {}", e); - false - } + let resp = inst.post_json(&push_file_url, self.headers.clone(), &body)?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", push_file_url, resp.status_code)); } + let out: UploadResponse = resp.json().map_err(|e| e.to_string())?; + Ok(out.commit_id) } - pub fn function_data(&self, id: i32) -> Option<Function> { + pub fn function_data(&self, id: i32) -> Result<Function, String> { let function_data_url = format!("{}/api/v1/functions/{}/data", self.server_url, id); - let response = self.client.get(&function_data_url).send().ok()?; - if !response.status().is_success() { - log::error!( - "Failed to fetch function data for {}: {}", - id, - response.status() - ); - return None; + let mut inst = self.provider.create_instance().unwrap(); + + let resp = inst.get(&function_data_url, self.headers.clone())?; + if !resp.is_success() { + return Err(format!( + "'{}' returned {}", + function_data_url, resp.status_code + )); } - let bytes = response.bytes().ok()?; - Function::from_bytes(bytes.as_ref()) + Function::from_bytes(&resp.data) + .ok_or_else(|| format!("Failed to parse function data for function {}", id,)) } - pub fn function_datas(&self, ids: &[i32]) -> Option<Vec<Function>> { + pub fn function_datas(&self, ids: &[i32]) -> Result<Vec<Function>, String> { if ids.is_empty() { - return Some(Vec::new()); + return Ok(Vec::new()); } let function_data_url = format!("{}/api/v1/functions/data", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); + let body = json!({ "ids": ids, }); - let response = self - .client - .post(&function_data_url) - .json(&body) - .send() - .ok()?; - if !response.status().is_success() { - log::error!("Failed to fetch function data: {}", response.status()); - return None; + let resp = inst.post_json(&function_data_url, self.headers.clone(), &body)?; + if !resp.is_success() { + return Err(format!( + "'{}' returned {}", + function_data_url, resp.status_code + )); } - let bytes = response.bytes().ok()?; - let file = WarpFile::from_bytes(bytes.as_ref())?; + let file = WarpFile::from_bytes(&resp.data) + .ok_or_else(|| format!("Failed to parse function data for functions {:?}", ids))?; let mut functions = Vec::with_capacity(ids.len()); for chunk in file.chunks { let ChunkKind::Signature(sc) = chunk.kind else { @@ -407,39 +372,37 @@ impl NetworkClient { }; functions.extend(sc.functions()); } - Some(functions) + Ok(functions) } - pub fn type_data(&self, guid: TypeGUID) -> Option<Type> { + pub fn type_data(&self, guid: TypeGUID) -> Result<Type, String> { let type_data_url = format!("{}/api/v1/types/{}/data", self.server_url, guid.to_string()); - let response = self.client.get(&type_data_url).send().ok()?; - if !response.status().is_success() { - log::error!( - "Failed to fetch type data for {}: {}", - guid.to_string(), - response.status() - ); - return None; + let mut inst = self.provider.create_instance().unwrap(); + + let resp = inst.get(&type_data_url, self.headers.clone())?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", type_data_url, resp.status_code)); } - let bytes = response.bytes().ok()?; - Type::from_bytes(bytes.as_ref()) + Type::from_bytes(&resp.data) + .ok_or_else(|| format!("Failed to parse type data for type {}", guid)) } - pub fn type_datas(&self, guids: &[TypeGUID]) -> Option<Vec<ComputedType>> { + pub fn type_datas(&self, guids: &[TypeGUID]) -> Result<Vec<ComputedType>, String> { if guids.is_empty() { - return Some(Vec::new()); + return Ok(Vec::new()); } let type_data_url = format!("{}/api/v1/types/data", self.server_url); + let mut inst = self.provider.create_instance().unwrap(); + let body = json!({ "ids": guids.iter().map(|g| g.to_string()).collect::<Vec<_>>(), }); - let response = self.client.post(&type_data_url).json(&body).send().ok()?; - if !response.status().is_success() { - log::error!("Failed to fetch type data: {}", response.status()); - return None; + let resp = inst.post_json(&type_data_url, self.headers.clone(), &body)?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", type_data_url, resp.status_code)); } - let bytes = response.bytes().ok()?; - let file = WarpFile::from_bytes(bytes.as_ref())?; + let file = WarpFile::from_bytes(&resp.data) + .ok_or_else(|| format!("Failed to parse type data for types {:?}", guids))?; let mut types = Vec::with_capacity(guids.len()); for chunk in file.chunks { let ChunkKind::Type(tc) = chunk.kind else { @@ -447,12 +410,10 @@ impl NetworkClient { }; types.extend(tc.types()); } - Some(types) + Ok(types) } - pub fn search(&self, query: &ContainerSearchQuery) -> Option<ContainerSearchResponse> { - let search_url = format!("{}/api/v1/search", self.server_url); - + pub fn search(&self, query: &ContainerSearchQuery) -> Result<ContainerSearchResponse, String> { #[derive(serde::Serialize)] struct SearchRequest<'a> { #[serde(rename = "q")] @@ -468,6 +429,26 @@ impl NetworkClient { #[serde(skip_serializing_if = "Option::is_none")] retrieve_data: Option<bool>, } + let source_id_str = query.source.map(|s| s.to_string()); + let request = SearchRequest { + q: &query.query, + limit: query.limit, + offset: query.offset, + source_id: source_id_str, + source_tags: match query.tags.is_empty() { + true => None, + false => Some(query.tags.clone()), + }, + // This must be passed to retrieve the function and type data. + retrieve_data: Some(true), + }; + let request_qs = serde_qs::to_string(&request).map_err(|e| e.to_string())?; + let search_url = match request_qs.is_empty() { + true => format!("{}/api/v1/search", self.server_url), + false => format!("{}/api/v1/search?{}", self.server_url, request_qs), + }; + + let mut inst = self.provider.create_instance().unwrap(); #[derive(serde::Deserialize)] struct SearchResponse { @@ -488,32 +469,11 @@ impl NetworkClient { data: Option<Vec<u8>>, } - let source_id_str = query.source.map(|s| s.to_string()); - let request = SearchRequest { - q: &query.query, - limit: query.limit, - offset: query.offset, - source_id: source_id_str, - source_tags: match query.tags.is_empty() { - true => None, - false => Some(query.tags.clone()), - }, - // This must be passed to retrieve the function and type data. - retrieve_data: Some(true), - }; - - let resp = match self.client.get(search_url).query(&request).send() { - Ok(r) => r, - Err(err) => { - log::error!("Failed to send search request: {}", err); - return None; - } - }; - - let Ok(parsed) = resp.json::<SearchResponse>() else { - log::error!("Failed to parse search response"); - return None; - }; + let resp = inst.get(&search_url, self.headers.clone())?; + if !resp.is_success() { + return Err(format!("'{}' returned {}", search_url, resp.status_code)); + } + let parsed: SearchResponse = resp.json().map_err(|e| e.to_string())?; // TODO: This is quite scuffed, but it works for now. (Mostly just that it looks bad and queries a lot) // TODO: Here I think would be a good place to sort it so sources always come first. @@ -580,7 +540,7 @@ impl NetworkClient { }); } - Some(ContainerSearchResponse { + Ok(ContainerSearchResponse { items, total: parsed.total, offset: parsed.offset, diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs index c396ebca..16462f00 100644 --- a/plugins/warp/src/plugin.rs +++ b/plugins/warp/src/plugin.rs @@ -16,7 +16,6 @@ use binaryninja::is_ui_enabled; use binaryninja::logger::Logger; use binaryninja::settings::{QueryOptions, Settings}; use log::LevelFilter; -use reqwest::StatusCode; mod commit; mod create; @@ -58,64 +57,49 @@ fn load_network_container() { let global_bn_settings = Settings::new(); let add_network_container = |url: String, api_key: Option<String>| { - let https_proxy_str = global_bn_settings.get_string("network.httpsProxy"); - let https_proxy = if https_proxy_str.is_empty() { - None - } else { - Some(https_proxy_str) - }; - match NetworkClient::new(url.clone(), api_key.clone(), https_proxy) { - Ok(network_client) => { - // Before constructing the container, let's make sure that the server is OK. - if let Ok(StatusCode::OK) = network_client.status() { - // Check if the user is logged in. If so, we should collect the writable sources. - let mut writable_sources = Vec::new(); - match network_client.current_user() { - Ok((id, username)) => { - log::info!( - "Server '{}' connected, logged in as user '{}'", - url, - username - ); - match network_client.query_sources(Some(id)) { - Ok(sources) => { - writable_sources = sources; - } - Err(e) => { - log::error!( - "Server '{}' failed to get sources for user: {}", - url, - e - ); - } - } - } - Err(e) if api_key.is_some() => { - log::error!( - "Server '{}' failed to authenticate with provided API key: {}", - url, - e - ); - } - Err(_) => { - log::info!("Server '{}' connected, logged in as guest", url); - } - } + let network_client = NetworkClient::new(url.clone(), api_key.clone()); + // Before constructing the container, let's make sure that the server is OK. + if let Err(e) = network_client.status() { + log::error!("Server '{}' failed to connect: {}", url, e); + return; + } - // TODO: Make the cache path include the domain or url, so that we can have multiple servers. - let main_cache_path = NetworkContainer::root_cache_location().join("main"); - let network_container = - NetworkContainer::new(network_client, main_cache_path, &writable_sources); - log::debug!("{:#?}", network_container); - add_cached_container(network_container); - } else { - log::error!("Server '{}' is not reachable, disabling container...", url); + // Check if the user is logged in. If so, we should collect the writable sources. + let mut writable_sources = Vec::new(); + match network_client.current_user() { + Ok((id, username)) => { + log::info!( + "Server '{}' connected, logged in as user '{}'", + url, + username + ); + match network_client.query_sources(Some(id)) { + Ok(sources) => { + writable_sources = sources; + } + Err(e) => { + log::error!("Server '{}' failed to get sources for user: {}", url, e); + } } } - Err(e) => { - log::error!("Failed to add networked container: {}", e); + Err(e) if api_key.is_some() => { + log::error!( + "Server '{}' failed to authenticate with provided API key: {}", + url, + e + ); + } + Err(_) => { + log::info!("Server '{}' connected, logged in as guest", url); } } + + // TODO: Make the cache path include the domain or url, so that we can have multiple servers. + let main_cache_path = NetworkContainer::root_cache_location().join("main"); + let network_container = + NetworkContainer::new(network_client, main_cache_path, &writable_sources); + log::debug!("{:#?}", network_container); + add_cached_container(network_container); }; let plugin_settings = |
