diff --git a/CHANGES.md b/CHANGES.md index 3fb016a..5e0de6f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,72 @@ All notable changes to this program are documented in this file. +## 0.34.0 (2024-01-03, `c44f0d09630a`) + +### Known problems + +- _Startup hang with Firefox running in a container (e.g. snap, flatpak):_ + + When Firefox is packaged inside a container (like the default Firefox browser + shipped with Ubuntu 22.04), it may see a different filesystem to the host. + This can affect access to the generated profile directory, which may result + in a hang when starting Firefox. Workarounds are listed in the geckodriver + [usage documentation]. + +### Added + +- Support for [Virtual Authenticators] + + [Virtual Authenticators] serve as a WebDriver Extension designed to simulate + user authentication (WebAuthn) on web applications during automated testing. + This functionality encompasses a range of methods, including passwords, + biometrics, and security keys. + + Geckodriver supports all available commands: + + - [Add Virtual Authenticator] + - [Remove Virtual Authenticator] + - [Add Credential] + - [Get Credentials] + - [Remove Credential] + - [Remove All Credentials] + - [Set User Verified] + +- Support for using a page range as integer for the [Print] command. + + Implemented by [Mitesh Gulecha]. + +### Changed + +- The error handling has undergone refactoring, now utilizing the + [anyhow](https://docs.rs/anyhow) and [thiserror](https://docs.rs/thiserror) + crates. + + Implemented by [James Hendry]. + +- Specifying `--port=0` as an argument allows geckodriver to dynamically find + and use an available free port on the system. + +- Updated dependencies (base64, clap, rust-url) + +### Fixed + +- While searching for a default Firefox installation on the system, geckodriver + used the `Contents/MacOS/firefox-bin` executable instead of the binary + specified in the app bundle's `info.plist` file. This behavior resulted in a + malfunction due to a regression in Firefox, particularly affecting the Firefox 121 release. + +- The Firefox version check has been extended to enable the execution of + distributions with custom prefixes for the application name. + + Implemented by [Razvan Cojocaru]. + +### Removed + +- Removed the `unknown path` error which is not part of the WebDriver specification. + + Implemented by [James Hendry]. + ## 0.33.0 (2023-04-03, `a80e5fd61076`) ### Known problems @@ -1816,15 +1882,27 @@ and greater. [Take Element Screenshot]: https://w3c.github.io/webdriver/webdriver-spec.html#take-element-screenshot [WebDriver errors]: https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors +[Virtual Authenticators]: https://www.w3.org/TR/webauthn-2/#sctn-automation +[Add Credential]: https://www.w3.org/TR/webauthn-2/#add-credential +[Add Virtual Authenticator]: https://www.w3.org/TR/webauthn-2/#add-virtual-authenticator +[Get Credentials]: https://www.w3.org/TR/webauthn-2/#get-credentials +[Remove All Credentials]: https://www.w3.org/TR/webauthn-2/#remove-all-credentials +[Remove Credential]: https://www.w3.org/TR/webauthn-2/#remove-credential +[Remove Virtual Authenticator]: https://www.w3.org/TR/webauthn-2/#remove-virtual-authenticator +[Set User Verified]: https://www.w3.org/TR/webauthn-2/#set-user-verified + [Bastien Orivel]: https://github.com/Eijebong [David Burns]: https://github.com/AutomatedTester +[James Hendry]: https://bugzilla.mozilla.org/user_profile?user_id=720249 [Jason Juang]: https://github.com/juangj [Jeremy Lempereur]: https://github.com/o0Ignition0o [Kalpesh Krishna]: https://github.com/martiansideofthemoon [Kriti Singh]: https://github.com/kritisingh1 +[Mitesh Gulecha]: https://github.com/mickyg03 [Mike Pennisi]: https://github.com/jugglinmike [Nupur Baghel]: https://github.com/nupurbaghel [Peter Major]: https://github.com/aldaris +[Razvan Cojocaru]: https://github.com/rzvncj [Shivam Singhal]: https://github.com/championshuttler [Sven Jost]: https://github/mythsunwind [Vlad Filippov]: https://github.com/vladikoff diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 157abfa..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,1656 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "clap" -version = "3.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "lazy_static", - "strsim", - "terminal_size", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "time 0.3.20", - "version_check", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpufeatures" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.13", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "errno" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "flate2" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "geckodriver" -version = "0.33.0" -dependencies = [ - "base64 0.13.1", - "chrono", - "clap", - "hyper", - "lazy_static", - "log", - "marionette", - "mozdevice", - "mozprofile", - "mozrunner", - "mozversion", - "regex", - "serde", - "serde_derive", - "serde_json", - "serde_yaml", - "tempfile", - "unicode-segmentation", - "url", - "uuid", - "webdriver", - "zip", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "h2" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "headers" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" -dependencies = [ - "base64 0.13.1", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" - -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "marionette" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834a6bbd4f1218f2e5588b2462b89c978841b2b64473152d15c4bbf725ac23a" -dependencies = [ - "serde", - "serde_json", - "serde_repr", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", -] - -[[package]] -name = "mozdevice" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f01c1b180a91304d9498e47120ac70498909647fefcccf9adb64ed3d6f4bf06c" -dependencies = [ - "log", - "once_cell", - "regex", - "tempfile", - "thiserror", - "unix_path", - "uuid", - "walkdir", -] - -[[package]] -name = "mozprofile" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22254a1861d33cce16327afbb5b071c819cd227aef40f382666ec537a689529" -dependencies = [ - "tempfile", -] - -[[package]] -name = "mozrunner" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8925a6f5235f6c586a1bcc79612325f2cb97c2d0da19b23ce668a60e7f6e5f" -dependencies = [ - "dirs", - "log", - "mozprofile", - "plist", - "winreg", -] - -[[package]] -name = "mozversion" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1c996f34cc52fa3de2ba1b683c35c66c279ea9f43735a179d0b0fab6c574d6" -dependencies = [ - "regex", - "rust-ini", - "semver", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "plist" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" -dependencies = [ - "base64 0.21.0", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time 0.3.20", -] - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-xml" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c1a97b1bc42b1d550bfb48d4262153fe400a12bab1511821736f7eac76d7e2" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rust-ini" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263" - -[[package]] -name = "rustix" -version = "0.37.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d097081ed288dfe45699b72f5b5d648e5f15d64d900c7080273baa20c16a6849" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64 0.21.0", -] - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "serde" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "serde_json" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[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 = "serde_yaml" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" -dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" -dependencies = [ - "terminal_size", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" -dependencies = [ - "itoa", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "time-macros" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys", -] - -[[package]] -name = "tokio-stream" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "log", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unix_path" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8e291873ae77c4c8d9c9b34d0bee68a35b048fb39c263a5155e0e353783eaf" -dependencies = [ - "unix_str", -] - -[[package]] -name = "unix_str" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ace0b4755d0a2959962769239d56267f8a024fef2d9b32666b3dcd0946b0906" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "uuid" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "warp" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "percent-encoding", - "pin-project", - "rustls-pemfile", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-util", - "tower-service", - "tracing", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "webdriver" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9ae70f0cb12332fe144def990a9e62b20db2361b8784f879bb2814aad6c763" -dependencies = [ - "base64 0.13.1", - "bytes", - "cookie", - "http", - "log", - "serde", - "serde_derive", - "serde_json", - "time 0.3.20", - "tokio", - "tokio-stream", - "unicode-segmentation", - "url", - "warp", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "zip" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" -dependencies = [ - "byteorder", - "crc32fast", - "crossbeam-utils", - "flate2", -] diff --git a/Cargo.toml b/Cargo.toml index 844bc6c..53ecfd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] -edition = "2018" +edition = "2021" name = "geckodriver" -version = "0.33.0" +version = "0.34.0" authors = ["Mozilla"] include = [ "/.cargo", @@ -21,27 +21,29 @@ license = "MPL-2.0" repository = "https://hg.mozilla.org/mozilla-central/file/tip/testing/geckodriver" [dependencies] -base64 = "0.13" +anyhow = "1" +base64 = "0.21" chrono = "0.4.6" -clap = { version = "~3.1", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help"] } +clap = { version = "4", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help", "string"] } hyper = "0.14" lazy_static = "1.0" log = { version = "0.4", features = ["std"] } -marionette = "0.4.0" -mozdevice = "0.5.1" -mozprofile = "0.9.1" -mozrunner = "0.15.1" -mozversion = "0.5.1" +marionette = "0.5.0" +mozdevice = "0.5.2" +mozprofile = "0.9.2" +mozrunner = "0.15.2" +mozversion = "0.5.2" regex = { version="1.0", default-features = false, features = ["perf", "std"] } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.8" tempfile = "3" +thiserror = "1" unicode-segmentation = "1.9" -url = "2.0" +url = "2.4" uuid = { version = "1.0", features = ["v4"] } -webdriver = "0.48.0" +webdriver = "0.50.0" zip = { version = "0.6", default-features = false, features = ["deflate"] } [dev-dependencies] diff --git a/doc/Bugs.md b/doc/Bugs.md index b561bd4..4c1b955 100644 --- a/doc/Bugs.md +++ b/doc/Bugs.md @@ -12,7 +12,7 @@ useful thing to provide is a minimal HTML document which permits the problem to be reproduced along with a [trace-level log] from geckodriver showing the exact wire protocol calls made. -Because of the wide variety and different charateristics of clients +Because of the wide variety and different characteristics of clients used with geckodriver, their stacktraces, logs, and code examples are typically not very useful as they distract from the actual underlying cause. **For this reason, we cannot overstate the importance of diff --git a/doc/Capabilities.md b/doc/Capabilities.md index c9eb7a5..f33bbc4 100644 --- a/doc/Capabilities.md +++ b/doc/Capabilities.md @@ -56,6 +56,8 @@ websocket and interact with the browser by using the CDP protocol. ## `moz:useNonSpecCompliantPointerOrigin` +Note: This capability is no longer supported in Firefox 116 and later. + A boolean value to indicate how the pointer origin for an action command will be calculated. @@ -67,10 +69,6 @@ referenced element, but on the in-view center point. To temporarily disable the WebDriver conformant behavior use `false` as value for this capability. -Please note that this capability exists only temporarily, and that -it will be removed once all Selenium bindings can handle the new -behavior. - ## `moz:webdriverClick` A boolean value to indicate which kind of interactability checks diff --git a/doc/CrashReports.md b/doc/CrashReports.md index 576bdda..640b50f 100644 --- a/doc/CrashReports.md +++ b/doc/CrashReports.md @@ -5,46 +5,31 @@ running automated tests via Selenium and geckodriver Firefox could crash. In those cases it is very helpful to retrieve the generated crash data aka minidump files, and report these to us. -## Retrieve the crash data +## Retrieve the crash information Because geckodriver creates a temporary user profile for Firefox, it also automatically removes all its folders once the tests have been finished. That -also means that if Firefox crashed the created minidump files are lost. To -prevent that a custom profile has to be used instead. The following code -shows an example by using the Python Selenium bindings on Mac OS: - -```python -import tempfile - -from selenium import webdriver -from selenium.webdriver.firefox.options import Options - -# Custom profile folder to keep the minidump files -profile = tempfile.mkdtemp(".selenium") -print("*** Using profile: {}".format(profile)) - -# Use the above folder as custom profile -opts = Options() -opts.add_argument("-profile") -opts.add_argument(profile) -opts.binary = "/Applications/Firefox.app/Contents/MacOS/firefox" +also means that if Firefox or just a tab crashed the created minidump files +cannot be retrieved. To prevent that the `MINIDUMP_SAVE_PATH` environment +variable can be used. It needs to be forwarded to geckodriver and has to point +to an existing folder on the local machine. Then, whenever a crash occurs the +related crash information will then be written to the `.dmp` and +`.extra` files within the given folder. + +```bash +MINIDUMP_SAVE_PATH="/home/test/crashes" pytest path/to/test.py +``` -driver = webdriver.Firefox( - options=opts, - # hard-code the Marionette port so geckodriver can connect - service_args=["--marionette-port", "2828"] -) +By running this command Firefox will now write minidump files to that folder: -# Your test code which crashes Firefox +```bash +$ ls /home/test/crashes +4ad24258-ec0f-87bd-fd78-496d9170bd35.dmp +4ad24258-ec0f-87bd-fd78-496d9170bd35.extra ``` -Executing the test with Selenium now, which triggers the crash of Firefox -will leave all the files from the user profile around in the above path. - -To retrieve the minidump files navigate to that folder and look for a sub -folder with the name `minidumps`. It should contain at least one series of -files. One file with the `.dmp` extension and another one with `.extra`. -Both of those files are needed. If more crash files are present grab them all. +Note that both of those files are needed when you want to file an issue for +geckodriver. If more files are present grab them all. Attach the files as best archived as zip file to the created [geckodriver issue] on Github. diff --git a/doc/Flags.md b/doc/Flags.md index 9c11ce5..0251293 100644 --- a/doc/Flags.md +++ b/doc/Flags.md @@ -1,7 +1,7 @@ # Flags -## --allow-hosts ALLOW_HOSTS... +## -\\-allow-hosts ALLOW_HOSTS... Values of the `Host` header to allow for incoming requests. @@ -12,7 +12,7 @@ with `Host` set to `geckodriver.test` or `webdriver.local`. Requests with `Host` set to an IP address are always allowed. -## --allow-origins ALLOW_ORIGINS... +## -\\-allow-origins ALLOW_ORIGINS... Values of the `Origin` header to allow for incoming requests. @@ -27,7 +27,7 @@ origin will be able to make requests to geckodriver. For example service on the origin with scheme `https`, hostname `webdriver.test`, and port `8080` to access the geckodriver instance. -## --android-storage ANDROID_STORAGE +## -\\-android-storage ANDROID_STORAGE **Deprecation warning**: This argument is deprecated and planned to be removed with the 0.31.0 release of geckodriver. As such it shouldn't be used with version @@ -55,28 +55,28 @@ By default `auto` is used. auto Best suitable location based on whether the device is rooted.
- If the device is rooted internal is used, otherwise app. + If the device is rooted `internal` is used, otherwise `app`. app -

