diff options
| -rw-r--r-- | Cargo.lock | 962 | ||||
| -rw-r--r-- | plugins/warp/Cargo.toml | 1 | ||||
| -rw-r--r-- | plugins/warp/api/python/_warpcore.py | 23 | ||||
| -rw-r--r-- | plugins/warp/api/python/warp.py | 7 | ||||
| -rw-r--r-- | plugins/warp/api/warp.cpp | 10 | ||||
| -rw-r--r-- | plugins/warp/api/warp.h | 2 | ||||
| -rw-r--r-- | plugins/warp/api/warpcore.h | 2 | ||||
| -rw-r--r-- | plugins/warp/src/container.rs | 13 | ||||
| -rw-r--r-- | plugins/warp/src/container/network.rs | 332 | ||||
| -rw-r--r-- | plugins/warp/src/container/network/client.rs | 228 | ||||
| -rw-r--r-- | plugins/warp/src/plugin.rs | 89 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/ffi/container.rs | 21 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/settings.rs | 28 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/workflow.rs | 17 | ||||
| -rw-r--r-- | plugins/warp/ui/matches.cpp | 71 | ||||
| -rw-r--r-- | plugins/warp/ui/matches.h | 9 | ||||
| -rw-r--r-- | plugins/warp/ui/plugin.cpp | 3 |
17 files changed, 1770 insertions, 48 deletions
@@ -150,6 +150,12 @@ 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" @@ -171,6 +177,12 @@ dependencies = [ ] [[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] name = "binaryninja" version = "0.1.0" dependencies = [ @@ -286,6 +298,12 @@ 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" @@ -423,6 +441,22 @@ 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" @@ -594,6 +628,17 @@ 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 = [ @@ -737,6 +782,30 @@ 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" @@ -849,6 +918,17 @@ dependencies = [ [[package]] name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" @@ -856,7 +936,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -877,6 +957,25 @@ 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" @@ -914,6 +1013,210 @@ 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.10" source = "git+https://github.com/Vector35/idb-rs?tag=0.1.10#f5e97df2a7949793d6d7319b95ee9aae2b3792c6" @@ -946,6 +1249,27 @@ 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" @@ -981,6 +1305,33 @@ 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" @@ -1031,7 +1382,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom", + "getrandom 0.3.3", "libc", ] @@ -1080,6 +1431,12 @@ 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" @@ -1111,6 +1468,22 @@ 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" @@ -1187,12 +1560,40 @@ 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" @@ -1365,6 +1766,50 @@ 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 = "parking_lot" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1489,6 +1934,15 @@ 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" @@ -1667,6 +2121,63 @@ 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 = [ @@ -1757,6 +2268,39 @@ 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" @@ -1798,6 +2342,15 @@ 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" @@ -1836,6 +2389,29 @@ 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" @@ -1874,6 +2450,18 @@ dependencies = [ ] [[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] name = "serial_test" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1946,6 +2534,16 @@ 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" @@ -1964,6 +2562,12 @@ 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" @@ -2022,6 +2626,47 @@ 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" @@ -2038,7 +2683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom", + "getrandom 0.3.3", "once_cell", "rustix 1.0.7", "windows-sys 0.59.0", @@ -2127,6 +2772,16 @@ 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" @@ -2137,6 +2792,56 @@ 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" @@ -2154,6 +2859,51 @@ 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" @@ -2186,6 +2936,12 @@ 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" @@ -2196,12 +2952,41 @@ 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" @@ -2213,13 +2998,19 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom", + "getrandom 0.3.3", "js-sys", "sha1_smol", "wasm-bindgen", ] [[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" @@ -2236,6 +3027,15 @@ 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" @@ -2264,6 +3064,7 @@ dependencies = [ "minijinja-embed", "rayon", "regex", + "reqwest", "serde", "serde_json", "tempdir", @@ -2275,6 +3076,12 @@ dependencies = [ [[package]] name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" @@ -2309,6 +3116,19 @@ 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" @@ -2388,6 +3208,50 @@ 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" @@ -2609,6 +3473,12 @@ 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" @@ -2626,6 +3496,30 @@ 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" @@ -2646,6 +3540,66 @@ 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 afebf577..761ac961 100644 --- a/plugins/warp/Cargo.toml +++ b/plugins/warp/Cargo.toml @@ -24,6 +24,7 @@ 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"] } # For reports minijinja = "2.10.2" diff --git a/plugins/warp/api/python/_warpcore.py b/plugins/warp/api/python/_warpcore.py index 740072ab..da262f18 100644 --- a/plugins/warp/api/python/_warpcore.py +++ b/plugins/warp/api/python/_warpcore.py @@ -205,6 +205,29 @@ def BNWARPContainerCommitSource( # ------------------------------------------------------- +# _BNWARPContainerFetchFunctions + +_BNWARPContainerFetchFunctions = core.BNWARPContainerFetchFunctions +_BNWARPContainerFetchFunctions.restype = None +_BNWARPContainerFetchFunctions.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTarget), + ctypes.POINTER(BNWARPTypeGUID), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPContainerFetchFunctions( + container: ctypes.POINTER(BNWARPContainer), + target: ctypes.POINTER(BNWARPTarget), + guids: ctypes.POINTER(BNWARPTypeGUID), + count: int + ) -> None: + return _BNWARPContainerFetchFunctions(container, target, guids, count) + + +# ------------------------------------------------------- # _BNWARPContainerGetFunctionsWithGUID _BNWARPContainerGetFunctionsWithGUID = core.BNWARPContainerGetFunctionsWithGUID diff --git a/plugins/warp/api/python/warp.py b/plugins/warp/api/python/warp.py index c761c323..c7486b8c 100644 --- a/plugins/warp/api/python/warp.py +++ b/plugins/warp/api/python/warp.py @@ -305,6 +305,13 @@ class WarpContainer(metaclass=_WarpContainerMetaclass): core_guids[i] = guids[i].uuid return warpcore.BNWARPContainerRemoveTypes(self.handle, source.uuid, core_guids, count) + def fetch_functions(self, target: WarpTarget, guids: List[FunctionGUID]): + count = len(guids) + core_guids = (warpcore.BNWARPFunctionGUID * count)() + for i in range(count): + core_guids[i] = guids[i].uuid + warpcore.BNWARPContainerFetchFunctions(self.handle, target.handle, core_guids, count) + def get_sources_with_function_guid(self, target: WarpTarget, guid: FunctionGUID) -> List[Source]: count = ctypes.c_size_t() sources = warpcore.BNWARPContainerGetSourcesWithFunctionGUID(self.handle, target.handle, guid.uuid, count) diff --git a/plugins/warp/api/warp.cpp b/plugins/warp/api/warp.cpp index 147add8e..52c7ea9d 100644 --- a/plugins/warp/api/warp.cpp +++ b/plugins/warp/api/warp.cpp @@ -249,6 +249,16 @@ bool Container::RemoveTypes(const Source &source, const std::vector<TypeGUID> &g return result; } +void Container::FetchFunctions(const Target &target, const std::vector<FunctionGUID> &guids) const +{ + size_t count = guids.size(); + BNWARPFunctionGUID *apiGuids = new BNWARPFunctionGUID[count]; + for (size_t i = 0; i < count; i++) + apiGuids[i] = *guids[i].Raw(); + BNWARPContainerFetchFunctions(m_object, target.m_object, apiGuids, count); + delete[] apiGuids; +} + std::vector<Source> Container::GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const { size_t count; diff --git a/plugins/warp/api/warp.h b/plugins/warp/api/warp.h index b57a0c7b..807ba998 100644 --- a/plugins/warp/api/warp.h +++ b/plugins/warp/api/warp.h @@ -354,6 +354,8 @@ namespace Warp { bool RemoveTypes(const Source &source, const std::vector<TypeGUID> &guids) const; + void FetchFunctions(const Target& target, const std::vector<FunctionGUID> &guids) const; + std::vector<Source> GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const; std::vector<Source> GetSourcesWithTypeGUID(const TypeGUID &guid) const; diff --git a/plugins/warp/api/warpcore.h b/plugins/warp/api/warpcore.h index 09190126..20a59b7b 100644 --- a/plugins/warp/api/warpcore.h +++ b/plugins/warp/api/warpcore.h @@ -108,6 +108,8 @@ extern "C" WARP_FFI_API bool BNWARPContainerRemoveFunctions(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPSource* source, BNWARPFunction** functions, size_t count); WARP_FFI_API bool BNWARPContainerRemoveTypes(BNWARPContainer* container, const BNWARPSource* source, BNWARPTypeGUID* types, size_t count); + WARP_FFI_API void BNWARPContainerFetchFunctions(BNWARPContainer* container, BNWARPTarget* target, const BNWARPTypeGUID* guids, size_t count); + WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithFunctionGUID(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPFunctionGUID* guid, size_t* count); WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithTypeGUID(BNWARPContainer* container, const BNWARPTypeGUID* guid, size_t* count); WARP_FFI_API BNWARPFunction** BNWARPContainerGetFunctionsWithGUID(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPSource* source, const BNWARPFunctionGUID* guid, size_t* count); diff --git a/plugins/warp/src/container.rs b/plugins/warp/src/container.rs index 8d720021..4cabc60e 100644 --- a/plugins/warp/src/container.rs +++ b/plugins/warp/src/container.rs @@ -208,6 +208,19 @@ pub trait Container: Send + Sync + Display + Debug { functions: &[Function], ) -> ContainerResult<()>; + /// Fetches WARP information for the associated functions. + /// + /// Typically, a container that resides only in memory has nothing to fetch, so the default implementation + /// will do nothing. This function is blocking, so assume it will take a few seconds for a container + /// that intends to fetch over the network. + fn fetch_functions( + &mut self, + _target: &Target, + _functions: &[FunctionGUID], + ) -> ContainerResult<()> { + Ok(()) + } + /// Get the sources that contain a type with the given [`TypeGUID`]. fn sources_with_type_guid(&self, guid: &TypeGUID) -> ContainerResult<Vec<SourceId>>; diff --git a/plugins/warp/src/container/network.rs b/plugins/warp/src/container/network.rs index ffbe6108..2a2d7c65 100644 --- a/plugins/warp/src/container/network.rs +++ b/plugins/warp/src/container/network.rs @@ -1,13 +1,323 @@ -pub struct NetworkContainer {} +use crate::container::disk::DiskContainer; +use crate::container::{Container, ContainerError, ContainerResult, SourceId, SourcePath}; +use std::collections::HashMap; +use std::fmt::{Debug, Display, Formatter}; +use warp::chunk::{Chunk, ChunkKind, CompressionType}; +use warp::r#type::guid::TypeGUID; +use warp::r#type::{ComputedType, Type}; +use warp::signature::chunk::SignatureChunk; +use warp::signature::function::{Function, FunctionGUID}; +use warp::target::Target; +use warp::{WarpFile, WarpFileHeader}; -// TODO: The container is populated as the user is navigating a binary -// TODO: We need to have a few helper functions here to post and pull -// TODO: Then in the interface we operate off the network cache -// TODO: The network cache could just be a disk container? Or disk container sources? -// TODO: We should also store the cache on the filesystem for a certain time, will need to timestamp -// TODO: When we commit we need to actually POST i believe. -// TODO: There needs to be a setting that adjusts the sweep size of functions at the cursor. -// TODO: Probably need a callback or something to tell the network containers to refresh from the network. -// TODO: The network container should never instantiate itself, unless its gurenteed to not have any data in it? +pub mod client; -// TODO: Need to PUSH chunks and PULL chunks +pub use client::NetworkClient; + +/// This is the id on the server for the [`Target`], we can get it via [`NetworkClient::query_target_id`]. +pub type NetworkTargetId = i32; + +pub struct NetworkContainer { + client: NetworkClient, + /// This is the store that the interface will write to; then we have special functions for pulling + /// and pushing to the network source. + cache: DiskContainer, + /// Populated when targets are queried. + known_targets: HashMap<Target, Option<NetworkTargetId>>, + /// Populated with function sources are queried. + known_function_sources: HashMap<FunctionGUID, Vec<SourceId>>, + /// Populated when user adds function, this is used for writing back to the server. + added_chunks: HashMap<SourceId, Vec<Chunk<'static>>>, +} + +impl NetworkContainer { + pub fn new(client: NetworkClient) -> Self { + Self { + cache: DiskContainer::new("Network Container".to_string(), HashMap::new()), + client, + known_targets: HashMap::new(), + known_function_sources: HashMap::new(), + added_chunks: HashMap::new(), + } + } + + /// Gets the network id for the `target`, this will be used in later function queries. + /// + /// **This is blocking** + /// + /// # Caching policy + /// + /// The [`NetworkTargetId`] is unique and immutable, so they will be persisted indefinitely. + pub fn get_target_id(&mut self, target: &Target) -> Option<NetworkTargetId> { + // It's highly probable we have previously queried the target, check that first. + if let Some(target_id) = self.known_targets.get(target) { + return target_id.clone(); + } + + let target_id = self.client.query_target_id(target); + // Keep the target id so the next lookup is free. + self.known_targets.insert(target.clone(), target_id); + target_id + } + + /// Pulls sources for the set of unseen function guids. + /// + /// **This is blocking** + /// + /// # Caching policy + /// + /// When we get the source, we store the results indefinitely in the container; this is fine + /// for now as the requests for functions come at the request of some user interaction. Any guid + /// with no sources will still be cached. + pub fn get_unseen_functions_source( + &mut self, + target: Option<&Target>, + guids: &[FunctionGUID], + ) -> HashMap<SourceId, Vec<FunctionGUID>> { + let Some(target_id) = target.and_then(|t| self.get_target_id(t)) else { + log::debug!("Cannot query functions source without a target, skipping..."); + return HashMap::new(); + }; + + // Split guids into known and unknown + let (_known, unknown): (Vec<_>, Vec<_>) = guids + .into_iter() + .cloned() + .partition(|guid| self.known_function_sources.contains_key(guid)); + + 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 + .query_functions_source(Some(target_id), &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)) + .cloned() + .collect(); + self.known_function_sources.insert(*guid, sources); + } + + for (source_id, guids) in queried_results { + result.entry(source_id).or_default().extend(guids); + } + } + } + + result + } + + /// Pulls function metadata from the server and adds it into the container cache. + /// + /// **This is blocking** + /// + /// # Caching policy + /// + /// Every request we store the returned objects on disk, this means that users will first + /// query against the disk objects, then the server. This also means we need to cache functions f + /// or which we have not received any functions for, as otherwise we would keep trying to query it. + pub fn pull_functions( + &mut self, + target: &Target, + source: &SourceId, + functions: &[FunctionGUID], + ) { + let target_id = self.get_target_id(target); + if let Some(file) = 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(); + 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(_) => {} + } + } + } + } + + /// Push a file to the network source. + /// + /// **This is blocking** + pub fn push_file(&mut self, source_id: SourceId, file: &WarpFile) { + self.client.push_file(source_id, file); + } +} + +impl Container for NetworkContainer { + fn sources(&self) -> ContainerResult<Vec<SourceId>> { + self.cache.sources() + } + + fn add_source(&mut self, path: SourcePath) -> ContainerResult<SourceId> { + // TODO: How do we want to let users create new sources? + log::error!("NetworkContainer::add_source not allowed"); + Err(ContainerError::CannotCreateSource(path)) + } + + fn commit_source(&mut self, source: &SourceId) -> ContainerResult<bool> { + let chunks = self + .added_chunks + .remove(source) + .ok_or(ContainerError::SourceNotFound(source.clone()))?; + let file = WarpFile::new(WarpFileHeader::new(), chunks); + self.push_file(*source, &file); + Ok(true) + } + + fn is_source_writable(&self, source: &SourceId) -> ContainerResult<bool> { + // TODO: This is retrievable from /users/me/sources we will grab it when connecting. + log::error!("NetworkContainer::is_source_writable not allowed"); + Err(ContainerError::SourceNotWritable(source.clone())) + } + + fn is_source_uncommitted(&self, source: &SourceId) -> ContainerResult<bool> { + Ok(self.added_chunks.contains_key(source)) + } + + fn source_path(&self, source: &SourceId) -> ContainerResult<SourcePath> { + self.cache.source_path(source) + } + + fn add_computed_types( + &mut self, + source: &SourceId, + types: &[ComputedType], + ) -> ContainerResult<()> { + self.cache.add_computed_types(source, types) + } + + fn remove_types(&mut self, source: &SourceId, guids: &[TypeGUID]) -> ContainerResult<()> { + self.cache.remove_types(source, guids) + } + + fn add_functions( + &mut self, + target: &Target, + source: &SourceId, + functions: &[Function], + ) -> ContainerResult<()> { + let signature_chunk = SignatureChunk::new(functions).ok_or( + ContainerError::CorruptedData("signature chunk failed to validate"), + )?; + let chunk = Chunk::new_with_target( + ChunkKind::Signature(signature_chunk), + CompressionType::None, + target.clone(), + ); + self.added_chunks.entry(*source).or_default().push(chunk); + Ok(()) + } + + fn remove_functions( + &mut self, + target: &Target, + source: &SourceId, + functions: &[Function], + ) -> ContainerResult<()> { + // TODO: Wont persist, need to add remote removal. + self.cache.remove_functions(target, source, functions) + } + + fn fetch_functions( + &mut self, + target: &Target, + functions: &[FunctionGUID], + ) -> ContainerResult<()> { + // NOTE: Blocking request to get the mapped function sources. + let mapped_unseen_functions = self.get_unseen_functions_source(Some(&target), functions); + + // Actually get the function data for the unseen guids, we really only want to do this once per + // session, anymore, and this is annoying! + for (source, unseen_guids) in mapped_unseen_functions { + // NOTE: Blocking request to get the function data in the container cache. + self.pull_functions(&target, &source, &unseen_guids); + } + + Ok(()) + } + + fn sources_with_type_guid(&self, guid: &TypeGUID) -> ContainerResult<Vec<SourceId>> { + self.cache.sources_with_type_guid(guid) + } + + fn sources_with_type_guids( + &self, + guids: &[TypeGUID], + ) -> ContainerResult<HashMap<TypeGUID, Vec<SourceId>>> { + self.cache.sources_with_type_guids(guids) + } + + fn type_guids_with_name( + &self, + source: &SourceId, + name: &str, + ) -> ContainerResult<Vec<TypeGUID>> { + self.cache.type_guids_with_name(source, name) + } + + fn type_with_guid(&self, source: &SourceId, guid: &TypeGUID) -> ContainerResult<Option<Type>> { + self.cache.type_with_guid(source, guid) + } + + fn sources_with_function_guid( + &self, + target: &Target, + guid: &FunctionGUID, + ) -> ContainerResult<Vec<SourceId>> { + self.cache.sources_with_function_guid(target, guid) + } + + fn sources_with_function_guids( + &self, + target: &Target, + guids: &[FunctionGUID], + ) -> ContainerResult<HashMap<FunctionGUID, Vec<SourceId>>> { + self.cache.sources_with_function_guids(target, guids) + } + + fn functions_with_guid( + &self, + target: &Target, + source: &SourceId, + guid: &FunctionGUID, + ) -> ContainerResult<Vec<Function>> { + self.cache.functions_with_guid(target, source, guid) + } +} + +impl Debug for NetworkContainer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NetworkContainer").finish() + } +} + +impl Display for NetworkContainer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NetworkContainer").finish() + } +} diff --git a/plugins/warp/src/container/network/client.rs b/plugins/warp/src/container/network/client.rs new file mode 100644 index 00000000..f77f1118 --- /dev/null +++ b/plugins/warp/src/container/network/client.rs @@ -0,0 +1,228 @@ +use crate::container::network::NetworkTargetId; +use crate::container::SourceId; +use reqwest::blocking::Client; +use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION}; +use reqwest::StatusCode; +use serde_json::json; +use std::collections::HashMap; +use std::str::FromStr; +use warp::signature::function::FunctionGUID; +use warp::target::Target; +use warp::WarpFile; + +/// Responsible for sending and receiving data from the server. +/// +/// NOTE: **All requests are blocking**. +#[derive(Clone, Debug)] +pub struct NetworkClient { + client: Client, + 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 + ); + // TODO: This might want to be kept for the request header? + let mut headers = HeaderMap::new(); + if let Some(token) = &server_token { + headers.insert( + AUTHORIZATION, + HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(), + ); + } + // 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()?, + server_url, + }) + } + + /// Check to see the status of the server. + /// + /// This is useful if you want to fail early and prevent constructing a network container to a + /// server that is unresponsive. + /// + /// Route: `api/v1/status` + pub fn status(&self) -> reqwest::Result<StatusCode> { + let status_url = format!("{}/api/v1/status", self.server_url); + let resp = self.client.get(&status_url).send()?; + Ok(resp.status()) + } + + /// Query the [`NetworkTargetId`] for the given [`Target`]. + /// + /// NOTE: **THIS IS BLOCKING** + /// + /// 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 query = HashMap::new(); + if let Some(platform) = &target.platform { + query.insert("platform", platform); + } + if let Some(architecture) = &target.architecture { + query.insert("architecture", architecture); + } + + // NOTE: This is blocking. + let target_id: NetworkTargetId = self + .client + .get(query_target_url) + .query(&query) + .send() + .ok()? + .json::<NetworkTargetId>() + .ok()?; + + Some(target_id) + } + + fn query_functions_body( + target: Option<NetworkTargetId>, + source: Option<SourceId>, + guids: &[FunctionGUID], + ) -> serde_json::Value { + let guids_str: Vec<String> = guids.iter().map(|g| g.to_string()).collect(); + // TODO: The limit here needs to be somewhat flexible. But 1000 will do for now. + let mut body = json!({ + "format": "flatbuffer", + "guids": guids_str, + "limit": 1000 + }); + if let Some(target_id) = target { + body["target_id"] = json!(target_id); + } + if let Some(source_id) = source { + body["source_id"] = json!(source_id.to_string()); + } + body + } + + /// Query the functions, returning the warp file response containing the entries. + /// + /// NOTE: **THIS IS BLOCKING** + /// + /// Route: `api/v1/functions/query` (TODO: Comment about the query) + pub fn query_functions( + &self, + target: Option<NetworkTargetId>, + source: Option<SourceId>, + guids: &[FunctionGUID], + ) -> Option<WarpFile<'static>> { + let query_functions_url = format!("{}/api/v1/functions/query", self.server_url); + let payload = Self::query_functions_body(target, source, guids); + + // 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; + } + + // Get response bytes and convert to WarpFile + let bytes = response.bytes().ok()?; + WarpFile::from_owned_bytes(bytes.to_vec()) + } + + /// Query the functions, returning the sources and the corresponding function guids. + /// + /// NOTE: **THIS IS BLOCKING** + /// + /// Route: `api/v1/functions/query/source` (TODO: Comment about the query) + pub fn query_functions_source( + &self, + target: Option<NetworkTargetId>, + guids: &[FunctionGUID], + ) -> Option<HashMap<SourceId, Vec<FunctionGUID>>> { + let query_functions_source_url = + format!("{}/api/v1/functions/query/source", self.server_url); + let payload = Self::query_functions_body(target, None, guids); + + // 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; + } + + // Mapping of source id to function guids + let json_response: HashMap<String, Vec<String>> = response.json().ok()?; + let mapped_function_guids = json_response + .into_iter() + .filter_map(|(source_str, guid_strs)| { + let source_id = SourceId::from_str(&source_str).ok()?; + let guids = guid_strs + .into_iter() + .filter_map(|guid_str| FunctionGUID::from_str(&guid_str).ok()) + .collect(); + Some((source_id, guids)) + }) + .collect(); + + Some(mapped_function_guids) + } + + /// Pushes the file to the remote source. + /// + /// NOTE: **THIS IS BLOCKING** + /// + /// Route: `api/v1/files/{source}` + pub fn push_file(&self, source_id: SourceId, file: &WarpFile) -> bool { + let push_file_url = format!("{}/api/v1/files/{}", self.server_url, source_id.to_string()); + + // Convert WarpFile to bytes + let file_bytes = file.to_bytes(); + + // Create the form part with the file + let form = reqwest::blocking::multipart::Form::new().part( + "file", + reqwest::blocking::multipart::Part::bytes(file_bytes) + .file_name("data.warp") + .mime_str("application/octet-stream") + .unwrap(), + ); + + // 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 + } + } + } +} diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs index 3380c619..7f0481b8 100644 --- a/plugins/warp/src/plugin.rs +++ b/plugins/warp/src/plugin.rs @@ -3,6 +3,7 @@ use std::time::Instant; use crate::cache::container::add_cached_container; use crate::container::disk::DiskContainer; +use crate::container::network::{NetworkClient, NetworkContainer}; use crate::matcher::MatcherSettings; use crate::plugin::render_layer::HighlightRenderLayer; use crate::plugin::settings::PluginSettings; @@ -11,9 +12,11 @@ use binaryninja::background_task::BackgroundTask; use binaryninja::command::{ register_command, register_command_for_function, register_command_for_project, }; +use binaryninja::is_ui_enabled; use binaryninja::logger::Logger; use binaryninja::settings::Settings; use log::LevelFilter; +use reqwest::StatusCode; mod create; mod debug; @@ -26,6 +29,63 @@ mod render_layer; mod settings; mod workflow; +fn load_bundled_signatures() { + let global_bn_settings = Settings::new(); + let plugin_settings = PluginSettings::from_settings(&global_bn_settings); + // We want to load all the bundled directories into the container cache. + let background_task = BackgroundTask::new("Loading WARP files...", false); + let start = Instant::now(); + if plugin_settings.load_bundled_files { + let core_disk_container = DiskContainer::new_from_dir(core_signature_dir()); + log::debug!("{:#?}", core_disk_container); + add_cached_container(core_disk_container); + } + if plugin_settings.load_user_files { + let user_disk_container = DiskContainer::new_from_dir(user_signature_dir()); + log::debug!("{:#?}", user_disk_container); + add_cached_container(user_disk_container); + } + log::info!("Loading bundled files took {:?}", start.elapsed()); + background_task.finish(); +} + +fn load_network_container() { + let global_bn_settings = Settings::new(); + let plugin_settings = PluginSettings::from_settings(&global_bn_settings); + let background_task = BackgroundTask::new("Initializing WARP server...", false); + let start = Instant::now(); + if plugin_settings.enable_server { + let server_url = plugin_settings.server_url.clone(); + let server_api_key = plugin_settings.server_api_key.clone(); + 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(server_url.clone(), server_api_key, 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() { + let network_container = NetworkContainer::new(network_client); + log::debug!("{:#?}", network_container); + add_cached_container(network_container); + } else { + log::error!( + "Server '{}' is not reachable, disabling container...", + server_url + ); + } + } + Err(e) => { + log::error!("Failed to add networked container: {}", e); + } + } + } + log::debug!("Initializing warp server took {:?}", start.elapsed()); + background_task.finish(); +} + #[no_mangle] #[allow(non_snake_case)] pub extern "C" fn CorePluginInit() -> bool { @@ -44,22 +104,21 @@ pub extern "C" fn CorePluginInit() -> bool { workflow::insert_workflow(); - let plugin_settings = PluginSettings::from_settings(&global_bn_settings); - // We want to load all the bundled directories into the container cache. - let background_task = BackgroundTask::new("Loading WARP files...", false); - let start = Instant::now(); - if plugin_settings.load_bundled_files { - let core_disk_container = DiskContainer::new_from_dir(core_signature_dir()); - log::debug!("{:#?}", core_disk_container); - add_cached_container(core_disk_container); + // TODO: Make the retrieval of containers wait on this to be done. + // TODO: We could also have a mechanism for lazily loading the files using the chunk header target. + // Loading bundled signatures might take a few hundred milliseconds. + if is_ui_enabled() { + std::thread::spawn(|| { + load_bundled_signatures(); + load_network_container(); + }); + } else { + load_bundled_signatures(); + std::thread::spawn(|| { + // Dependence on this is likely to not matter in headless, so we throw it on another thread. + load_network_container(); + }); } - if plugin_settings.load_user_files { - let user_disk_container = DiskContainer::new_from_dir(user_signature_dir()); - log::debug!("{:#?}", user_disk_container); - add_cached_container(user_disk_container); - } - log::info!("Loading bundled files took {:?}", start.elapsed()); - background_task.finish(); register_command( "WARP\\Run Matcher", diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs index 21ad4dc0..4de6bab3 100644 --- a/plugins/warp/src/plugin/ffi/container.rs +++ b/plugins/warp/src/plugin/ffi/container.rs @@ -36,6 +36,27 @@ pub unsafe extern "C" fn BNWARPContainerGetName(container: *mut BNWARPContainer) } #[no_mangle] +pub unsafe extern "C" fn BNWARPContainerFetchFunctions( + container: *mut BNWARPContainer, + target: *mut BNWARPTarget, + guids: *const BNWARPFunctionGUID, + count: usize, +) { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return; + }; + + let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) }; + + let guids = unsafe { std::slice::from_raw_parts(guids, count) }; + + if let Err(e) = container.fetch_functions(&target, guids) { + log::error!("Failed to fetch functions: {}", e); + } +} + +#[no_mangle] pub unsafe extern "C" fn BNWARPContainerGetSources( container: *mut BNWARPContainer, count: *mut usize, diff --git a/plugins/warp/src/plugin/settings.rs b/plugins/warp/src/plugin/settings.rs index 6cd2e0cc..489deb23 100644 --- a/plugins/warp/src/plugin/settings.rs +++ b/plugins/warp/src/plugin/settings.rs @@ -19,7 +19,7 @@ pub struct PluginSettings { /// The API key to use for the selected WARP server, if not specified, you will be unable to push data and may be rate-limited. /// /// This is set to [PluginSettings::SERVER_API_KEY_DEFAULT] by default. - pub server_api_key: String, + pub server_api_key: Option<String>, /// Whether to allow networked WARP requests. Turning this off will not disable local WARP functionality. /// /// This is set to [PluginSettings::ENABLE_SERVER_DEFAULT] by default. @@ -33,9 +33,9 @@ impl PluginSettings { pub const LOAD_USER_FILES_SETTING: &'static str = "analysis.warp.loadUserFiles"; pub const SERVER_URL_DEFAULT: &'static str = "https://warp.binary.ninja"; pub const SERVER_URL_SETTING: &'static str = "analysis.warp.serverUrl"; - pub const SERVER_API_KEY_DEFAULT: &'static str = ""; + pub const SERVER_API_KEY_DEFAULT: Option<String> = None; pub const SERVER_API_KEY_SETTING: &'static str = "analysis.warp.serverApiKey"; - pub const ENABLE_SERVER_DEFAULT: bool = true; + pub const ENABLE_SERVER_DEFAULT: bool = false; pub const ENABLE_SERVER_SETTING: &'static str = "network.enableWARP"; pub fn register(bn_settings: &mut BNSettings) { @@ -44,7 +44,8 @@ impl PluginSettings { "type" : "boolean", "default" : Self::LOAD_BUNDLED_FILES_DEFAULT, "description" : "Whether to load bundled WARP files on startup. Turn this off if you want to manually load them.", - "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"], + "requiresRestart" : true }); bn_settings.register_setting_json( Self::LOAD_BUNDLED_FILES_SETTING, @@ -55,7 +56,8 @@ impl PluginSettings { "type" : "boolean", "default" : Self::LOAD_USER_FILES_DEFAULT, "description" : "Whether to load user WARP files on startup. Turn this off if you want to manually load them.", - "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"], + "requiresRestart" : true }); bn_settings.register_setting_json( Self::LOAD_USER_FILES_SETTING, @@ -66,7 +68,8 @@ impl PluginSettings { "type" : "string", "default" : Self::SERVER_URL_DEFAULT, "description" : "The WARP server to use.", - "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"], + "requiresRestart" : true }); bn_settings.register_setting_json(Self::SERVER_URL_SETTING, &server_url_prop.to_string()); let server_api_key_prop = json!({ @@ -75,7 +78,8 @@ impl PluginSettings { "default" : Self::SERVER_API_KEY_DEFAULT, "description" : "The API key to use for the selected WARP server, if not specified you will be unable to push data, and may be rate limited.", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"], - "hidden": true + "hidden": true, + "requiresRestart" : true }); bn_settings.register_setting_json( Self::SERVER_API_KEY_SETTING, @@ -86,7 +90,8 @@ impl PluginSettings { "type" : "boolean", "default" : Self::ENABLE_SERVER_DEFAULT, "description" : "Whether or not to allow networked WARP requests. Turning this off will not disable local WARP functionality.", - "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"], + "requiresRestart" : true }); bn_settings.register_setting_json( Self::ENABLE_SERVER_SETTING, @@ -107,7 +112,10 @@ impl PluginSettings { settings.server_url = bn_settings.get_string(Self::SERVER_URL_SETTING); } if bn_settings.contains(Self::SERVER_API_KEY_SETTING) { - settings.server_url = bn_settings.get_string(Self::SERVER_API_KEY_SETTING); + let server_api_key_str = bn_settings.get_string(Self::SERVER_API_KEY_SETTING); + if !server_api_key_str.is_empty() { + settings.server_api_key = Some(server_api_key_str); + } } if bn_settings.contains(Self::ENABLE_SERVER_SETTING) { settings.enable_server = bn_settings.get_bool(Self::ENABLE_SERVER_SETTING); @@ -122,7 +130,7 @@ impl Default for PluginSettings { load_bundled_files: PluginSettings::LOAD_BUNDLED_FILES_DEFAULT, load_user_files: PluginSettings::LOAD_USER_FILES_DEFAULT, server_url: PluginSettings::SERVER_URL_DEFAULT.to_string(), - server_api_key: PluginSettings::SERVER_API_KEY_DEFAULT.to_string(), + server_api_key: PluginSettings::SERVER_API_KEY_DEFAULT, enable_server: PluginSettings::ENABLE_SERVER_DEFAULT, } } diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs index 2d76222c..c2f82bd9 100644 --- a/plugins/warp/src/plugin/workflow.rs +++ b/plugins/warp/src/plugin/workflow.rs @@ -60,6 +60,15 @@ impl Command for RunMatcher { fn action(&self, view: &BinaryView) { let view = view.to_owned(); std::thread::spawn(move || { + // For embedded targets the user may not have set the sections up. + // Alert the user if we have no actual regions (+1 comes from the synthetic section). + let regions = relocatable_regions(&view); + if regions.len() <= 1 && view.memory_map().is_activated() { + log::warn!( + "No relocatable regions found, for best results please define sections for the binary!" + ); + } + run_matcher(&view); }); } @@ -75,14 +84,6 @@ pub fn run_matcher(view: &BinaryView) { let _ = get_warp_tag_type(view); view.file().forget_undo_actions(&undo_id); - // Alert the user if we have no actual regions (one comes from the synthetic section). - let regions = relocatable_regions(view); - if regions.len() <= 1 && view.memory_map().is_activated() { - log::warn!( - "No relocatable regions found, for best results please define sections for the binary!" - ); - } - // Then we want to actually find matching functions. let background_task = BackgroundTask::new("Matching on WARP functions...", true); let start = Instant::now(); diff --git a/plugins/warp/ui/matches.cpp b/plugins/warp/ui/matches.cpp index fad729d6..ed77085a 100644 --- a/plugins/warp/ui/matches.cpp +++ b/plugins/warp/ui/matches.cpp @@ -5,6 +5,7 @@ #include <QClipboard> #include <QFormLayout> +#include <thread> #include "theme.h" #include "warp.h" @@ -15,6 +16,8 @@ WarpCurrentFunctionWidget::WarpCurrentFunctionWidget(FunctionRef current) // NOTE: Might be nullptr if the no selected function. m_current = current; + m_logger = new BinaryNinja::Logger("WARP"); + // Create the QT stuff QGridLayout *layout = new QGridLayout(this); layout->setContentsMargins(2, 2, 2, 2); @@ -110,6 +113,26 @@ void WarpCurrentFunctionWidget::SetCurrentFunction(FunctionRef current) return; m_current = current; m_infoWidget->SetAnalysisFunction(m_current); + + if (current) + { + // Add the function to the processing list only if we have no already done so. + // If a user goes to a function, then navigates away, they do not want to + // have us try and send a network request! + { + std::lock_guard<std::mutex> lock(m_requestMutex); + uint64_t funcStart = current->GetStart(); + if (m_processedFunctions.find(funcStart) == m_processedFunctions.end()) { + m_pendingRequests.push_back(current); + } + } + if (!m_requestInProgress.exchange(true)) { + BinaryNinja::WorkerPriorityEnqueue([this]() { + ProcessPendingFetchRequests(); + }); + } + } + UpdateMatches(); } @@ -162,3 +185,51 @@ void WarpCurrentFunctionWidget::UpdateMatches() m_tableWidget->SetFunctions(matches); } + +void WarpCurrentFunctionWidget::ProcessPendingFetchRequests() +{ + std::vector<FunctionRef> requests; + { + std::lock_guard<std::mutex> lock(m_requestMutex); + requests = std::move(m_pendingRequests); + m_pendingRequests.clear(); + } + + if (requests.empty()) { + m_requestInProgress = false; + return; + } + + auto start_time = std::chrono::high_resolution_clock::now(); + + std::vector<Warp::FunctionGUID> guids; + Warp::Ref<Warp::Target> target; + for (const auto& func : requests) { + // TODO: Need to send multiple requests if there is multiple targets. + if (!target) + target = Warp::Target::FromPlatform(*func->GetPlatform()); + if (const auto guid = Warp::GetAnalysisFunctionGUID(*func); guid.has_value()) + guids.push_back(guid.value()); + } + + // Actually fetch the data! + if (!guids.empty()) + for (const auto &container: Warp::Container::All()) + container->FetchFunctions(*target, guids); + + { + std::lock_guard<std::mutex> lock(m_requestMutex); + for (const auto& func : requests) { + m_processedFunctions.insert(func->GetStart()); + } + } + + // TODO: Update the matches, make sure there was stuff added first lol. + // TODO: UpdateMatches(); + + const auto end_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration<double> elapsed_time = end_time - start_time; + m_logger->LogDebug("ProcessPendingRequests took %f seconds", elapsed_time.count()); + + m_requestInProgress = false; +} diff --git a/plugins/warp/ui/matches.h b/plugins/warp/ui/matches.h index 4021f10c..251dcb89 100644 --- a/plugins/warp/ui/matches.h +++ b/plugins/warp/ui/matches.h @@ -16,6 +16,13 @@ class WarpCurrentFunctionWidget : public QWidget WarpFunctionTableWidget *m_tableWidget; WarpFunctionInfoWidget *m_infoWidget; + LoggerRef m_logger; + + std::mutex m_requestMutex; + std::vector<FunctionRef> m_pendingRequests; + std::atomic<bool> m_requestInProgress {false}; + std::unordered_set<uint64_t> m_processedFunctions; + public: explicit WarpCurrentFunctionWidget(FunctionRef current); @@ -26,4 +33,6 @@ public: FunctionRef GetCurrentFunction() { return m_current; }; void UpdateMatches(); + + void ProcessPendingFetchRequests(); }; diff --git a/plugins/warp/ui/plugin.cpp b/plugins/warp/ui/plugin.cpp index 69aaaf34..923a79b3 100644 --- a/plugins/warp/ui/plugin.cpp +++ b/plugins/warp/ui/plugin.cpp @@ -170,6 +170,9 @@ void WarpSidebarWidget::notifyViewChanged(ViewFrame *view) void WarpSidebarWidget::notifyViewLocationChanged(View *view, const ViewLocation &location) { + // Warp sidebar really should only update if it is visible, otherwise its a waste of cycles. + if (!this->isVisible()) + return; auto function = location.getFunction(); // TODO: Only update if the function exists? // NOTE: The function called will exit early if it is the same function. |
