summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock932
-rw-r--r--plugins/warp/Cargo.toml3
-rw-r--r--plugins/warp/src/container.rs4
-rw-r--r--plugins/warp/src/container/network.rs110
-rw-r--r--plugins/warp/src/container/network/client.rs386
-rw-r--r--plugins/warp/src/plugin.rs92
6 files changed, 286 insertions, 1241 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6ed30022..2290dd5d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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(&current_user_url)
- .send()?
- .error_for_status()?;
- let user: CurrentUser = resp.json()?;
+ let resp = inst.get(&current_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 =