Location: /data/data/%androidPackage%/test_root

- Based on the androidPackage capability that is passed as part of - moz:firefoxOptions when creating a new session. Commands that +

Location: `/data/data/%androidPackage%/test_root`

+ Based on the `androidPackage` capability that is passed as part of + `moz:firefoxOptions` when creating a new session. Commands that change data in the app's directory are executed using run-as. This requires that the installed app is debuggable. internal -

Location: /data/local/tmp/test_root

+

Location: `/data/local/tmp/test_root`

The device must be rooted since when the app runs, files that are created in the profile, which is owned by the app user, cannot be changed by the - shell user. Commands will be executed via su. + shell user. Commands will be executed via `su`. sdcard -

Location: $EXTERNAL_STORAGE/Android/data/%androidPackage%/files/test_root

+

Location: `$EXTERNAL_STORAGE/Android/data/%androidPackage%/files/test_root`

This location is supported by all versions of Android whether if the device is rooted or not. -## -b BINARY / --binary BINARY +## -b BINARY / -\\-binary BINARY Path to the Firefox binary to use. By default geckodriver tries to find and use the system installation of Firefox, but that behaviour @@ -93,7 +93,7 @@ equivalent to calling [whereis(1)] and extracting the second column: firefox: /usr/bin/firefox /usr/local/firefox ``` -On macOS, the binary is found by looking for the first _firefox-bin_ +On macOS, the binary is found by looking for the first _firefox_ binary in the same fashion as on Linux systems. This means it is possible to also use `PATH` to control where geckodriver should find Firefox on macOS. It will then look for _/Applications/Firefox.app_. @@ -104,7 +104,7 @@ scanning the Windows registry. [creating a new session]: https://w3c.github.io/webdriver/#new-session [whereis(1)]: http://www.manpagez.com/man/1/whereis/ -## --connect-existing +## -\\-connect-existing Connect geckodriver to an existing Firefox instance. This means geckodriver will abstain from the default of starting a new Firefox @@ -112,18 +112,16 @@ session. The existing Firefox instance must have [Marionette] enabled. To enable the remote protocol in Firefox, you can pass the -`-marionette` flag. Unless the `marionette.port` preference +`--marionette` flag. Unless the `marionette.port` preference has been user-set, Marionette will listen on port 2828. So when using `--connect-existing` it is likely you will also have to use `--marionette-port` to set the correct port. -`--marionette-port`: #marionette-port - -## --host HOST +## -\\-host HOST Host to use for the WebDriver server. Defaults to 127.0.0.1. -## --jsdebugger +## -\\-jsdebugger Attach [browser toolbox] debugger when Firefox starts. This is useful for debugging [Marionette] internals. @@ -156,21 +154,21 @@ argument is passed to geckodriver. [browser toolbox]: https://developer.mozilla.org/en-US/docs/Tools/Browser_Toolbox -## --log LEVEL +## -\\-log LEVEL Set the Gecko and geckodriver log level. Possible values are `fatal`, `error`, `warn`, `info`, `config`, `debug`, and `trace`. -## --log-no-truncate +## -\\-log-no-truncate Disables truncation of long log lines. -## --marionette-host HOST +## -\\-marionette-host HOST Selects the host for geckodriver’s connection to the [Marionette] remote protocol. Defaults to 127.0.0.1. -## --marionette-port PORT +## -\\-marionette-port PORT Selects the port for geckodriver’s connection to the [Marionette] remote protocol. @@ -184,14 +182,14 @@ under geckodriver’s control, it will simply connect to PORT. `--connect-existing`: #connect-existing -## -p PORT / --port PORT +## -p PORT / -\\-port PORT Port to use for the WebDriver server. Defaults to 4444. A helpful trick is that it is possible to bind to 0 to get the system to atomically assign a free port. -## --profile-root PROFILE_ROOT +## -\\-profile-root PROFILE_ROOT Path to the directory to use when creating temporary profiles. By default this is the system temporary directory. Both geckodriver and @@ -202,13 +200,13 @@ filesystem such that it doesn't share the same system temporary directory as geckodriver (e.g. when running Firefox inside a container or packaged as a snap). -## -v[v] +## -v[v] Increases the logging verbosity by to debug level when passing a single `-v`, or to trace level if `-vv` is passed. This is analogous to passing `--log debug` and `--log trace`, respectively. -## --websocket-portPORT +## -\\-websocket-portPORT Port to use to connect to WebDriver BiDi. Defaults to 9222. diff --git a/doc/Support.md b/doc/Support.md index 0c06ee1..731de14 100644 --- a/doc/Support.md +++ b/doc/Support.md @@ -23,32 +23,36 @@ and required versions of Selenium and Firefox: + + 0.34.0 + ≥ 3.11 (3.14 Python) + 115 ESR + n/a 0.33.0 ≥ 3.11 (3.14 Python) 102 ESR - n/a + 120 0.32.2 ≥ 3.11 (3.14 Python) 102 ESR - n/a + 120 0.32.1 ≥ 3.11 (3.14 Python) 102 ESR - n/a + 120 0.32.0 ≥ 3.11 (3.14 Python) 102 ESR - n/a + 120 0.31.0 ≥ 3.11 (3.14 Python) 91 ESR - n/a - + 120 0.30.0 ≥ 3.11 (3.14 Python) diff --git a/marionette/Cargo.toml b/marionette/Cargo.toml index 2bcfaa3..13ed995 100644 --- a/marionette/Cargo.toml +++ b/marionette/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "marionette" -version = "0.4.0" +version = "0.5.0" authors = ["Mozilla"] description = "Library implementing the client side of Gecko's Marionette remote automation protocol." edition = "2018" diff --git a/marionette/src/webdriver.rs b/marionette/src/webdriver.rs index fa1a489..a3046e7 100644 --- a/marionette/src/webdriver.rs +++ b/marionette/src/webdriver.rs @@ -56,6 +56,13 @@ pub struct Keys { pub value: Vec, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PrintPageRange { + Integer(u64), + Range(String), +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(default, rename_all = "camelCase")] pub struct PrintParameters { @@ -64,7 +71,7 @@ pub struct PrintParameters { pub background: bool, pub page: PrintPage, pub margin: PrintMargins, - pub page_ranges: Vec, + pub page_ranges: Vec, pub shrink_to_fit: bool, } @@ -82,18 +89,15 @@ impl Default for PrintParameters { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum PrintOrientation { Landscape, + #[default] Portrait, } -impl Default for PrintOrientation { - fn default() -> Self { - PrintOrientation::Portrait - } -} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct PrintPage { @@ -129,6 +133,52 @@ impl Default for PrintMargins { } } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum WebAuthnProtocol { + #[serde(rename = "ctap1/u2f")] + Ctap1U2f, + #[serde(rename = "ctap2")] + Ctap2, + #[serde(rename = "ctap2_1")] + Ctap2_1, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub enum AuthenticatorTransport { + Usb, + Nfc, + Ble, + SmartCard, + Hybrid, + Internal, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct AuthenticatorParameters { + pub protocol: WebAuthnProtocol, + pub transport: AuthenticatorTransport, + pub has_resident_key: bool, + pub has_user_verification: bool, + pub is_user_consenting: bool, + pub is_user_verified: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct CredentialParameters { + pub credential_id: String, + pub is_resident_credential: bool, + pub rp_id: String, + pub private_key: String, + pub user_handle: String, + pub sign_count: u64, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct UserVerificationParameters { + pub is_user_verified: bool, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ScreenshotOptions { pub id: Option, @@ -296,6 +346,20 @@ pub enum Command { TakeFullScreenshot(ScreenshotOptions), #[serde(rename = "WebDriver:TakeScreenshot")] TakeScreenshot(ScreenshotOptions), + #[serde(rename = "WebAuthn:AddVirtualAuthenticator")] + WebAuthnAddVirtualAuthenticator(AuthenticatorParameters), + #[serde(rename = "WebAuthn:RemoveVirtualAuthenticator")] + WebAuthnRemoveVirtualAuthenticator, + #[serde(rename = "WebAuthn:AddCredential")] + WebAuthnAddCredential(CredentialParameters), + #[serde(rename = "WebAuthn:GetCredentials")] + WebAuthnGetCredentials, + #[serde(rename = "WebAuthn:RemoveCredential")] + WebAuthnRemoveCredential, + #[serde(rename = "WebAuthn:RemoveAllCredentials")] + WebAuthnRemoveAllCredentials, + #[serde(rename = "WebAuthn:SetUserVerified")] + WebAuthnSetUserVerified(UserVerificationParameters), } #[cfg(test)] diff --git a/src/android.rs b/src/android.rs index 10293d5..763639c 100644 --- a/src/android.rs +++ b/src/android.rs @@ -3,9 +3,9 @@ use mozdevice::{AndroidStorage, Device, Host, UnixPathBuf}; use mozprofile::profile::Profile; use serde::Serialize; use serde_yaml::{Mapping, Value}; -use std::fmt; use std::io; use std::time; +use thiserror::Error; use webdriver::error::{ErrorStatus, WebDriverError}; // TODO: avoid port clashes across GeckoView-vehicles. @@ -20,47 +20,22 @@ const CONFIG_FILE_HEADING: &str = r#"## GeckoView configuration YAML pub type Result = std::result::Result; -#[derive(Debug)] +#[derive(Debug, Error)] pub enum AndroidError { + #[error("Activity for package '{0}' not found")] ActivityNotFound(String), - Device(mozdevice::DeviceError), - IO(io::Error), - PackageNotFound(String), - Serde(serde_yaml::Error), -} -impl fmt::Display for AndroidError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - AndroidError::ActivityNotFound(ref package) => { - write!(f, "Activity for package '{}' not found", package) - } - AndroidError::Device(ref message) => message.fmt(f), - AndroidError::IO(ref message) => message.fmt(f), - AndroidError::PackageNotFound(ref package) => { - write!(f, "Package '{}' not found", package) - } - AndroidError::Serde(ref message) => message.fmt(f), - } - } -} + #[error(transparent)] + Device(#[from] mozdevice::DeviceError), -impl From for AndroidError { - fn from(value: io::Error) -> AndroidError { - AndroidError::IO(value) - } -} + #[error(transparent)] + IO(#[from] io::Error), -impl From for AndroidError { - fn from(value: mozdevice::DeviceError) -> AndroidError { - AndroidError::Device(value) - } -} + #[error("Package '{0}' not found")] + PackageNotFound(String), -impl From for AndroidError { - fn from(value: serde_yaml::Error) -> AndroidError { - AndroidError::Serde(value) - } + #[error(transparent)] + Serde(#[from] serde_yaml::Error), } impl From for WebDriverError { diff --git a/src/browser.rs b/src/browser.rs index 7d99d9b..a33a755 100644 --- a/src/browser.rs +++ b/src/browser.rs @@ -391,6 +391,8 @@ mod tests { use super::set_prefs; use crate::browser::read_marionette_port; use crate::capabilities::{FirefoxOptions, ProfileType}; + use base64::prelude::BASE64_STANDARD; + use base64::Engine; use mozprofile::preferences::{Pref, PrefValue}; use mozprofile::profile::Profile; use serde_json::{Map, Value}; @@ -403,7 +405,7 @@ mod tests { let mut profile_data = Vec::with_capacity(1024); let mut profile = File::open("src/tests/profile.zip").unwrap(); profile.read_to_end(&mut profile_data).unwrap(); - Value::String(base64::encode(&profile_data)) + Value::String(BASE64_STANDARD.encode(&profile_data)) } // This is not a pretty test, mostly due to the nature of diff --git a/src/capabilities.rs b/src/capabilities.rs index 73e1452..bd58741 100644 --- a/src/capabilities.rs +++ b/src/capabilities.rs @@ -5,6 +5,8 @@ use crate::command::LogOptions; use crate::logging::Level; use crate::marionette::MarionetteSettings; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; use mozdevice::AndroidStorageInput; use mozprofile::preferences::Pref; use mozprofile::profile::Profile; @@ -16,37 +18,24 @@ use serde_json::{Map, Value}; use std::collections::BTreeMap; use std::default::Default; use std::ffi::OsString; -use std::fmt::{self, Display}; use std::fs; use std::io; use std::io::BufWriter; use std::io::Cursor; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; +use thiserror::Error; use webdriver::capabilities::{BrowserCapabilities, Capabilities}; use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Error)] enum VersionError { - VersionError(mozversion::Error), + #[error(transparent)] + VersionError(#[from] mozversion::Error), + #[error("No binary provided")] MissingBinary, } -impl From for VersionError { - fn from(err: mozversion::Error) -> VersionError { - VersionError::VersionError(err) - } -} - -impl Display for VersionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - VersionError::VersionError(ref x) => x.fmt(f), - VersionError::MissingBinary => "No binary provided".fmt(f), - } - } -} - impl From for WebDriverError { fn from(err: VersionError) -> WebDriverError { WebDriverError::new(ErrorStatus::SessionNotCreated, err.to_string()) @@ -182,6 +171,26 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> { Ok(true) } + fn webauthn_virtual_authenticators(&mut self, _: &Capabilities) -> WebDriverResult { + Ok(true) + } + + fn webauthn_extension_uvm(&mut self, _: &Capabilities) -> WebDriverResult { + Ok(false) + } + + fn webauthn_extension_prf(&mut self, _: &Capabilities) -> WebDriverResult { + Ok(false) + } + + fn webauthn_extension_large_blob(&mut self, _: &Capabilities) -> WebDriverResult { + Ok(false) + } + + fn webauthn_extension_cred_blob(&mut self, _: &Capabilities) -> WebDriverResult { + Ok(false) + } + fn validate_custom(&mut self, name: &str, value: &Value) -> WebDriverResult<()> { if !name.starts_with("moz:") { return Ok(()); @@ -368,19 +377,14 @@ impl AndroidOptions { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, Default, PartialEq)] pub enum ProfileType { Path(Profile), Named, + #[default] Temporary, } -impl Default for ProfileType { - fn default() -> Self { - ProfileType::Temporary - } -} - /// Rust representation of `moz:firefoxOptions`. /// /// Calling `FirefoxOptions::from_capabilities(binary, capabilities)` causes @@ -555,7 +559,7 @@ impl FirefoxOptions { let profile_base64 = profile_json.as_str().ok_or_else(|| { WebDriverError::new(ErrorStatus::InvalidArgument, "Profile is not a string") })?; - let profile_zip = &*base64::decode(profile_base64)?; + let profile_zip = &*BASE64_STANDARD.decode(profile_base64)?; // Create an emtpy profile directory let profile = Profile::new(profile_root)?; @@ -681,7 +685,7 @@ impl FirefoxOptions { // https://developer.android.com/studio/build/application-id let package_regexp = - Regex::new(r#"^([a-zA-Z][a-zA-Z0-9_]*\.){1,}([a-zA-Z][a-zA-Z0-9_]*)$"#).unwrap(); + Regex::new(r"^([a-zA-Z][a-zA-Z0-9_]*\.){1,}([a-zA-Z][a-zA-Z0-9_]*)$").unwrap(); if !package_regexp.is_match(package.as_bytes()) { return Err(WebDriverError::new( ErrorStatus::InvalidArgument, @@ -867,7 +871,7 @@ mod tests { let mut profile_data = Vec::with_capacity(1024); let mut profile = File::open("src/tests/profile.zip").unwrap(); profile.read_to_end(&mut profile_data).unwrap(); - Value::String(base64::encode(&profile_data)) + Value::String(BASE64_STANDARD.encode(&profile_data)) } fn make_options( diff --git a/src/command.rs b/src/command.rs index 798a4c0..c92eabf 100644 --- a/src/command.rs +++ b/src/command.rs @@ -3,6 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::logging; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; use hyper::Method; use serde::de::{self, Deserialize, Deserializer}; use serde_json::{self, Value}; @@ -142,7 +144,9 @@ impl<'de> Deserialize<'de> for AddonInstallParameters { temporary: data.temporary, }, Helper::Base64(ref mut data) => { - let content = base64::decode(&data.addon).map_err(de::Error::custom)?; + let content = BASE64_STANDARD + .decode(&data.addon) + .map_err(de::Error::custom)?; let path = env::temp_dir() .as_path() diff --git a/src/main.rs b/src/main.rs index 64df65a..a5c34c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,14 +27,13 @@ extern crate zip; extern crate log; use std::env; -use std::fmt; -use std::io; use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::path::PathBuf; -use std::result; +use std::process::ExitCode; + use std::str::FromStr; -use clap::{AppSettings, Arg, Command}; +use clap::{Arg, ArgAction, Command}; macro_rules! try_opt { ($expr:expr, $err_type:expr, $err_msg:expr) => {{ @@ -60,69 +59,13 @@ pub mod test; use crate::command::extension_routes; use crate::logging::Level; use crate::marionette::{MarionetteHandler, MarionetteSettings}; +use anyhow::{bail, Result as ProgramResult}; +use clap::ArgMatches; use mozdevice::AndroidStorageInput; use url::{Host, Url}; -const EXIT_SUCCESS: i32 = 0; -const EXIT_USAGE: i32 = 64; -const EXIT_UNAVAILABLE: i32 = 69; - -enum FatalError { - Parsing(clap::Error), - Usage(String), - Server(io::Error), -} - -impl FatalError { - fn exit_code(&self) -> i32 { - use FatalError::*; - match *self { - Parsing(_) | Usage(_) => EXIT_USAGE, - Server(_) => EXIT_UNAVAILABLE, - } - } - - fn help_included(&self) -> bool { - matches!(*self, FatalError::Parsing(_)) - } -} - -impl From for FatalError { - fn from(err: clap::Error) -> FatalError { - FatalError::Parsing(err) - } -} - -impl From for FatalError { - fn from(err: io::Error) -> FatalError { - FatalError::Server(err) - } -} - -// harmonise error message from clap to avoid duplicate "error:" prefix -impl fmt::Display for FatalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use FatalError::*; - let s = match *self { - Parsing(ref err) => err.to_string(), - Usage(ref s) => format!("error: {}", s), - Server(ref err) => format!("error: {}", err), - }; - write!(f, "{}", s) - } -} - -macro_rules! usage { - ($msg:expr) => { - return Err(FatalError::Usage($msg.to_string())) - }; - - ($fmt:expr, $($arg:tt)+) => { - return Err(FatalError::Usage(format!($fmt, $($arg)+))) - }; -} - -type ProgramResult = result::Result; +const EXIT_USAGE: u8 = 64; +const EXIT_UNAVAILABLE: u8 = 69; #[allow(clippy::large_enum_variant)] enum Operation { @@ -151,10 +94,10 @@ fn server_address(webdriver_host: &str, webdriver_port: u16) -> ProgramResult addrs.collect::>(), - Err(e) => usage!("{}: {}:{}", e, webdriver_host, webdriver_port), + Err(e) => bail!("{}: {}:{}", e, webdriver_host, webdriver_port), }; if socket_addrs.is_empty() { - usage!( + bail!( "Unable to resolve host: {}:{}", webdriver_host, webdriver_port @@ -190,7 +133,7 @@ fn parse_hostname(webdriver_host: &str) -> Result { /// /// This only covers domain names, not IP addresses, since IP adresses /// are always accepted. -fn get_default_allowed_hosts(ip: IpAddr) -> Vec> { +fn get_default_allowed_hosts(ip: IpAddr) -> Vec { let localhost_is_loopback = ("localhost".to_string(), 80) .to_socket_addrs() .map(|addr_iter| { @@ -202,74 +145,62 @@ fn get_default_allowed_hosts(ip: IpAddr) -> Vec> { .len() > 0; if ip.is_loopback() && localhost_is_loopback { - vec![Host::parse("localhost")] + vec![Host::parse("localhost").unwrap()] } else { vec![] } } -fn get_allowed_hosts( - host: Host, - allow_hosts: Option, -) -> Result, url::ParseError> { +fn get_allowed_hosts(host: Host, allow_hosts: Option>) -> Vec { allow_hosts - .map(|hosts| hosts.map(Host::parse).collect::>()) + .map(|hosts| hosts.cloned().collect()) .unwrap_or_else(|| match host { Host::Domain(_) => { - vec![Ok(host.clone())] + vec![host.clone()] } Host::Ipv4(ip) => get_default_allowed_hosts(IpAddr::V4(ip)), Host::Ipv6(ip) => get_default_allowed_hosts(IpAddr::V6(ip)), }) - .into_iter() - .collect::, url::ParseError>>() } -fn get_allowed_origins(allow_origins: Option) -> Result, url::ParseError> { - allow_origins - .map(|origins| { - origins - .map(Url::parse) - .collect::, url::ParseError>>() - }) - .unwrap_or_else(|| Ok(vec![])) +fn get_allowed_origins(allow_origins: Option>) -> Vec { + allow_origins.into_iter().flatten().cloned().collect() } -fn parse_args(cmd: &mut Command) -> ProgramResult { - let args = cmd.try_get_matches_from_mut(env::args())?; - - if args.is_present("help") { +fn parse_args(args: &ArgMatches) -> ProgramResult { + if args.get_flag("help") { return Ok(Operation::Help); - } else if args.is_present("version") { + } else if args.get_flag("version") { return Ok(Operation::Version); } - let log_level = if args.is_present("log_level") { - Level::from_str(args.value_of("log_level").unwrap()).ok() + let log_level = if let Some(log_level) = args.get_one::("log_level") { + Level::from_str(log_level).ok() } else { - Some(match args.occurrences_of("verbosity") { + Some(match args.get_count("verbosity") { 0 => Level::Info, 1 => Level::Debug, _ => Level::Trace, }) }; - let webdriver_host = args.value_of("webdriver_host").unwrap(); + let webdriver_host = args.get_one::("webdriver_host").unwrap(); let webdriver_port = { - let s = args.value_of("webdriver_port").unwrap(); + let s = args.get_one::("webdriver_port").unwrap(); match u16::from_str(s) { Ok(n) => n, - Err(e) => usage!("invalid --port: {}: {}", e, s), + Err(e) => bail!("invalid --port: {}: {}", e, s), } }; let android_storage = args - .value_of_t::("android_storage") + .get_one::("android_storage") + .and_then(|arg| AndroidStorageInput::from_str(arg).ok()) .unwrap_or(AndroidStorageInput::Auto); - let binary = args.value_of("binary").map(PathBuf::from); + let binary = args.get_one::("binary").map(PathBuf::from); - let profile_root = args.value_of("profile_root").map(PathBuf::from); + let profile_root = args.get_one::("profile_root").map(PathBuf::from); // Try to create a temporary directory on startup to check that the directory exists and is writable { @@ -279,71 +210,65 @@ fn parse_args(cmd: &mut Command) -> ProgramResult { tempfile::tempdir() }; if tmp_dir.is_err() { - usage!("Unable to write to temporary directory; consider --profile-root with a writeable directory") + bail!("Unable to write to temporary directory; consider --profile-root with a writeable directory") } } - let marionette_host = args.value_of("marionette_host").unwrap(); - let marionette_port = match args.value_of("marionette_port") { + let marionette_host = args.get_one::("marionette_host").unwrap(); + let marionette_port = match args.get_one::("marionette_port") { Some(s) => match u16::from_str(s) { Ok(n) => Some(n), - Err(e) => usage!("invalid --marionette-port: {}", e), + Err(e) => bail!("invalid --marionette-port: {}", e), }, None => None, }; // For Android the port on the device must be the same as the one on the // host. For now default to 9222, which is the default for --remote-debugging-port. - let websocket_port = match args.value_of("websocket_port") { + let websocket_port = match args.get_one::("websocket_port") { Some(s) => match u16::from_str(s) { Ok(n) => n, - Err(e) => usage!("invalid --websocket-port: {}", e), + Err(e) => bail!("invalid --websocket-port: {}", e), }, None => 9222, }; let host = match parse_hostname(webdriver_host) { Ok(name) => name, - Err(e) => usage!("invalid --host {}: {}", webdriver_host, e), + Err(e) => bail!("invalid --host {}: {}", webdriver_host, e), }; - let allow_hosts = match get_allowed_hosts(host, args.values_of("allow_hosts")) { - Ok(hosts) => hosts, - Err(e) => usage!("invalid --allow-hosts {}", e), - }; + let allow_hosts = get_allowed_hosts(host, args.get_many("allow_hosts")); - let allow_origins = match get_allowed_origins(args.values_of("allow_origins")) { - Ok(origins) => origins, - Err(e) => usage!("invalid --allow-origins {}", e), - }; + let allow_origins = get_allowed_origins(args.get_many("allow_origins")); let address = server_address(webdriver_host, webdriver_port)?; let settings = MarionetteSettings { binary, profile_root, - connect_existing: args.is_present("connect_existing"), + connect_existing: args.get_flag("connect_existing"), host: marionette_host.into(), port: marionette_port, websocket_port, allow_hosts: allow_hosts.clone(), allow_origins: allow_origins.clone(), - jsdebugger: args.is_present("jsdebugger"), + jsdebugger: args.get_flag("jsdebugger"), android_storage, }; Ok(Operation::Server { log_level, - log_truncate: !args.is_present("log_no_truncate"), + log_truncate: !args.get_flag("log_no_truncate"), allow_hosts, allow_origins, address, settings, - deprecated_storage_arg: args.is_present("android_storage"), + deprecated_storage_arg: args.contains_id("android_storage"), }) } -fn inner_main(cmd: &mut Command) -> ProgramResult<()> { - match parse_args(cmd)? { +fn inner_main(operation: Operation, cmd: &mut Command) -> ProgramResult<()> { + match operation { Operation::Help => print_help(cmd), Operation::Version => print_version(), @@ -381,151 +306,166 @@ fn inner_main(cmd: &mut Command) -> ProgramResult<()> { Ok(()) } -fn main() { - use std::process::exit; - +fn main() -> ExitCode { let mut cmd = make_command(); - // use std::process:Termination when it graduates - exit(match inner_main(&mut cmd) { - Ok(_) => EXIT_SUCCESS, - + let args = match cmd.try_get_matches_from_mut(env::args()) { + Ok(args) => args, Err(e) => { + // Clap already says "error:" and don't repeat help. eprintln!("{}: {}", get_program_name(), e); - if !e.help_included() { - print_help(&mut cmd); - } + return ExitCode::from(EXIT_USAGE); + } + }; - e.exit_code() + let operation = match parse_args(&args) { + Ok(op) => op, + Err(e) => { + eprintln!("{}: error: {}", get_program_name(), e); + print_help(&mut cmd); + return ExitCode::from(EXIT_USAGE); } - }); + }; + + if let Err(e) = inner_main(operation, &mut cmd) { + eprintln!("{}: error: {}", get_program_name(), e); + print_help(&mut cmd); + return ExitCode::from(EXIT_UNAVAILABLE); + } + + ExitCode::SUCCESS } -fn make_command<'a>() -> Command<'a> { +fn make_command() -> Command { Command::new(format!("geckodriver {}", build::build_info())) - .setting(AppSettings::NoAutoHelp) - .setting(AppSettings::NoAutoVersion) + .disable_help_flag(true) + .disable_version_flag(true) .about("WebDriver implementation for Firefox") .arg( - Arg::new("webdriver_host") - .long("host") - .takes_value(true) - .value_name("HOST") - .default_value("127.0.0.1") - .help("Host IP to use for WebDriver server"), + Arg::new("allow_hosts") + .long("allow-hosts") + .num_args(1..) + .value_parser(clap::builder::ValueParser::new(Host::parse)) + .value_name("ALLOW_HOSTS") + .help("List of hostnames to allow. By default the value of --host is allowed, and in addition if that's a well known local address, other variations on well known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed."), ) .arg( - Arg::new("webdriver_port") - .short('p') - .long("port") - .takes_value(true) - .value_name("PORT") - .default_value("4444") - .help("Port to use for WebDriver server"), + Arg::new("allow_origins") + .long("allow-origins") + .num_args(1..) + .value_parser(clap::builder::ValueParser::new(Url::parse)) + .value_name("ALLOW_ORIGINS") + .help("List of request origins to allow. These must be formatted as scheme://host:port. By default any request with an origin header is rejected. If --allow-origins is provided then only exactly those origins are allowed."), + ) + .arg( + Arg::new("android_storage") + .long("android-storage") + .value_parser(["auto", "app", "internal", "sdcard"]) + .value_name("ANDROID_STORAGE") + .help("Selects storage location to be used for test data (deprecated)."), ) .arg( Arg::new("binary") .short('b') .long("binary") - .takes_value(true) + .num_args(1) .value_name("BINARY") .help("Path to the Firefox binary"), ) - .arg( - Arg::new("marionette_host") - .long("marionette-host") - .takes_value(true) - .value_name("HOST") - .default_value("127.0.0.1") - .help("Host to use to connect to Gecko"), - ) - .arg( - Arg::new("marionette_port") - .long("marionette-port") - .takes_value(true) - .value_name("PORT") - .help("Port to use to connect to Gecko [default: system-allocated port]"), - ) - .arg( - Arg::new("websocket_port") - .long("websocket-port") - .takes_value(true) - .value_name("PORT") - .conflicts_with("connect_existing") - .help("Port to use to connect to WebDriver BiDi [default: 9222]"), - ) .arg( Arg::new("connect_existing") .long("connect-existing") .requires("marionette_port") + .action(ArgAction::SetTrue) .help("Connect to an existing Firefox instance"), ) + .arg( + Arg::new("help") + .short('h') + .long("help") + .action(ArgAction::SetTrue) + .help("Prints this message"), + ) + .arg( + Arg::new("webdriver_host") + .long("host") + .num_args(1) + .value_name("HOST") + .default_value("127.0.0.1") + .help("Host IP to use for WebDriver server"), + ) .arg( Arg::new("jsdebugger") .long("jsdebugger") + .action(ArgAction::SetTrue) .help("Attach browser toolbox debugger for Firefox"), ) - .arg( - Arg::new("verbosity") - .multiple_occurrences(true) - .conflicts_with("log_level") - .short('v') - .help("Log level verbosity (-v for debug and -vv for trace level)"), - ) .arg( Arg::new("log_level") .long("log") - .takes_value(true) + .num_args(1) .value_name("LEVEL") - .possible_values(["fatal", "error", "warn", "info", "config", "debug", "trace"]) + .value_parser(["fatal", "error", "warn", "info", "config", "debug", "trace"]) .help("Set Gecko log level"), ) .arg( Arg::new("log_no_truncate") .long("log-no-truncate") + .action(ArgAction::SetTrue) .help("Disable truncation of long log lines"), ) .arg( - Arg::new("help") - .short('h') - .long("help") - .help("Prints this message"), + Arg::new("marionette_host") + .long("marionette-host") + .num_args(1) + .value_name("HOST") + .default_value("127.0.0.1") + .help("Host to use to connect to Gecko"), ) .arg( - Arg::new("version") - .short('V') - .long("version") - .help("Prints version and copying information"), + Arg::new("marionette_port") + .long("marionette-port") + .num_args(1) + .value_name("PORT") + .help("Port to use to connect to Gecko [default: system-allocated port]"), + ) + .arg( + Arg::new("webdriver_port") + .short('p') + .long("port") + .num_args(1) + .value_name("PORT") + .default_value("4444") + .help("Port to use for WebDriver server"), ) .arg( Arg::new("profile_root") .long("profile-root") - .takes_value(true) + .num_args(1) .value_name("PROFILE_ROOT") .help("Directory in which to create profiles. Defaults to the system temporary directory."), ) .arg( - Arg::new("android_storage") - .long("android-storage") - .possible_values(["auto", "app", "internal", "sdcard"]) - .value_name("ANDROID_STORAGE") - .help("Selects storage location to be used for test data (deprecated)."), + Arg::new("verbosity") + .conflicts_with("log_level") + .short('v') + .action(ArgAction::Count) + .help("Log level verbosity (-v for debug and -vv for trace level)"), ) .arg( - Arg::new("allow_hosts") - .long("allow-hosts") - .takes_value(true) - .multiple_values(true) - .value_name("ALLOW_HOSTS") - .help("List of hostnames to allow. By default the value of --host is allowed, and in addition if that's a well known local address, other variations on well known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed."), + Arg::new("version") + .short('V') + .long("version") + .action(ArgAction::SetTrue) + .help("Prints version and copying information"), ) .arg( - Arg::new("allow_origins") - .long("allow-origins") - .takes_value(true) - .multiple_values(true) - .value_name("ALLOW_ORIGINS") - .help("List of request origins to allow. These must be formatted as scheme://host:port. By default any request with an origin header is rejected. If --allow-origins is provided then only exactly those origins are allowed."), + Arg::new("websocket_port") + .long("websocket-port") + .num_args(1) + .value_name("PORT") + .conflicts_with("connect_existing") + .help("Port to use to connect to WebDriver BiDi [default: 9222]"), ) } diff --git a/src/marionette.rs b/src/marionette.rs index 836382b..063fcc2 100644 --- a/src/marionette.rs +++ b/src/marionette.rs @@ -17,11 +17,16 @@ use marionette_rs::common::{ use marionette_rs::marionette::AppStatus; use marionette_rs::message::{Command, Message, MessageId, Request}; use marionette_rs::webdriver::{ - Command as MarionetteWebDriverCommand, Keys as MarionetteKeys, Locator as MarionetteLocator, - NewWindow as MarionetteNewWindow, PrintMargins as MarionettePrintMargins, - PrintOrientation as MarionettePrintOrientation, PrintPage as MarionettePrintPage, + AuthenticatorParameters as MarionetteAuthenticatorParameters, + AuthenticatorTransport as MarionetteAuthenticatorTransport, + Command as MarionetteWebDriverCommand, CredentialParameters as MarionetteCredentialParameters, + Keys as MarionetteKeys, Locator as MarionetteLocator, NewWindow as MarionetteNewWindow, + PrintMargins as MarionettePrintMargins, PrintOrientation as MarionettePrintOrientation, + PrintPage as MarionettePrintPage, PrintPageRange as MarionettePrintPageRange, PrintParameters as MarionettePrintParameters, ScreenshotOptions, Script as MarionetteScript, - Selector as MarionetteSelector, Url as MarionetteUrl, WindowRect as MarionetteWindowRect, + Selector as MarionetteSelector, Url as MarionetteUrl, + UserVerificationParameters as MarionetteUserVerificationParameters, + WebAuthnProtocol as MarionetteWebAuthnProtocol, WindowRect as MarionetteWindowRect, }; use mozdevice::AndroidStorageInput; use serde::de::{self, Deserialize, Deserializer}; @@ -49,18 +54,22 @@ use webdriver::command::WebDriverCommand::{ GetWindowRect, GoBack, GoForward, IsDisplayed, IsEnabled, IsSelected, MaximizeWindow, MinimizeWindow, NewSession, NewWindow, PerformActions, Print, Refresh, ReleaseActions, SendAlertText, SetTimeouts, SetWindowRect, Status, SwitchToFrame, SwitchToParentFrame, - SwitchToWindow, TakeElementScreenshot, TakeScreenshot, + SwitchToWindow, TakeElementScreenshot, TakeScreenshot, WebAuthnAddCredential, + WebAuthnAddVirtualAuthenticator, WebAuthnGetCredentials, WebAuthnRemoveAllCredentials, + WebAuthnRemoveCredential, WebAuthnRemoveVirtualAuthenticator, WebAuthnSetUserVerified, }; use webdriver::command::{ - ActionsParameters, AddCookieParameters, GetNamedCookieParameters, GetParameters, - JavascriptCommandParameters, LocatorParameters, NewSessionParameters, NewWindowParameters, - PrintMargins, PrintOrientation, PrintPage, PrintParameters, SendKeysParameters, - SwitchToFrameParameters, SwitchToWindowParameters, TimeoutsParameters, WindowRectParameters, + ActionsParameters, AddCookieParameters, AuthenticatorParameters, AuthenticatorTransport, + GetNamedCookieParameters, GetParameters, JavascriptCommandParameters, LocatorParameters, + NewSessionParameters, NewWindowParameters, PrintMargins, PrintOrientation, PrintPage, + PrintPageRange, PrintParameters, SendKeysParameters, SwitchToFrameParameters, + SwitchToWindowParameters, TimeoutsParameters, UserVerificationParameters, WebAuthnProtocol, + WindowRectParameters, }; use webdriver::command::{WebDriverCommand, WebDriverMessage}; use webdriver::common::{ - Cookie, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, ELEMENT_KEY, FRAME_KEY, - SHADOW_KEY, WINDOW_KEY, + Cookie, CredentialParameters, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, + ELEMENT_KEY, FRAME_KEY, SHADOW_KEY, WINDOW_KEY, }; use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; use webdriver::response::{ @@ -447,7 +456,14 @@ impl MarionetteSession { | GetAlertText | TakeScreenshot | Print(_) - | TakeElementScreenshot(_) => { + | TakeElementScreenshot(_) + | WebAuthnAddVirtualAuthenticator(_) + | WebAuthnRemoveVirtualAuthenticator + | WebAuthnAddCredential(_) + | WebAuthnGetCredentials + | WebAuthnRemoveCredential + | WebAuthnRemoveAllCredentials + | WebAuthnSetUserVerified(_) => { WebDriverResponse::Generic(resp.into_value_response(true)?) } GetTimeouts => { @@ -949,6 +965,27 @@ fn try_convert_to_marionette_message( Print(ref x) => Some(Command::WebDriver(MarionetteWebDriverCommand::Print( x.to_marionette()?, ))), + WebAuthnAddVirtualAuthenticator(ref x) => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnAddVirtualAuthenticator(x.to_marionette()?), + )), + WebAuthnRemoveVirtualAuthenticator => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnRemoveVirtualAuthenticator, + )), + WebAuthnAddCredential(ref x) => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnAddCredential(x.to_marionette()?), + )), + WebAuthnGetCredentials => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnGetCredentials, + )), + WebAuthnRemoveCredential => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnRemoveCredential, + )), + WebAuthnRemoveAllCredentials => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnRemoveAllCredentials, + )), + WebAuthnSetUserVerified(ref x) => Some(Command::WebDriver( + MarionetteWebDriverCommand::WebAuthnSetUserVerified(x.to_marionette()?), + )), Refresh => Some(Command::WebDriver(MarionetteWebDriverCommand::Refresh)), ReleaseActions => Some(Command::WebDriver( MarionetteWebDriverCommand::ReleaseActions, @@ -1432,7 +1469,11 @@ impl ToMarionette for PrintParameters { background: self.background, page: self.page.to_marionette()?, margin: self.margin.to_marionette()?, - page_ranges: self.page_ranges.clone(), + page_ranges: self + .page_ranges + .iter() + .map(|x| x.to_marionette()) + .collect::>>()?, shrink_to_fit: self.shrink_to_fit, }) } @@ -1456,6 +1497,15 @@ impl ToMarionette for PrintPage { } } +impl ToMarionette for PrintPageRange { + fn to_marionette(&self) -> WebDriverResult { + Ok(match self { + PrintPageRange::Integer(num) => MarionettePrintPageRange::Integer(*num), + PrintPageRange::Range(range) => MarionettePrintPageRange::Range(range.clone()), + }) + } +} + impl ToMarionette for PrintMargins { fn to_marionette(&self) -> WebDriverResult { Ok(MarionettePrintMargins { @@ -1467,6 +1517,63 @@ impl ToMarionette for PrintMargins { } } +impl ToMarionette for AuthenticatorParameters { + fn to_marionette(&self) -> WebDriverResult { + Ok(MarionetteAuthenticatorParameters { + protocol: self.protocol.to_marionette()?, + transport: self.transport.to_marionette()?, + has_resident_key: self.has_resident_key, + has_user_verification: self.has_user_verification, + is_user_consenting: self.is_user_consenting, + is_user_verified: self.is_user_verified, + }) + } +} + +impl ToMarionette for AuthenticatorTransport { + fn to_marionette(&self) -> WebDriverResult { + Ok(match self { + AuthenticatorTransport::Usb => MarionetteAuthenticatorTransport::Usb, + AuthenticatorTransport::Nfc => MarionetteAuthenticatorTransport::Nfc, + AuthenticatorTransport::Ble => MarionetteAuthenticatorTransport::Ble, + AuthenticatorTransport::SmartCard => MarionetteAuthenticatorTransport::SmartCard, + AuthenticatorTransport::Hybrid => MarionetteAuthenticatorTransport::Hybrid, + AuthenticatorTransport::Internal => MarionetteAuthenticatorTransport::Internal, + }) + } +} + +impl ToMarionette for CredentialParameters { + fn to_marionette(&self) -> WebDriverResult { + Ok(MarionetteCredentialParameters { + credential_id: self.credential_id.clone(), + is_resident_credential: self.is_resident_credential, + rp_id: self.rp_id.clone(), + private_key: self.private_key.clone(), + user_handle: self.user_handle.clone(), + sign_count: self.sign_count, + }) + } +} + +impl ToMarionette for UserVerificationParameters { + fn to_marionette(&self) -> WebDriverResult { + Ok(MarionetteUserVerificationParameters { + is_user_verified: self.is_user_verified, + }) + } +} + +impl ToMarionette for WebAuthnProtocol { + fn to_marionette(&self) -> WebDriverResult { + Ok(match self { + WebAuthnProtocol::Ctap1U2f => MarionetteWebAuthnProtocol::Ctap1U2f, + WebAuthnProtocol::Ctap2 => MarionetteWebAuthnProtocol::Ctap2, + WebAuthnProtocol::Ctap2_1 => MarionetteWebAuthnProtocol::Ctap2_1, + }) + } +} + impl ToMarionette> for ActionsParameters { fn to_marionette(&self) -> WebDriverResult> { Ok(try_opt!( diff --git a/src/prefs.rs b/src/prefs.rs index d3c874c..7e8f0df 100644 --- a/src/prefs.rs +++ b/src/prefs.rs @@ -32,13 +32,6 @@ lazy_static! { ("browser.dom.window.dump.enabled", Pref::new(true)), ("devtools.console.stdout.chrome", Pref::new(true)), - // Disable safebrowsing components - ("browser.safebrowsing.blockedURIs.enabled", Pref::new(false)), - ("browser.safebrowsing.downloads.enabled", Pref::new(false)), - ("browser.safebrowsing.passwords.enabled", Pref::new(false)), - ("browser.safebrowsing.malware.enabled", Pref::new(false)), - ("browser.safebrowsing.phishing.enabled", Pref::new(false)), - // Do not restore the last open set of tabs if the browser crashed ("browser.sessionstore.resume_from_crash", Pref::new(false)), @@ -118,16 +111,11 @@ lazy_static! { // Make sure SNTP requests do not hit the network ("network.sntp.pools", Pref::new("%(server)s")), - // Disable Flash. The plugin container it is run in is - // causing problems when quitting Firefox from geckodriver, - // c.f. https://github.com/mozilla/geckodriver/issues/225. - ("plugin.state.flash", Pref::new(0)), - // Don't do network connections for mitm priming ("security.certerrors.mitm.priming.enabled", Pref::new(false)), - // Ensure blocklist updates don't hit the network - ("services.settings.server", Pref::new("")), + // Ensure remote settings do not hit the network + ("services.settings.server", Pref::new("data:,#remote-settings-dummy/v1")), // Disable first run pages ("startup.homepage_welcome_url", Pref::new("about:blank")), @@ -137,12 +125,18 @@ lazy_static! { ("browser.newtabpage.activity-stream.asrouter.providers.cfr", Pref::new("null")), // TODO: Remove once minimum supported Firefox release is 93. ("browser.newtabpage.activity-stream.asrouter.providers.cfr-fxa", Pref::new("null")), + + // TODO: Remove once minimum supported Firefox release is 128. ("browser.newtabpage.activity-stream.asrouter.providers.snippets", Pref::new("null")), + ("browser.newtabpage.activity-stream.asrouter.providers.message-groups", Pref::new("null")), ("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", Pref::new("null")), ("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", Pref::new("null")), ("browser.newtabpage.activity-stream.feeds.system.topstories", Pref::new(false)), + + // TODO: Remove once minimum supported Firefox release is 128. ("browser.newtabpage.activity-stream.feeds.snippets", Pref::new(false)), + ("browser.newtabpage.activity-stream.tippyTop.service.endpoint", Pref::new("")), ("browser.newtabpage.activity-stream.discoverystream.config", Pref::new("[]")),