tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit e285c7f3d366a63e6fd365ccc346ef9e3aeb4184
parent 57129f85b8b10593c4ce23a1eaf62604bccae7bd
Author: Johannes Schmidt <joschmidt@mozilla.com>
Date:   Thu,  2 Oct 2025 08:12:32 +0000

Bug 1966326 - use rust logins: vendor rust and generate uniffi r=supply-chain-reviewers,markh

These are the build artefacts from the previously configured application
sevrices components, split out for easier review. It's the result of
both `./mach vendor rust` and `./mach uniffi generate` commands.

Differential Revision: https://phabricator.services.mozilla.com/D260122

Diffstat:
MCargo.lock | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adocs/rust-components/api/js/init_rust_components.md | 3+++
Adocs/rust-components/api/js/logins.md | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msupply-chain/audits.toml | 2+-
Msupply-chain/config.toml | 1-
Msupply-chain/imports.lock | 7+++++++
Athird_party/rust/base16/.cargo-checksum.json | 2++
Athird_party/rust/base16/CHANGELOG.md | 35+++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/Cargo.toml | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/LICENSE-CC0 | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/README.md | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/benches/bench.rs | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/src/lib.rs | 639+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/tests/doctest_copies.rs | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/base16/tests/tests.rs | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/.cargo-checksum.json | 2++
Athird_party/rust/hawk/CHANGELOG.md | 45+++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/CODE_OF_CONDUCT.md | 15+++++++++++++++
Athird_party/rust/hawk/CONTRIBUTING.md | 28++++++++++++++++++++++++++++
Athird_party/rust/hawk/Cargo.toml | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/LICENSE | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/README.md | 4++++
Athird_party/rust/hawk/build.rs | 7+++++++
Athird_party/rust/hawk/clippy.toml | 2++
Athird_party/rust/hawk/src/b64.rs | 19+++++++++++++++++++
Athird_party/rust/hawk/src/bewit.rs | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/credentials.rs | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/crypto/holder.rs | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/crypto/mod.rs | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/crypto/openssl.rs | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/crypto/ring.rs | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/error.rs | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/header.rs | 472+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/lib.rs | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/mac.rs | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/payload.rs | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/request.rs | 954+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/hawk/src/response.rs | 307+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/init_rust_components/.cargo-checksum.json | 2++
Athird_party/rust/init_rust_components/Cargo.toml | 38++++++++++++++++++++++++++++++++++++++
Athird_party/rust/init_rust_components/README.md | 24++++++++++++++++++++++++
Athird_party/rust/init_rust_components/src/lib.rs | 37+++++++++++++++++++++++++++++++++++++
Athird_party/rust/init_rust_components/uniffi.toml | 6++++++
Athird_party/rust/jwcrypto/.cargo-checksum.json | 2++
Athird_party/rust/jwcrypto/Cargo.toml | 45+++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/aes.rs | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/direct.rs | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/ec.rs | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/encdec.rs | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/error.rs | 29+++++++++++++++++++++++++++++
Athird_party/rust/jwcrypto/src/lib.rs | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/.cargo-checksum.json | 2++
Athird_party/rust/logins/Cargo.toml | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/README.md | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/build.rs | 8++++++++
Athird_party/rust/logins/fixtures/profile/.gitignore | 1+
Athird_party/rust/logins/fixtures/profile/README.md | 6++++++
Athird_party/rust/logins/fixtures/profile/key4.db | 0
Athird_party/rust/logins/metrics.yaml | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/db.rs | 1896+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/encryption.rs | 504+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/error.rs | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/lib.rs | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/login.rs | 1299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/logins.udl | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/schema.rs | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/store.rs | 548+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/sync/engine.rs | 1188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/sync/merge.rs | 432+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/sync/mod.rs | 19+++++++++++++++++++
Athird_party/rust/logins/src/sync/payload.rs | 436+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/sync/update_plan.rs | 653+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/src/util.rs | 40++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/logins/uniffi.toml | 6++++++
Athird_party/rust/nss/.cargo-checksum.json | 2++
Athird_party/rust/nss/Cargo.toml | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/README.md | 21+++++++++++++++++++++
Athird_party/rust/nss/src/aes.rs | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/cert.rs | 43+++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/ec.rs | 422+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/ecdh.rs | 46++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/error.rs | 38++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/lib.rs | 23+++++++++++++++++++++++
Athird_party/rust/nss/src/pbkdf2.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/pk11/context.rs | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/pk11/mod.rs | 8++++++++
Athird_party/rust/nss/src/pk11/slot.rs | 32++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/pk11/sym_key.rs | 277+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/pk11/types.rs | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/pkixc.rs | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss/src/secport.rs | 24++++++++++++++++++++++++
Athird_party/rust/nss/src/util.rs | 282+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_build_common/.cargo-checksum.json | 2++
Athird_party/rust/nss_build_common/Cargo.toml | 30++++++++++++++++++++++++++++++
Athird_party/rust/nss_build_common/src/lib.rs | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/.cargo-checksum.json | 2++
Athird_party/rust/nss_sys/Cargo.toml | 45+++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/README.md | 18++++++++++++++++++
Athird_party/rust/nss_sys/build.rs | 7+++++++
Athird_party/rust/nss_sys/src/bindings/blapit.rs | 10++++++++++
Athird_party/rust/nss_sys/src/bindings/certdb.rs | 24++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/keyhi.rs | 12++++++++++++
Athird_party/rust/nss_sys/src/bindings/keythi.rs | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/mod.rs | 44++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/nss.rs | 29+++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/pk11pub.rs | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/pkcs11n.rs | 32++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/pkcs11t.rs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/pkixc.rs | 18++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/plarena.rs | 22++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/prerror.rs | 14++++++++++++++
Athird_party/rust/nss_sys/src/bindings/prtypes.rs | 13+++++++++++++
Athird_party/rust/nss_sys/src/bindings/secasn1t.rs | 5+++++
Athird_party/rust/nss_sys/src/bindings/seccomon.rs | 43+++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/secitem.rs | 9+++++++++
Athird_party/rust/nss_sys/src/bindings/seckey.rs | 9+++++++++
Athird_party/rust/nss_sys/src/bindings/secmodt.rs | 33+++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/secoid.rs | 10++++++++++
Athird_party/rust/nss_sys/src/bindings/secoidt.rs | 401+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/nss_sys/src/bindings/secport.rs | 13+++++++++++++
Athird_party/rust/nss_sys/src/lib.rs | 16++++++++++++++++
Athird_party/rust/rc_crypto/.cargo-checksum.json | 2++
Athird_party/rust/rc_crypto/Cargo.toml | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/README.md | 27+++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/aead.rs | 324+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/aead/aes_cbc.rs | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/aead/aes_gcm.rs | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/agreement.rs | 417+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/constant_time.rs | 48++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/contentsignature.rs | 430+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/digest.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/ece_crypto.rs | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/error.rs | 38++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/hawk_crypto.rs | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/hkdf.rs | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/hmac.rs | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/lib.rs | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/pbkdf2.rs | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/rand.rs | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/rc_crypto/src/signature.rs | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustInitRustComponents.sys.mjs | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustLogins.sys.mjs | 3668+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs | 26+++++++++++++-------------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs | 40++++++++++++++++++++--------------------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs | 16++++++++--------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs | 60++++++++++++++++++++++++++++++------------------------------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs | 62+++++++++++++++++++++++++++++++-------------------------------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTracing.sys.mjs | 10+++++-----
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustViaduct.sys.mjs | 12++++++------
Mtoolkit/components/uniffi-bindgen-gecko-js/components/generated/RustWebextstorage.sys.mjs | 54+++++++++++++++++++++++++++---------------------------
Mtoolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTests.sys.mjs | 196++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtoolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsCollision.sys.mjs | 4++--
Mtoolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsExternalTypes.sys.mjs | 8++++----
Mtoolkit/components/uniffi-js/GeneratedScaffolding.cpp | 12647+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
154 files changed, 32867 insertions(+), 4989 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -394,6 +394,12 @@ name = "backtrace" version = "0.3.999" [[package]] +name = "base16" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" + +[[package]] name = "base64" version = "0.21.999" dependencies = [ @@ -2673,6 +2679,8 @@ dependencies = [ "context_id", "error-support", "filter_adult", + "init_rust_components", + "logins", "relevancy", "search", "suggest", @@ -2951,6 +2959,20 @@ dependencies = [ ] [[package]] +name = "hawk" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302457b3e28e621daab18932d67a67328f29240bfaa5f604b7627ece1eacda" +dependencies = [ + "anyhow", + "base64 0.22.1", + "log", + "once_cell", + "thiserror 1.999.999", + "url", +] + +[[package]] name = "headers" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3386,6 +3408,15 @@ dependencies = [ ] [[package]] +name = "init_rust_components" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "nss", + "uniffi", +] + +[[package]] name = "interrupt-support" version = "0.1.0" source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" @@ -3566,6 +3597,20 @@ dependencies = [ ] [[package]] +name = "jwcrypto" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "base64 0.21.999", + "error-support", + "rc_crypto", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.12", +] + +[[package]] name = "keccak" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3876,6 +3921,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] +name = "logins" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "anyhow", + "async-trait", + "error-support", + "futures", + "interrupt-support", + "jwcrypto", + "lazy_static", + "nss", + "parking_lot", + "rusqlite 0.37.0", + "serde", + "serde_derive", + "serde_json", + "sql-support", + "sync-guid", + "sync15", + "thiserror 2.0.12", + "uniffi", + "url", +] + +[[package]] name = "mach2" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4898,6 +4969,20 @@ dependencies = [ ] [[package]] +name = "nss" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "base64 0.21.999", + "error-support", + "nss_sys", + "once_cell", + "serde", + "serde_derive", + "thiserror 2.0.12", +] + +[[package]] name = "nss-gk-api" version = "0.3.0" source = "git+https://github.com/beurdouche/nss-gk-api?rev=e48a946811ffd64abc78de3ee284957d8d1c0d63#e48a946811ffd64abc78de3ee284957d8d1c0d63" @@ -4913,6 +4998,20 @@ dependencies = [ ] [[package]] +name = "nss_build_common" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" + +[[package]] +name = "nss_sys" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "libsqlite3-sys", + "nss_build_common", +] + +[[package]] name = "nsstring" version = "0.1.0" dependencies = [ @@ -5689,6 +5788,19 @@ dependencies = [ ] [[package]] +name = "rc_crypto" +version = "0.1.0" +source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" +dependencies = [ + "base64 0.21.999", + "error-support", + "hawk", + "hex", + "nss", + "thiserror 2.0.12", +] + +[[package]] name = "redox_syscall" version = "0.5.999" @@ -6609,10 +6721,13 @@ version = "0.1.0" source = "git+https://github.com/mozilla/application-services?rev=f6f667f590ac15367fc37eb1ad3a6bdea4ffc526#f6f667f590ac15367fc37eb1ad3a6bdea4ffc526" dependencies = [ "anyhow", + "base16", + "base64 0.21.999", "error-support", "interrupt-support", "lazy_static", "payload-support", + "rc_crypto", "serde", "serde_derive", "serde_json", @@ -6620,6 +6735,8 @@ dependencies = [ "sync-guid", "thiserror 2.0.12", "uniffi", + "url", + "viaduct", ] [[package]] diff --git a/docs/rust-components/api/js/init_rust_components.md b/docs/rust-components/api/js/init_rust_components.md @@ -0,0 +1,3 @@ +# RustInitRustComponents.sys.mjs +```{js:autofunction} RustInitRustComponents.sys.initialize +``` diff --git a/docs/rust-components/api/js/logins.md b/docs/rust-components/api/js/logins.md @@ -0,0 +1,103 @@ +# RustLogins.sys.mjs +```{js:autoclass} RustLogins.sys.AuthenticationCanceled + :members: + :exclude-members: AuthenticationCanceled +``` +```{js:autoclass} RustLogins.sys.AuthenticationError + :members: + :exclude-members: AuthenticationError +``` +```{js:autoclass} RustLogins.sys.BulkResultEntry + :members: + :exclude-members: BulkResultEntry +``` +```{js:autoclass} RustLogins.sys.DecryptionFailed + :members: + :exclude-members: DecryptionFailed +``` +```{js:autoclass} RustLogins.sys.EncryptionFailed + :members: + :exclude-members: EncryptionFailed +``` +```{js:autoclass} RustLogins.sys.Interrupted + :members: + :exclude-members: Interrupted +``` +```{js:autoclass} RustLogins.sys.InvalidKey + :members: + :exclude-members: InvalidKey +``` +```{js:autoclass} RustLogins.sys.InvalidRecord + :members: + :exclude-members: InvalidRecord +``` +```{js:autoclass} RustLogins.sys.Login + :members: + :exclude-members: Login +``` +```{js:autoclass} RustLogins.sys.LoginEntry + :members: + :exclude-members: LoginEntry +``` +```{js:autoclass} RustLogins.sys.LoginEntryWithMeta + :members: + :exclude-members: LoginEntryWithMeta +``` +```{js:autoclass} RustLogins.sys.LoginMeta + :members: + :exclude-members: LoginMeta +``` +```{js:autoclass} RustLogins.sys.LoginsApiError + :members: + :exclude-members: LoginsApiError +``` +```{js:autoclass} RustLogins.sys.LoginsDeletionMetrics + :members: + :exclude-members: LoginsDeletionMetrics +``` +```{js:autoclass} RustLogins.sys.MissingKey + :members: + :exclude-members: MissingKey +``` +```{js:autoclass} RustLogins.sys.NoSuchRecord + :members: + :exclude-members: NoSuchRecord +``` +```{js:autoclass} RustLogins.sys.NssAuthenticationError + :members: + :exclude-members: NssAuthenticationError +``` +```{js:autoclass} RustLogins.sys.NssKeyManager + :members: + :exclude-members: NssKeyManager +``` +```{js:autoclass} RustLogins.sys.NssUninitialized + :members: + :exclude-members: NssUninitialized +``` +```{js:autoclass} RustLogins.sys.PrimaryPasswordAuthenticator + :members: + :exclude-members: PrimaryPasswordAuthenticator +``` +```{js:autoclass} RustLogins.sys.SyncAuthInvalid + :members: + :exclude-members: SyncAuthInvalid +``` +```{js:autoclass} RustLogins.sys.UnexpectedLoginsApiError + :members: + :exclude-members: UnexpectedLoginsApiError +``` +```{js:autofunction} RustLogins.sys.checkCanary +``` +```{js:autofunction} RustLogins.sys.createCanary +``` +```{js:autofunction} RustLogins.sys.createKey +``` +```{js:autofunction} RustLogins.sys.createLoginStoreWithNssKeymanager +``` +```{js:autofunction} RustLogins.sys.createLoginStoreWithStaticKeyManager +``` +```{js:autofunction} RustLogins.sys.createManagedEncdec +``` +```{js:autofunction} RustLogins.sys.createStaticKeyManager +``` diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml @@ -315,7 +315,7 @@ end = "2025-08-30" [[wildcard-audits.hawk]] who = "Ryan Safaeian <rsafaeian@mozilla.com>" criteria = "safe-to-deploy" -user-id = 158511 +user-id = 158511 # Yarik (lotas) start = "2022-05-05" end = "2026-04-24" notes = "Hawk is written and maintained by mozilla employees." diff --git a/supply-chain/config.toml b/supply-chain/config.toml @@ -181,7 +181,6 @@ audit-as-crates-io = false [policy.mtu] audit-as-crates-io = true -notes = "This is a first-party crate which is also published to crates.io, but since <https://github.com/mozilla/neqo/pull/2897> part of <https://github.com/mozilla/neqo>." [policy.naga] audit-as-crates-io = true diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock @@ -302,6 +302,13 @@ user-id = 2915 user-login = "Amanieu" user-name = "Amanieu d'Antras" +[[publisher.hawk]] +version = "5.0.1" +when = "2024-09-13" +user-id = 158511 +user-login = "lotas" +user-name = "Yarik" + [[publisher.headers]] version = "0.3.9" when = "2023-08-31" diff --git a/third_party/rust/base16/.cargo-checksum.json b/third_party/rust/base16/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"fe5fc3587d67ecbe1f26f917e448120b163c88dd2f770fd057215965a23fb318","Cargo.toml":"2d899ced4d3d938d5f4ecfba787b4443787d24d474e4511beeed6ae565bfa1c3","LICENSE-CC0":"a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499","README.md":"66ce64772ee5fd96c954a1d8ae5679c684f5dbdb2c8bf29e09bac1158c089e1e","benches/bench.rs":"df402e28f2b0ea63ba725cf20db57307e1ebfadc3120d8af6193f30c5db0dd14","src/lib.rs":"2bd2cf157991c5d79a85d4a095294f60ee238956922518fe3a35953be8197812","tests/doctest_copies.rs":"b274efd7a8a95e5a7d9d4e59eacb0458329343169628f389c7d867bc39846524","tests/tests.rs":"6f93802e5eb447966bbe154707ff552a251a30653e955902f04669af7eecd6f2"},"package":"d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8"} +\ No newline at end of file diff --git a/third_party/rust/base16/CHANGELOG.md b/third_party/rust/base16/CHANGELOG.md @@ -0,0 +1,35 @@ +# 0.2.0 + +- `encode_byte` now returns `[u8; 2]` instead of `(u8, u8)`, as in practice this + tends to be more convenient. + +- The use of `std` which requires the `alloc` trait has been split into the + `alloc` feature. + +- `base16` has been relicensed as CC0-1.0 from dual MIT/Apache-2.0. + +# 0.2.1 + +- Make code more bulletproof in the case of panics when using the `decode_buf` + or `encode_config_buf` functions. + + Previously, if the innermost encode/decode function paniced, code that + inspected the contents of the Vec (either in a Drop implementation, or by + catching the panic) could read from uninitialized memory. + + However, I don't believe it is possible for the innermost encode/decode + functions to panic, so I don't think there was any risk in previous + versions. + + I don't believe the panic is possible because only two panics exist in the generated assembly (both only in debug configuration, and not in release). The two panics are respectively: + + - a debug_assert verifying the caller performed a check (which it does). + + - a usize overflow check on an index variable, which is impossible as we've + already tested for that. + + That said, this is some powerful rationalization, so I'm cutting a new version + with this fix anyway. + +- Additionally, several functions that previously used unsafe internally now + either use less unsafe, or are entirely safe. diff --git a/third_party/rust/base16/Cargo.toml b/third_party/rust/base16/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "base16" +version = "0.2.1" +authors = ["Thom Chiovoloni <tchiovoloni@mozilla.com>"] +description = "base16 (hex) encoding and decoding" +readme = "README.md" +keywords = ["hex", "base16", "encode", "decode", "no_std"] +categories = ["encoding", "no-std"] +license = "CC0-1.0" +repository = "https://github.com/thomcc/rust-base16" +[package.metadata.docs.rs] +all-features = true + +[[bench]] +name = "bench" +harness = false + +[dependencies] +[dev-dependencies.criterion] +version = "0.2.11" + +[dev-dependencies.rand] +version = "0.6.5" + +[features] +alloc = [] +default = ["std"] +std = ["alloc"] +[badges.circle-ci] +branch = "master" +repository = "thomcc/rust-base16" + +[badges.codecov] +branch = "master" +repository = "thomcc/rust-base16" +service = "github" diff --git a/third_party/rust/base16/LICENSE-CC0 b/third_party/rust/base16/LICENSE-CC0 @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/third_party/rust/base16/README.md b/third_party/rust/base16/README.md @@ -0,0 +1,62 @@ +# [base16](https://crates.io/crates/base16) (hex) encoding for Rust. + +[![Docs](https://docs.rs/base16/badge.svg)](https://docs.rs/base16) [![CircleCI](https://circleci.com/gh/thomcc/rust-base16.svg?style=svg)](https://circleci.com/gh/thomcc/rust-base16) [![codecov](https://codecov.io/gh/thomcc/rust-base16/branch/master/graph/badge.svg)](https://codecov.io/gh/thomcc/rust-base16) + +This is a base16 (e.g. hexadecimal) encoding and decoding library which was initially written with an emphasis on performance. + +This was before Rust added SIMD, and I haven't gotten around to adding that. It's still probably the fastest non-SIMD impl. + +## Usage + +Add `base16 = "0.2"` to Cargo.toml, then: + +```rust +fn main() { + let original_msg = "Foobar"; + let hex_string = base16::encode_lower(original_msg); + assert_eq!(hex_string, "466f6f626172"); + let decoded = base16::decode(&hex_string).unwrap(); + assert_eq!(String::from_utf8(decoded).unwrap(), original_msg); +} +``` + +More usage examples in the [docs](https://docs.rs/base16). + +## `no_std` Usage + +This crate supports use in `no_std` configurations using the following knobs. + +- The `"alloc"` feature, which is on by default, adds a number of helpful functions + that require use of the [`alloc`](https://doc.rust-lang.org/alloc/index.html) crate, + but not the rest of `std`. This is `no_std` compatible. + - Each function documents if it requires use of the `alloc` feature. +- The `"std"` feature, which is on by default, enables the `"alloc"` feature, and + additionally makes `base16::DecodeError` implement the `std::error::Error` trait. + (Frustratingly, this trait is in `std` and not in `core` or `alloc`...) + +For clarity, this means that by default, we assume you are okay with use of `std`. + +If you'd like to disable the use of `std`, but are in an environment where you have +an allocator (e.g. use of the [`alloc`](https://doc.rust-lang.org/alloc/index.html) +crate is acceptable), then you require this as `alloc`-only as follows: + +```toml +[dependencies] +# Turn of use of `std` (but leave use of `alloc`). +base16 = { version = "0.2", default-features = false, features = ["alloc"] } +``` + +If you just want the core `base16` functionality and none of the helpers, then +you should turn off all features. + +```toml +[dependencies] +# Turn of use of `std` and `alloc`. +base16 = { version = "0.2", default-features = false } +``` + +Both of these configurations are `no_std` compatible. + +# License + +Public domain, as explained [here](https://creativecommons.org/publicdomain/zero/1.0/legalcode) diff --git a/third_party/rust/base16/benches/bench.rs b/third_party/rust/base16/benches/bench.rs @@ -0,0 +1,145 @@ +#![allow(unknown_lints)] + +use criterion::{criterion_group, criterion_main, Criterion, BatchSize, Throughput, ParameterizedBenchmark}; +use rand::prelude::*; + + +const SIZES: &[usize] = &[3, 16, 64, 256, 1024]; + +fn rand_enc_input(sz: usize) -> (Vec<u8>, base16::EncConfig) { + let mut rng = thread_rng(); + let mut vec = vec![0u8; sz]; + let cfg = if rng.gen::<bool>() { + base16::EncodeUpper + } else { + base16::EncodeLower + }; + rng.fill_bytes(&mut vec); + (vec, cfg) +} + +fn batch_size_for_input(i: usize) -> BatchSize { + if i < 1024 { + BatchSize::SmallInput + } else { + BatchSize::LargeInput + } +} + +fn bench_encode(c: &mut Criterion) { + c.bench( + "encode to fresh string", + ParameterizedBenchmark::new( + "encode_config", + |b, items| { + b.iter_batched( + || rand_enc_input(*items), + |(input, enc)| base16::encode_config(&input, enc), + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32)), + ); + + c.bench( + "encode to preallocated string", + ParameterizedBenchmark::new( + "encode_config_buf", + |b, items| { + b.iter_batched( + || (rand_enc_input(*items), String::with_capacity(2 * *items)), + |((input, enc), mut buf)| { + buf.truncate(0); + base16::encode_config_buf(&input, enc, &mut buf) + }, + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32)), + ); + + c.bench( + "encode to slice", + ParameterizedBenchmark::new( + "encode_config_slice", + |b, items| { + b.iter_batched( + || (rand_enc_input(*items), vec![0u8; 2 * *items]), + |((input, enc), mut dst)| { + base16::encode_config_slice(&input, enc, &mut dst) + }, + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32)), + ); +} + +fn rand_hex_string(size: usize) -> String { + let mut rng = thread_rng(); + let mut s = String::with_capacity(size); + let chars: &[u8] = b"0123456789abcdefABCDEF"; + while s.len() < size { + s.push(*chars.choose(&mut rng).unwrap() as char); + } + s +} + +fn bench_decode(c: &mut Criterion) { + c.bench( + "decode to fresh vec", + ParameterizedBenchmark::new( + "decode", + |b, items| { + b.iter_batched( + || rand_hex_string(*items), + |input| base16::decode(&input), + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32 * 2)), + ); + + c.bench( + "decode to preallocated vec", + ParameterizedBenchmark::new( + "decode_buf", + |b, items| { + b.iter_batched( + || (rand_hex_string(*items), Vec::with_capacity(*items)), + |(input, mut buf)| { + buf.truncate(0); + base16::decode_buf(&input, &mut buf) + }, + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32 * 2)), + ); + + c.bench( + "decode to slice", + ParameterizedBenchmark::new( + "decode_slice", + |b, items| { + b.iter_batched( + || (rand_hex_string(*items), vec![0u8; *items]), + |(input, mut buf)| { + base16::decode_slice(&input, &mut buf) + }, + batch_size_for_input(*items), + ) + }, + SIZES.iter().cloned(), + ).throughput(|bytes| Throughput::Bytes(*bytes as u32 * 2)), + ); +} + + +criterion_group!(benches, bench_encode, bench_decode); +criterion_main!(benches); diff --git a/third_party/rust/base16/src/lib.rs b/third_party/rust/base16/src/lib.rs @@ -0,0 +1,639 @@ +//! This is a base16 (e.g. hexadecimal) encoding and decoding library with an +//! emphasis on performance. The API is very similar and inspired by the base64 +//! crate's API, however it's less complex (base16 is much more simple than +//! base64). +//! +//! # Encoding +//! +//! The config options at the moment are limited to the output case (upper vs +//! lower). +//! +//! | Function | Output | Allocates | Requires `alloc` feature | +//! | ---------------------------------- | ---------------------------- | ----------------------- | ------------------------ | +//! | [`encode_upper`], [`encode_lower`] | Returns a new `String` | Always | Yes | +//! | [`encode_config`] | Returns a new `String` | Always | Yes | +//! | [`encode_config_buf`] | Appends to provided `String` | If buffer needs to grow | Yes | +//! | [`encode_config_slice`] | Writes to provided `&[u8]` | Never | No | +//! +//! # Decoding +//! +//! Note that there are no config options (In the future one might be added to +//! restrict the input character set, but it's not clear to me that this is +//! useful). +//! +//! | Function | Output | Allocates | Requires `alloc` feature | +//! | ----------------- | ----------------------------- | ----------------------- | ------------------------ | +//! | [`decode`] | Returns a new `Vec<u8>` | Always | Yes | +//! | [`decode_slice`] | Writes to provided `&[u8]` | Never | No | +//! | [`decode_buf`] | Appends to provided `Vec<u8>` | If buffer needs to grow | Yes | +//! +//! # Features +//! +//! This crate has two features, both are enabled by default and exist to allow +//! users in `no_std` environments to disable various portions of . +//! +//! - The `"alloc"` feature, which is on by default, adds a number of helpful +//! functions that require use of the [`alloc`][alloc_crate] crate, but not the +//! rest of `std`. +//! - This is `no_std` compatible. +//! - Each function should list whether or not it requires this feature +//! under the `Availability` of its documentation. +//! +//! - The `"std"` feature, which is on by default, enables the `"alloc"` +//! feature, and additionally makes [`DecodeError`] implement the +//! `std::error::Error` trait. +//! +//! - Frustratingly, this trait is in `std` (and not in `core` or `alloc`), +//! but not implementing it would be quite annoying for some users, so +//! it's kept, even though it's what prevents us from being `no_std` +//! compatible in all configurations. +//! +//! [alloc_crate]: https://doc.rust-lang.org/alloc/index.html + +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::{vec::Vec, string::String}; + +/// Configuration options for encoding. Just specifies whether or not output +/// should be uppercase or lowercase. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum EncConfig { + /// Encode using lower case characters for hex values >= 10 + EncodeLower, + /// Encode using upper case characters for hex values >= 10 + EncodeUpper, +} + +pub use EncConfig::*; + +#[inline] +fn encoded_size(source_len: usize) -> usize { + const USIZE_TOP_BIT: usize = 1usize << (core::mem::size_of::<usize>() * 8 - 1); + if (source_len & USIZE_TOP_BIT) != 0 { + usize_overflow(source_len) + } + source_len << 1 +} + +#[inline] +fn encode_slice_raw(src: &[u8], cfg: EncConfig, dst: &mut [u8]) { + let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER }; + debug_assert!(dst.len() == encoded_size(src.len())); + dst.chunks_exact_mut(2).zip(src.iter().copied()).for_each(|(d, sb)| { + d[0] = lut[(sb >> 4) as usize]; + d[1] = lut[(sb & 0xf) as usize]; + }) +} + +#[cfg(feature = "alloc")] +#[inline] +fn encode_to_string(bytes: &[u8], cfg: EncConfig) -> String { + let size = encoded_size(bytes.len()); + let mut buf: Vec<u8> = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + encode_slice_raw(bytes, cfg, &mut buf); + debug_assert!(core::str::from_utf8(&buf).is_ok()); + unsafe { String::from_utf8_unchecked(buf) } +} + +#[cfg(feature = "alloc")] +#[inline] +unsafe fn grow_vec_uninitialized(v: &mut Vec<u8>, grow_by: usize) -> usize { + v.reserve(grow_by); + let initial_len = v.len(); + let new_len = initial_len + grow_by; + debug_assert!(new_len <= v.capacity()); + v.set_len(new_len); + initial_len +} + +/// Encode bytes as base16, using lower case characters for nibbles between 10 +/// and 15 (`a` through `f`). +/// +/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`. +/// +/// # Example +/// +/// ``` +/// assert_eq!(base16::encode_lower(b"Hello World"), "48656c6c6f20576f726c64"); +/// assert_eq!(base16::encode_lower(&[0xff, 0xcc, 0xaa]), "ffccaa"); +/// ``` +/// +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs to produce a String. +#[cfg(feature = "alloc")] +#[inline] +pub fn encode_lower<T: ?Sized + AsRef<[u8]>>(input: &T) -> String { + encode_to_string(input.as_ref(), EncodeLower) +} + +/// Encode bytes as base16, using upper case characters for nibbles between +/// 10 and 15 (`A` through `F`). +/// +/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`. +/// +/// # Example +/// +/// ``` +/// assert_eq!(base16::encode_upper(b"Hello World"), "48656C6C6F20576F726C64"); +/// assert_eq!(base16::encode_upper(&[0xff, 0xcc, 0xaa]), "FFCCAA"); +/// ``` +/// +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs to produce a `String`. +#[cfg(feature = "alloc")] +#[inline] +pub fn encode_upper<T: ?Sized + AsRef<[u8]>>(input: &T) -> String { + encode_to_string(input.as_ref(), EncodeUpper) +} + + +/// Encode `input` into a string using the listed config. The resulting string +/// contains `input.len() * 2` bytes. +/// +/// # Example +/// +/// ``` +/// let data = [1, 2, 3, 0xaa, 0xbb, 0xcc]; +/// assert_eq!(base16::encode_config(&data, base16::EncodeLower), "010203aabbcc"); +/// assert_eq!(base16::encode_config(&data, base16::EncodeUpper), "010203AABBCC"); +/// ``` +/// +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs to produce a `String`. +#[cfg(feature = "alloc")] +#[inline] +pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, cfg: EncConfig) -> String { + encode_to_string(input.as_ref(), cfg) +} + +/// Encode `input` into the end of the provided buffer. Returns the number of +/// bytes that were written. +/// +/// Only allocates when `dst.size() + (input.len() * 2) >= dst.capacity()`. +/// +/// # Example +/// +/// ``` +/// let messages = &["Taako, ", "Merle, ", "Magnus"]; +/// let mut buffer = String::new(); +/// for msg in messages { +/// let bytes_written = base16::encode_config_buf(msg.as_bytes(), +/// base16::EncodeUpper, +/// &mut buffer); +/// assert_eq!(bytes_written, msg.len() * 2); +/// } +/// assert_eq!(buffer, "5461616B6F2C204D65726C652C204D61676E7573"); +/// ``` +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs write to a `String`. +#[cfg(feature = "alloc")] +#[inline] +pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T, + cfg: EncConfig, + dst: &mut String) -> usize { + let src = input.as_ref(); + let bytes_to_write = encoded_size(src.len()); + // Swap the string out while we work on it, so that if we panic, we don't + // leave behind garbage (we do clear the string if we panic, but that's + // better than UB) + let mut buf = core::mem::replace(dst, String::new()).into_bytes(); + let cur_size = unsafe { grow_vec_uninitialized(&mut buf, bytes_to_write) }; + + encode_slice_raw(src, cfg, &mut buf[cur_size..]); + + debug_assert!(core::str::from_utf8(&buf).is_ok()); + // Put `buf` back into `dst`. + *dst = unsafe { String::from_utf8_unchecked(buf) }; + + bytes_to_write +} + +/// Write bytes as base16 into the provided output buffer. Never allocates. +/// +/// This is useful if you wish to avoid allocation entirely (e.g. your +/// destination buffer is on the stack), or control it precisely. +/// +/// # Panics +/// +/// Panics if the desination buffer is insufficiently large. +/// +/// # Example +/// +/// ``` +/// # extern crate core as std; +/// // Writing to a statically sized buffer on the stack. +/// let message = b"Wu-Tang Killa Bees"; +/// let mut buffer = [0u8; 1024]; +/// +/// let wrote = base16::encode_config_slice(message, +/// base16::EncodeLower, +/// &mut buffer); +/// +/// assert_eq!(message.len() * 2, wrote); +/// assert_eq!(std::str::from_utf8(&buffer[..wrote]).unwrap(), +/// "57752d54616e67204b696c6c612042656573"); +/// +/// // Appending to an existing buffer is possible too. +/// let wrote2 = base16::encode_config_slice(b": The Swarm", +/// base16::EncodeLower, +/// &mut buffer[wrote..]); +/// let write_end = wrote + wrote2; +/// assert_eq!(std::str::from_utf8(&buffer[..write_end]).unwrap(), +/// "57752d54616e67204b696c6c6120426565733a2054686520537761726d"); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn encode_config_slice<T: ?Sized + AsRef<[u8]>>(input: &T, + cfg: EncConfig, + dst: &mut [u8]) -> usize { + let src = input.as_ref(); + let need_size = encoded_size(src.len()); + if dst.len() < need_size { + dest_too_small_enc(dst.len(), need_size); + } + encode_slice_raw(src, cfg, &mut dst[..need_size]); + need_size +} + +/// Encode a single character as hex, returning a tuple containing the two +/// encoded bytes in big-endian order -- the order the characters would be in +/// when written out (e.g. the top nibble is the first item in the tuple) +/// +/// # Example +/// ``` +/// assert_eq!(base16::encode_byte(0xff, base16::EncodeLower), [b'f', b'f']); +/// assert_eq!(base16::encode_byte(0xa0, base16::EncodeUpper), [b'A', b'0']); +/// assert_eq!(base16::encode_byte(3, base16::EncodeUpper), [b'0', b'3']); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn encode_byte(byte: u8, cfg: EncConfig) -> [u8; 2] { + let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER }; + let lo = lut[(byte & 15) as usize]; + let hi = lut[(byte >> 4) as usize]; + [hi, lo] +} + +/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeLower)` +/// +/// See also `base16::encode_byte_u`. +/// +/// # Example +/// ``` +/// assert_eq!(base16::encode_byte_l(0xff), [b'f', b'f']); +/// assert_eq!(base16::encode_byte_l(30), [b'1', b'e']); +/// assert_eq!(base16::encode_byte_l(0x2d), [b'2', b'd']); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn encode_byte_l(byte: u8) -> [u8; 2] { + encode_byte(byte, EncodeLower) +} + +/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeUpper)` +/// +/// See also `base16::encode_byte_l`. +/// +/// # Example +/// ``` +/// assert_eq!(base16::encode_byte_u(0xff), [b'F', b'F']); +/// assert_eq!(base16::encode_byte_u(30), [b'1', b'E']); +/// assert_eq!(base16::encode_byte_u(0x2d), [b'2', b'D']); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn encode_byte_u(byte: u8) -> [u8; 2] { + encode_byte(byte, EncodeUpper) +} + +/// Represents a problem with the data we want to decode. +/// +/// This implements `std::error::Error` and `Display` if the `std` +/// feature is enabled, but only `Display` if it is not. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum DecodeError { + /// An invalid byte was found in the input (bytes must be `[0-9a-fA-F]`) + InvalidByte { + /// The index at which the problematic byte was found. + index: usize, + /// The byte that we cannot decode. + byte: u8 + }, + /// The length of the input not a multiple of two + InvalidLength { + /// The input length. + length: usize + }, +} + +#[cold] +fn invalid_length(length: usize) -> DecodeError { + DecodeError::InvalidLength { length } +} + +#[cold] +fn invalid_byte(index: usize, src: &[u8]) -> DecodeError { + DecodeError::InvalidByte { index, byte: src[index] } +} + +impl core::fmt::Display for DecodeError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match *self { + DecodeError::InvalidByte { index, byte } => { + write!(f, "Invalid byte `b{:?}`, at index {}.", + byte as char, index) + } + DecodeError::InvalidLength { length } => + write!(f, "Base16 data cannot have length {} (must be even)", + length), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for DecodeError { + fn description(&self) -> &str { + match *self { + DecodeError::InvalidByte { .. } => "Illegal byte in base16 data", + DecodeError::InvalidLength { .. } => "Illegal length for base16 data", + } + } + + fn cause(&self) -> Option<&dyn std::error::Error> { + None + } +} + +#[inline] +fn decode_slice_raw(src: &[u8], dst: &mut[u8]) -> Result<(), usize> { + // checked in caller. + debug_assert!(src.len() / 2 == dst.len()); + debug_assert!((src.len() & 1) == 0); + src.chunks_exact(2).enumerate().zip(dst.iter_mut()).try_for_each(|((si, s), d)| { + let r0 = DECODE_LUT[s[0] as usize]; + let r1 = DECODE_LUT[s[1] as usize]; + if (r0 | r1) >= 0 { + *d = ((r0 << 4) | r1) as u8; + Ok(()) + } else { + Err(si * 2) + } + }).map_err(|bad_idx| raw_decode_err(bad_idx, src)) +} + +#[cold] +#[inline(never)] +fn raw_decode_err(idx: usize, src: &[u8]) -> usize { + let b0 = src[idx]; + if decode_byte(b0).is_none() { + idx + } else { + idx + 1 + } +} + +/// Decode bytes from base16, and return a new `Vec<u8>` containing the results. +/// +/// # Example +/// +/// ``` +/// assert_eq!(&base16::decode("48656c6c6f20576f726c64".as_bytes()).unwrap(), +/// b"Hello World"); +/// assert_eq!(&base16::decode(b"deadBEEF").unwrap(), +/// &[0xde, 0xad, 0xbe, 0xef]); +/// // Error cases: +/// assert_eq!(base16::decode(b"Not Hexadecimal!"), +/// Err(base16::DecodeError::InvalidByte { byte: b'N', index: 0 })); +/// assert_eq!(base16::decode(b"a"), +/// Err(base16::DecodeError::InvalidLength { length: 1 })); +/// ``` +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs to produce a Vec. +#[cfg(feature = "alloc")] +#[inline] +pub fn decode<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>, DecodeError> { + let src = input.as_ref(); + if (src.len() & 1) != 0 { + return Err(invalid_length(src.len())); + } + let need_size = src.len() >> 1; + let mut dst = Vec::with_capacity(need_size); + unsafe { dst.set_len(need_size); } + match decode_slice_raw(src, &mut dst) { + Ok(()) => Ok(dst), + Err(index) => Err(invalid_byte(index, src)) + } +} + + +/// Decode bytes from base16, and appends into the provided buffer. Only +/// allocates if the buffer could not fit the data. Returns the number of bytes +/// written. +/// +/// In the case of an error, the buffer should remain the same size. +/// +/// # Example +/// +/// ``` +/// # extern crate core as std; +/// # extern crate alloc; +/// # use alloc::vec::Vec; +/// let mut result = Vec::new(); +/// assert_eq!(base16::decode_buf(b"4d61646f6b61", &mut result).unwrap(), 6); +/// assert_eq!(base16::decode_buf(b"486F6D757261", &mut result).unwrap(), 6); +/// assert_eq!(std::str::from_utf8(&result).unwrap(), "MadokaHomura"); +/// ``` +/// # Availability +/// +/// This function is only available when the `alloc` feature is enabled, as it +/// needs to write to a Vec. +#[cfg(feature = "alloc")] +#[inline] +pub fn decode_buf<T: ?Sized + AsRef<[u8]>>(input: &T, v: &mut Vec<u8>) -> Result<usize, DecodeError> { + let src = input.as_ref(); + if (src.len() & 1) != 0 { + return Err(invalid_length(src.len())); + } + // Swap the vec out while we work on it, so that if we panic, we don't leave + // behind garbage (this will end up cleared if we panic, but that's better + // than UB) + let mut work = core::mem::replace(v, Vec::default()); + let need_size = src.len() >> 1; + let current_size = unsafe { + grow_vec_uninitialized(&mut work, need_size) + }; + match decode_slice_raw(src, &mut work[current_size..]) { + Ok(()) => { + // Swap back + core::mem::swap(v, &mut work); + Ok(need_size) + } + Err(index) => { + work.truncate(current_size); + // Swap back + core::mem::swap(v, &mut work); + Err(invalid_byte(index, src)) + } + } +} + +/// Decode bytes from base16, and write into the provided buffer. Never +/// allocates. +/// +/// In the case of a decoder error, the output is not specified, but in practice +/// will remain untouched for an `InvalidLength` error, and will contain the +/// decoded input up to the problem byte in the case of an InvalidByte error. +/// +/// # Panics +/// +/// Panics if the provided buffer is not large enough for the input. +/// +/// # Example +/// ``` +/// let msg = "476f6f642072757374206c6962726172696573207573652073696c6c79206578616d706c6573"; +/// let mut buf = [0u8; 1024]; +/// assert_eq!(base16::decode_slice(&msg[..], &mut buf).unwrap(), 38); +/// assert_eq!(&buf[..38], b"Good rust libraries use silly examples".as_ref()); +/// +/// let msg2 = b"2E20416C736F2C20616E696D65207265666572656e636573"; +/// assert_eq!(base16::decode_slice(&msg2[..], &mut buf[38..]).unwrap(), 24); +/// assert_eq!(&buf[38..62], b". Also, anime references".as_ref()); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn decode_slice<T: ?Sized + AsRef<[u8]>>(input: &T, out: &mut [u8]) -> Result<usize, DecodeError> { + let src = input.as_ref(); + if (src.len() & 1) != 0 { + return Err(invalid_length(src.len())); + } + let need_size = src.len() >> 1; + if out.len() < need_size { + dest_too_small_dec(out.len(), need_size); + } + match decode_slice_raw(src, &mut out[..need_size]) { + Ok(()) => Ok(need_size), + Err(index) => Err(invalid_byte(index, src)) + } +} + +/// Decode a single character as hex. +/// +/// Returns `None` for values outside the ASCII hex range. +/// +/// # Example +/// ``` +/// assert_eq!(base16::decode_byte(b'a'), Some(10)); +/// assert_eq!(base16::decode_byte(b'B'), Some(11)); +/// assert_eq!(base16::decode_byte(b'0'), Some(0)); +/// assert_eq!(base16::decode_byte(b'q'), None); +/// assert_eq!(base16::decode_byte(b'x'), None); +/// ``` +/// # Availability +/// +/// This function is available whether or not the `alloc` feature is enabled. +#[inline] +pub fn decode_byte(c: u8) -> Option<u8> { + if c.wrapping_sub(b'0') <= 9 { + Some(c.wrapping_sub(b'0')) + } else if c.wrapping_sub(b'a') < 6 { + Some(c.wrapping_sub(b'a') + 10) + } else if c.wrapping_sub(b'A') < 6 { + Some(c.wrapping_sub(b'A') + 10) + } else { + None + } +} +static HEX_UPPER: [u8; 16] = *b"0123456789ABCDEF"; +static HEX_LOWER: [u8; 16] = *b"0123456789abcdef"; +static DECODE_LUT: [i8; 256] = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1 +]; +// Outlined assertions. +#[inline(never)] +#[cold] +fn usize_overflow(len: usize) -> ! { + panic!("usize overflow when computing size of destination: {}", len); +} + +#[cold] +#[inline(never)] +fn dest_too_small_enc(dst_len: usize, need_size: usize) -> ! { + panic!("Destination is not large enough to encode input: {} < {}", dst_len, need_size); +} + +#[cold] +#[inline(never)] +fn dest_too_small_dec(dst_len: usize, need_size: usize) -> ! { + panic!("Destination buffer not large enough for decoded input {} < {}", dst_len, need_size); +} + +// encoded_size smoke tests +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[should_panic] + #[cfg(pointer_size )] + fn test_encoded_size_panic_top_bit() { + #[cfg(target_pointer_width = "64")] + let usz = 0x8000_0000_0000_0000usize; + #[cfg(target_pointer_width = "32")] + let usz = 0x8000_0000usize; + let _ = encoded_size(usz); + } + + #[test] + #[should_panic] + fn test_encoded_size_panic_max() { + let _ = encoded_size(usize::max_value()); + } + + #[test] + fn test_encoded_size_allows_almost_max() { + #[cfg(target_pointer_width = "64")] + let usz = 0x7fff_ffff_ffff_ffffusize; + #[cfg(target_pointer_width = "32")] + let usz = 0x7fff_ffffusize; + assert_eq!(encoded_size(usz), usz * 2); + } +} diff --git a/third_party/rust/base16/tests/doctest_copies.rs b/third_party/rust/base16/tests/doctest_copies.rs @@ -0,0 +1,135 @@ + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +// Can't run doctests for a no_std crate if it uses allocator (e.g. can't run +// them if we're using `alloc`), so we duplicate them here... +// See https://github.com/rust-lang/rust/issues/54010 + +#[cfg(feature = "alloc")] +#[test] +fn test_encode_lower() { + assert_eq!(base16::encode_lower(b"Hello World"), "48656c6c6f20576f726c64"); + assert_eq!(base16::encode_lower(&[0xff, 0xcc, 0xaa]), "ffccaa"); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_encode_upper() { + assert_eq!(base16::encode_upper(b"Hello World"), "48656C6C6F20576F726C64"); + assert_eq!(base16::encode_upper(&[0xff, 0xcc, 0xaa]), "FFCCAA"); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_encode_config() { + let data = [1, 2, 3, 0xaa, 0xbb, 0xcc]; + assert_eq!(base16::encode_config(&data, base16::EncodeLower), "010203aabbcc"); + assert_eq!(base16::encode_config(&data, base16::EncodeUpper), "010203AABBCC"); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_encode_config_buf() { + use alloc::string::String; + let messages = &["Taako, ", "Merle, ", "Magnus"]; + let mut buffer = String::new(); + for msg in messages { + let bytes_written = base16::encode_config_buf(msg.as_bytes(), + base16::EncodeUpper, + &mut buffer); + assert_eq!(bytes_written, msg.len() * 2); + } + assert_eq!(buffer, "5461616B6F2C204D65726C652C204D61676E7573"); +} + +#[test] +fn test_encode_config_slice() { + // Writing to a statically sized buffer on the stack. + let message = b"Wu-Tang Killa Bees"; + let mut buffer = [0u8; 1024]; + + let wrote = base16::encode_config_slice(message, + base16::EncodeLower, + &mut buffer); + + assert_eq!(message.len() * 2, wrote); + assert_eq!(core::str::from_utf8(&buffer[..wrote]).unwrap(), + "57752d54616e67204b696c6c612042656573"); + + // Appending to an existing buffer is possible too. + let wrote2 = base16::encode_config_slice(b": The Swarm", + base16::EncodeLower, + &mut buffer[wrote..]); + let write_end = wrote + wrote2; + assert_eq!(core::str::from_utf8(&buffer[..write_end]).unwrap(), + "57752d54616e67204b696c6c6120426565733a2054686520537761726d"); +} + +#[test] +fn test_encode_config_byte() { + assert_eq!(base16::encode_byte(0xff, base16::EncodeLower), [b'f', b'f']); + assert_eq!(base16::encode_byte(0xa0, base16::EncodeUpper), [b'A', b'0']); + assert_eq!(base16::encode_byte(3, base16::EncodeUpper), [b'0', b'3']); +} + +#[test] +fn test_encode_config_byte_l() { + assert_eq!(base16::encode_byte_l(0xff), [b'f', b'f']); + assert_eq!(base16::encode_byte_l(30), [b'1', b'e']); + assert_eq!(base16::encode_byte_l(0x2d), [b'2', b'd']); +} + +#[test] +fn test_encode_config_byte_u() { + assert_eq!(base16::encode_byte_u(0xff), [b'F', b'F']); + assert_eq!(base16::encode_byte_u(30), [b'1', b'E']); + assert_eq!(base16::encode_byte_u(0x2d), [b'2', b'D']); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_decode() { + assert_eq!(&base16::decode("48656c6c6f20576f726c64".as_bytes()).unwrap(), + b"Hello World"); + assert_eq!(&base16::decode(b"deadBEEF").unwrap(), + &[0xde, 0xad, 0xbe, 0xef]); + // Error cases: + assert_eq!(base16::decode(b"Not Hexadecimal!"), + Err(base16::DecodeError::InvalidByte { byte: b'N', index: 0 })); + assert_eq!(base16::decode(b"a"), + Err(base16::DecodeError::InvalidLength { length: 1 })); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_decode_buf() { + use alloc::vec::Vec; + let mut result = Vec::new(); + assert_eq!(base16::decode_buf(b"4d61646f6b61", &mut result).unwrap(), 6); + assert_eq!(base16::decode_buf(b"486F6D757261", &mut result).unwrap(), 6); + assert_eq!(core::str::from_utf8(&result).unwrap(), "MadokaHomura"); +} + +#[test] +fn test_decode_slice() { + let msg = "476f6f642072757374206c6962726172696573207573652073696c6c79206578616d706c6573"; + let mut buf = [0u8; 1024]; + assert_eq!(base16::decode_slice(&msg[..], &mut buf).unwrap(), 38); + assert_eq!(&buf[..38], b"Good rust libraries use silly examples".as_ref()); + + let msg2 = b"2E20416C736F2C20616E696D65207265666572656e636573"; + assert_eq!(base16::decode_slice(&msg2[..], &mut buf[38..]).unwrap(), 24); + assert_eq!(&buf[38..62], b". Also, anime references".as_ref()); +} + +#[test] +fn test_decode_byte() { + assert_eq!(base16::decode_byte(b'a'), Some(10)); + assert_eq!(base16::decode_byte(b'B'), Some(11)); + assert_eq!(base16::decode_byte(b'0'), Some(0)); + assert_eq!(base16::decode_byte(b'q'), None); + assert_eq!(base16::decode_byte(b'x'), None); +} diff --git a/third_party/rust/base16/tests/tests.rs b/third_party/rust/base16/tests/tests.rs @@ -0,0 +1,169 @@ + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + +use base16::*; + +const ALL_LOWER: &[&str] = &[ + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", + "0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", + "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", "50", "51", "52", "53", + "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", + "6c", "6d", "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83", + "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", + "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3", + "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", + "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", + "cc", "cd", "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", + "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", + "fc", "fd", "fe", "ff", +]; + +const ALL_UPPER: &[&str] = &[ + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", + "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", + "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", + "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", + "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", + "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", + "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", + "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", + "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", + "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", + "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", + "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", + "FC", "FD", "FE", "FF", +]; + +#[cfg(feature = "alloc")] +#[test] +fn test_exhaustive_bytes_encode() { + for i in 0..256 { + assert_eq!(&encode_lower(&[i as u8]), ALL_LOWER[i]); + assert_eq!(&encode_upper(&[i as u8]), ALL_UPPER[i]); + } +} + +#[cfg(feature = "alloc")] +#[test] +fn test_exhaustive_bytes_decode() { + for i in 0..16 { + for j in 0..16 { + let all_cases = format!("{0:x}{1:x}{0:x}{1:X}{0:X}{1:x}{0:X}{1:X}", i, j); + let byte = i * 16 + j; + let expect = &[byte, byte, byte, byte]; + assert_eq!(&decode(&all_cases).unwrap(), expect, + "Failed for {}", all_cases); + } + } + for b in 0..256 { + let i = b as u8; + let expected = match i { + b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' => Ok(vec![i - b'0']), + b'a' | b'b' | b'c' | b'd' | b'e' | b'f' => Ok(vec![i - b'a' + 10]), + b'A' | b'B' | b'C' | b'D' | b'E' | b'F' => Ok(vec![i - b'A' + 10]), + _ => Err(DecodeError::InvalidByte { byte: i, index: 1 }) + }; + assert_eq!(decode(&[b'0', i]), expected); + } +} + +#[cfg(feature = "alloc")] +#[test] +fn test_decode_errors() { + let mut buf = decode(b"686f6d61646f6b61").unwrap(); + let orig = buf.clone(); + + assert_eq!(buf.len(), 8); + + assert_eq!(decode_buf(b"abc", &mut buf), + Err(DecodeError::InvalidLength { length: 3 })); + assert_eq!(buf, orig); + + assert_eq!(decode_buf(b"6d61646f686f6d75g_", &mut buf), + Err(DecodeError::InvalidByte { byte: b'g', index: 16 })); + assert_eq!(buf, orig); +} + +#[test] +#[should_panic] +fn test_panic_slice_encode() { + let mut slice = [0u8; 8]; + encode_config_slice(b"Yuasa", EncodeLower, &mut slice); +} + +#[test] +#[should_panic] +fn test_panic_slice_decode() { + let mut slice = [0u8; 32]; + let input = b"4920646f6e277420636172652074686174206d7563682061626f757420504d4d4d20544248"; + let _ignore = decode_slice(&input[..], &mut slice); +} + +#[test] +fn test_enc_slice_exact_fit() { + let mut slice = [0u8; 12]; + let res = encode_config_slice(b"abcdef", EncodeLower, &mut slice); + assert_eq!(res, 12); + assert_eq!(&slice, b"616263646566") +} + +#[test] +fn test_exhaustive_encode_byte() { + for i in 0..256 { + let byte = i as u8; + let su = ALL_UPPER[byte as usize].as_bytes(); + let sl = ALL_LOWER[byte as usize].as_bytes(); + let tu = encode_byte(byte, EncodeUpper); + let tl = encode_byte(byte, EncodeLower); + + assert_eq!(tu[0], su[0]); + assert_eq!(tu[1], su[1]); + + assert_eq!(tl[0], sl[0]); + assert_eq!(tl[1], sl[1]); + + assert_eq!(tu, encode_byte_u(byte)); + assert_eq!(tl, encode_byte_l(byte)); + } +} + +const HEX_TO_VALUE: &[(u8, u8)] = &[ + (b'0', 0x0), (b'1', 0x1), (b'2', 0x2), (b'3', 0x3), (b'4', 0x4), + (b'5', 0x5), (b'6', 0x6), (b'7', 0x7), (b'8', 0x8), (b'9', 0x9), + (b'a', 0xa), (b'b', 0xb), (b'c', 0xc), (b'd', 0xd), (b'e', 0xe), (b'f', 0xf), + (b'A', 0xA), (b'B', 0xB), (b'C', 0xC), (b'D', 0xD), (b'E', 0xE), (b'F', 0xF), +]; + +#[test] +fn test_exhaustive_decode_byte() { + let mut expected = [None::<u8>; 256]; + for &(k, v) in HEX_TO_VALUE { + expected[k as usize] = Some(v); + } + for i in 0..256 { + assert_eq!(decode_byte(i as u8), expected[i]); + } +} diff --git a/third_party/rust/hawk/.cargo-checksum.json b/third_party/rust/hawk/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"2c917c2285781054146c5ce672f2cc8f6c82a87975e6ebe2318dbc9f94e3436c","CODE_OF_CONDUCT.md":"902d5357af363426631d907e641e220b3ec89039164743f8442b3f120479b7cf","CONTRIBUTING.md":"2f395c6bff5805ada946b38d407bedea743230c845fd69cbd004da36871b9580","Cargo.toml":"1f22ec3a611f4fbe52eb851cdaab8ff28b1a6f98718364a68150809d421954c7","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"43f86b667ba065459d185ec47e5a48f943ce6dfe04dc02e1cfff0baf58714243","build.rs":"ae11c573f1edf605d7a6dc740e48f2af9ec0a8c0578bf5d381d52126582fb67e","clippy.toml":"20c46fb795c2ef5317874716faa5c8ddc1ff076f3028c85c38dc560d71347ee5","src/b64.rs":"d23d82df26f8718a58c6c9f7f79d0a7391fd0df6c102639c20941b10213c84d4","src/bewit.rs":"fc91415bd87b7d62cd39597b2d5499b4c6c4f0458cb0ca94954534659bd882df","src/credentials.rs":"6c727d846161216b2c333a843f17f8965c664cbb3ed7ff4b14eb89fb614cac59","src/crypto/holder.rs":"c0ad1269bb9b98a9f1abc17453813cc2983e958d7d3c0c95943ce74580c9fe97","src/crypto/mod.rs":"0df4f7d1e7f81553c99c31a994949e8d88ad7c4486b5f9279c486c0887e0c8ab","src/crypto/openssl.rs":"ced672fd59b70912095a718f112e4c02f63caf006680aa0db2f79306781d0cc9","src/crypto/ring.rs":"363c9bbb4269e40c160ff2d70d7232f7f4e0e29c717ca5b07c9c40dd5306ef76","src/error.rs":"7349b04c8a7a9faa818f14af05a877599126ca747669aae8f8f959319c818381","src/header.rs":"ff57d3b925187e877db408ca3c7f642142ceec89cbd7dd706897c35667674c68","src/lib.rs":"cd33cd4922732060b7bc2f1ae3a96a81a78452e0db4b2e47ac54ba949ff8e87c","src/mac.rs":"a81fbb90a0ea93fba9d167f0382a1e2541cfc8bc4cef0e1f588ed57c522f5b2f","src/payload.rs":"fb70b564296050ff3e86d9199f0c5f2a02ebde5ca9770a95a5d174a9c2409d7b","src/request.rs":"8e565c2b0b41dac4330cd462e19763d905bd29dcfdf27f3f9eb39820bba26104","src/response.rs":"d74318c3b6e9ea5570cb099d5874c085500366cdc75ba154df2cf1f28a10223c"},"package":"ab302457b3e28e621daab18932d67a67328f29240bfaa5f604b7627ece1eacda"} +\ No newline at end of file diff --git a/third_party/rust/hawk/CHANGELOG.md b/third_party/rust/hawk/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog + +## v5.0.1 + +- `base64` upgraded to 0.22 + +## v5.0.0 + +- `ring` upgraded to 0.17.0 +- `base64` upgraded +- Support Rust 2021 edition + +## v4.0.0 + +- Hide base64::DecodeError + +## v3.0.0 + +- The cryptography library used is now configurable. + - By default `ring` is used (the `use_ring` feature). + - You can use the `use_openssl` feature to use openssl instead + - e.g. in your Cargo.toml: + ```toml + [dependencies.hawk] + version = "..." + features = ["use_openssl"] + default-features = false + ``` + - You can use neither and provide your own implementation using the functions in + `hawk::crypto` if neither feature is enabled. + - Note that enabling both `use_ring` and `use_openssl` will cause a build + failure. + +- BREAKING: Many functions that previously returned `T` now return `hawk::Result<T>`. + - Specifically, `PayloadHasher::{hash,update,finish}`, `Key::{new,sign}`. + +- BREAKING: `hawk::SHA{256,384,512}` are now `const` `DigestAlgorithm`s and not + aliases for `ring::Algorithm` + +- BREAKING: `Key::new` now takes a `DigestAlgorithm` and not a + `&'static ring::Algorithm`. + - If you were passing e.g. `&hawk::SHA256`, you probably just need + to pass `hawk::SHA256` now instead. + +- BREAKING (though unlikely): `Error::Rng` has been removed, and `Error::Crypto` added diff --git a/third_party/rust/hawk/CODE_OF_CONDUCT.md b/third_party/rust/hawk/CODE_OF_CONDUCT.md @@ -0,0 +1,15 @@ +# Community Participation Guidelines + +This repository is governed by Mozilla's code of conduct and etiquette guidelines. +For more details, please read the +[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). + +## How to Report +For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. + +<!-- +## Project Specific Etiquette + +In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html). +Please update for your project. +--> diff --git a/third_party/rust/hawk/CONTRIBUTING.md b/third_party/rust/hawk/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# How to Contribute + +We welcome pull requests from everyone. We do expect everyone to adhere to the [Mozilla Community Participation Guidelines][participation]. + +If you're trying to figure out what to work on, here are some places to find suitable projects: +* [Good first bugs][goodfirstbug]: these are scoped to make it easy for first-time contributors to get their feet wet with Taskcluster code. +* [Mentored bugs][bugsahoy]: these are slightly more involved projects that may require insight or guidance from someone on the Taskcluster team. +* [Full list of open issues][issues]: everything else + +If the project you're interested in working on isn't covered by a bug or issue, or you're unsure about how to proceed on an existing issue, it's a good idea to talk to someone on the Taskcluster team before you go too far down a particular path. You can find us in the #taskcluster channel on [Mozilla's IRC server][irc] to discuss. You can also simply add a comment to the issue or bug. + +Once you've found an issue to work on and written a patch, submit a pull request. Some things that will increase the chance that your pull request is accepted: + +* Follow our [best practices][bestpractices]. +* This includes [writing or updating tests][testing]. +* Write a [good commit message][commit]. + +Welcome to the team! + +[participation]: https://www.mozilla.org/en-US/about/governance/policies/participation/ +[issues]: ../../issues +[bugsahoy]: https://www.joshmatthews.net/bugsahoy/?taskcluster=1 +[goodfirstbug]: http://www.joshmatthews.net/bugsahoy/?taskcluster=1&simple=1 +[irc]: https://wiki.mozilla.org/IRC +[bestpractices]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices +[testing]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices/testing +[commit]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices/commits + diff --git a/third_party/rust/hawk/Cargo.toml b/third_party/rust/hawk/Cargo.toml @@ -0,0 +1,65 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "hawk" +version = "5.0.1" +authors = [ + "Jonas Finnemann Jensen <jopsen@gmail.com>", + "Dustin J. Mitchell <dustin@mozilla.com>", +] +build = "build.rs" +exclude = [ + "docker/*", + ".taskcluster.yml", + ".git*", +] +description = "Hawk Implementation for Rust" +homepage = "https://docs.rs/hawk/" +documentation = "https://docs.rs/hawk/" +readme = "README.md" +license = "MPL-2.0" +repository = "https://github.com/taskcluster/rust-hawk" + +[dependencies.anyhow] +version = "1.0" + +[dependencies.base64] +version = "0.22" + +[dependencies.log] +version = "0.4" + +[dependencies.once_cell] +version = "1.4" + +[dependencies.openssl] +version = "0.10.20" +optional = true + +[dependencies.ring] +version = "0.17.0" +optional = true + +[dependencies.thiserror] +version = "1.0" + +[dependencies.url] +version = "2.1" + +[dev-dependencies.pretty_assertions] +version = "^1.0.0" + +[features] +default = ["use_ring"] +use_openssl = ["openssl"] +use_ring = ["ring"] diff --git a/third_party/rust/hawk/LICENSE b/third_party/rust/hawk/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/third_party/rust/hawk/README.md b/third_party/rust/hawk/README.md @@ -0,0 +1,4 @@ +Hawk Authentication for Rust +============================ + +This is a Rust implementation of [Hawk](https://github.com/hueniverse/hawk). diff --git a/third_party/rust/hawk/build.rs b/third_party/rust/hawk/build.rs @@ -0,0 +1,7 @@ +// Just check that we aren't asked to use an impossible configuration. +fn main() { + assert!( + !(cfg!(feature = "use_ring") && cfg!(feature = "use_openssl")), + "Cannot configure `hawk` with both `use_ring` and `use_openssl`!" + ); +} diff --git a/third_party/rust/hawk/clippy.toml b/third_party/rust/hawk/clippy.toml @@ -0,0 +1,2 @@ +# hawk headers have a lot of fields, and we pass them positionally.. +too-many-arguments-threshold = 15 diff --git a/third_party/rust/hawk/src/b64.rs b/third_party/rust/hawk/src/b64.rs @@ -0,0 +1,19 @@ +//! This module contains basic base64 functionality as used in Hawk. + +use base64::engine::{ + general_purpose::{GeneralPurpose, GeneralPurposeConfig}, + DecodePaddingMode, +}; + +/// BEWIT_ENGINE encodes to a url-safe value with no padding, but is indifferent to padding on +/// decode. This is used to encode bewits, which often appear in URLs. +pub(crate) const BEWIT_ENGINE: GeneralPurpose = GeneralPurpose::new( + &base64::alphabet::URL_SAFE, + GeneralPurposeConfig::new() + .with_encode_padding(false) + .with_decode_padding_mode(DecodePaddingMode::Indifferent), +); + +/// STANDARD_ENGINE encodes with the standard alphabet and includes padding. This is +/// used to encode MACs and hashes. +pub(crate) const STANDARD_ENGINE: GeneralPurpose = base64::engine::general_purpose::STANDARD; diff --git a/third_party/rust/hawk/src/bewit.rs b/third_party/rust/hawk/src/bewit.rs @@ -0,0 +1,216 @@ +use crate::b64; +use crate::error::*; +use crate::mac::Mac; +use base64::Engine; +use std::borrow::Cow; +use std::str; +use std::str::FromStr; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +/// A Bewit is a piece of data attached to a GET request that functions in place of a Hawk +/// Authentication header. It contains an id, a timestamp, a MAC, and an optional `ext` value. +/// These are available using accessor functions. +#[derive(Clone, Debug, PartialEq)] +pub struct Bewit<'a> { + id: Cow<'a, str>, + exp: SystemTime, + mac: Cow<'a, Mac>, + ext: Option<Cow<'a, str>>, +} + +impl<'a> Bewit<'a> { + /// Create a new Bewit with the given values. + /// + /// See Request.make_bewit for an easier way to make a Bewit + pub fn new(id: &'a str, exp: SystemTime, mac: Mac, ext: Option<&'a str>) -> Bewit<'a> { + Bewit { + id: Cow::Borrowed(id), + exp, + mac: Cow::Owned(mac), + ext: ext.map(Cow::Borrowed), + } + } + + /// Generate the fully-encoded string for this Bewit + pub fn to_str(&self) -> String { + let raw = format!( + "{}\\{}\\{}\\{}", + self.id, + self.exp + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs(), + b64::STANDARD_ENGINE.encode(self.mac.as_ref()), + match self.ext { + Some(ref cow) => cow.as_ref(), + None => "", + } + ); + + b64::BEWIT_ENGINE.encode(raw) + } + + /// Get the Bewit's client identifier + pub fn id(&self) -> &str { + self.id.as_ref() + } + + /// Get the expiration time of the bewit + pub fn exp(&self) -> SystemTime { + self.exp + } + + /// Get the MAC included in the Bewit + pub fn mac(&self) -> &Mac { + self.mac.as_ref() + } + + /// Get the Bewit's `ext` field. + pub fn ext(&self) -> Option<&str> { + match self.ext { + Some(ref cow) => Some(cow.as_ref()), + None => None, + } + } +} + +const BACKSLASH: u8 = b'\\'; + +impl<'a> FromStr for Bewit<'a> { + type Err = Error; + fn from_str(bewit: &str) -> Result<Bewit<'a>> { + let bewit = b64::BEWIT_ENGINE + .decode(bewit) + .map_err(Error::from_base64_error)?; + + let parts: Vec<&[u8]> = bewit.split(|c| *c == BACKSLASH).collect(); + if parts.len() != 4 { + return Err(InvalidBewit::Format.into()); + } + + let id = String::from_utf8(parts[0].to_vec()).map_err(|_| InvalidBewit::Id)?; + + let exp = str::from_utf8(parts[1]).map_err(|_| InvalidBewit::Exp)?; + let exp = u64::from_str(exp).map_err(|_| InvalidBewit::Exp)?; + let exp = UNIX_EPOCH + Duration::new(exp, 0); + + let mac = str::from_utf8(parts[2]).map_err(|_| InvalidBewit::Mac)?; + let mac = Mac::from( + b64::STANDARD_ENGINE + .decode(mac) + .map_err(|_| InvalidBewit::Mac)?, + ); + + let ext = match parts[3].len() { + 0 => None, + _ => Some(Cow::Owned( + String::from_utf8(parts[3].to_vec()).map_err(|_| InvalidBewit::Ext)?, + )), + }; + + Ok(Bewit { + id: Cow::Owned(id), + exp, + mac: Cow::Owned(mac), + ext, + }) + } +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod test { + use super::*; + use crate::credentials::Key; + use crate::mac::{Mac, MacType}; + use std::str::FromStr; + + const BEWIT_STR: &str = + "bWVcMTM1MzgzMjgzNFxmaXk0ZTV3QmRhcEROeEhIZUExOE5yU3JVMVUzaVM2NmdtMFhqVEpwWXlVPVw"; + const BEWIT_WITH_EXT_STR: &str = + "bWVcMTM1MzgzMjgzNFxmaXk0ZTV3QmRhcEROeEhIZUExOE5yU3JVMVUzaVM2NmdtMFhqVEpwWXlVPVxhYmNk"; + + fn make_mac() -> Mac { + let key = Key::new( + vec![ + 11u8, 19, 228, 209, 79, 189, 200, 59, 166, 47, 86, 254, 235, 184, 120, 197, 75, + 152, 201, 79, 115, 61, 111, 242, 219, 187, 173, 14, 227, 108, 60, 232, + ], + crate::DigestAlgorithm::Sha256, + ) + .unwrap(); + Mac::new( + MacType::Header, + &key, + UNIX_EPOCH + Duration::new(1353832834, 100), + "nonny", + "POST", + "mysite.com", + 443, + "/v1/api", + None, + None, + ) + .unwrap() + } + + #[test] + fn test_to_str() { + let bewit = Bewit::new( + "me", + UNIX_EPOCH + Duration::new(1353832834, 0), + make_mac(), + None, + ); + assert_eq!(bewit.to_str(), BEWIT_STR); + let bewit = Bewit::new( + "me", + UNIX_EPOCH + Duration::new(1353832834, 0), + make_mac(), + Some("abcd"), + ); + assert_eq!(bewit.to_str(), BEWIT_WITH_EXT_STR); + } + + #[test] + fn test_accessors() { + let bewit = Bewit::from_str(BEWIT_STR).unwrap(); + assert_eq!(bewit.id(), "me"); + assert_eq!(bewit.exp(), UNIX_EPOCH + Duration::new(1353832834, 0)); + assert_eq!(bewit.mac(), &make_mac()); + assert_eq!(bewit.ext(), None); + } + + #[test] + fn test_from_str_invalid_base64() { + assert!(Bewit::from_str("!/==").is_err()); + } + + #[test] + fn test_from_str_invalid_too_many_parts() { + let bewit = b64::BEWIT_ENGINE.encode("a\\123\\abc\\ext\\WHUT?".as_bytes()); + assert!(Bewit::from_str(&bewit).is_err()); + } + + #[test] + fn test_from_str_invalid_too_few_parts() { + let bewit = b64::BEWIT_ENGINE.encode("a\\123\\abc".as_bytes()); + assert!(Bewit::from_str(&bewit).is_err()); + } + + #[test] + fn test_from_str_invalid_not_utf8() { + let a = b'a'; + let one = b'1'; + let slash = b'\\'; + let invalid1 = 0u8; + let invalid2 = 159u8; + let bewit = b64::BEWIT_ENGINE.encode([invalid1, invalid2, slash, one, slash, a, slash, a]); + assert!(Bewit::from_str(&bewit).is_err()); + let bewit = b64::BEWIT_ENGINE.encode([a, slash, invalid1, invalid2, slash, a, slash, a]); + assert!(Bewit::from_str(&bewit).is_err()); + let bewit = b64::BEWIT_ENGINE.encode([a, slash, one, slash, invalid1, invalid2, slash, a]); + assert!(Bewit::from_str(&bewit).is_err()); + let bewit = b64::BEWIT_ENGINE.encode([a, slash, one, slash, a, slash, invalid1, invalid2]); + assert!(Bewit::from_str(&bewit).is_err()); + } +} diff --git a/third_party/rust/hawk/src/credentials.rs b/third_party/rust/hawk/src/credentials.rs @@ -0,0 +1,56 @@ +use crate::crypto::{self, HmacKey}; + +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] +#[non_exhaustive] +pub enum DigestAlgorithm { + Sha256, + Sha384, + Sha512, +} + +/// Hawk key. +/// +/// While any sequence of bytes can be specified as a key, note that each digest algorithm has +/// a suggested key length, and that passwords should *not* be used as keys. Keys of incorrect +/// length are handled according to the digest's implementation. +pub struct Key(Box<dyn HmacKey>); + +impl Key { + pub fn new<B>(key: B, algorithm: DigestAlgorithm) -> crate::Result<Key> + where + B: AsRef<[u8]>, + { + Ok(Key(crypto::new_key(algorithm, key.as_ref())?)) + } + + pub fn sign(&self, data: &[u8]) -> crate::Result<Vec<u8>> { + Ok(self.0.sign(data)?) + } +} + +/// Hawk credentials: an ID and a key associated with that ID. The digest algorithm +/// must be agreed between the server and the client, and the length of the key is +/// specific to that algorithm. +pub struct Credentials { + pub id: String, + pub key: Key, +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod test { + use super::*; + + #[test] + fn test_new_sha256() { + let key = vec![77u8; 32]; + // hmac::SigningKey doesn't allow any visibilty inside, so we just build the + // key and assume it works.. + Key::new(key, DigestAlgorithm::Sha256).unwrap(); + } + + #[test] + fn test_new_sha256_bad_length() { + let key = vec![0u8; 99]; + Key::new(key, DigestAlgorithm::Sha256).unwrap(); + } +} diff --git a/third_party/rust/hawk/src/crypto/holder.rs b/third_party/rust/hawk/src/crypto/holder.rs @@ -0,0 +1,52 @@ +use super::Cryptographer; +use once_cell::sync::OnceCell; + +static CRYPTOGRAPHER: OnceCell<&'static dyn Cryptographer> = OnceCell::new(); + +#[derive(Debug, thiserror::Error)] +#[error("Cryptographer already initialized")] +pub struct SetCryptographerError(()); + +/// Sets the global object that will be used for cryptographic operations. +/// +/// This is a convenience wrapper over [`set_cryptographer`], +/// but takes a `Box<dyn Cryptographer>` instead. +#[cfg(not(any(feature = "use_ring", feature = "use_openssl")))] +pub fn set_boxed_cryptographer(c: Box<dyn Cryptographer>) -> Result<(), SetCryptographerError> { + // Just leak the Box. It wouldn't be freed as a `static` anyway, and we + // never allow this to be re-assigned (so it's not a meaningful memory leak). + set_cryptographer(Box::leak(c)) +} + +/// Sets the global object that will be used for cryptographic operations. +/// +/// This function may only be called once in the lifetime of a program. +/// +/// Any calls into this crate that perform cryptography prior to calling this +/// function will panic. +pub fn set_cryptographer(c: &'static dyn Cryptographer) -> Result<(), SetCryptographerError> { + CRYPTOGRAPHER.set(c).map_err(|_| SetCryptographerError(())) +} + +pub(crate) fn get_crypographer() -> &'static dyn Cryptographer { + autoinit_crypto(); + *CRYPTOGRAPHER + .get() + .expect("`hawk` cryptographer not initialized!") +} + +#[cfg(feature = "use_ring")] +#[inline] +fn autoinit_crypto() { + let _ = set_cryptographer(&super::ring::RingCryptographer); +} + +#[cfg(feature = "use_openssl")] +#[inline] +fn autoinit_crypto() { + let _ = set_cryptographer(&super::openssl::OpensslCryptographer); +} + +#[cfg(not(any(feature = "use_openssl", feature = "use_ring")))] +#[inline] +fn autoinit_crypto() {} diff --git a/third_party/rust/hawk/src/crypto/mod.rs b/third_party/rust/hawk/src/crypto/mod.rs @@ -0,0 +1,83 @@ +//! `hawk` must perform certain cryptographic operations in order to function, +//! and applications may need control over which library is used for these. +//! +//! This module can be used for that purpose. If you do not care, this crate can +//! be configured so that a default implementation is provided based on either +//! `ring` or `openssl` (via the `use_ring` and `use_openssl` features respectively). +//! +//! Should you need something custom, then you can provide it by implementing +//! [`Cryptographer`] and using the [`set_cryptographer`] or +//! [`set_boxed_cryptographer`] functions. +use crate::DigestAlgorithm; + +pub(crate) mod holder; +pub(crate) use holder::get_crypographer; + +#[cfg(feature = "use_openssl")] +mod openssl; +#[cfg(feature = "use_ring")] +mod ring; + +#[cfg(not(any(feature = "use_ring", feature = "use_openssl")))] +pub use self::holder::{set_boxed_cryptographer, set_cryptographer}; + +#[derive(Debug, thiserror::Error)] +pub enum CryptoError { + /// The configured cryptographer does not support the digest algorithm + /// specified. This should only happen for custom `Cryptographer` implementations + #[error("Digest algorithm {0:?} is unsupported by this Cryptographer")] + UnsupportedDigest(DigestAlgorithm), + + /// The configured cryptographer implementation failed to perform an + /// operation in some way. + #[error("{0}")] + Other(#[source] anyhow::Error), +} + +/// A trait encapsulating the cryptographic operations required by this library. +/// +/// If you use this library with either the `use_ring` or `use_openssl` features enabled, +/// then you do not have to worry about this. +pub trait Cryptographer: Send + Sync + 'static { + fn rand_bytes(&self, output: &mut [u8]) -> Result<(), CryptoError>; + fn new_key( + &self, + algorithm: DigestAlgorithm, + key: &[u8], + ) -> Result<Box<dyn HmacKey>, CryptoError>; + fn new_hasher(&self, algo: DigestAlgorithm) -> Result<Box<dyn Hasher>, CryptoError>; + fn constant_time_compare(&self, a: &[u8], b: &[u8]) -> bool; +} + +/// Type-erased hmac key type. +pub trait HmacKey: Send + Sync + 'static { + fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CryptoError>; +} + +/// Type-erased hash context type. +pub trait Hasher: Send + Sync + 'static { + fn update(&mut self, data: &[u8]) -> Result<(), CryptoError>; + // Note: this would take by move but that's not object safe :( + fn finish(&mut self) -> Result<Vec<u8>, CryptoError>; +} + +// For convenience + +pub(crate) fn rand_bytes(buffer: &mut [u8]) -> Result<(), CryptoError> { + get_crypographer().rand_bytes(buffer) +} + +pub(crate) fn new_key( + algorithm: DigestAlgorithm, + key: &[u8], +) -> Result<Box<dyn HmacKey>, CryptoError> { + get_crypographer().new_key(algorithm, key) +} + +pub(crate) fn constant_time_compare(a: &[u8], b: &[u8]) -> bool { + get_crypographer().constant_time_compare(a, b) +} + +pub(crate) fn new_hasher(algorithm: DigestAlgorithm) -> Result<Box<dyn Hasher>, CryptoError> { + get_crypographer().new_hasher(algorithm) +} diff --git a/third_party/rust/hawk/src/crypto/openssl.rs b/third_party/rust/hawk/src/crypto/openssl.rs @@ -0,0 +1,98 @@ +use super::{CryptoError, Cryptographer, Hasher, HmacKey}; +use crate::DigestAlgorithm; +use std::convert::{TryFrom, TryInto}; + +use openssl::error::ErrorStack; +use openssl::hash::MessageDigest; +use openssl::pkey::{PKey, Private}; +use openssl::sign::Signer; + +impl From<ErrorStack> for CryptoError { + fn from(e: ErrorStack) -> Self { + CryptoError::Other(e.into()) + } +} + +pub struct OpensslCryptographer; + +struct OpensslHmacKey { + key: PKey<Private>, + digest: MessageDigest, +} + +impl HmacKey for OpensslHmacKey { + fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CryptoError> { + let mut hmac_signer = Signer::new(self.digest, &self.key)?; + hmac_signer.update(&data)?; + let digest = hmac_signer.sign_to_vec()?; + let mut mac = vec![0; self.digest.size()]; + mac.clone_from_slice(digest.as_ref()); + Ok(mac) + } +} + +// This is always `Some` until `finish` is called. +struct OpensslHasher(Option<openssl::hash::Hasher>); + +impl Hasher for OpensslHasher { + fn update(&mut self, data: &[u8]) -> Result<(), CryptoError> { + self.0 + .as_mut() + .expect("update called after `finish`") + .update(data)?; + Ok(()) + } + + fn finish(&mut self) -> Result<Vec<u8>, CryptoError> { + let digest = self.0.take().expect("`finish` called twice").finish()?; + let bytes: &[u8] = digest.as_ref(); + Ok(bytes.to_owned()) + } +} + +impl Cryptographer for OpensslCryptographer { + fn rand_bytes(&self, output: &mut [u8]) -> Result<(), CryptoError> { + openssl::rand::rand_bytes(output)?; + Ok(()) + } + + fn new_key( + &self, + algorithm: DigestAlgorithm, + key: &[u8], + ) -> Result<Box<dyn HmacKey>, CryptoError> { + let digest = algorithm.try_into()?; + Ok(Box::new(OpensslHmacKey { + key: PKey::hmac(key)?, + digest, + })) + } + + fn constant_time_compare(&self, a: &[u8], b: &[u8]) -> bool { + // openssl::memcmp::eq panics if the lengths are not the same. ring + // returns `Err` (and notes in the docs that it is not constant time if + // the lengths are not the same). We make this behave like ring. + if a.len() != b.len() { + false + } else { + openssl::memcmp::eq(a, b) + } + } + + fn new_hasher(&self, algorithm: DigestAlgorithm) -> Result<Box<dyn Hasher>, CryptoError> { + let ctx = openssl::hash::Hasher::new(algorithm.try_into()?)?; + Ok(Box::new(OpensslHasher(Some(ctx)))) + } +} + +impl TryFrom<DigestAlgorithm> for MessageDigest { + type Error = CryptoError; + fn try_from(algorithm: DigestAlgorithm) -> Result<Self, CryptoError> { + match algorithm { + DigestAlgorithm::Sha256 => Ok(MessageDigest::sha256()), + DigestAlgorithm::Sha384 => Ok(MessageDigest::sha384()), + DigestAlgorithm::Sha512 => Ok(MessageDigest::sha512()), + algo => Err(CryptoError::UnsupportedDigest(algo)), + } + } +} diff --git a/third_party/rust/hawk/src/crypto/ring.rs b/third_party/rust/hawk/src/crypto/ring.rs @@ -0,0 +1,97 @@ +use super::{CryptoError, Cryptographer, Hasher, HmacKey}; +use crate::DigestAlgorithm; +use ring::{digest, hmac}; +use std::convert::{TryFrom, TryInto}; + +impl From<ring::error::Unspecified> for CryptoError { + // Ring's errors are entirely opaque + fn from(_: ring::error::Unspecified) -> Self { + CryptoError::Other(anyhow::Error::msg("Unspecified ring error")) + } +} + +impl From<std::convert::Infallible> for CryptoError { + fn from(_: std::convert::Infallible) -> Self { + unreachable!() + } +} + +pub struct RingCryptographer; + +struct RingHmacKey(hmac::Key); + +impl HmacKey for RingHmacKey { + fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CryptoError> { + let digest = hmac::sign(&self.0, data); + let mut mac = vec![0; self.0.algorithm().digest_algorithm().output_len()]; + mac.copy_from_slice(digest.as_ref()); + Ok(mac) + } +} +// This is always `Some` until `finish` is called. +struct RingHasher(Option<digest::Context>); + +impl Hasher for RingHasher { + fn update(&mut self, data: &[u8]) -> Result<(), CryptoError> { + self.0 + .as_mut() + .expect("update called after `finish`") + .update(data); + Ok(()) + } + + fn finish(&mut self) -> Result<Vec<u8>, CryptoError> { + let digest = self.0.take().expect("`finish` called twice").finish(); + let bytes: &[u8] = digest.as_ref(); + Ok(bytes.to_owned()) + } +} + +impl Cryptographer for RingCryptographer { + fn rand_bytes(&self, output: &mut [u8]) -> Result<(), CryptoError> { + use ring::rand::SecureRandom; + let rnd = ring::rand::SystemRandom::new(); + rnd.fill(output)?; + Ok(()) + } + + fn new_key( + &self, + algorithm: DigestAlgorithm, + key: &[u8], + ) -> Result<Box<dyn HmacKey>, CryptoError> { + let k = hmac::Key::new(algorithm.try_into()?, key); + Ok(Box::new(RingHmacKey(k))) + } + + fn constant_time_compare(&self, a: &[u8], b: &[u8]) -> bool { + ring::constant_time::verify_slices_are_equal(a, b).is_ok() + } + + fn new_hasher(&self, algorithm: DigestAlgorithm) -> Result<Box<dyn Hasher>, CryptoError> { + let ctx = digest::Context::new(algorithm.try_into()?); + Ok(Box::new(RingHasher(Some(ctx)))) + } +} + +impl TryFrom<DigestAlgorithm> for &'static digest::Algorithm { + type Error = CryptoError; + fn try_from(algorithm: DigestAlgorithm) -> Result<Self, CryptoError> { + match algorithm { + DigestAlgorithm::Sha256 => Ok(&digest::SHA256), + DigestAlgorithm::Sha384 => Ok(&digest::SHA384), + DigestAlgorithm::Sha512 => Ok(&digest::SHA512), + } + } +} + +impl TryFrom<DigestAlgorithm> for hmac::Algorithm { + type Error = CryptoError; + fn try_from(algorithm: DigestAlgorithm) -> Result<Self, CryptoError> { + match algorithm { + DigestAlgorithm::Sha256 => Ok(hmac::HMAC_SHA256), + DigestAlgorithm::Sha384 => Ok(hmac::HMAC_SHA384), + DigestAlgorithm::Sha512 => Ok(hmac::HMAC_SHA512), + } + } +} diff --git a/third_party/rust/hawk/src/error.rs b/third_party/rust/hawk/src/error.rs @@ -0,0 +1,72 @@ +use crate::crypto::CryptoError; + +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Unparseable Hawk header: {0}")] + HeaderParseError(String), + + #[error("Invalid url: {0}")] + InvalidUrl(String), + + #[error("Missing `ts` attribute in Hawk header")] + MissingTs, + + #[error("Missing `nonce` attribute in Hawk header")] + MissingNonce, + + #[error("{0}")] + InvalidBewit(#[source] InvalidBewit), + + #[error("{0}")] + Io(#[source] std::io::Error), + + #[error("Base64 Decode error: {0}")] + Decode(String), + + #[error("Crypto error: {0}")] + Crypto(#[source] CryptoError), +} + +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum InvalidBewit { + #[error("Multiple bewits in URL")] + Multiple, + #[error("Invalid bewit format")] + Format, + #[error("Invalid bewit id")] + Id, + #[error("Invalid bewit exp")] + Exp, + #[error("Invalid bewit mac")] + Mac, + #[error("Invalid bewit ext")] + Ext, +} + +impl Error { + // this cannot be a `From<..>` implementation as that publicly exposes the version of base64 + // used in this crate. + pub(crate) fn from_base64_error(e: base64::DecodeError) -> Self { + Error::Decode(e.to_string()) + } +} + +impl From<std::io::Error> for Error { + fn from(e: std::io::Error) -> Self { + Error::Io(e) + } +} + +impl From<CryptoError> for Error { + fn from(e: CryptoError) -> Self { + Error::Crypto(e) + } +} + +impl From<InvalidBewit> for Error { + fn from(e: InvalidBewit) -> Self { + Error::InvalidBewit(e) + } +} diff --git a/third_party/rust/hawk/src/header.rs b/third_party/rust/hawk/src/header.rs @@ -0,0 +1,472 @@ +use crate::b64; +use crate::error::*; +use crate::mac::Mac; +use base64::Engine; +use std::fmt; +use std::str::FromStr; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +/// Representation of a Hawk `Authorization` header value (the part following "Hawk "). +/// +/// Headers can be derived from strings using the `FromStr` trait, and formatted into a +/// string using the `fmt_header` method. +/// +/// All fields are optional, although for specific purposes some fields must be present. +#[derive(Clone, PartialEq, Debug)] +pub struct Header { + pub id: Option<String>, + pub ts: Option<SystemTime>, + pub nonce: Option<String>, + pub mac: Option<Mac>, + pub ext: Option<String>, + pub hash: Option<Vec<u8>>, + pub app: Option<String>, + pub dlg: Option<String>, +} + +impl Header { + /// Create a new Header with the full set of Hawk fields. + /// + /// This is a low-level function. Headers are more often created from Requests or Responses. + /// + /// Note that none of the string-formatted header components can contain the character `\"`. + pub fn new<S>( + id: Option<S>, + ts: Option<SystemTime>, + nonce: Option<S>, + mac: Option<Mac>, + ext: Option<S>, + hash: Option<Vec<u8>>, + app: Option<S>, + dlg: Option<S>, + ) -> Result<Header> + where + S: Into<String>, + { + Ok(Header { + id: Header::check_component(id)?, + ts, + nonce: Header::check_component(nonce)?, + mac, + ext: Header::check_component(ext)?, + hash, + app: Header::check_component(app)?, + dlg: Header::check_component(dlg)?, + }) + } + + /// Check a header component for validity. + fn check_component<S>(value: Option<S>) -> Result<Option<String>> + where + S: Into<String>, + { + if let Some(value) = value { + let value = value.into(); + if value.contains('\"') { + return Err(Error::HeaderParseError( + "Hawk headers cannot contain `\\`".into(), + )); + } + Ok(Some(value)) + } else { + Ok(None) + } + } + + /// Format the header for transmission in an Authorization header, omitting the `"Hawk "` + /// prefix. + pub fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut sep = ""; + if let Some(ref id) = self.id { + write!(f, "{sep}id=\"{id}\"")?; + sep = ", "; + } + if let Some(ref ts) = self.ts { + write!( + f, + "{}ts=\"{}\"", + sep, + ts.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() + )?; + sep = ", "; + } + if let Some(ref nonce) = self.nonce { + write!(f, "{sep}nonce=\"{nonce}\"")?; + sep = ", "; + } + if let Some(ref mac) = self.mac { + write!(f, "{}mac=\"{}\"", sep, b64::STANDARD_ENGINE.encode(mac))?; + sep = ", "; + } + if let Some(ref ext) = self.ext { + write!(f, "{sep}ext=\"{ext}\"")?; + sep = ", "; + } + if let Some(ref hash) = self.hash { + write!(f, "{}hash=\"{}\"", sep, b64::STANDARD_ENGINE.encode(hash))?; + sep = ", "; + } + if let Some(ref app) = self.app { + write!(f, "{sep}app=\"{app}\"")?; + sep = ", "; + } + if let Some(ref dlg) = self.dlg { + write!(f, "{sep}dlg=\"{dlg}\"")?; + } + Ok(()) + } +} + +impl fmt::Display for Header { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.fmt_header(f) + } +} + +impl FromStr for Header { + type Err = Error; + fn from_str(s: &str) -> Result<Header> { + let mut p = s; + + // Required attributes + let mut id: Option<&str> = None; + let mut ts: Option<SystemTime> = None; + let mut nonce: Option<&str> = None; + let mut mac: Option<Vec<u8>> = None; + // Optional attributes + let mut hash: Option<Vec<u8>> = None; + let mut ext: Option<&str> = None; + let mut app: Option<&str> = None; + let mut dlg: Option<&str> = None; + + while !p.is_empty() { + // Skip whitespace and commas used as separators + p = p.trim_start_matches(|c| c == ',' || char::is_whitespace(c)); + // Find first '=' which delimits attribute name from value + let assign_end = p + .find('=') + .ok_or_else(|| Error::HeaderParseError("Expected '='".into()))?; + let attr = &p[..assign_end].trim(); + if p.len() < assign_end + 1 { + return Err(Error::HeaderParseError( + "Missing right hand side of =".into(), + )); + } + p = p[assign_end + 1..].trim_start(); + if !p.starts_with('\"') { + return Err(Error::HeaderParseError("Expected opening quote".into())); + } + p = &p[1..]; + // We have poor RFC 7235 compliance here as we ought to support backslash + // escaped characters, but hawk doesn't allow this we won't either. All + // strings must be surrounded by ".." and contain no such characters. + let end = p.find('\"'); + let val_end = + end.ok_or_else(|| Error::HeaderParseError("Expected closing quote".into()))?; + let val = &p[..val_end]; + match *attr { + "id" => id = Some(val), + "ts" => { + let epoch = u64::from_str(val) + .map_err(|_| Error::HeaderParseError("Error parsing `ts` field".into()))?; + ts = Some(UNIX_EPOCH + Duration::new(epoch, 0)); + } + "mac" => { + mac = Some(b64::STANDARD_ENGINE.decode(val).map_err(|_| { + Error::HeaderParseError("Error parsing `mac` field".into()) + })?); + } + "nonce" => nonce = Some(val), + "ext" => ext = Some(val), + "hash" => { + hash = Some(b64::STANDARD_ENGINE.decode(val).map_err(|_| { + Error::HeaderParseError("Error parsing `hash` field".into()) + })?); + } + "app" => app = Some(val), + "dlg" => dlg = Some(val), + _ => { + return Err(Error::HeaderParseError(format!( + "Invalid Hawk field {}", + *attr + ))) + } + }; + // Break if we are at end of string, otherwise skip separator + if p.len() < val_end + 1 { + break; + } + p = p[val_end + 1..].trim_start(); + } + + Ok(Header { + id: id.map(|id| id.to_string()), + ts, + nonce: nonce.map(|nonce| nonce.to_string()), + mac: mac.map(Mac::from), + ext: ext.map(|ext| ext.to_string()), + hash, + app: app.map(|app| app.to_string()), + dlg: dlg.map(|dlg| dlg.to_string()), + }) + } +} + +#[cfg(test)] +mod test { + use super::Header; + use crate::mac::Mac; + use std::str::FromStr; + use std::time::{Duration, UNIX_EPOCH}; + + #[test] + fn illegal_id() { + assert!(Header::new( + Some("ab\"cdef"), + Some(UNIX_EPOCH + Duration::new(1234, 0)), + Some("nonce"), + Some(Mac::from(vec![])), + Some("ext"), + None, + None, + None + ) + .is_err()); + } + + #[test] + fn illegal_nonce() { + assert!(Header::new( + Some("abcdef"), + Some(UNIX_EPOCH + Duration::new(1234, 0)), + Some("no\"nce"), + Some(Mac::from(vec![])), + Some("ext"), + None, + None, + None + ) + .is_err()); + } + + #[test] + fn illegal_ext() { + assert!(Header::new( + Some("abcdef"), + Some(UNIX_EPOCH + Duration::new(1234, 0)), + Some("nonce"), + Some(Mac::from(vec![])), + Some("ex\"t"), + None, + None, + None + ) + .is_err()); + } + + #[test] + fn illegal_app() { + assert!(Header::new( + Some("abcdef"), + Some(UNIX_EPOCH + Duration::new(1234, 0)), + Some("nonce"), + Some(Mac::from(vec![])), + None, + None, + Some("a\"pp"), + None + ) + .is_err()); + } + + #[test] + fn illegal_dlg() { + assert!(Header::new( + Some("abcdef"), + Some(UNIX_EPOCH + Duration::new(1234, 0)), + Some("nonce"), + Some(Mac::from(vec![])), + None, + None, + None, + Some("d\"lg") + ) + .is_err()); + } + + #[test] + fn from_str() { + let s = Header::from_str( + "id=\"dh37fgj492je\", ts=\"1353832234\", \ + nonce=\"j4h3g2\", ext=\"some-app-ext-data\", \ + mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\", \ + hash=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\", \ + app=\"my-app\", dlg=\"my-authority\"", + ) + .unwrap(); + assert!(s.id == Some("dh37fgj492je".to_string())); + assert!(s.ts == Some(UNIX_EPOCH + Duration::new(1353832234, 0))); + assert!(s.nonce == Some("j4h3g2".to_string())); + assert!( + s.mac + == Some(Mac::from(vec![ + 233, 30, 43, 87, 152, 132, 248, 211, 232, 202, 111, 150, 194, 55, 135, 206, 48, + 6, 93, 75, 75, 52, 140, 102, 163, 91, 233, 50, 135, 233, 44, 1 + ])) + ); + assert!(s.ext == Some("some-app-ext-data".to_string())); + assert!(s.app == Some("my-app".to_string())); + assert!(s.dlg == Some("my-authority".to_string())); + } + + #[test] + fn from_str_invalid_mac() { + let r = Header::from_str( + "id=\"dh37fgj492je\", ts=\"1353832234\", \ + nonce=\"j4h3g2\", ext=\"some-app-ext-data\", \ + mac=\"6!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AE=\", \ + app=\"my-app\", dlg=\"my-authority\"", + ); + assert!(r.is_err()); + } + + #[test] + fn from_str_no_field() { + let s = Header::from_str("").unwrap(); + assert!(s.id.is_none()); + assert!(s.ts.is_none()); + assert!(s.nonce.is_none()); + assert!(s.mac.is_none()); + assert!(s.ext.is_none()); + assert!(s.app.is_none()); + assert!(s.dlg.is_none()); + } + + #[test] + fn from_str_few_field() { + let s = Header::from_str( + "id=\"xyz\", ts=\"1353832234\", \ + nonce=\"abc\", \ + mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\"", + ) + .unwrap(); + assert!(s.id == Some("xyz".to_string())); + assert!(s.ts == Some(UNIX_EPOCH + Duration::new(1353832234, 0))); + assert!(s.nonce == Some("abc".to_string())); + assert!( + s.mac + == Some(Mac::from(vec![ + 233, 30, 43, 87, 152, 132, 248, 211, 232, 202, 111, 150, 194, 55, 135, 206, 48, + 6, 93, 75, 75, 52, 140, 102, 163, 91, 233, 50, 135, 233, 44, 1 + ])) + ); + assert!(s.ext.is_none()); + assert!(s.app.is_none()); + assert!(s.dlg.is_none()); + } + + #[test] + fn from_str_messy() { + let s = Header::from_str( + ", id = \"dh37fgj492je\", ts=\"1353832234\", \ + nonce=\"j4h3g2\" , , ext=\"some-app-ext-data\", \ + mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\"", + ) + .unwrap(); + assert!(s.id == Some("dh37fgj492je".to_string())); + assert!(s.ts == Some(UNIX_EPOCH + Duration::new(1353832234, 0))); + assert!(s.nonce == Some("j4h3g2".to_string())); + assert!( + s.mac + == Some(Mac::from(vec![ + 233, 30, 43, 87, 152, 132, 248, 211, 232, 202, 111, 150, 194, 55, 135, 206, 48, + 6, 93, 75, 75, 52, 140, 102, 163, 91, 233, 50, 135, 233, 44, 1 + ])) + ); + assert!(s.ext == Some("some-app-ext-data".to_string())); + assert!(s.app.is_none()); + assert!(s.dlg.is_none()); + } + + #[test] + fn to_str_no_fields() { + // must supply a type for S, since it is otherwise unused + let s = Header::new::<String>(None, None, None, None, None, None, None, None).unwrap(); + let formatted = format!("{s}"); + println!("got: {formatted}"); + assert!(formatted.is_empty()) + } + + #[test] + fn to_str_few_fields() { + let s = Header::new( + Some("dh37fgj492je"), + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + Some(Mac::from(vec![ + 8, 35, 182, 149, 42, 111, 33, 192, 19, 22, 94, 43, 118, 176, 65, 69, 86, 4, 156, + 184, 85, 107, 249, 242, 172, 200, 66, 209, 57, 63, 38, 83, + ])), + None, + None, + None, + None, + ) + .unwrap(); + let formatted = format!("{s}"); + println!("got: {formatted}"); + assert!( + formatted + == "id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", \ + mac=\"CCO2lSpvIcATFl4rdrBBRVYEnLhVa/nyrMhC0Tk/JlM=\"" + ) + } + + #[test] + fn to_str_maximal() { + let s = Header::new( + Some("dh37fgj492je"), + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + Some(Mac::from(vec![ + 8, 35, 182, 149, 42, 111, 33, 192, 19, 22, 94, 43, 118, 176, 65, 69, 86, 4, 156, + 184, 85, 107, 249, 242, 172, 200, 66, 209, 57, 63, 38, 83, + ])), + Some("my-ext-value"), + Some(vec![1, 2, 3, 4]), + Some("my-app"), + Some("my-dlg"), + ) + .unwrap(); + let formatted = format!("{s}"); + println!("got: {formatted}"); + assert!( + formatted + == "id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", \ + mac=\"CCO2lSpvIcATFl4rdrBBRVYEnLhVa/nyrMhC0Tk/JlM=\", ext=\"my-ext-value\", \ + hash=\"AQIDBA==\", app=\"my-app\", dlg=\"my-dlg\"" + ) + } + + #[test] + fn round_trip() { + let s = Header::new( + Some("dh37fgj492je"), + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + Some(Mac::from(vec![ + 8, 35, 182, 149, 42, 111, 33, 192, 19, 22, 94, 43, 118, 176, 65, 69, 86, 4, 156, + 184, 85, 107, 249, 242, 172, 200, 66, 209, 57, 63, 38, 83, + ])), + Some("my-ext-value"), + Some(vec![1, 2, 3, 4]), + Some("my-app"), + Some("my-dlg"), + ) + .unwrap(); + let formatted = format!("{s}"); + println!("got: {s}"); + let s2 = Header::from_str(&formatted).unwrap(); + assert!(s2 == s); + } +} diff --git a/third_party/rust/hawk/src/lib.rs b/third_party/rust/hawk/src/lib.rs @@ -0,0 +1,171 @@ +//! The `hawk` crate provides support for [Hawk](https://github.com/hueniverse/hawk) +//! authentictation. It is a low-level crate, used by higher-level crates to integrate with various +//! Rust HTTP libraries. For example `hyper-hawk` integrates Hawk with Hyper. +//! +//! # Examples +//! +//! ## Hawk Client +//! +//! A client can attach a Hawk Authorization header to requests by providing credentials to a +//! Request instance, which will generate the header. +//! +//! ``` +//! use hawk::{RequestBuilder, Credentials, Key, SHA256, PayloadHasher}; +//! use std::time::{Duration, UNIX_EPOCH}; +//! +//! // provide the Hawk id and key +//! let credentials = Credentials { +//! id: "test-client".to_string(), +//! key: Key::new(vec![99u8; 32], SHA256).unwrap(), +//! }; +//! +//! let payload_hash = PayloadHasher::hash("text/plain", SHA256, "request-body").unwrap(); +//! +//! // provide the details of the request to be authorized +//! let request = RequestBuilder::new("POST", "example.com", 80, "/v1/users") +//! .hash(&payload_hash[..]) +//! .request(); +//! +//! // Get the resulting header, including the calculated MAC; this involves a random +//! // nonce, so the MAC will be different on every request. +//! let header = request.make_header(&credentials).unwrap(); +//! +//! // the header would the be attached to the request +//! assert_eq!(header.id.unwrap(), "test-client"); +//! assert_eq!(header.mac.unwrap().len(), 32); +//! assert_eq!(header.hash.unwrap().len(), 32); +//! ``` +//! +//! A client that wishes to use a bewit (URL parameter) can do so as follows: +//! +//! ``` +//! use hawk::{RequestBuilder, Credentials, Key, SHA256, Bewit}; +//! use std::time::Duration; +//! use std::borrow::Cow; +//! +//! let credentials = Credentials { +//! id: "me".to_string(), +//! key: Key::new("tok", SHA256).unwrap(), +//! }; +//! +//! let client_req = RequestBuilder::new("GET", "mysite.com", 443, "/resource").request(); +//! let client_bewit = client_req +//! .make_bewit_with_ttl(&credentials, Duration::from_secs(10)) +//! .unwrap(); +//! let request_path = format!("/resource?bewit={}", client_bewit.to_str()); +//! // .. make the request +//! ``` +//! +//! ## Hawk Server +//! +//! To act as a server, parse the Hawk Authorization header from the request, generate a new +//! Request instance, and use the request to validate the header. +//! +//! ``` +//! use hawk::{RequestBuilder, Header, Key, SHA256}; +//! use hawk::mac::Mac; +//! use std::time::{Duration, UNIX_EPOCH}; +//! +//! let mac = Mac::from(vec![7, 22, 226, 240, 84, 78, 49, 75, 115, 144, 70, +//! 106, 102, 134, 144, 128, 225, 239, 95, 132, 202, +//! 154, 213, 118, 19, 63, 183, 108, 215, 134, 118, 115]); +//! // get the header (usually from the received request; constructed directly here) +//! let hdr = Header::new(Some("dh37fgj492je"), +//! Some(UNIX_EPOCH + Duration::new(1353832234, 0)), +//! Some("j4h3g2"), +//! Some(mac), +//! Some("my-ext-value"), +//! Some(vec![1, 2, 3, 4]), +//! Some("my-app"), +//! Some("my-dlg")).unwrap(); +//! +//! // build a request object based on what we know +//! let hash = vec![1, 2, 3, 4]; +//! let request = RequestBuilder::new("GET", "localhost", 443, "/resource") +//! .hash(&hash[..]) +//! .request(); +//! +//! let key = Key::new(vec![99u8; 32], SHA256).unwrap(); +//! let one_week_in_secs = 7 * 24 * 60 * 60; +//! if !request.validate_header(&hdr, &key, Duration::from_secs(5200 * one_week_in_secs)) { +//! panic!("header validation failed. Is it 2117 already?"); +//! } +//! ``` +//! +//! A server which validates bewits looks like this: +//! +//! ``` +//! use hawk::{RequestBuilder, Credentials, Key, SHA256, Bewit}; +//! use std::time::Duration; +//! use std::borrow::Cow; +//! +//! let credentials = Credentials { +//! id: "me".to_string(), +//! key: Key::new("tok", SHA256).unwrap(), +//! }; +//! +//! // simulate the client generation of a bewit +//! let client_req = RequestBuilder::new("GET", "mysite.com", 443, "/resource").request(); +//! let client_bewit = client_req +//! .make_bewit_with_ttl(&credentials, Duration::from_secs(10)) +//! .unwrap(); +//! let request_path = format!("/resource?bewit={}", client_bewit.to_str()); +//! +//! let mut maybe_bewit = None; +//! let server_req = RequestBuilder::new("GET", "mysite.com", 443, &request_path) +//! .extract_bewit(&mut maybe_bewit).unwrap() +//! .request(); +//! let bewit = maybe_bewit.unwrap(); +//! assert_eq!(bewit.id(), "me"); +//! assert!(server_req.validate_bewit(&bewit, &credentials.key)); +//! ``` +//! +//! ## Features +//! +//! By default, the `use_ring` feature is enabled, which means that this crate will +//! use `ring` for all cryptographic operations. +//! +//! Alternatively, one can configure the crate with the `use_openssl` +//! feature to use the `openssl` crate. +//! +//! If no features are enabled, you must provide a custom implementation of the +//! [`hawk::crypto::Cryptographer`] trait to the `set_cryptographer` function, or +//! the cryptographic operations will panic. +//! +//! Attempting to configure both the `use_ring` and `use_openssl` features will +//! result in a build error. + +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; + +mod header; +pub use crate::header::Header; + +mod credentials; +pub use crate::credentials::{Credentials, DigestAlgorithm, Key}; + +mod request; +pub use crate::request::{Request, RequestBuilder}; + +mod response; +pub use crate::response::{Response, ResponseBuilder}; + +mod error; +pub use crate::error::*; + +mod payload; +pub use crate::payload::PayloadHasher; + +mod bewit; +pub use crate::bewit::Bewit; + +mod b64; + +pub mod mac; + +pub mod crypto; + +pub const SHA256: DigestAlgorithm = DigestAlgorithm::Sha256; +pub const SHA384: DigestAlgorithm = DigestAlgorithm::Sha384; +pub const SHA512: DigestAlgorithm = DigestAlgorithm::Sha512; diff --git a/third_party/rust/hawk/src/mac.rs b/third_party/rust/hawk/src/mac.rs @@ -0,0 +1,201 @@ +use crate::b64; +use crate::credentials::Key; +use crate::error::*; +use base64::Engine; +use std::io::Write; +use std::ops::Deref; +use std::time::{SystemTime, UNIX_EPOCH}; + +/// The kind of MAC calcuation (corresponding to the first line of the message) +pub enum MacType { + Header, + Response, + Bewit, +} + +/// Mac represents a message authentication code, the signature in a Hawk transaction. +/// +/// This class supports creating Macs using the Hawk specification, and comparing Macs +/// using a cosntant-time comparison (thus preventing timing side-channel attacks). +#[derive(Debug, Clone)] +pub struct Mac(Vec<u8>); + +impl Mac { + pub fn new( + mac_type: MacType, + key: &Key, + ts: SystemTime, + nonce: &str, + method: &str, + host: &str, + port: u16, + path: &str, + hash: Option<&[u8]>, + ext: Option<&str>, + ) -> Result<Mac> { + // Note: there's a \n after each item. + let mut buffer: Vec<u8> = Vec::with_capacity( + 15 + 1 + // mac_type (worst case since it doesn't really matter) + 10 + 1 + // ts (in practice this will be 10 bytes) + nonce.len() + 1 + + host.len() + 1 + + 6 + 1 + // Longer than 6 bytes of port seems very unlikely + path.len() + 1 + + hash.map_or(0, |h| h.len() * 4 / 3) + 1 + + ext.map_or(0, str::len) + 1, + ); + + writeln!( + buffer, + "{mac_type}\n{ts}\n{nonce}\n{method}\n{path}\n{host}\n{port}", + mac_type = match mac_type { + MacType::Header => "hawk.1.header", + MacType::Response => "hawk.1.response", + MacType::Bewit => "hawk.1.bewit", + }, + ts = ts.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(), + nonce = nonce, + method = method, + path = path, + host = host, + port = port, + )?; + + if let Some(h) = hash { + writeln!(buffer, "{}", b64::STANDARD_ENGINE.encode(h),)?; + } else { + writeln!(buffer)?; + } + writeln!(buffer, "{}", ext.unwrap_or_default())?; + + Ok(Mac(key.sign(buffer.as_ref())?)) + } +} + +impl AsRef<[u8]> for Mac { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl From<Vec<u8>> for Mac { + fn from(original: Vec<u8>) -> Self { + Mac(original) + } +} + +impl Deref for Mac { + type Target = Vec<u8>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl PartialEq for Mac { + fn eq(&self, other: &Mac) -> bool { + crate::crypto::constant_time_compare(&self.0, &other.0) + } +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod test { + use super::{Mac, MacType}; + use crate::credentials::Key; + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + + fn key() -> Key { + Key::new( + vec![ + 11u8, 19, 228, 209, 79, 189, 200, 59, 166, 47, 86, 254, 235, 184, 120, 197, 75, + 152, 201, 79, 115, 61, 111, 242, 219, 187, 173, 14, 227, 108, 60, 232, + ], + crate::SHA256, + ) + .unwrap() + } + + fn sys_time(secs: u64, ns: u32) -> SystemTime { + UNIX_EPOCH + Duration::new(secs, ns) + } + + #[test] + fn test_make_mac() { + let key = key(); + let mac = Mac::new( + MacType::Header, + &key, + sys_time(1000, 100), + "nonny", + "POST", + "mysite.com", + 443, + "/v1/api", + None, + None, + ) + .unwrap(); + println!("got {mac:?}"); + assert!( + mac.0 + == vec![ + 192, 227, 235, 121, 157, 185, 197, 79, 189, 214, 235, 139, 9, 232, 99, 55, 67, + 30, 68, 0, 150, 187, 192, 238, 21, 200, 209, 107, 245, 159, 243, 178 + ] + ); + } + + #[test] + fn test_make_mac_hash() { + let key = key(); + let hash = vec![1, 2, 3, 4, 5]; + let mac = Mac::new( + MacType::Header, + &key, + sys_time(1000, 100), + "nonny", + "POST", + "mysite.com", + 443, + "/v1/api", + Some(&hash), + None, + ) + .unwrap(); + println!("got {mac:?}"); + assert!( + mac.0 + == vec![ + 61, 128, 208, 253, 88, 135, 190, 196, 1, 69, 153, 193, 124, 4, 195, 87, 38, 96, + 181, 34, 65, 234, 58, 157, 175, 175, 145, 151, 61, 0, 57, 5 + ] + ); + } + + #[test] + fn test_make_mac_ext() { + let key = key(); + let ext = "ext-data".to_string(); + let mac = Mac::new( + MacType::Header, + &key, + sys_time(1000, 100), + "nonny", + "POST", + "mysite.com", + 443, + "/v1/api", + None, + Some(&ext), + ) + .unwrap(); + println!("got {mac:?}"); + assert!( + mac.0 + == vec![ + 187, 104, 238, 100, 168, 112, 37, 68, 187, 141, 168, 155, 177, 193, 113, 0, 50, + 105, 127, 36, 24, 117, 200, 251, 138, 199, 108, 14, 105, 123, 234, 119 + ] + ); + } +} diff --git a/third_party/rust/hawk/src/payload.rs b/third_party/rust/hawk/src/payload.rs @@ -0,0 +1,87 @@ +use crate::error::*; +use crate::{crypto, DigestAlgorithm}; +/// A utility for hashing payloads. Feed your entity body to this, then pass the `finish` +/// result to a request or response. +pub struct PayloadHasher(Box<dyn crypto::Hasher>); + +impl PayloadHasher { + /// Create a new PayloadHasher. The `content_type` should be lower-case and should + /// not include parameters. The digest is assumed to be the same as the digest used + /// for the credentials in the request. + pub fn new<B>(content_type: B, algorithm: DigestAlgorithm) -> Result<Self> + where + B: AsRef<[u8]>, + { + let mut hasher = PayloadHasher(crypto::new_hasher(algorithm)?); + hasher.update(b"hawk.1.payload\n")?; + hasher.update(content_type.as_ref())?; + hasher.update(b"\n")?; + Ok(hasher) + } + + /// Hash a single value and return it + pub fn hash<B1, B2>( + content_type: B1, + algorithm: DigestAlgorithm, + payload: B2, + ) -> Result<Vec<u8>> + where + B1: AsRef<[u8]>, + B2: AsRef<[u8]>, + { + let mut hasher = PayloadHasher::new(content_type, algorithm)?; + hasher.update(payload)?; + hasher.finish() + } + + /// Update the hash with new data. + pub fn update<B>(&mut self, data: B) -> Result<()> + where + B: AsRef<[u8]>, + { + self.0.update(data.as_ref())?; + Ok(()) + } + + /// Finish hashing and return the result + /// + /// Note that this appends a newline to the payload, as does the JS Hawk implementaiton. + pub fn finish(mut self) -> Result<Vec<u8>> { + self.update(b"\n")?; + Ok(self.0.finish()?) + } +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod tests { + use super::PayloadHasher; + + #[test] + fn hash_consistency() -> super::Result<()> { + let mut hasher1 = PayloadHasher::new("text/plain", crate::SHA256)?; + hasher1.update("pày")?; + hasher1.update("load")?; + let hash1 = hasher1.finish()?; + + let mut hasher2 = PayloadHasher::new("text/plain", crate::SHA256)?; + hasher2.update("pàyload")?; + let hash2 = hasher2.finish()?; + + let hash3 = PayloadHasher::hash("text/plain", crate::SHA256, "pàyload")?; + + let hash4 = // "pàyload" as utf-8 bytes + PayloadHasher::hash("text/plain", crate::SHA256, vec![112, 195, 160, 121, 108, 111, 97, 100])?; + + assert_eq!( + hash1, + vec![ + 228, 238, 241, 224, 235, 114, 158, 112, 211, 254, 118, 89, 25, 236, 87, 176, 181, + 54, 61, 135, 42, 223, 188, 103, 194, 59, 83, 36, 136, 31, 198, 50 + ] + ); + assert_eq!(hash2, hash1); + assert_eq!(hash3, hash1); + assert_eq!(hash4, hash1); + Ok(()) + } +} diff --git a/third_party/rust/hawk/src/request.rs b/third_party/rust/hawk/src/request.rs @@ -0,0 +1,954 @@ +use crate::b64; +use crate::bewit::Bewit; +use crate::credentials::{Credentials, Key}; +use crate::error::*; +use crate::header::Header; +use crate::mac::{Mac, MacType}; +use crate::response::ResponseBuilder; +use base64::Engine; +use log::debug; +use std::borrow::Cow; +use std::str; +use std::str::FromStr; +use std::time::{Duration, SystemTime}; +use url::{Position, Url}; + +/// Request represents a single HTTP request. +/// +/// The structure is created using (RequestBuilder)[struct.RequestBuilder.html]. Most uses of this +/// library will hold several of the fields in this structure fixed. Cloning the structure with +/// these fields applied is a convenient way to avoid repeating those fields. Most fields are +/// references, since in common use the values already exist and will outlive the request. +/// +/// A request can be used on the client, to generate a header or a bewit, or on the server, to +/// validate the same. +/// +/// # Examples +/// +/// ``` +/// use hawk::RequestBuilder; +/// let bldr = RequestBuilder::new("GET", "mysite.com", 443, "/"); +/// let request1 = bldr.clone().method("POST").path("/api/user").request(); +/// let request2 = bldr.path("/api/users").request(); +/// ``` +/// +/// See the documentation in the crate root for examples of creating and validating headers. +#[derive(Debug, Clone)] +pub struct Request<'a> { + method: &'a str, + host: &'a str, + port: u16, + path: Cow<'a, str>, + hash: Option<&'a [u8]>, + ext: Option<&'a str>, + app: Option<&'a str>, + dlg: Option<&'a str>, +} + +impl<'a> Request<'a> { + /// Create a new Header for this request, inventing a new nonce and setting the + /// timestamp to the current time. + pub fn make_header(&self, credentials: &Credentials) -> Result<Header> { + let nonce = random_string(10)?; + self.make_header_full(credentials, SystemTime::now(), nonce) + } + + /// Similar to `make_header`, but allowing specification of the timestamp + /// and nonce. + pub fn make_header_full<S>( + &self, + credentials: &Credentials, + ts: SystemTime, + nonce: S, + ) -> Result<Header> + where + S: Into<String>, + { + let nonce = nonce.into(); + let mac = Mac::new( + MacType::Header, + &credentials.key, + ts, + &nonce, + self.method, + self.host, + self.port, + self.path.as_ref(), + self.hash, + self.ext, + )?; + Header::new( + Some(credentials.id.clone()), + Some(ts), + Some(nonce), + Some(mac), + self.ext.map(|v| v.to_string()), + self.hash.map(|v| v.to_vec()), + self.app.map(|v| v.to_string()), + self.dlg.map(|v| v.to_string()), + ) + } + + /// Make a "bewit" that can be attached to a URL to authenticate GET access. + /// + /// The ttl gives the time for which this bewit is valid, starting now. + pub fn make_bewit(&self, credentials: &'a Credentials, exp: SystemTime) -> Result<Bewit<'a>> { + // note that this includes `method` and `hash` even though they must always be GET and None + // for bewits. If they aren't, then the bewit just won't validate -- no need to catch + // that now + let mac = Mac::new( + MacType::Bewit, + &credentials.key, + exp, + "", + self.method, + self.host, + self.port, + self.path.as_ref(), + self.hash, + self.ext, + )?; + let bewit = Bewit::new(&credentials.id, exp, mac, self.ext); + Ok(bewit) + } + + /// Variant of `make_bewit` that takes a Duration (starting from now) + /// instead of a SystemTime, provided for convenience. + pub fn make_bewit_with_ttl( + &self, + credentials: &'a Credentials, + ttl: Duration, + ) -> Result<Bewit<'a>> { + let exp = SystemTime::now() + ttl; + self.make_bewit(credentials, exp) + } + + /// Validate the given header. This validates that the `mac` field matches that calculated + /// using the other header fields and the given request information. + /// + /// The header's timestamp is verified to be within `ts_skew` of the current time. If any of + /// the required header fields are missing, the method will return false. + /// + /// It is up to the caller to examine the header's `id` field and supply the corresponding key. + /// + /// If desired, it is up to the caller to validate that `nonce` has not been used before. + /// + /// If a hash has been supplied, then the header must contain a matching hash. Note that this + /// hash must be calculated based on the request body, not copied from the request header! + pub fn validate_header(&self, header: &Header, key: &Key, ts_skew: Duration) -> bool { + // extract required fields, returning early if they are not present + let ts = match header.ts { + Some(ts) => ts, + None => { + debug!("missing timestamp from header"); + return false; + } + }; + let nonce = match header.nonce { + Some(ref nonce) => nonce, + None => { + debug!("missing nonce from header"); + return false; + } + }; + let header_mac = match header.mac { + Some(ref mac) => mac, + None => { + debug!("missing mac from header"); + return false; + } + }; + let header_hash = header.hash.as_ref().map(|hash| &hash[..]); + let header_ext = header.ext.as_ref().map(|ext| &ext[..]); + + // first verify the MAC + match Mac::new( + MacType::Header, + key, + ts, + nonce, + self.method, + self.host, + self.port, + self.path.as_ref(), + header_hash, + header_ext, + ) { + Ok(calculated_mac) => { + if &calculated_mac != header_mac { + debug!("calculated mac doesn't match header"); + return false; + } + } + Err(e) => { + debug!("unexpected mac error: {:?}", e); + return false; + } + }; + + // ..then the hashes + if let Some(local_hash) = self.hash { + if let Some(server_hash) = header_hash { + if local_hash != server_hash { + debug!("server hash doesn't match header"); + return false; + } + } else { + debug!("missing hash from header"); + return false; + } + } + + // ..then the timestamp + let now = SystemTime::now(); + let skew = if now > ts { + now.duration_since(ts).unwrap() + } else { + ts.duration_since(now).unwrap() + }; + if skew > ts_skew { + debug!( + "bad timestamp skew, timestamp too old? detected skew: {:?}, ts_skew: {:?}", + &skew, &ts_skew + ); + return false; + } + + true + } + + /// Validate the given bewit matches this request. + /// + /// It is up to the caller to consult the Bewit's `id` and look up the + /// corresponding key. + /// + /// Nonces and hashes do not apply when using bewits. + pub fn validate_bewit(&self, bewit: &Bewit, key: &Key) -> bool { + let calculated_mac = Mac::new( + MacType::Bewit, + key, + bewit.exp(), + "", + self.method, + self.host, + self.port, + self.path.as_ref(), + self.hash, + match bewit.ext() { + Some(e) => Some(e), + None => None, + }, + ); + let calculated_mac = match calculated_mac { + Ok(m) => m, + Err(_) => { + return false; + } + }; + + if bewit.mac() != &calculated_mac { + return false; + } + + let now = SystemTime::now(); + if bewit.exp() < now { + return false; + } + + true + } + + /// Get a Response instance for a response to this request. This is a convenience + /// wrapper around `Response::from_request_header`. + pub fn make_response_builder(&'a self, req_header: &'a Header) -> ResponseBuilder<'a> { + ResponseBuilder::from_request_header( + req_header, + self.method, + self.host, + self.port, + self.path.as_ref(), + ) + } +} + +#[derive(Debug, Clone)] +pub struct RequestBuilder<'a>(Request<'a>); + +impl<'a> RequestBuilder<'a> { + /// Create a new request with the given method, host, port, and path. + pub fn new(method: &'a str, host: &'a str, port: u16, path: &'a str) -> Self { + RequestBuilder(Request { + method, + host, + port, + path: Cow::Borrowed(path), + hash: None, + ext: None, + app: None, + dlg: None, + }) + } + + /// Create a new request with the host, port, and path determined from the URL. + pub fn from_url(method: &'a str, url: &'a Url) -> Result<Self> { + let (host, port, path) = RequestBuilder::parse_url(url)?; + Ok(RequestBuilder(Request { + method, + host, + port, + path: Cow::Borrowed(path), + hash: None, + ext: None, + app: None, + dlg: None, + })) + } + + /// Set the request method. This should be a capitalized string. + pub fn method(mut self, method: &'a str) -> Self { + self.0.method = method; + self + } + + /// Set the URL path for the request. + pub fn path(mut self, path: &'a str) -> Self { + self.0.path = Cow::Borrowed(path); + self + } + + /// Set the URL hostname for the request + pub fn host(mut self, host: &'a str) -> Self { + self.0.host = host; + self + } + + /// Set the URL port for the request + pub fn port(mut self, port: u16) -> Self { + self.0.port = port; + self + } + + /// Set the hostname, port, and path for the request, from a string URL. + pub fn url(self, url: &'a Url) -> Result<Self> { + let (host, port, path) = RequestBuilder::parse_url(url)?; + Ok(self.path(path).host(host).port(port)) + } + + /// Set the content hash for the request + pub fn hash<H: Into<Option<&'a [u8]>>>(mut self, hash: H) -> Self { + self.0.hash = hash.into(); + self + } + + /// Set the `ext` Hawk property for the request + pub fn ext<S: Into<Option<&'a str>>>(mut self, ext: S) -> Self { + self.0.ext = ext.into(); + self + } + + /// Set the `app` Hawk property for the request + pub fn app<S: Into<Option<&'a str>>>(mut self, app: S) -> Self { + self.0.app = app.into(); + self + } + + /// Set the `dlg` Hawk property for the request + pub fn dlg<S: Into<Option<&'a str>>>(mut self, dlg: S) -> Self { + self.0.dlg = dlg.into(); + self + } + + /// Get the request from this builder + pub fn request(self) -> Request<'a> { + self.0 + } + + /// Extract the `bewit` query parameter, if any, from the path, and return it in the output + /// parameter, returning a modified RequestBuilder omitting the `bewit=..` query parameter. If + /// no bewit is present, or if an error is returned, the output parameter is reset to None. + /// + /// The path manipulation is tested to correspond to that preformed by the hueniverse/hawk + /// implementation-specification + pub fn extract_bewit(mut self, bewit: &mut Option<Bewit<'a>>) -> Result<Self> { + const PREFIX: &str = "bewit="; + *bewit = None; + + if let Some(query_index) = self.0.path.find('?') { + let (bewit_components, components): (Vec<&str>, Vec<&str>) = self.0.path + [query_index + 1..] + .split('&') + .partition(|comp| comp.starts_with(PREFIX)); + + if bewit_components.len() == 1 { + let bewit_str = bewit_components[0]; + *bewit = Some(Bewit::from_str(&bewit_str[PREFIX.len()..])?); + + // update the path to omit the bewit=... segment + let new_path = if !components.is_empty() { + format!("{}{}", &self.0.path[..=query_index], components.join("&")) + } else { + // no query left, so return the remaining path, omitting the '?' + self.0.path[..query_index].to_string() + }; + self.0.path = Cow::Owned(new_path); + Ok(self) + } else if bewit_components.is_empty() { + Ok(self) + } else { + Err(InvalidBewit::Multiple.into()) + } + } else { + Ok(self) + } + } + + fn parse_url(url: &'a Url) -> Result<(&'a str, u16, &'a str)> { + let host = url + .host_str() + .ok_or_else(|| Error::InvalidUrl(format!("url {url} has no host")))?; + let port = url + .port_or_known_default() + .ok_or_else(|| Error::InvalidUrl(format!("url {url} has no port")))?; + let path = &url[Position::BeforePath..]; + Ok((host, port, path)) + } +} + +/// Create a random string with `bytes` bytes of entropy. The string +/// is base64-encoded. so it will be longer than bytes characters. +fn random_string(bytes: usize) -> Result<String> { + let mut bytes = vec![0u8; bytes]; + crate::crypto::rand_bytes(&mut bytes)?; + Ok(b64::BEWIT_ENGINE.encode(&bytes)) +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod test { + use super::*; + use crate::credentials::{Credentials, Key}; + use crate::header::Header; + use std::str::FromStr; + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + use url::Url; + + // this is a header from a real request using the JS Hawk library, to + // https://pulse.taskcluster.net:443/v1/namespaces with credentials "me" / "tok" + const REAL_HEADER: &str = "id=\"me\", ts=\"1491183061\", nonce=\"RVnYzW\", \ + mac=\"1kqRT9EoxiZ9AA/ayOCXB+AcjfK/BoJ+n7z0gfvZotQ=\""; + const BEWIT_STR: &str = + "bWVcMTM1MzgzMjgzNFxmaXk0ZTV3QmRhcEROeEhIZUExOE5yU3JVMVUzaVM2NmdtMFhqVEpwWXlVPVw"; + + // this is used as the initial bewit when calling extract_bewit, to verify that it is + // not allowing the original value of the parameter to remain in place. + const INITIAL_BEWIT_STR: &str = + "T0ggTk9FU1wxMzUzODMyODM0XGZpeTRlNXdCZGFwRE54SEhlQTE4TnJTclUxVTNpUzY2Z20wWGpUSnBZeVU9XCZtdXQgYmV3aXQgbm90IHJlc2V0IQ"; + + #[test] + fn test_empty() { + let req = RequestBuilder::new("GET", "site", 80, "/").request(); + assert_eq!(req.method, "GET"); + assert_eq!(req.host, "site"); + assert_eq!(req.port, 80); + assert_eq!(req.path, "/"); + assert_eq!(req.hash, None); + assert_eq!(req.ext, None); + assert_eq!(req.app, None); + assert_eq!(req.dlg, None); + } + + #[test] + fn test_builder() { + let hash = vec![0u8]; + let req = RequestBuilder::new("GET", "example.com", 443, "/foo") + .hash(Some(&hash[..])) + .ext("ext") + .app("app") + .dlg("dlg") + .request(); + + assert_eq!(req.method, "GET"); + assert_eq!(req.path, "/foo"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); + assert_eq!(req.hash, Some(&hash[..])); + assert_eq!(req.ext, Some("ext")); + assert_eq!(req.app, Some("app")); + assert_eq!(req.dlg, Some("dlg")); + } + + #[test] + fn test_builder_clone() { + let rb = RequestBuilder::new("GET", "site", 443, "/foo"); + let req = rb.clone().request(); + let req2 = rb.path("/bar").request(); + + assert_eq!(req.method, "GET"); + assert_eq!(req.path, "/foo"); + assert_eq!(req2.method, "GET"); + assert_eq!(req2.path, "/bar"); + } + + #[test] + fn test_url_builder() { + let url = Url::parse("https://example.com/foo").unwrap(); + let req = RequestBuilder::from_url("GET", &url).unwrap().request(); + + assert_eq!(req.path, "/foo"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_query() { + let url = Url::parse("https://example.com/foo?foo=bar").unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, None); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?foo=bar"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_encodable_chars() { + let url = Url::parse("https://example.com/ñoo?foo=año").unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, None); + + let req = bldr.request(); + + assert_eq!(req.path, "/%C3%B1oo?foo=a%C3%B1o"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_empty_query() { + let url = Url::parse("https://example.com/foo?").unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, None); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_bewit_alone() { + let url = Url::parse(&format!("https://example.com/foo?bewit={BEWIT_STR}")).unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, Some(Bewit::from_str(BEWIT_STR).unwrap())); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo"); // NOTE: strips the `?` + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_bewit_first() { + let url = Url::parse(&format!("https://example.com/foo?bewit={BEWIT_STR}&a=1")).unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, Some(Bewit::from_str(BEWIT_STR).unwrap())); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?a=1"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_bewit_multiple() { + let url = Url::parse(&format!( + "https://example.com/foo?bewit={BEWIT_STR}&bewit={BEWIT_STR}" + )) + .unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + assert!(bldr.extract_bewit(&mut bewit).is_err()); + assert_eq!(bewit, None); + } + + #[test] + fn test_url_builder_with_bewit_invalid() { + let url = Url::parse("https://example.com/foo?bewit=1234").unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + assert!(bldr.extract_bewit(&mut bewit).is_err()); + assert_eq!(bewit, None); + } + + #[test] + fn test_url_builder_with_bewit_last() { + let url = Url::parse(&format!("https://example.com/foo?a=1&bewit={BEWIT_STR}")).unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, Some(Bewit::from_str(BEWIT_STR).unwrap())); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?a=1"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_bewit_middle() { + let url = Url::parse(&format!( + "https://example.com/foo?a=1&bewit={BEWIT_STR}&b=2" + )) + .unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, Some(Bewit::from_str(BEWIT_STR).unwrap())); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?a=1&b=2"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_bewit_percent_encoding() { + // Note that this *over*-encodes things. Perfectly legal, but the kind + // of thing that incautious libraries can sometimes fail to reproduce, + // causing Hawk validation failures + let url = Url::parse(&format!( + "https://example.com/foo?%66oo=1&bewit={BEWIT_STR}&%62ar=2" + )) + .unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, Some(Bewit::from_str(BEWIT_STR).unwrap())); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?%66oo=1&%62ar=2"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_xxxbewit() { + // check that we're not doing a simple string search for "bewit=.." + let url = Url::parse(&format!( + "https://example.com/foo?a=1&xxxbewit={BEWIT_STR}&b=2" + )) + .unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, None); + + let req = bldr.request(); + + assert_eq!(req.path, format!("/foo?a=1&xxxbewit={BEWIT_STR}&b=2")); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_url_builder_with_username_password() { + let url = Url::parse("https://a:b@example.com/foo?x=y").unwrap(); + let bldr = RequestBuilder::from_url("GET", &url).unwrap(); + + let mut bewit = Some(Bewit::from_str(INITIAL_BEWIT_STR).unwrap()); + let bldr = bldr.extract_bewit(&mut bewit).unwrap(); + assert_eq!(bewit, None); + + let req = bldr.request(); + + assert_eq!(req.path, "/foo?x=y"); + assert_eq!(req.host, "example.com"); + assert_eq!(req.port, 443); // default for https + } + + #[test] + fn test_make_header_full() { + let req = RequestBuilder::new("GET", "example.com", 443, "/foo").request(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new(vec![99u8; 32], crate::SHA256).unwrap(), + }; + let header = req + .make_header_full(&credentials, UNIX_EPOCH + Duration::new(1000, 100), "nonny") + .unwrap(); + assert_eq!( + header, + Header { + id: Some("me".to_string()), + ts: Some(UNIX_EPOCH + Duration::new(1000, 100)), + nonce: Some("nonny".to_string()), + mac: Some(Mac::from(vec![ + 122, 47, 2, 53, 195, 247, 185, 107, 133, 250, 61, 134, 200, 35, 118, 94, 48, + 175, 237, 108, 60, 71, 4, 2, 244, 66, 41, 172, 91, 7, 233, 140 + ])), + ext: None, + hash: None, + app: None, + dlg: None, + } + ); + } + + #[test] + fn test_make_header_full_with_optional_fields() { + let hash = vec![0u8]; + let req = RequestBuilder::new("GET", "example.com", 443, "/foo") + .hash(Some(&hash[..])) + .ext("ext") + .app("app") + .dlg("dlg") + .request(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new(vec![99u8; 32], crate::SHA256).unwrap(), + }; + let header = req + .make_header_full(&credentials, UNIX_EPOCH + Duration::new(1000, 100), "nonny") + .unwrap(); + assert_eq!( + header, + Header { + id: Some("me".to_string()), + ts: Some(UNIX_EPOCH + Duration::new(1000, 100)), + nonce: Some("nonny".to_string()), + mac: Some(Mac::from(vec![ + 72, 123, 243, 214, 145, 81, 129, 54, 183, 90, 22, 136, 192, 146, 208, 53, 216, + 138, 145, 94, 175, 204, 217, 8, 77, 16, 202, 50, 10, 144, 133, 162 + ])), + ext: Some("ext".to_string()), + hash: Some(hash.clone()), + app: Some("app".to_string()), + dlg: Some("dlg".to_string()), + } + ); + } + + #[test] + fn test_validate_matches_generated() { + let req = RequestBuilder::new("GET", "example.com", 443, "/foo").request(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new(vec![99u8; 32], crate::SHA256).unwrap(), + }; + let header = req + .make_header_full(&credentials, SystemTime::now(), "nonny") + .unwrap(); + assert!(req.validate_header(&header, &credentials.key, Duration::from_secs(60))); + } + + // Well, close enough. + const ONE_YEAR_IN_SECS: u64 = 365 * 24 * 60 * 60; + + #[test] + fn test_validate_real_request() { + let header = Header::from_str(REAL_HEADER).unwrap(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new("tok", crate::SHA256).unwrap(), + }; + let req = + RequestBuilder::new("GET", "pulse.taskcluster.net", 443, "/v1/namespaces").request(); + // allow 1000 years skew, since this was a real request that + // happened back in 2017, when life was simple and carefree + assert!(req.validate_header( + &header, + &credentials.key, + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + #[test] + fn test_validate_real_request_bad_creds() { + let header = Header::from_str(REAL_HEADER).unwrap(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new("WRONG", crate::SHA256).unwrap(), + }; + let req = + RequestBuilder::new("GET", "pulse.taskcluster.net", 443, "/v1/namespaces").request(); + assert!(!req.validate_header( + &header, + &credentials.key, + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + #[test] + fn test_validate_real_request_bad_req_info() { + let header = Header::from_str(REAL_HEADER).unwrap(); + let credentials = Credentials { + id: "me".to_string(), + key: Key::new("tok", crate::SHA256).unwrap(), + }; + let req = RequestBuilder::new("GET", "pulse.taskcluster.net", 443, "WRONG PATH").request(); + assert!(!req.validate_header( + &header, + &credentials.key, + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + fn make_header_without_hash() -> Header { + Header::new( + Some("dh37fgj492je"), + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + Some(Mac::from(vec![ + 161, 105, 122, 110, 248, 62, 129, 193, 148, 206, 239, 193, 219, 46, 137, 221, 51, + 170, 135, 114, 81, 68, 145, 182, 15, 165, 145, 168, 114, 237, 52, 35, + ])), + None, + None, + None, + None, + ) + .unwrap() + } + + fn make_header_with_hash() -> Header { + Header::new( + Some("dh37fgj492je"), + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + Some(Mac::from(vec![ + 189, 53, 155, 244, 203, 150, 255, 238, 135, 144, 186, 93, 6, 189, 184, 21, 150, + 210, 226, 61, 93, 154, 17, 218, 142, 250, 254, 193, 123, 132, 131, 195, + ])), + None, + Some(vec![1, 2, 3, 4]), + None, + None, + ) + .unwrap() + } + + #[test] + fn test_validate_no_hash() { + let header = make_header_without_hash(); + let req = RequestBuilder::new("", "", 0, "").request(); + assert!(req.validate_header( + &header, + &Key::new("tok", crate::SHA256).unwrap(), + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + #[test] + fn test_validate_hash_in_header() { + let header = make_header_with_hash(); + let req = RequestBuilder::new("", "", 0, "").request(); + assert!(req.validate_header( + &header, + &Key::new("tok", crate::SHA256).unwrap(), + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + #[test] + fn test_validate_hash_required_but_not_given() { + let header = make_header_without_hash(); + let hash = vec![1, 2, 3, 4]; + let req = RequestBuilder::new("", "", 0, "") + .hash(Some(&hash[..])) + .request(); + assert!(!req.validate_header( + &header, + &Key::new("tok", crate::SHA256).unwrap(), + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + #[test] + fn test_validate_hash_validated() { + let header = make_header_with_hash(); + let hash = vec![1, 2, 3, 4]; + let req = RequestBuilder::new("", "", 0, "") + .hash(Some(&hash[..])) + .request(); + assert!(req.validate_header( + &header, + &Key::new("tok", crate::SHA256).unwrap(), + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + + // ..but supplying the wrong hash will cause validation to fail + let hash = vec![99, 99, 99, 99]; + let req = RequestBuilder::new("", "", 0, "") + .hash(Some(&hash[..])) + .request(); + assert!(!req.validate_header( + &header, + &Key::new("tok", crate::SHA256).unwrap(), + Duration::from_secs(1000 * ONE_YEAR_IN_SECS) + )); + } + + fn round_trip_bewit(req: Request, ts: SystemTime, expected: bool) { + let credentials = Credentials { + id: "me".to_string(), + key: Key::new("tok", crate::SHA256).unwrap(), + }; + + let bewit = req.make_bewit(&credentials, ts).unwrap(); + + // convert to a string and back + let bewit = bewit.to_str(); + let bewit = Bewit::from_str(&bewit).unwrap(); + + // and validate it maches the original request + assert_eq!(req.validate_bewit(&bewit, &credentials.key), expected); + } + + #[test] + fn test_validate_bewit() { + let req = RequestBuilder::new("GET", "foo.com", 443, "/x/y/z").request(); + round_trip_bewit(req, SystemTime::now() + Duration::from_secs(10 * 60), true); + } + + #[test] + fn test_validate_bewit_ext() { + let req = RequestBuilder::new("GET", "foo.com", 443, "/x/y/z") + .ext("abcd") + .request(); + round_trip_bewit(req, SystemTime::now() + Duration::from_secs(10 * 60), true); + } + + #[test] + fn test_validate_bewit_expired() { + let req = RequestBuilder::new("GET", "foo.com", 443, "/x/y/z").request(); + round_trip_bewit(req, SystemTime::now() - Duration::from_secs(10 * 60), false); + } +} diff --git a/third_party/rust/hawk/src/response.rs b/third_party/rust/hawk/src/response.rs @@ -0,0 +1,307 @@ +use crate::credentials::Key; +use crate::error::*; +use crate::header::Header; +use crate::mac::{Mac, MacType}; + +/// A Response represents a response from an HTTP server. +/// +/// The structure is created from a request and then used to either create (server) or validate +/// (client) a `Server-Authentication` header. +/// +/// Like `Request`, Responses are built with `ResponseBuilders`. +/// +/// # Examples +/// +/// See the documentation in the crate root for examples. +#[derive(Debug, Clone)] +pub struct Response<'a> { + method: &'a str, + host: &'a str, + port: u16, + path: &'a str, + req_header: &'a Header, + hash: Option<&'a [u8]>, + ext: Option<&'a str>, +} + +impl<'a> Response<'a> { + /// Create a new Header for this response, based on the given request and request header + pub fn make_header(&self, key: &Key) -> Result<Header> { + let ts = self.req_header.ts.ok_or(Error::MissingTs)?; + let nonce = self.req_header.nonce.as_ref().ok_or(Error::MissingNonce)?; + let mac = Mac::new( + MacType::Response, + key, + ts, + nonce, + self.method, + self.host, + self.port, + self.path, + self.hash, + self.ext, + )?; + + // Per JS implementation, the Server-Authorization header includes only mac, hash, and ext + Header::new( + None, + None, + None, + Some(mac), + self.ext.map(|v| v.to_string()), + self.hash.map(|v| v.to_vec()), + None, + None, + ) + } + + /// Validate a Server-Authorization header. + /// + /// This checks that the MAC matches and, if a hash has been supplied locally, + /// checks that one was provided from the server and that it, too, matches. + pub fn validate_header(&self, response_header: &Header, key: &Key) -> bool { + // extract required fields, returning early if they are not present + let ts = match self.req_header.ts { + Some(ts) => ts, + None => { + return false; + } + }; + let nonce = match self.req_header.nonce { + Some(ref nonce) => nonce, + None => { + return false; + } + }; + let header_mac = match response_header.mac { + Some(ref mac) => mac, + None => { + return false; + } + }; + let header_ext = response_header.ext.as_ref().map(|ext| &ext[..]); + let header_hash = response_header.hash.as_ref().map(|hash| &hash[..]); + + // first verify the MAC + match Mac::new( + MacType::Response, + key, + ts, + nonce, + self.method, + self.host, + self.port, + self.path, + header_hash, + header_ext, + ) { + Ok(calculated_mac) => { + if &calculated_mac != header_mac { + return false; + } + } + Err(_) => { + return false; + } + }; + + // ..then the hashes + if let Some(local_hash) = self.hash { + if let Some(server_hash) = header_hash { + if local_hash != server_hash { + return false; + } + } else { + return false; + } + } + + // NOTE: the timestamp self.req_header.ts was generated locally, so + // there is no need to verify it + + true + } +} + +#[derive(Debug, Clone)] +pub struct ResponseBuilder<'a>(Response<'a>); + +impl<'a> ResponseBuilder<'a> { + /// Generate a new Response from a request header. + /// + /// This is more commonly accessed through `Request::make_response`. + pub fn from_request_header( + req_header: &'a Header, + method: &'a str, + host: &'a str, + port: u16, + path: &'a str, + ) -> Self { + ResponseBuilder(Response { + method, + host, + port, + path, + req_header, + hash: None, + ext: None, + }) + } + + /// Set the content hash for the response. + /// + /// This should always be calculated from the response payload, not copied from a header. + pub fn hash<H: Into<Option<&'a [u8]>>>(mut self, hash: H) -> Self { + self.0.hash = hash.into(); + self + } + + /// Set the `ext` Hawk property for the response. + /// + /// This need only be set on the server; it is ignored in validating responses on the client. + pub fn ext<S: Into<Option<&'a str>>>(mut self, ext: S) -> Self { + self.0.ext = ext.into(); + self + } + + /// Get the response from this builder + pub fn response(self) -> Response<'a> { + self.0 + } +} + +#[cfg(all(test, any(feature = "use_ring", feature = "use_openssl")))] +mod test { + use super::ResponseBuilder; + use crate::credentials::Key; + use crate::header::Header; + use crate::mac::Mac; + use std::time::{Duration, UNIX_EPOCH}; + + fn make_req_header() -> Header { + Header::new( + None, + Some(UNIX_EPOCH + Duration::new(1353832234, 0)), + Some("j4h3g2"), + None, + None, + None, + None, + None, + ) + .unwrap() + } + + #[test] + fn test_validation_no_hash() { + let req_header = make_req_header(); + let resp = + ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b") + .response(); + let mac: Mac = Mac::from(vec![ + 48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71, 120, 68, 238, 228, 40, 55, + 64, 190, 73, 102, 123, 79, 185, 199, 26, 62, 1, 137, 170, + ]); + let server_header = Header::new( + None, + None, + None, + Some(mac), + Some("server-ext"), + None, + None, + None, + ) + .unwrap(); + assert!(resp.validate_header(&server_header, &Key::new("tok", crate::SHA256).unwrap())); + } + + #[test] + fn test_validation_hash_in_header() { + // When a hash is provided in the response header, but no hash is added to the Response, + // it is ignored (so validation succeeds) + let req_header = make_req_header(); + let resp = + ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b") + .response(); + let mac: Mac = Mac::from(vec![ + 33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161, 215, 145, 22, 34, 206, 207, + 242, 100, 33, 193, 36, 96, 149, 133, 180, 4, 132, 87, 207, 238, + ]); + let server_header = Header::new( + None, + None, + None, + Some(mac), + Some("server-ext"), + Some(vec![1, 2, 3, 4]), + None, + None, + ) + .unwrap(); + assert!(resp.validate_header(&server_header, &Key::new("tok", crate::SHA256).unwrap())); + } + + #[test] + fn test_validation_hash_required_but_not_given() { + // When Response.hash is called, but no hash is in the hader, validation fails. + let req_header = make_req_header(); + let hash = vec![1, 2, 3, 4]; + let resp = + ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b") + .hash(&hash[..]) + .response(); + let mac: Mac = Mac::from(vec![ + 48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71, 120, 68, 238, 228, 40, 55, + 64, 190, 73, 102, 123, 79, 185, 199, 26, 62, 1, 137, 170, + ]); + let server_header = Header::new( + None, + None, + None, + Some(mac), + Some("server-ext"), + None, + None, + None, + ) + .unwrap(); + assert!(!resp.validate_header(&server_header, &Key::new("tok", crate::SHA256).unwrap())); + } + + #[test] + fn test_validation_hash_validated() { + // When a hash is provided in the response header and the Response.hash method is called, + // the two must match + let req_header = make_req_header(); + let hash = vec![1, 2, 3, 4]; + let resp = + ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b") + .hash(&hash[..]) + .response(); + let mac: Mac = Mac::from(vec![ + 33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161, 215, 145, 22, 34, 206, 207, + 242, 100, 33, 193, 36, 96, 149, 133, 180, 4, 132, 87, 207, 238, + ]); + let server_header = Header::new( + None, + None, + None, + Some(mac), + Some("server-ext"), + Some(vec![1, 2, 3, 4]), + None, + None, + ) + .unwrap(); + assert!(resp.validate_header(&server_header, &Key::new("tok", crate::SHA256).unwrap())); + + // a different supplied hash won't match.. + let hash = vec![99, 99, 99, 99]; + let resp = + ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b") + .hash(&hash[..]) + .response(); + assert!(!resp.validate_header(&server_header, &Key::new("tok", crate::SHA256).unwrap())); + } +} diff --git a/third_party/rust/init_rust_components/.cargo-checksum.json b/third_party/rust/init_rust_components/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"4fec7d9fed833f35258bbde30b032257bc1967ab8ddb9987c307c8a9c1ee323f","README.md":"4c4ba1a04d445dca0507eef3ff8cd79e0954474d2a75feadd98946187fd8374f","src/lib.rs":"a296a8e15e029e513501fe40f3df5ebc59d3817b4a3242d5eb5e4f7b59d2d832","uniffi.toml":"2e98a909732dc83db0c0b41438b0935c1fd5f869cea327e3ef5501fae5fa5d01"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/init_rust_components/Cargo.toml b/third_party/rust/init_rust_components/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "init_rust_components" +version = "0.1.0" +authors = ["Johannes Schmidt <joschmidt@mozilla.com>"] +build = false +exclude = ["/android"] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = "README.md" +license = "MPL-2.0" + +[features] +keydb = ["nss/keydb"] + +[lib] +name = "init_rust_components" +path = "src/lib.rs" + +[dependencies.nss] +path = "../support/rc_crypto/nss" + +[dependencies.uniffi] +version = "0.29.0" diff --git a/third_party/rust/init_rust_components/README.md b/third_party/rust/init_rust_components/README.md @@ -0,0 +1,24 @@ +# Init Rust Components + +This component is used to initialize the other Rust components globally. + +Some services, such as logging and cryptography, are used in several components +and require explicit initialization. This component was created for this +purpose. + +Currently, the Init Rust Componentes component only handles the initialization +of NSS. + +If you encounter the error message 'NSS not initialized' in your code, it is +probably because you have not called the initialization routine of this +component before calling a method that uses NSS. + +Therefore, call the initialization method as early as possible in your code: +``` +init_rust_components::initialize(); +``` + +When using the `logins/keydb` feature to use NSS for keymanagement, provide a path to the initialization function: +``` +init_rust_components::initialize(profile_path.to_string()); +``` diff --git a/third_party/rust/init_rust_components/src/lib.rs b/third_party/rust/init_rust_components/src/lib.rs @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#[cfg(not(feature = "keydb"))] +use nss::ensure_initialized as ensure_nss_initialized; +#[cfg(feature = "keydb")] +use nss::ensure_initialized_with_profile_dir as ensure_nss_initialized_with_profile_dir; + +uniffi::setup_scaffolding!(); + +/// Global initialization routines for Rust components. Must be called before any other calls to +/// Rust components. +/// +/// For adding additional initialization code: Note that this function is called very early in the +/// app lifetime and therefore affects the startup time. Only the most necessary things should be +/// done here. +#[cfg(not(feature = "keydb"))] +#[uniffi::export] +pub fn initialize() { + ensure_nss_initialized(); +} + +/// Global initialization routines for Rust components, when `logins/keydb` feature is activated. Must be +/// called before any other calls to Rust components. +/// +/// Receives the path to the profile directory. +/// +/// For adding additional initialization code: Note that this function is called very early in the +/// app lifetime and therefore affects the startup time. Only the most necessary things should be +/// done here. +#[cfg(feature = "keydb")] +#[uniffi::export] +pub fn initialize(profile_path: String) { + ensure_nss_initialized_with_profile_dir(profile_path); +} diff --git a/third_party/rust/init_rust_components/uniffi.toml b/third_party/rust/init_rust_components/uniffi.toml @@ -0,0 +1,6 @@ +[bindings.kotlin] +package_name = "mozilla.appservices.init_rust_components" + +[bindings.swift] +ffi_module_name = "MozillaRustComponents" +ffi_module_filename = "init_rust_componentsFFI" diff --git a/third_party/rust/jwcrypto/.cargo-checksum.json b/third_party/rust/jwcrypto/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"19e1ca5fdbc89a5ad9e87e7d2f37ef081056b886661bddd28538a29a8bdcdc58","src/aes.rs":"2bb4d236ee2962365f81dc44b314cdcc9c186e0fac3a87a354ca198cdc59478b","src/direct.rs":"2f4065ba0939ca111054e295fc36956d217720c319f34e49b420fb363cf95989","src/ec.rs":"0b19519dce70c091c8060fd544c0e52a98d3110b6f7f54bab9aae30af77a6676","src/encdec.rs":"49aa30c70087ffa9fe28fa7304840670d4aa777902be28b402769121c8e1b459","src/error.rs":"ed6729b7ec07a37559069ab366cbbdf0869be2fefdec54e27550ef6a41397111","src/lib.rs":"440a04e5ed04eca90775ba1e5717c3c066572dd195d4ca08ac37c3f48da6fb62"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/jwcrypto/Cargo.toml b/third_party/rust/jwcrypto/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "jwcrypto" +version = "0.1.0" +authors = ["Edouard Oger <eoger@fastmail.com>"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = false +license = "MPL-2.0" + +[lib] +name = "jwcrypto" +crate-type = ["lib"] +path = "src/lib.rs" + +[dependencies] +base64 = "0.21" +serde = "1" +serde_derive = "1" +serde_json = "1" +thiserror = "2" + +[dependencies.error-support] +path = "../error" + +[dependencies.rc_crypto] +path = "../rc_crypto" + +[dev-dependencies.nss] +path = "../rc_crypto/nss" diff --git a/third_party/rust/jwcrypto/src/aes.rs b/third_party/rust/jwcrypto/src/aes.rs @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Wrappers we use around rc_crypto's AES implementation. Specifically, +// "enc=A256GCM" from RFC7518, Section 4.7 - for all the gory details, see +// https://tools.ietf.org/html/rfc7518#section-4.7. + +use crate::{ + error::{JwCryptoError, Result}, + CompactJwe, EncryptionAlgorithm, JweHeader, +}; +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use rc_crypto::{aead, rand}; + +/// Does the AES-encrypt heavy-lifting for the schemes supported by this crate. +pub(crate) fn aes_gcm_encrypt( + data: &[u8], + protected_header: JweHeader, + content_encryption_key: &[u8], +) -> Result<CompactJwe> { + assert_eq!(protected_header.enc, EncryptionAlgorithm::A256GCM); + let sealing_key = aead::SealingKey::new(&aead::AES_256_GCM, content_encryption_key)?; + let additional_data = serde_json::to_string(&protected_header)?; + let additional_data = URL_SAFE_NO_PAD.encode(additional_data.as_bytes()); + let additional_data = additional_data.as_bytes(); + let aad = aead::Aad::from(additional_data); + // Note that RFC7518 specifies an IV of 96 bits == 12 bytes - which means + // that a random IV generally isn't safe with AESGCM due to the risk of + // collisions in this many bits. However, for the use-cases supported by + // this crate, the keys are either ephemeral, or the number of encryptions + // for the same key is expected to be low enough to not collide in + // practice. + let mut iv: Vec<u8> = vec![0; 12]; + rand::fill(&mut iv)?; + let nonce = aead::Nonce::try_assume_unique_for_key(&aead::AES_256_GCM, &iv)?; + let mut encrypted = aead::seal(&sealing_key, nonce, aad, data)?; + + let tag_idx = encrypted.len() - aead::AES_256_GCM.tag_len(); + let auth_tag = encrypted.split_off(tag_idx); + let ciphertext = encrypted; + + CompactJwe::new( + Some(protected_header), + None, + Some(iv), + ciphertext, + Some(auth_tag), + ) +} + +/// Does the AES-decrypt heavy-lifting for the schemes supported by this crate +pub(crate) fn aes_gcm_decrypt(jwe: &CompactJwe, content_encryption_key: &[u8]) -> Result<String> { + let protected_header = jwe + .protected_header()? + .ok_or(JwCryptoError::IllegalState("missing protected_header"))?; + assert_eq!(protected_header.enc, EncryptionAlgorithm::A256GCM); + let auth_tag = jwe + .auth_tag()? + .ok_or(JwCryptoError::IllegalState("auth_tag must be present."))?; + if auth_tag.len() != aead::AES_256_GCM.tag_len() { + return Err(JwCryptoError::IllegalState( + "The auth tag length is incorrect", + )); + } + let iv = jwe + .iv()? + .ok_or(JwCryptoError::IllegalState("iv must be present."))?; + let opening_key = aead::OpeningKey::new(&aead::AES_256_GCM, content_encryption_key)?; + let ciphertext_and_tag: Vec<u8> = [jwe.ciphertext()?, auth_tag].concat(); + let nonce = aead::Nonce::try_assume_unique_for_key(&aead::AES_256_GCM, &iv)?; + let aad = aead::Aad::from(jwe.protected_header_raw().as_bytes()); + let plaintext = aead::open(&opening_key, nonce, aad, &ciphertext_and_tag)?; + Ok(String::from_utf8(plaintext.to_vec())?) +} diff --git a/third_party/rust/jwcrypto/src/direct.rs b/third_party/rust/jwcrypto/src/direct.rs @@ -0,0 +1,281 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Support for "Direct Encryption with a Shared Symmetric Key" +//! See https://tools.ietf.org/html/rfc7518#section-4.5 for all the details. + +use crate::{ + aes, + error::{JwCryptoError, Result}, + Algorithm, CompactJwe, EncryptionAlgorithm, JweHeader, Jwk, JwkKeyParameters, +}; +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use rc_crypto::rand; + +impl Jwk { + /// Create a new random key suitable for `Direct` symmetric encryption. + /// Consumers can store this for later use, probably via serde serialization. + pub fn new_direct_key(kid: Option<String>) -> Result<Self> { + // We only support AES256 which has a 32byte key. + let mut bytes: Vec<u8> = vec![0; 32]; + rand::fill(&mut bytes)?; + Ok(Jwk { + kid, + key_parameters: JwkKeyParameters::Direct { + k: URL_SAFE_NO_PAD.encode(&bytes), + }, + }) + } + + // Create a new Jwk given the raw bytes of a `Direct` key. We generally + // prefer consumers to use serde with the entire key. + pub fn new_direct_from_bytes(kid: Option<String>, key: &[u8]) -> Self { + Jwk { + kid, + key_parameters: JwkKeyParameters::Direct { + k: URL_SAFE_NO_PAD.encode(key), + }, + } + } +} + +pub(crate) fn encrypt_to_jwe( + data: &[u8], + enc: EncryptionAlgorithm, + jwk: &Jwk, +) -> Result<CompactJwe> { + // It's slightly unfortunate we need to supply a struct with ECDH specific + // values all specified as None, but doesn't seem likely to ever actually hurt. + let protected_header = JweHeader { + kid: jwk.kid.clone(), + alg: Algorithm::Direct, + enc, + epk: None, + apu: None, + apv: None, + }; + let secret = match &jwk.key_parameters { + JwkKeyParameters::Direct { k } => URL_SAFE_NO_PAD.decode(k)?, + _ => return Err(JwCryptoError::IllegalState("Not a Direct key")), + }; + aes::aes_gcm_encrypt(data, protected_header, &secret) +} + +pub(crate) fn decrypt_jwe(jwe: &CompactJwe, jwk: Jwk) -> Result<String> { + let secret = match jwk.key_parameters { + JwkKeyParameters::Direct { k } => URL_SAFE_NO_PAD.decode(k)?, + _ => return Err(JwCryptoError::IllegalState("Not a Direct key")), + }; + // `alg="dir"` mandates no encrypted key. + if jwe.encrypted_key()?.is_some() { + return Err(JwCryptoError::IllegalState( + "The Encrypted Key must be empty.", + )); + } + aes::aes_gcm_decrypt(jwe, &secret) +} + +#[test] +fn test_simple_roundtrip() { + // We should be able to round-trip data. + use super::{decrypt_jwe, encrypt_to_jwe, DecryptionParameters, EncryptionParameters}; + use nss::ensure_initialized; + + ensure_initialized(); + + let jwk = Jwk::new_direct_key(Some("my key".to_string())).unwrap(); + let data = "to be, or not 🐝🐝"; + let encrypted = encrypt_to_jwe( + data.as_bytes(), + EncryptionParameters::Direct { + jwk: &jwk, + enc: EncryptionAlgorithm::A256GCM, + }, + ) + .unwrap(); + let decrypted = decrypt_jwe(&encrypted, DecryptionParameters::Direct { jwk }).unwrap(); + assert_eq!(data, decrypted); +} + +#[test] +fn test_modified_ciphertext() { + // Modifying the ciphertext will fail. + use super::{decrypt_jwe, encrypt_to_jwe, DecryptionParameters, EncryptionParameters}; + use nss::ensure_initialized; + use std::str::FromStr; + + ensure_initialized(); + + let jwk = Jwk::new_direct_key(Some("my key".to_string())).unwrap(); + let data = "to be, or not 🐝🐝"; + let encrypted = encrypt_to_jwe( + data.as_bytes(), + EncryptionParameters::Direct { + jwk: &jwk, + enc: EncryptionAlgorithm::A256GCM, + }, + ) + .unwrap(); + // additional text + assert!(matches!( + decrypt_jwe( + &(encrypted.clone() + "A"), + DecryptionParameters::Direct { jwk: jwk.clone() } + ), + Err(JwCryptoError::IllegalState(_)) + )); + // truncated text + assert!(matches!( + decrypt_jwe( + &(encrypted[0..encrypted.len() - 2]), + DecryptionParameters::Direct { jwk: jwk.clone() } + ), + Err(JwCryptoError::IllegalState(_)) + )); + // modified ciphertext - to make this test meaningful we need to + // reconsitute the CompactJwe and modify that, otherwise we are just going + // to get a base64 or json error. + let jwe = CompactJwe::from_str(&encrypted).unwrap(); + let mut new_ciphertext = jwe.ciphertext().unwrap(); + new_ciphertext[0] = new_ciphertext[0].wrapping_add(1); + let jwe_modified = CompactJwe::new( + jwe.protected_header().unwrap(), + jwe.encrypted_key().unwrap(), + jwe.iv().unwrap(), + new_ciphertext, + jwe.auth_tag().unwrap(), + ) + .unwrap(); + + // phew - finally (fail to) decrypt the modified ciphertext. + assert!(matches!( + decrypt_jwe( + &jwe_modified.to_string(), + DecryptionParameters::Direct { jwk } + ), + Err(JwCryptoError::CryptoError(_)) + )); +} + +#[test] +fn test_iv() { + // Encrypting the same thing twice should give different payloads due to + // different IV. + use super::{encrypt_to_jwe, EncryptionParameters}; + use nss::ensure_initialized; + + ensure_initialized(); + + let jwk = Jwk::new_direct_key(Some("my key".to_string())).unwrap(); + let data = "to be, or not 🐝🐝"; + let e1 = encrypt_to_jwe( + data.as_bytes(), + EncryptionParameters::Direct { + enc: EncryptionAlgorithm::A256GCM, + jwk: &jwk, + }, + ) + .unwrap(); + let e2 = encrypt_to_jwe( + data.as_bytes(), + EncryptionParameters::Direct { + jwk: &jwk, + enc: EncryptionAlgorithm::A256GCM, + }, + ) + .unwrap(); + assert_ne!(e1, e2); +} + +#[test] +fn test_jose() { + // ciphertext generated by node-jose via: + /* + const parseJwk = require("jose/jwk/parse").default; + const CompactEncrypt = require("jose/jwe/compact/encrypt").default; + const encoder = new TextEncoder(); + const payload = "Hello, World!"; + const key = "asecret256bitkeyasecret256bitkey"; + parseJwk({kty: "oct", k: Buffer.from(key).toString("base64")}, "A256GCM").then(key => { + new CompactEncrypt(encoder.encode(payload)) + .setProtectedHeader({ alg: "dir", enc: "A256GCM" }) + .encrypt(key) + .then(jwe => { + console.log(jwe); + }); + }) + */ + // (A note for future readers - we tried using python-jose, but it + // generated a 16 byte nonce, where the spec clearly calls for exactly 12 + // bytes. We could decrypt that python-jose payload if we modified + // `Nonce::try_assume_unique_for_key()` to allow a longer key, but we don't + // want to do that until we have evidence it's actually spec compliant.) + use super::{decrypt_jwe, DecryptionParameters}; + use nss::ensure_initialized; + + ensure_initialized(); + + let jwk = Jwk::new_direct_from_bytes(None, "asecret256bitkeyasecret256bitkey".as_bytes()); + let ciphertext = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..nhKdQEKqoKPzfCda.rQOj0Nfs6wO5Gj4Quw.CMJFS9YBADLLePdj1sssSg"; + let decrypted = decrypt_jwe(ciphertext, DecryptionParameters::Direct { jwk }).unwrap(); + assert_eq!(decrypted, "Hello, World!"); +} + +#[test] +fn test_bad_key() { + use super::{decrypt_jwe, DecryptionParameters}; + use crate::error::JwCryptoError; + use nss::ensure_initialized; + + ensure_initialized(); + + let jwk = Jwk::new_direct_from_bytes(None, "a_wrong256bitkeya_wrong256bitkey".as_bytes()); + let ciphertext = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..nhKdQEKqoKPzfCda.rQOj0Nfs6wO5Gj4Quw.CMJFS9YBADLLePdj1sssSg"; + assert!(matches!( + decrypt_jwe(ciphertext, DecryptionParameters::Direct { jwk }), + Err(JwCryptoError::CryptoError(_)) + )); +} + +#[test] +fn test_bad_key_type() { + use super::{encrypt_to_jwe, EncryptionParameters}; + use crate::error::JwCryptoError; + use nss::ensure_initialized; + + ensure_initialized(); + + let jwk = Jwk::new_direct_key(Some("my key".to_string())).unwrap(); + let data = b"The big brown fox fell down"; + assert!(matches!( + encrypt_to_jwe( + data, + EncryptionParameters::ECDH_ES { + enc: EncryptionAlgorithm::A256GCM, + peer_jwk: &jwk, + }, + ), + Err(JwCryptoError::IllegalState(_)) + )); +} + +#[test] +fn test_bad_key_type_direct() { + use super::{EncryptionAlgorithm, EphemeralKeyPair}; + use nss::ensure_initialized; + use rc_crypto::agreement; + + use crate::error::JwCryptoError; + + ensure_initialized(); + + let key_pair = EphemeralKeyPair::generate(&agreement::ECDH_P256).unwrap(); + let jwk = crate::ec::extract_pub_key_jwk(&key_pair).unwrap(); + + let data = b"The big brown fox fell down"; + assert!(matches!( + encrypt_to_jwe(data, EncryptionAlgorithm::A256GCM, &jwk,), + Err(JwCryptoError::IllegalState(_)) + )); +} diff --git a/third_party/rust/jwcrypto/src/ec.rs b/third_party/rust/jwcrypto/src/ec.rs @@ -0,0 +1,227 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Implements Elliptic-Curve Diffie-Hellman for JWE - specifically, the +//! "Ephemeral-Static direct key agreement" mode described in +//! https://tools.ietf.org/html/rfc7518#section-4.6 + +use crate::{ + aes, + error::{JwCryptoError, Result}, + Algorithm, CompactJwe, EncryptionAlgorithm, JweHeader, Jwk, JwkKeyParameters, +}; +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use rc_crypto::{ + agreement::{self, EphemeralKeyPair, InputKeyMaterial, UnparsedPublicKey}, + digest, +}; +use serde_derive::{Deserialize, Serialize}; + +/// Key params specific to ECDH encryption. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ECKeysParameters { + pub crv: String, + pub x: String, + pub y: String, +} + +/// The ECDH helper that takes the cleartext and key, creates the appropriate +/// header, then calls the `aes` module to do the actual encryption. +pub(crate) fn encrypt_to_jwe( + data: &[u8], + enc: EncryptionAlgorithm, + peer_jwk: &Jwk, +) -> Result<CompactJwe> { + let local_key_pair = EphemeralKeyPair::generate(&agreement::ECDH_P256)?; + let local_public_key = extract_pub_key_jwk(&local_key_pair)?; + let ec_key_params = match peer_jwk.key_parameters { + JwkKeyParameters::EC(ref params) => params, + _ => return Err(JwCryptoError::IllegalState("Not an EC key")), + }; + let protected_header = JweHeader { + kid: peer_jwk.kid.clone(), + alg: Algorithm::ECDH_ES, + enc, + epk: Some(local_public_key), + apu: None, + apv: None, + }; + let secret = derive_shared_secret(&protected_header, local_key_pair, ec_key_params)?; + match protected_header.enc { + EncryptionAlgorithm::A256GCM => { + aes::aes_gcm_encrypt(data, protected_header, secret.as_ref()) + } + } +} + +/// The ECDH helper that takes the ciphertext in the form of a CompactJwe, +/// and the keys, creates the appropriate header, then calls the `aes` module to +/// do the actual decryption. +pub(crate) fn decrypt_jwe(jwe: &CompactJwe, local_key_pair: EphemeralKeyPair) -> Result<String> { + // Part 0: Validate inputs. + let protected_header = jwe.protected_header()?.ok_or(JwCryptoError::IllegalState( + "protected_header must be present.", + ))?; + if protected_header.alg != Algorithm::ECDH_ES { + return Err(JwCryptoError::IllegalState("alg mismatch.")); + } + // `alg="ECDH-ES"` mandates no encrypted key. + if jwe.encrypted_key()?.is_some() { + return Err(JwCryptoError::IllegalState( + "The Encrypted Key must be empty.", + )); + } + + // Part 1: Reconstruct the secret. + let peer_jwk = protected_header + .epk + .as_ref() + .ok_or(JwCryptoError::IllegalState("epk not present"))?; + + let ec_key_params = match peer_jwk.key_parameters { + JwkKeyParameters::EC(ref params) => params, + _ => return Err(JwCryptoError::IllegalState("Not an EC key")), + }; + + let secret = derive_shared_secret(&protected_header, local_key_pair, ec_key_params)?; + + // Part 2: decrypt the payload + match protected_header.enc { + EncryptionAlgorithm::A256GCM => aes::aes_gcm_decrypt(jwe, secret.as_ref()), + } +} + +fn derive_shared_secret( + protected_header: &JweHeader, + local_key_pair: EphemeralKeyPair, + peer_key: &ECKeysParameters, +) -> Result<digest::Digest> { + let (private_key, _) = local_key_pair.split(); + let peer_public_key_raw_bytes = public_key_from_ec_params(peer_key)?; + let peer_public_key = UnparsedPublicKey::new(&agreement::ECDH_P256, &peer_public_key_raw_bytes); + // Note: We don't support key-wrapping, but if we did `algorithm_id` would be `alg` instead. + let algorithm_id = protected_header.enc.algorithm_id(); + let ikm = private_key.agree(&peer_public_key)?; + let apu = protected_header.apu.as_deref().unwrap_or_default(); + let apv = protected_header.apv.as_deref().unwrap_or_default(); + get_secret_from_ikm(ikm, apu, apv, algorithm_id) +} + +fn public_key_from_ec_params(jwk: &ECKeysParameters) -> Result<Vec<u8>> { + let x = URL_SAFE_NO_PAD.decode(&jwk.x)?; + let y = URL_SAFE_NO_PAD.decode(&jwk.y)?; + if jwk.crv != "P-256" { + return Err(JwCryptoError::PartialImplementation( + "Only P-256 curves are supported.", + )); + } + if x.len() != (256 / 8) { + return Err(JwCryptoError::IllegalState("X must be 32 bytes long.")); + } + if y.len() != (256 / 8) { + return Err(JwCryptoError::IllegalState("Y must be 32 bytes long.")); + } + let mut peer_pub_key: Vec<u8> = vec![0x04]; + peer_pub_key.extend_from_slice(&x); + peer_pub_key.extend_from_slice(&y); + Ok(peer_pub_key) +} + +fn get_secret_from_ikm( + ikm: InputKeyMaterial, + apu: &str, + apv: &str, + alg: &str, +) -> Result<digest::Digest> { + let secret = ikm.derive(|z| { + let mut buf: Vec<u8> = vec![]; + // ConcatKDF (1 iteration since keyLen <= hashLen). + // See rfc7518 section 4.6 for reference. + buf.extend_from_slice(&1u32.to_be_bytes()); + buf.extend_from_slice(z); + // otherinfo + buf.extend_from_slice(&(alg.len() as u32).to_be_bytes()); + buf.extend_from_slice(alg.as_bytes()); + buf.extend_from_slice(&(apu.len() as u32).to_be_bytes()); + buf.extend_from_slice(apu.as_bytes()); + buf.extend_from_slice(&(apv.len() as u32).to_be_bytes()); + buf.extend_from_slice(apv.as_bytes()); + buf.extend_from_slice(&256u32.to_be_bytes()); + digest::digest(&digest::SHA256, &buf) + })?; + Ok(secret) +} + +/// Extracts the public key from an [EphemeralKeyPair] as a [Jwk]. +pub fn extract_pub_key_jwk(key_pair: &EphemeralKeyPair) -> Result<Jwk> { + let pub_key_bytes = key_pair.public_key().to_bytes()?; + // Uncompressed form (see SECG SEC1 section 2.3.3). + // First byte is 4, then 32 bytes for x, and 32 bytes for y. + assert_eq!(pub_key_bytes.len(), 1 + 32 + 32); + assert_eq!(pub_key_bytes[0], 0x04); + let x = Vec::from(&pub_key_bytes[1..33]); + let x = URL_SAFE_NO_PAD.encode(x); + let y = Vec::from(&pub_key_bytes[33..]); + let y = URL_SAFE_NO_PAD.encode(y); + Ok(Jwk { + kid: None, + key_parameters: JwkKeyParameters::EC(ECKeysParameters { + crv: "P-256".to_owned(), + x, + y, + }), + }) +} + +#[test] +fn test_encrypt_decrypt_jwe_ecdh_es() { + use super::{decrypt_jwe, encrypt_to_jwe, DecryptionParameters, EncryptionParameters}; + use nss::ensure_initialized; + use rc_crypto::agreement; + + ensure_initialized(); + + let key_pair = EphemeralKeyPair::generate(&agreement::ECDH_P256).unwrap(); + let jwk = extract_pub_key_jwk(&key_pair).unwrap(); + let data = b"The big brown fox jumped over... What?"; + let encrypted = encrypt_to_jwe( + data, + EncryptionParameters::ECDH_ES { + enc: EncryptionAlgorithm::A256GCM, + peer_jwk: &jwk, + }, + ) + .unwrap(); + let decrypted = decrypt_jwe( + &encrypted, + DecryptionParameters::ECDH_ES { + local_key_pair: key_pair, + }, + ) + .unwrap(); + assert_eq!(decrypted, std::str::from_utf8(data).unwrap()); +} + +#[test] +fn test_bad_key_type() { + use super::{encrypt_to_jwe, EncryptionParameters}; + use crate::error::JwCryptoError; + use nss::ensure_initialized; + + ensure_initialized(); + + let key_pair = EphemeralKeyPair::generate(&agreement::ECDH_P256).unwrap(); + let jwk = extract_pub_key_jwk(&key_pair).unwrap(); + let data = b"The big brown fox fell down"; + assert!(matches!( + encrypt_to_jwe( + data, + EncryptionParameters::Direct { + enc: EncryptionAlgorithm::A256GCM, + jwk: &jwk + }, + ), + Err(JwCryptoError::IllegalState(_)) + )); +} diff --git a/third_party/rust/jwcrypto/src/encdec.rs b/third_party/rust/jwcrypto/src/encdec.rs @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{JwCryptoError, Jwk}; +use serde::{de::DeserializeOwned, Serialize}; + +/// High-level struct for handling Encryption/Decryption +pub struct EncryptorDecryptor { + jwk: Jwk, +} + +impl EncryptorDecryptor { + /// Create a key that can be used to construct an EncryptorDecryptor + pub fn create_key() -> Result<String, JwCryptoError> { + let key = crate::Jwk::new_direct_key(None)?; + Ok(serde_json::to_string(&key)?) + } + + pub fn new(key: &str) -> Result<Self, JwCryptoError> { + match serde_json::from_str(key) { + Ok(jwk) => Ok(Self { jwk }), + Err(_) => Err(JwCryptoError::InvalidKey), + } + } + + pub fn new_with_random_key() -> Result<Self, JwCryptoError> { + Self::new(&Self::create_key()?) + } + + /// Encrypt a string + /// + /// `description` is a developer-friendly description of the operation that gets reported to Sentry + /// on crypto errors. + pub fn encrypt(&self, cleartext: &str) -> Result<String, JwCryptoError> { + crate::encrypt_to_jwe( + cleartext.as_bytes(), + crate::EncryptionParameters::Direct { + enc: crate::EncryptionAlgorithm::A256GCM, + jwk: &self.jwk, + }, + ) + } + + /// Encrypt a struct + /// + /// `description` is a developer-friendly description of the operation that gets reported to Sentry + /// on crypto errors. + pub fn encrypt_struct<T: Serialize>(&self, fields: &T) -> Result<String, JwCryptoError> { + let str = serde_json::to_string(fields)?; + self.encrypt(&str) + } + + /// Decrypt a string + /// + /// `description` is a developer-friendly description of the operation that gets reported to Sentry + /// on crypto errors. + pub fn decrypt(&self, ciphertext: &str) -> Result<String, JwCryptoError> { + if ciphertext.is_empty() { + return Err(JwCryptoError::EmptyCyphertext); + } + crate::decrypt_jwe( + ciphertext, + crate::DecryptionParameters::Direct { + jwk: self.jwk.clone(), + }, + ) + } + + /// Decrypt a struct + /// + /// `description` is a developer-friendly description of the operation that gets reported to Sentry + /// on crypto errors. + pub fn decrypt_struct<T: DeserializeOwned>( + &self, + ciphertext: &str, + ) -> Result<T, JwCryptoError> { + let json = self.decrypt(ciphertext)?; + Ok(serde_json::from_str(&json)?) + } + + // Create canary text. + // + // These are used to check if a key is still valid for a database. Call this when opening a + // database for the first time and save the result. + pub fn create_canary(&self, text: &str) -> Result<String, JwCryptoError> { + self.encrypt(text) + } + + // Create canary text. + // + // These are used to check if a key is still valid for a database. Call this when re-opening a + // database, using the same text parameter and the return value of the initial check_canary call. + // + // - If check_canary() returns true, then it's safe to assume the key can decrypt the DB data + // - If check_canary() returns false, then the key is no longer valid. It should be + // regenerated and the DB data should be wiped since we can no longer read it properly + pub fn check_canary(&self, canary: &str, text: &str) -> Result<bool, JwCryptoError> { + Ok(self.decrypt(canary)? == text) + } +} diff --git a/third_party/rust/jwcrypto/src/error.rs b/third_party/rust/jwcrypto/src/error.rs @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use thiserror::Error; + +pub(crate) type Result<T> = std::result::Result<T, JwCryptoError>; + +#[derive(Error, Debug)] +pub enum JwCryptoError { + #[error("Deserialization error")] + DeserializationError, + #[error("Illegal state error: {0}")] + IllegalState(&'static str), + #[error("Partial implementation error: {0}")] + PartialImplementation(&'static str), + #[error("Base64 decode error: {0}")] + Base64Decode(#[from] base64::DecodeError), + #[error("Crypto error: {0}")] + CryptoError(#[from] rc_crypto::Error), + #[error("JSON error: {0}")] + JsonError(#[from] serde_json::Error), + #[error("UTF8 decode error: {0}")] + UTF8DecodeError(#[from] std::string::FromUtf8Error), + #[error("InvalidKey")] + InvalidKey, + #[error("EmptyCyphertext")] + EmptyCyphertext, +} diff --git a/third_party/rust/jwcrypto/src/lib.rs b/third_party/rust/jwcrypto/src/lib.rs @@ -0,0 +1,323 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! A library for using JSON Object Signing and Encryption (JOSE) data formats +//! such as JWE and JWK, as described in https://tools.ietf.org/html/rfc7518 +//! and related standards. +//! The encryption is done by [rc_crypto] - this crate just does the JOSE +//! wrappers around this crypto. As a result, most of the structs etc here +//! support serialization and deserialization to and from JSON via serde in +//! a way that's compatible with rfc7518 etc. + +// Theoretically, everything done in this crate could and should be done in a JWT library. +// However, none of the existing rust JWT libraries can handle ECDH-ES encryption, and API choices +// made by their authors make it difficult to add this feature. +// In the past, we chose cjose to do that job, but it added three C dependencies to build and link +// against: jansson, openssl and cjose itself. +// So now, this *is* our JWT library. + +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +pub use error::JwCryptoError; +use error::Result; +use rc_crypto::agreement::EphemeralKeyPair; +use serde_derive::{Deserialize, Serialize}; +use std::{fmt, str::FromStr}; + +mod aes; +mod direct; +pub mod ec; +mod encdec; +mod error; + +pub use encdec::EncryptorDecryptor; + +/// Specifies the mode, algorithm and keys of the encryption operation. +pub enum EncryptionParameters<'a> { + // ECDH-ES in Direct Key Agreement mode. + #[allow(non_camel_case_types)] + ECDH_ES { + enc: EncryptionAlgorithm, + peer_jwk: &'a Jwk, + }, + // Direct Encryption with a shared symmetric key. + Direct { + enc: EncryptionAlgorithm, + jwk: &'a Jwk, + }, +} + +/// Specifies the mode and keys of the decryption operation. +pub enum DecryptionParameters { + // ECDH-ES in Direct Key Agreement mode. + #[allow(non_camel_case_types)] + ECDH_ES { + local_key_pair: EphemeralKeyPair, + }, + // Direct with a shared symmetric key. + Direct { + jwk: Jwk, + }, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +enum Algorithm { + #[serde(rename = "ECDH-ES")] + #[allow(non_camel_case_types)] + ECDH_ES, + #[serde(rename = "dir")] + Direct, +} + +/// The encryption algorithms supported by this crate. +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] +pub enum EncryptionAlgorithm { + A256GCM, +} + +impl EncryptionAlgorithm { + fn algorithm_id(&self) -> &'static str { + match self { + Self::A256GCM => "A256GCM", + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +struct JweHeader { + alg: Algorithm, + enc: EncryptionAlgorithm, + #[serde(skip_serializing_if = "Option::is_none")] + kid: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + epk: Option<Jwk>, + #[serde(skip_serializing_if = "Option::is_none")] + apu: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + apv: Option<String>, +} + +/// Defines the key to use for all operations in this crate. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct Jwk { + #[serde(skip_serializing_if = "Option::is_none")] + pub kid: Option<String>, + #[serde(flatten)] + pub key_parameters: JwkKeyParameters, +} + +/// The enum passed in to hold the encryption and decryption keys. The variant +/// of the enum must match the variant of the Encryption/Decryption parameters +/// or the encryption/decryption operations will fail. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(tag = "kty")] +pub enum JwkKeyParameters { + /// When doing ECDH (asymmetric) encryption, you specify elliptic curve points. + EC(ec::ECKeysParameters), + /// When doing Direct (symmetric) encryption, you specify random bytes of + /// the appropriate length, base64 encoded. + #[serde(rename = "oct")] // rfc7518 section-6.1 specifies "oct" as key-type... + Direct { k: String }, // ...and "k" for the base64 value. +} + +/// Internal representation of a CompactJwe. The public interface of this +/// crate is all via strings, so it's not public. +#[derive(Debug)] +struct CompactJwe { + jwe_segments: Vec<String>, +} + +impl CompactJwe { + // A builder pattern would be nicer, but this will do for now. + fn new( + protected_header: Option<JweHeader>, + encrypted_key: Option<Vec<u8>>, + iv: Option<Vec<u8>>, + ciphertext: Vec<u8>, + auth_tag: Option<Vec<u8>>, + ) -> Result<Self> { + let protected_header = protected_header + .as_ref() + .map(|h| serde_json::to_string(&h)) + .transpose()? + .map(|h| URL_SAFE_NO_PAD.encode(h)) + .unwrap_or_default(); + let encrypted_key = encrypted_key + .as_ref() + .map(|k| URL_SAFE_NO_PAD.encode(k)) + .unwrap_or_default(); + let iv = iv + .as_ref() + .map(|iv| URL_SAFE_NO_PAD.encode(iv)) + .unwrap_or_default(); + let ciphertext = URL_SAFE_NO_PAD.encode(ciphertext); + let auth_tag = auth_tag + .as_ref() + .map(|t| URL_SAFE_NO_PAD.encode(t)) + .unwrap_or_default(); + let jwe_segments = vec![protected_header, encrypted_key, iv, ciphertext, auth_tag]; + Ok(Self { jwe_segments }) + } + + fn protected_header(&self) -> Result<Option<JweHeader>> { + Ok(self + .try_deserialize_base64_segment(0)? + .map(|s| serde_json::from_slice(&s)) + .transpose()?) + } + + fn protected_header_raw(&self) -> &str { + &self.jwe_segments[0] + } + + fn encrypted_key(&self) -> Result<Option<Vec<u8>>> { + self.try_deserialize_base64_segment(1) + } + + fn iv(&self) -> Result<Option<Vec<u8>>> { + self.try_deserialize_base64_segment(2) + } + + fn ciphertext(&self) -> Result<Vec<u8>> { + self.try_deserialize_base64_segment(3)? + .ok_or(JwCryptoError::IllegalState("Ciphertext is empty")) + } + + fn auth_tag(&self) -> Result<Option<Vec<u8>>> { + self.try_deserialize_base64_segment(4) + } + + fn try_deserialize_base64_segment(&self, index: usize) -> Result<Option<Vec<u8>>> { + Ok(match self.jwe_segments[index].is_empty() { + true => None, + false => Some(URL_SAFE_NO_PAD.decode(&self.jwe_segments[index])?), + }) + } +} + +impl FromStr for CompactJwe { + type Err = JwCryptoError; + fn from_str(str: &str) -> Result<Self> { + let jwe_segments: Vec<String> = str.split('.').map(|s| s.to_owned()).collect(); + if jwe_segments.len() != 5 { + error_support::breadcrumb!( + "Error in CompactJwe::from_str ({})", + error_support::redact_compact_jwe(str) + ); + return Err(JwCryptoError::DeserializationError); + } + Ok(Self { jwe_segments }) + } +} + +impl fmt::Display for CompactJwe { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + assert!(self.jwe_segments.len() == 5); + write!(f, "{}", self.jwe_segments.join(".")) + } +} + +/// Encrypt and serialize data in the JWE compact form. +pub fn encrypt_to_jwe(data: &[u8], encryption_params: EncryptionParameters) -> Result<String> { + let jwe = match encryption_params { + EncryptionParameters::ECDH_ES { enc, peer_jwk } => ec::encrypt_to_jwe(data, enc, peer_jwk), + EncryptionParameters::Direct { enc, jwk } => direct::encrypt_to_jwe(data, enc, jwk), + }?; + Ok(jwe.to_string()) +} + +/// Deserialize and decrypt data in the JWE compact form. +pub fn decrypt_jwe(jwe: &str, decryption_params: DecryptionParameters) -> Result<String> { + let jwe = jwe.parse()?; + match decryption_params { + DecryptionParameters::ECDH_ES { local_key_pair } => ec::decrypt_jwe(&jwe, local_key_pair), + DecryptionParameters::Direct { jwk } => direct::decrypt_jwe(&jwe, jwk), + } +} + +#[test] +fn test_jwk_ec_deser_with_kid() { + use nss::ensure_initialized; + + ensure_initialized(); + let jwk = Jwk { + kid: Some("the-key-id".to_string()), + key_parameters: JwkKeyParameters::EC(ec::ECKeysParameters { + crv: "CRV".to_string(), + x: "X".to_string(), + y: "Y".to_string(), + }), + }; + let jstr = serde_json::to_string(&jwk).unwrap(); + // Make sure all the tags get the right info by checking the literal string. + assert_eq!( + jstr, + r#"{"kid":"the-key-id","kty":"EC","crv":"CRV","x":"X","y":"Y"}"# + ); + // And check it round-trips. + assert_eq!(jwk, serde_json::from_str(&jstr).unwrap()); +} + +#[test] +fn test_jwk_deser_no_kid() { + use nss::ensure_initialized; + + ensure_initialized(); + let jwk = Jwk { + kid: None, + key_parameters: JwkKeyParameters::EC(ec::ECKeysParameters { + crv: "CRV".to_string(), + x: "X".to_string(), + y: "Y".to_string(), + }), + }; + let jstr = serde_json::to_string(&jwk).unwrap(); + // Make sure all the tags get the right info by checking the literal string. + assert_eq!(jstr, r#"{"kty":"EC","crv":"CRV","x":"X","y":"Y"}"#); + // And check it round-trips. + assert_eq!(jwk, serde_json::from_str(&jstr).unwrap()); +} + +#[test] +fn test_jwk_direct_deser_with_kid() { + use nss::ensure_initialized; + + ensure_initialized(); + let jwk = Jwk::new_direct_from_bytes(Some("key-id".to_string()), &[0, 1, 2, 3]); + let jstr = serde_json::to_string(&jwk).unwrap(); + // Make sure all the tags get the right info by checking the literal string. + assert_eq!(jstr, r#"{"kid":"key-id","kty":"oct","k":"AAECAw"}"#); + // And check it round-trips. + assert_eq!(jwk, serde_json::from_str(&jstr).unwrap()); +} + +#[test] +fn test_compact_jwe_roundtrip() { + use nss::ensure_initialized; + + ensure_initialized(); + let mut iv = [0u8; 16]; + rc_crypto::rand::fill(&mut iv).unwrap(); + let mut ciphertext = [0u8; 243]; + rc_crypto::rand::fill(&mut ciphertext).unwrap(); + let mut auth_tag = [0u8; 16]; + rc_crypto::rand::fill(&mut auth_tag).unwrap(); + let jwe = CompactJwe::new( + Some(JweHeader { + alg: Algorithm::ECDH_ES, + enc: EncryptionAlgorithm::A256GCM, + kid: None, + epk: None, + apu: None, + apv: None, + }), + None, + Some(iv.to_vec()), + ciphertext.to_vec(), + Some(auth_tag.to_vec()), + ) + .unwrap(); + let compacted = jwe.to_string(); + let jwe2: CompactJwe = compacted.parse().unwrap(); + assert_eq!(jwe.jwe_segments, jwe2.jwe_segments); +} diff --git a/third_party/rust/logins/.cargo-checksum.json b/third_party/rust/logins/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"932aaba3c932b809da6c86cc2c808cbba983011b923545674e62dc3a164867eb","README.md":"2c25808f8371b5d9ceb58e51f71304a270d5b33dad5a280a6e95e06e606f4492","build.rs":"63ff52215682b7d516679e7aaeaaaf5d3ac98ebdf0c08361193c34c99506bfdf","fixtures/profile/.gitignore":"611878d7fde9ba090134c1d0caffe525e69d63a46b7f6060ce8ca061b8524e59","fixtures/profile/README.md":"a801e141cf954b809aed59d7a0f3a573dce23231035dbab95c6350117c346a75","fixtures/profile/key4.db":"065522fb32423422a99ed096bee267f28068881b186a9258c8f0efc19f7bd89b","metrics.yaml":"a875db3d9d759935f43131bd5c830307f8fe5d42df0e47768deb91e4568d0f6b","src/db.rs":"0c52daac61d9d91d2197e3033e19fea0c62545776e92ba138d5e2708ebe13825","src/encryption.rs":"30d4683ba394b61f52713c05bc96296333f5eda0e841820b7b4f82be7bbd9381","src/error.rs":"236b8d9b5b497204cbe7a528adb07ceed16c421706a36ebeb88e1bfe259d0ded","src/lib.rs":"31e8775f54fc3871b9096140df80df538bbe13b3f7263841affe365c7862ae8f","src/login.rs":"ef152c51b38be6ae6edb2890fd5972dd1fe66d7fdb5af803f8709375e3860fa4","src/logins.udl":"92efe79861974a15e42a889e7ea2bc0d44f1089b78d23122f490fd2cf9020828","src/schema.rs":"a652eec0b5ada90b8ed9ac481616d070f212ebd1b4238b0bc1b7768700c55ffc","src/store.rs":"772bba97f3f8fc579be850e6647d4c9b36f8d0a8b9488c06a6be93c3e02ebe77","src/sync/engine.rs":"62f4812b68962b7c55857314afd30adc3e00bd18335b71b40e110284679c6c29","src/sync/merge.rs":"6469f8bd582358c96bc35579ac228c95ad4bd64e84a29dda0cde0d87d2dcc5ed","src/sync/mod.rs":"00eb3bdd5fcac411fb314400a3d66aea874aa117db1003caf75ea43d385e372e","src/sync/payload.rs":"202f56cf0af9ffc3cc3d57c72ad61e4fa006bf5104386d9ef58a2611d539accb","src/sync/update_plan.rs":"c1d45f5972237785e274b1ecbd350cef7c1d7f530e66b9068d707eb1dfa1304e","src/util.rs":"1ced78e185164640e9859b0316f4798ccacd30bad9d6c549f9f650350a5f97b6","uniffi.toml":"1b1ea1a488fc051b9fe5a289e474462f7c676bcd02ca176713d885d280414bf6"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/logins/Cargo.toml b/third_party/rust/logins/Cargo.toml @@ -0,0 +1,110 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "logins" +version = "0.1.0" +authors = ["Thom Chiovoloni <tchiovoloni@mozilla.com>"] +build = "build.rs" +exclude = [ + "/android", + "/ios", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = "README.md" +license = "MPL-2.0" + +[features] +default = [] +keydb = [ + "nss/keydb", + "dep:async-trait", + "dep:futures", +] + +[lib] +name = "logins" +path = "src/lib.rs" + +[dependencies] +anyhow = "1.0" +lazy_static = "1.4" +parking_lot = ">=0.11,<=0.12" +serde = "1" +serde_derive = "1" +serde_json = "1" +thiserror = "2" +url = "2.2" + +[dependencies.async-trait] +version = "0.1" +optional = true + +[dependencies.error-support] +path = "../support/error" + +[dependencies.futures] +version = "0.3" +features = ["executor"] +optional = true + +[dependencies.interrupt-support] +path = "../support/interrupt" + +[dependencies.jwcrypto] +path = "../support/jwcrypto" + +[dependencies.nss] +path = "../support/rc_crypto/nss" +default-features = false + +[dependencies.rusqlite] +version = "0.37.0" +features = [ + "limits", + "unlock_notify", +] + +[dependencies.sql-support] +path = "../support/sql" + +[dependencies.sync-guid] +path = "../support/guid" +features = [ + "rusqlite_support", + "random", +] + +[dependencies.sync15] +path = "../sync15" +features = ["standalone-sync"] + +[dependencies.uniffi] +version = "0.29.0" + +[dev-dependencies] +tempfile = "3.2.0" + +[dev-dependencies.error-support] +path = "../support/error" +features = ["testing"] + +[dev-dependencies.nss] +path = "../support/rc_crypto/nss" + +[build-dependencies.uniffi] +version = "0.29.0" +features = ["build"] diff --git a/third_party/rust/logins/README.md b/third_party/rust/logins/README.md @@ -0,0 +1,178 @@ +# Logins Component + +![status-img](https://img.shields.io/static/v1?label=production&message=Lockwise,%20Firefox%20for%20iOS&color=darkgreen) +![status-img](https://img.shields.io/static/v1?label=beta&message=Firefox%20for%20Android&color=yellow) +![status-img](https://img.shields.io/static/v1?label=not%20implemented&message=Desktop&color=darkred) + + +The Logins component can be used to store website logins (i.e. usernames, passwords, and related metadata) +and to sync them between applications using [Firefox Sync](../sync_manager/README.md). + +* [Features](#features) +* [Using the Logins component](#using-the-logins-component) +* [Working on the Logins component](#working-on-the-logins-component) + +## Features + +The Logins component offers: + +1. Local encrypted storage of login records (including usernames, passwords, and website metadata). +1. Basic Create, Read, Update and Delete (CRUD) operations for login data. +1. Syncing of logins data between applications, via Firefox Sync. +1. Import functionality from existing login storage (ex: Fx Desktop or Fennec). +1. Data migration functionality from Fennec to Firefox Preview storage. + +The Logins component ***does not*** offer, and we have no concrete plans to offer: + +1. Any form-autofill of other UI-level functionality. +1. Storage of other secret data, such as credit card numbers. + +If you'd like to see new capabilities added to this component, please file an issue for discussion, +but on the understanding that it may be a lengthy discussion. + +## Using the Logins component + +### Before using this component + +Products sending telemetry and using this component *must request* a data-review following +[this process](https://wiki.mozilla.org/Firefox/Data_Collection). +This component provides data collection using the [Glean SDK](https://mozilla.github.io/glean/book/index.html). +The list of metrics being collected is available in the [metrics documentation](../../docs/metrics/logins/metrics.md). + +### Prerequisites + +To use this component for local storage of logins data, you will need to know how to integrate appservices components +into an application on your target platform: +* **Android**: integrate via the + [sync-logins](https://github.com/mozilla-mobile/android-components/blob/main/components/service/sync-logins/README.md) + component from android-components. +* **iOS**: start with the [guide to consuming rust components on + iOS](https://github.com/mozilla/application-services/blob/main/docs/howtos/consuming-rust-components-on-ios.md). +* **Other Platforms**: we don't know yet; please reach out on slack to discuss! + +To sync logins data between devices, you will additionally need to integrate the +[FxAClient component](../fxa-client/README.md) in order to obtain the necessary user credentials and encryption keys, +and the [SyncManager component](../sync_manager/README.md) in order to orchestrate the syncing process. + +### Core Concepts + +* A **login record** contains a single saved password along with other metadata about where it should be used. +Each record is uniquely identified by an opaque string id, and contains fields such as username, password and origin. +You can read about the fields on a login record in the code [here](./src/login.rs). +* A **logins store** is a syncable encrypted database containing login records. In order to use the logins store, +the application must first *unlock* it by providing a secret key (preferably obtained from an OS-level keystore +mechanism). It can then create, read, update and delete login records from the database. + * If the application is connected to Firefox Sync, it can instruct the store to sync itself with the user's + server-side logins data. This will upload any local modifications as well as download any new logins data + from the server, automatically reconciling records in the case of conflict. + +### Examples +- [Android integration](https://github.com/mozilla-mobile/android-components/blob/main/components/service/sync-logins/README.md) + + +### API Documentation +- TODO [Expand and update API docs](https://github.com/mozilla/application-services/issues/1747) + + +## Working on the Logins component + +### Prerequisites + +To effectively work on the Logins component, you will need to be familiar with: + +* Our general [guidelines for contributors](../../docs/contributing.md). +* The [core concepts](#core-concepts) for users of the component, outlined above. +* The way we [generate ffi bindings](../../docs/howtos/building-a-rust-component.md) and expose them to + [Kotlin](../../docs/howtos/exposing-rust-components-to-kotlin.md) and + [Swift](../../docs/howtos/exposing-rust-components-to-swift.md). +* The key ideas behind [how Firefox Sync works](../../docs/synconomicon/) and the [sync15 crate](../sync15/README.md). + +### Implementation Overview + +Logins implements encrypted storage for login records on top of a consumer +implemented EncryptorDecryptor, or via ManagedEncryptorDecryptor, using NSS +based crypto algorithms (AES256-GCM). + +The `EncryptorDecryptor` trait defines an interface for encrypting and decrypting data. It allows consumers to either implement their own encryption mechanism or use the built in functionality provided by the component. +- **Implementations**: + The component provides a default implementation in the form of `ManagedEncryptorDecryptor`, which leverages NSS for encryption/decryption. This implementation delegates key retrieval to a `KeyManager`. + +The `KeyManager` trait abstracts the process of obtaining an encryption key. This allows encryption to be decoupled from the specifics of key storage or generation. +- **Implementations**: + - `StaticKeyManager`, which is used in contexts where the key is fixed during runtime (e.g. in tests). + - `NSSKeyManager`, which uses this trait to dynamically obtain keys that may be wrapped with user-provided credentials. + +The `NSSKeyManager` is responsible for managing encryption keys via NSS. Its responsibilities include: +- Checking if primary password authentication is needed. +- Coordinating with `PrimaryPasswordAuthenticator` to obtain the primary password when required. +- Retrieving or creating an AES-256 key that is wrapped with the primary password if one is set. +- Serializing the key into a JSON format for use by encryption and decryption routines. + +The `PrimaryPasswordAuthenticator` is a foreign trait that is used to supply the primary password necessary for unlocking the NSS key database. + +See the header comment in [`src/encryption.rs`](./src/encryption.rs) for a more detailed explanation of encryption options and key management in the logins component. + +The storage schema is based on the one +originally used in [Firefox for +iOS](https://github.com/mozilla-mobile/firefox-ios/blob/faa6a2839abf4da2c54ff1b3291174b50b31ab2c/Storage/SQL/SQLiteLogins.swift), +but with the following notable differences: +- the queries; they've been substantially modified for our needs here. +- how sync is performed; the version here allows syncs to complete with fewer database operations. +- timestamps; iOS uses microseconds, where the Logins component uses milliseconds. + +See the header comment in [`src/schema.rs`](./src/schema.rs) for an overview of the schema. + +### Directory structure +The relevant directories are as follows: + +- [`src`](./src): The meat of the library. This contains cross-platform rust code that + implements the actual storage and sync of login records. +- [`examples`](./examples): This contains example rust code that implements a command-line app + for syncing, displaying, and editing logins using the code in `src`. You can run it via + cargo like so: `cargo run --example sync_pass_sql`. +- [`ffi`](./ffi): The Rust public FFI bindings. This is a (memory-unsafe, by necessity) + API that is exposed to Kotlin and Swift. It leverages the [`ffi_support`](https://github.com/mozilla/ffi-support) + crate to avoid many issues and make it more safe than it otherwise would be. At the + time of this writing, it uses JSON for marshalling data over the FFI, however + in the future we will likely use protocol buffers. +- [`android`](./android): This contains android bindings to logins, written in Kotlin. These + use JNA to call into to the code in `ffi`. +- [`ios`](./ios): This contains the iOS binding to logins, written in Swift. These use + Swift's native support for calling code written in C to call into the code in + `ffi`. + +### Business Logic + +#### Record storage + +At any given time records can exist in 3 places, the local storage, the remote record, and the shared parent. The shared parent refers to a record that has been synced previously and is referred to in the code as the mirror. Login records are encrypted and stored locally. For any record that does not have a shared parent the login component tracks that the record has never been synced. + +Reference the [Logins chapter of the synconomicon](https://mozilla.github.io/application-services/synconomicon/ch01.1-logins.html) for detailed information on the record storage format. + +#### Sign-out behavior +When the user signs out of their Firefox Account, we reset the storage and clear the shared parent. + +#### Merging records +When records are added, the logins component performs a three-way merge between the local record, the remote record and the shared parent (last update on the server). Details on the merging algorithm are contained in the [generic sync rfc](https://github.com/mozilla/application-services/blob/1e2ba102ee1709f51d200a2dd5e96155581a81b2/docs/design/remerge/rfc.md#three-way-merge-algorithm). + +#### Record de-duplication + +De-duplication compares the records for same the username and same url, but with different passwords. +Deduplication logic is based on age, the username and hostname: +- If the changes are more recent than the local record it performs an update. +- If the change is older than our local records, and you have changed the same field on both, the record is not updated. + +### Testing + +![status-img](https://img.shields.io/static/v1?label=test%20status&message=acceptable&color=darkgreen) + +Our goal is to seek an _acceptable_ level of test coverage. When making changes in an area, make an effort to improve (or minimally not reduce) coverage. Test coverage assessment includes: +* [rust tests](https://github.com/mozilla/application-services/blob/main/testing/sync-test/src/logins.rs) +* [android tests](https://github.com/mozilla/application-services/tree/main/components/logins/android/src/test/java/mozilla/appservices/logins) +* [ios tests](https://github.com/mozilla/application-services/blob/main/megazords/ios-rust/MozillaTestServicesTests/LoginsTests.swift) +* TODO [measure and report test coverage of logins component](https://github.com/mozilla/application-services/issues/1745) + +### Telemetry +- TODO [implement logins sync ping telemety via glean](https://github.com/mozilla/application-services/issues/1867) +- TODO [Define instrument and measure success metrics](https://github.com/mozilla/application-services/issues/1749) +- TODO [Define instrument and measure quality metrics](https://github.com/mozilla/application-services/issues/1748) diff --git a/third_party/rust/logins/build.rs b/third_party/rust/logins/build.rs @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +fn main() { + uniffi::generate_scaffolding("./src/logins.udl").unwrap(); +} diff --git a/third_party/rust/logins/fixtures/profile/.gitignore b/third_party/rust/logins/fixtures/profile/.gitignore @@ -0,0 +1 @@ +pkcs11.txt diff --git a/third_party/rust/logins/fixtures/profile/README.md b/third_party/rust/logins/fixtures/profile/README.md @@ -0,0 +1,6 @@ +# Profile Fixture + +To test the integration of logins using the `keydb` feature in a profile with +an activated primary password, we use this profile, which was created +externally as long as Rust-side bindings for setting a primary password are not +yet implemented. diff --git a/third_party/rust/logins/fixtures/profile/key4.db b/third_party/rust/logins/fixtures/profile/key4.db Binary files differ. diff --git a/third_party/rust/logins/metrics.yaml b/third_party/rust/logins/metrics.yaml @@ -0,0 +1,200 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This file defines the metrics that will be gathered for the "logins" +# storage component. +# These are emitted for all users of the component. Additional metrics +# specific to the *syncing* of logins are defined in a separate "sync_ping" +# package. +# +# Changes to these metrics require data review, which should take into +# consideration the following known consumers of the logins component +# Android bindings: +# +# * Fenix for Android + +--- +$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 + +logins_store: + # These track when we need to regenerate the encryption key which causes all + # local data to be lost + key_regenerated_lost: + type: event + description: > + The encryption key was regenerated because it was lost + bugs: + - https://github.com/mozilla/application-services/issues/4554 + data_reviews: + - https://github.com/mozilla/application-services/issues/4582 + - https://github.com/mozilla/application-services/issues/4899 + - https://github.com/mozilla/application-services/issues/5051 + data_sensitivity: + - technical + notification_emails: + - synced-client-integrations@mozilla.com + - bdk@mozilla.com + expires: never + + key_regenerated_corrupt: + type: event + description: > + The encryption key was regenerated because it didn't match the encrypted + data + bugs: + - https://github.com/mozilla/application-services/issues/4554 + data_reviews: + - https://github.com/mozilla/application-services/issues/4582 + - https://github.com/mozilla/application-services/issues/4899 + - https://github.com/mozilla/application-services/issues/5051 + data_sensitivity: + - technical + notification_emails: + - synced-client-integrations@mozilla.com + - bdk@mozilla.com + expires: never + + key_regenerated_other: + type: event + description: > + The encryption key was regenerated for an unknown reason + bugs: + - https://github.com/mozilla/application-services/issues/4554 + data_reviews: + - https://github.com/mozilla/application-services/issues/4582 + - https://github.com/mozilla/application-services/issues/4899 + - https://github.com/mozilla/application-services/issues/5051 + data_sensitivity: + - technical + notification_emails: + - synced-client-integrations@mozilla.com + - bdk@mozilla.com + expires: never + + # These help us understand how much the logins store is being used, and + # whether it's succeeding in the duties asked of it. We'll use them to + # graph e.g. the error rate of applications trying to use the logins store, + # and identify application or platform features that lead to unusually + # high error rates. + read_query_count: + type: counter + description: > + The total number of read operations performed on the logins store. + The count only includes operations triggered by the application, not + e.g. incidental reads performed as part of a sync. It is intended to be + used together with `read_query_error_count` to measure the overall error + rate of read operations on the logins store. + bugs: + - https://github.com/mozilla/application-services/issues/2225 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1597895 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1649044 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1694316 + data_sensitivity: + - interaction + notification_emails: + - mhammond@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" + + read_query_error_count: + type: labeled_counter + description: > + The total number of errors encountered during read operations on the + logins store, labeled by type. + It is intended to be used together with `read_query_count` to measure + the overall error rate of read operations on the logins store. + labels: + - interrupted + - storage_error + bugs: + - https://github.com/mozilla/application-services/issues/2225 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1597895 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1649044 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1694316 + data_sensitivity: + - interaction + notification_emails: + - mhammond@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" + + write_query_count: + type: counter + description: > + The total number of write operations performed on the logins store. + The count only includes operations triggered by the application, not + e.g. incidental writes performed as part of a sync. It is intended to + be used together with `write_query_error_count` to measure the overall + error rate of write operations on the logins store. + bugs: + - https://github.com/mozilla/application-services/issues/2225 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1597895 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1649044 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1694316 + data_sensitivity: + - interaction + notification_emails: + - mhammond@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" + + write_query_error_count: + type: labeled_counter + description: > + The total number of errors encountered during write operations on the + logins store, labeled by type. + It is intended to be used together with `write_query_count` to measure + the overall error rate of write operations on the logins store. + labels: + - no_such_record + - interrupted + - invalid_record + - storage_error + bugs: + - https://github.com/mozilla/application-services/issues/2225 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1597895 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1649044 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1694316 + data_sensitivity: + - interaction + notification_emails: + - mhammond@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" + + local_undecryptable_deleted: + type: counter + description: > + Track how many logins we deleted locally due to various reasons + that prevent us from decrypting the login + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1972437 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1972437 + data_sensitivity: + - technical + notification_emails: + - skhamis@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" + + mirror_undecryptable_deleted: + type: counter + description: > + Track how many logins we deleted in the mirror table due to various reasons + that prevent us from decrypting the login + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1972437 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1972437 + data_sensitivity: + - technical + notification_emails: + - skhamis@mozilla.com + - synced-client-integrations@mozilla.com + expires: "never" diff --git a/third_party/rust/logins/src/db.rs b/third_party/rust/logins/src/db.rs @@ -0,0 +1,1896 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/// Logins DB handling +/// +/// The logins database works differently than other components because "mirror" and "local" mean +/// different things. At some point we should probably refactor to make it match them, but here's +/// how it works for now: +/// +/// - loginsM is the mirror table, which means it stores what we believe is on the server. This +/// means either the last record we fetched from the server or the last record we uploaded. +/// - loginsL is the local table, which means it stores local changes that have not been sent to +/// the server. +/// - When we want to fetch a record, we need to look in both loginsL and loginsM for the data. +/// If a record is in both tables, then we prefer the loginsL data. GET_BY_GUID_SQL contains a +/// clever UNION query to accomplish this. +/// - If a record is in both the local and mirror tables, we call the local record the "overlay" +/// and set the is_overridden flag on the mirror record. +/// - When we sync, the presence of a record in loginsL means that there was a local change that +/// we need to send to the the server and/or reconcile it with incoming changes from the +/// server. +/// - After we sync, we move all records from loginsL to loginsM, overwriting any previous data. +/// loginsL will be an empty table after this. See mark_as_synchronized() for the details. +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::login::*; +use crate::schema; +use crate::sync::SyncStatus; +use crate::util; +use interrupt_support::{SqlInterruptHandle, SqlInterruptScope}; +use lazy_static::lazy_static; +use rusqlite::{ + named_params, + types::{FromSql, ToSql}, + Connection, +}; +use sql_support::ConnExt; +use std::ops::Deref; +use std::path::Path; +use std::sync::Arc; +use std::time::SystemTime; +use sync_guid::Guid; +use url::{Host, Url}; + +pub struct LoginDb { + pub db: Connection, + pub encdec: Arc<dyn EncryptorDecryptor>, + interrupt_handle: Arc<SqlInterruptHandle>, +} + +pub struct LoginsDeletionMetrics { + pub local_deleted: u64, + pub mirror_deleted: u64, +} + +impl LoginDb { + pub fn with_connection(db: Connection, encdec: Arc<dyn EncryptorDecryptor>) -> Result<Self> { + #[cfg(test)] + { + util::init_test_logging(); + } + + // `temp_store = 2` is required on Android to force the DB to keep temp + // files in memory, since on Android there's no tmp partition. See + // https://github.com/mozilla/mentat/issues/505. Ideally we'd only + // do this on Android, or allow caller to configure it. + db.set_pragma("temp_store", 2)?; + + let mut logins = Self { + interrupt_handle: Arc::new(SqlInterruptHandle::new(&db)), + encdec, + db, + }; + let tx = logins.db.transaction()?; + schema::init(&tx)?; + tx.commit()?; + Ok(logins) + } + + pub fn open(path: impl AsRef<Path>, encdec: Arc<dyn EncryptorDecryptor>) -> Result<Self> { + Self::with_connection(Connection::open(path)?, encdec) + } + + #[cfg(test)] + pub fn open_in_memory() -> Self { + let encdec: Arc<dyn EncryptorDecryptor> = + crate::encryption::test_utils::TEST_ENCDEC.clone(); + Self::with_connection(Connection::open_in_memory().unwrap(), encdec).unwrap() + } + + pub fn new_interrupt_handle(&self) -> Arc<SqlInterruptHandle> { + Arc::clone(&self.interrupt_handle) + } + + #[inline] + pub fn begin_interrupt_scope(&self) -> Result<SqlInterruptScope> { + Ok(self.interrupt_handle.begin_interrupt_scope()?) + } +} + +impl ConnExt for LoginDb { + #[inline] + fn conn(&self) -> &Connection { + &self.db + } +} + +impl Deref for LoginDb { + type Target = Connection; + #[inline] + fn deref(&self) -> &Connection { + &self.db + } +} + +// login specific stuff. + +impl LoginDb { + pub(crate) fn put_meta(&self, key: &str, value: &dyn ToSql) -> Result<()> { + self.execute_cached( + "REPLACE INTO loginsSyncMeta (key, value) VALUES (:key, :value)", + named_params! { ":key": key, ":value": value }, + )?; + Ok(()) + } + + pub(crate) fn get_meta<T: FromSql>(&self, key: &str) -> Result<Option<T>> { + self.try_query_row( + "SELECT value FROM loginsSyncMeta WHERE key = :key", + named_params! { ":key": key }, + |row| Ok::<_, Error>(row.get(0)?), + true, + ) + } + + pub(crate) fn delete_meta(&self, key: &str) -> Result<()> { + self.execute_cached( + "DELETE FROM loginsSyncMeta WHERE key = :key", + named_params! { ":key": key }, + )?; + Ok(()) + } + + pub fn count_all(&self) -> Result<i64> { + let mut stmt = self.db.prepare_cached(&COUNT_ALL_SQL)?; + + let count: i64 = stmt.query_row([], |row| row.get(0))?; + Ok(count) + } + + pub fn count_by_origin(&self, origin: &str) -> Result<i64> { + let mut stmt = self.db.prepare_cached(&COUNT_BY_ORIGIN_SQL)?; + + let count: i64 = stmt.query_row(named_params! { ":origin": origin }, |row| row.get(0))?; + Ok(count) + } + + pub fn count_by_form_action_origin(&self, form_action_origin: &str) -> Result<i64> { + let mut stmt = self.db.prepare_cached(&COUNT_BY_FORM_ACTION_ORIGIN_SQL)?; + + let count: i64 = stmt.query_row( + named_params! { ":form_action_origin": form_action_origin }, + |row| row.get(0), + )?; + Ok(count) + } + + pub fn get_all(&self) -> Result<Vec<EncryptedLogin>> { + let mut stmt = self.db.prepare_cached(&GET_ALL_SQL)?; + let rows = stmt.query_and_then([], EncryptedLogin::from_row)?; + rows.collect::<Result<_>>() + } + + pub fn get_by_base_domain(&self, base_domain: &str) -> Result<Vec<EncryptedLogin>> { + // We first parse the input string as a host so it is normalized. + let base_host = match Host::parse(base_domain) { + Ok(d) => d, + Err(e) => { + // don't log the input string as it's PII. + warn!("get_by_base_domain was passed an invalid domain: {}", e); + return Ok(vec![]); + } + }; + // We just do a linear scan. Another option is to have an indexed + // reverse-host column or similar, but current thinking is that it's + // extra complexity for (probably) zero actual benefit given the record + // counts are expected to be so low. + // A regex would probably make this simpler, but we don't want to drag + // in a regex lib just for this. + let mut stmt = self.db.prepare_cached(&GET_ALL_SQL)?; + let rows = stmt + .query_and_then([], EncryptedLogin::from_row)? + .filter(|r| { + let login = r + .as_ref() + .ok() + .and_then(|login| Url::parse(&login.fields.origin).ok()); + let this_host = login.as_ref().and_then(|url| url.host()); + match (&base_host, this_host) { + (Host::Domain(base), Some(Host::Domain(look))) => { + // a fairly long-winded way of saying + // `login.fields.origin == base_domain || + // login.fields.origin.ends_with('.' + base_domain);` + let mut rev_input = base.chars().rev(); + let mut rev_host = look.chars().rev(); + loop { + match (rev_input.next(), rev_host.next()) { + (Some(ref a), Some(ref b)) if a == b => continue, + (None, None) => return true, // exactly equal + (None, Some(ref h)) => return *h == '.', + _ => return false, + } + } + } + // ip addresses must match exactly. + (Host::Ipv4(base), Some(Host::Ipv4(look))) => *base == look, + (Host::Ipv6(base), Some(Host::Ipv6(look))) => *base == look, + // all "mismatches" in domain types are false. + _ => false, + } + }); + rows.collect::<Result<_>>() + } + + pub fn get_by_id(&self, id: &str) -> Result<Option<EncryptedLogin>> { + self.try_query_row( + &GET_BY_GUID_SQL, + &[(":guid", &id as &dyn ToSql)], + EncryptedLogin::from_row, + true, + ) + } + + // Match a `LoginEntry` being saved to existing logins in the DB + // + // When a user is saving new login, there are several cases for how we want to save the data: + // + // - Adding a new login: `None` will be returned + // - Updating an existing login: `Some(login)` will be returned and the username will match + // the one for look. + // - Filling in a blank username for an existing login: `Some(login)` will be returned + // with a blank username. + // + // Returns an Err if the new login is not valid and could not be fixed up + pub fn find_login_to_update( + &self, + look: LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<Option<Login>> { + let look = look.fixup()?; + let logins = self + .get_by_entry_target(&look)? + .into_iter() + .map(|enc_login| enc_login.decrypt(encdec)) + .collect::<Result<Vec<Login>>>()?; + Ok(logins + // First, try to match the username + .iter() + .find(|login| login.username == look.username) + // Fall back on a blank username + .or_else(|| logins.iter().find(|login| login.username.is_empty())) + // Clone the login to avoid ref issues when returning across the FFI + .cloned()) + } + + pub fn touch(&self, id: &str) -> Result<()> { + let tx = self.unchecked_transaction()?; + self.ensure_local_overlay_exists(id)?; + self.mark_mirror_overridden(id)?; + let now_ms = util::system_time_ms_i64(SystemTime::now()); + // As on iOS, just using a record doesn't flip it's status to changed. + // TODO: this might be wrong for lockbox! + self.execute_cached( + "UPDATE loginsL + SET timeLastUsed = :now_millis, + timesUsed = timesUsed + 1, + local_modified = :now_millis + WHERE guid = :guid + AND is_deleted = 0", + named_params! { + ":now_millis": now_ms, + ":guid": id, + }, + )?; + tx.commit()?; + Ok(()) + } + + // The single place we insert new rows or update existing local rows. + // just the SQL - no validation or anything. + fn insert_new_login(&self, login: &EncryptedLogin) -> Result<()> { + let sql = format!( + "INSERT OR REPLACE INTO loginsL ( + origin, + httpRealm, + formActionOrigin, + usernameField, + passwordField, + timesUsed, + secFields, + guid, + timeCreated, + timeLastUsed, + timePasswordChanged, + local_modified, + is_deleted, + sync_status + ) VALUES ( + :origin, + :http_realm, + :form_action_origin, + :username_field, + :password_field, + :times_used, + :sec_fields, + :guid, + :time_created, + :time_last_used, + :time_password_changed, + :local_modified, + 0, -- is_deleted + {new} -- sync_status + )", + new = SyncStatus::New as u8 + ); + + self.execute( + &sql, + named_params! { + ":origin": login.fields.origin, + ":http_realm": login.fields.http_realm, + ":form_action_origin": login.fields.form_action_origin, + ":username_field": login.fields.username_field, + ":password_field": login.fields.password_field, + ":time_created": login.meta.time_created, + ":times_used": login.meta.times_used, + ":time_last_used": login.meta.time_last_used, + ":time_password_changed": login.meta.time_password_changed, + ":local_modified": login.meta.time_created, + ":sec_fields": login.sec_fields, + ":guid": login.guid(), + }, + )?; + Ok(()) + } + + fn update_existing_login(&self, login: &EncryptedLogin) -> Result<()> { + // assumes the "local overlay" exists, so the guid must too. + let sql = format!( + "UPDATE loginsL + SET local_modified = :now_millis, + timeLastUsed = :time_last_used, + timePasswordChanged = :time_password_changed, + httpRealm = :http_realm, + formActionOrigin = :form_action_origin, + usernameField = :username_field, + passwordField = :password_field, + timesUsed = :times_used, + secFields = :sec_fields, + origin = :origin, + -- leave New records as they are, otherwise update them to `changed` + sync_status = max(sync_status, {changed}) + WHERE guid = :guid", + changed = SyncStatus::Changed as u8 + ); + + self.db.execute( + &sql, + named_params! { + ":origin": login.fields.origin, + ":http_realm": login.fields.http_realm, + ":form_action_origin": login.fields.form_action_origin, + ":username_field": login.fields.username_field, + ":password_field": login.fields.password_field, + ":time_last_used": login.meta.time_last_used, + ":times_used": login.meta.times_used, + ":time_password_changed": login.meta.time_password_changed, + ":sec_fields": login.sec_fields, + ":guid": &login.meta.id, + // time_last_used has been set to now. + ":now_millis": login.meta.time_last_used, + }, + )?; + Ok(()) + } + + /// Adds multiple logins within a single transaction and returns the successfully saved logins. + pub fn add_many( + &self, + entries: Vec<LoginEntry>, + encdec: &dyn EncryptorDecryptor, + ) -> Result<Vec<Result<EncryptedLogin>>> { + let now_ms = util::system_time_ms_i64(SystemTime::now()); + + let entries_with_meta = entries + .into_iter() + .map(|entry| { + let guid = Guid::random(); + LoginEntryWithMeta { + entry, + meta: LoginMeta { + id: guid.to_string(), + time_created: now_ms, + time_password_changed: now_ms, + time_last_used: now_ms, + times_used: 1, + }, + } + }) + .collect(); + + self.add_many_with_meta(entries_with_meta, encdec) + } + + /// Adds multiple logins **including metadata** within a single transaction and returns the successfully saved logins. + /// Normally, you will use `add_many` instead, and AS Logins will take care of the metadata (setting timestamps, generating an ID) itself. + /// However, in some cases, this method is necessary, for example when migrating data from another store that already contains the metadata. + pub fn add_many_with_meta( + &self, + entries_with_meta: Vec<LoginEntryWithMeta>, + encdec: &dyn EncryptorDecryptor, + ) -> Result<Vec<Result<EncryptedLogin>>> { + let tx = self.unchecked_transaction()?; + let mut results = vec![]; + for entry_with_meta in entries_with_meta { + let guid = Guid::from_string(entry_with_meta.meta.id.clone()); + match self.fixup_and_check_for_dupes(&guid, entry_with_meta.entry, encdec) { + Ok(new_entry) => { + let sec_fields = SecureLoginFields { + username: new_entry.username, + password: new_entry.password, + } + .encrypt(encdec, &entry_with_meta.meta.id)?; + let encrypted_login = EncryptedLogin { + meta: entry_with_meta.meta, + fields: LoginFields { + origin: new_entry.origin, + form_action_origin: new_entry.form_action_origin, + http_realm: new_entry.http_realm, + username_field: new_entry.username_field, + password_field: new_entry.password_field, + }, + sec_fields, + }; + let result = self + .insert_new_login(&encrypted_login) + .map(|_| encrypted_login); + results.push(result); + } + + Err(error) => results.push(Err(error)), + } + } + tx.commit()?; + Ok(results) + } + + pub fn add( + &self, + entry: LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<EncryptedLogin> { + let guid = Guid::random(); + let now_ms = util::system_time_ms_i64(SystemTime::now()); + + let entry_with_meta = LoginEntryWithMeta { + entry, + meta: LoginMeta { + id: guid.to_string(), + time_created: now_ms, + time_password_changed: now_ms, + time_last_used: now_ms, + times_used: 1, + }, + }; + + self.add_with_meta(entry_with_meta, encdec) + } + + /// Adds a login **including metadata**. + /// Normally, you will use `add` instead, and AS Logins will take care of the metadata (setting timestamps, generating an ID) itself. + /// However, in some cases, this method is necessary, for example when migrating data from another store that already contains the metadata. + pub fn add_with_meta( + &self, + entry_with_meta: LoginEntryWithMeta, + encdec: &dyn EncryptorDecryptor, + ) -> Result<EncryptedLogin> { + let mut results = self.add_many_with_meta(vec![entry_with_meta], encdec)?; + results.pop().expect("there should be a single result") + } + + pub fn update( + &self, + sguid: &str, + entry: LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<EncryptedLogin> { + let guid = Guid::new(sguid); + let now_ms = util::system_time_ms_i64(SystemTime::now()); + let tx = self.unchecked_transaction()?; + + let entry = entry.fixup()?; + + // Check if there's an existing login that's the dupe of this login. That indicates that + // something has gone wrong with our underlying logic. However, if we do see a dupe login, + // just log an error and continue. This avoids a crash on android-components + // (mozilla-mobile/android-components#11251). + + if self.check_for_dupes(&guid, &entry, encdec).is_err() { + // Try to detect if sync is enabled by checking if there are any mirror logins + let has_mirror_row: bool = self + .db + .conn_ext_query_one("SELECT EXISTS (SELECT 1 FROM loginsM)")?; + let has_http_realm = entry.http_realm.is_some(); + let has_form_action_origin = entry.form_action_origin.is_some(); + report_error!( + "logins-duplicate-in-update", + "(mirror: {has_mirror_row}, realm: {has_http_realm}, form_origin: {has_form_action_origin})"); + } + + // Note: This fail with NoSuchRecord if the record doesn't exist. + self.ensure_local_overlay_exists(&guid)?; + self.mark_mirror_overridden(&guid)?; + + // We must read the existing record so we can correctly manage timePasswordChanged. + let existing = match self.get_by_id(sguid)? { + Some(e) => e.decrypt(encdec)?, + None => return Err(Error::NoSuchRecord(sguid.to_owned())), + }; + let time_password_changed = if existing.password == entry.password { + existing.time_password_changed + } else { + now_ms + }; + + // Make the final object here - every column will be updated. + let sec_fields = SecureLoginFields { + username: entry.username, + password: entry.password, + } + .encrypt(encdec, &existing.id)?; + let result = EncryptedLogin { + meta: LoginMeta { + id: existing.id, + time_created: existing.time_created, + time_password_changed, + time_last_used: now_ms, + times_used: existing.times_used + 1, + }, + fields: LoginFields { + origin: entry.origin, + form_action_origin: entry.form_action_origin, + http_realm: entry.http_realm, + username_field: entry.username_field, + password_field: entry.password_field, + }, + sec_fields, + }; + + self.update_existing_login(&result)?; + tx.commit()?; + Ok(result) + } + + pub fn add_or_update( + &self, + entry: LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<EncryptedLogin> { + // Make sure to fixup the entry first, in case that changes the username + let entry = entry.fixup()?; + match self.find_login_to_update(entry.clone(), encdec)? { + Some(login) => self.update(&login.id, entry, encdec), + None => self.add(entry, encdec), + } + } + + pub fn fixup_and_check_for_dupes( + &self, + guid: &Guid, + entry: LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<LoginEntry> { + let entry = entry.fixup()?; + self.check_for_dupes(guid, &entry, encdec)?; + Ok(entry) + } + + pub fn check_for_dupes( + &self, + guid: &Guid, + entry: &LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<()> { + if self.dupe_exists(guid, entry, encdec)? { + return Err(InvalidLogin::DuplicateLogin.into()); + } + Ok(()) + } + + pub fn dupe_exists( + &self, + guid: &Guid, + entry: &LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<bool> { + Ok(self.find_dupe(guid, entry, encdec)?.is_some()) + } + + pub fn find_dupe( + &self, + guid: &Guid, + entry: &LoginEntry, + encdec: &dyn EncryptorDecryptor, + ) -> Result<Option<Guid>> { + for possible in self.get_by_entry_target(entry)? { + if possible.guid() != *guid { + let pos_sec_fields = possible.decrypt_fields(encdec)?; + if pos_sec_fields.username == entry.username { + return Ok(Some(possible.guid())); + } + } + } + Ok(None) + } + + // Find saved logins that match the target for a `LoginEntry` + // + // This means that: + // - `origin` matches + // - Either `form_action_origin` or `http_realm` matches, depending on which one is non-null + // + // This is used for dupe-checking and `find_login_to_update()` + fn get_by_entry_target(&self, entry: &LoginEntry) -> Result<Vec<EncryptedLogin>> { + // Could be lazy_static-ed... + lazy_static::lazy_static! { + static ref GET_BY_FORM_ACTION_ORIGIN: String = format!( + "SELECT {common_cols} FROM loginsL + WHERE is_deleted = 0 + AND origin = :origin + AND formActionOrigin = :form_action_origin + + UNION ALL + + SELECT {common_cols} FROM loginsM + WHERE is_overridden = 0 + AND origin = :origin + AND formActionOrigin = :form_action_origin + ", + common_cols = schema::COMMON_COLS + ); + static ref GET_BY_HTTP_REALM: String = format!( + "SELECT {common_cols} FROM loginsL + WHERE is_deleted = 0 + AND origin = :origin + AND httpRealm = :http_realm + + UNION ALL + + SELECT {common_cols} FROM loginsM + WHERE is_overridden = 0 + AND origin = :origin + AND httpRealm = :http_realm + ", + common_cols = schema::COMMON_COLS + ); + } + match (entry.form_action_origin.as_ref(), entry.http_realm.as_ref()) { + (Some(form_action_origin), None) => { + let params = named_params! { + ":origin": &entry.origin, + ":form_action_origin": form_action_origin, + }; + self.db + .prepare_cached(&GET_BY_FORM_ACTION_ORIGIN)? + .query_and_then(params, EncryptedLogin::from_row)? + .collect() + } + (None, Some(http_realm)) => { + let params = named_params! { + ":origin": &entry.origin, + ":http_realm": http_realm, + }; + self.db + .prepare_cached(&GET_BY_HTTP_REALM)? + .query_and_then(params, EncryptedLogin::from_row)? + .collect() + } + (Some(_), Some(_)) => Err(InvalidLogin::BothTargets.into()), + (None, None) => Err(InvalidLogin::NoTarget.into()), + } + } + + pub fn exists(&self, id: &str) -> Result<bool> { + Ok(self.db.query_row( + "SELECT EXISTS( + SELECT 1 FROM loginsL + WHERE guid = :guid AND is_deleted = 0 + UNION ALL + SELECT 1 FROM loginsM + WHERE guid = :guid AND is_overridden IS NOT 1 + )", + named_params! { ":guid": id }, + |row| row.get(0), + )?) + } + + /// Delete the record with the provided id. Returns true if the record + /// existed already. + pub fn delete(&self, id: &str) -> Result<bool> { + let mut results = self.delete_many(vec![id])?; + Ok(results.pop().expect("there should be a single result")) + } + + /// Delete the records with the specified IDs. Returns a list of Boolean values + /// indicating whether the respective records already existed. + pub fn delete_many(&self, ids: Vec<&str>) -> Result<Vec<bool>> { + let tx = self.unchecked_transaction_imm()?; + let sql = format!( + " + UPDATE loginsL + SET local_modified = :now_ms, + sync_status = {status_changed}, + is_deleted = 1, + secFields = '', + origin = '', + httpRealm = NULL, + formActionOrigin = NULL + WHERE guid = :guid AND is_deleted IS FALSE + ", + status_changed = SyncStatus::Changed as u8 + ); + let mut stmt = self.db.prepare_cached(&sql)?; + + let mut result = vec![]; + + for id in ids { + let now_ms = util::system_time_ms_i64(SystemTime::now()); + + // For IDs that have, mark is_deleted and clear sensitive fields + let update_result = stmt.execute(named_params! { ":now_ms": now_ms, ":guid": id })?; + + let exists = update_result == 1; + + // Mark the mirror as overridden + self.execute( + "UPDATE loginsM SET is_overridden = 1 WHERE guid = :guid", + named_params! { ":guid": id }, + )?; + + // If we don't have a local record for this ID, but do have it in the mirror + // insert a tombstone. + self.execute(&format!(" + INSERT OR IGNORE INTO loginsL + (guid, local_modified, is_deleted, sync_status, origin, timeCreated, timePasswordChanged, secFields) + SELECT guid, :now_ms, 1, {changed}, '', timeCreated, :now_ms, '' + FROM loginsM + WHERE guid = :guid", + changed = SyncStatus::Changed as u8), + named_params! { ":now_ms": now_ms, ":guid": id })?; + + result.push(exists); + } + + tx.commit()?; + + Ok(result) + } + + pub fn delete_undecryptable_records_for_remote_replacement( + &self, + encdec: &dyn EncryptorDecryptor, + ) -> Result<LoginsDeletionMetrics> { + // Retrieve a list of guids for logins that cannot be decrypted + let corrupted_logins = self + .get_all()? + .into_iter() + .filter(|login| login.clone().decrypt(encdec).is_err()) + .collect::<Vec<_>>(); + let ids = corrupted_logins + .iter() + .map(|login| login.guid_str()) + .collect::<Vec<_>>(); + + self.delete_local_records_for_remote_replacement(ids) + } + + pub fn delete_local_records_for_remote_replacement( + &self, + ids: Vec<&str>, + ) -> Result<LoginsDeletionMetrics> { + let tx = self.unchecked_transaction_imm()?; + let mut local_deleted = 0; + let mut mirror_deleted = 0; + + sql_support::each_chunk(&ids, |chunk, _| -> Result<()> { + let deleted = self.execute( + &format!( + "DELETE FROM loginsL WHERE guid IN ({})", + sql_support::repeat_sql_values(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + local_deleted += deleted; + Ok(()) + })?; + + sql_support::each_chunk(&ids, |chunk, _| -> Result<()> { + let deleted = self.execute( + &format!( + "DELETE FROM loginsM WHERE guid IN ({})", + sql_support::repeat_sql_values(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + mirror_deleted += deleted; + Ok(()) + })?; + + tx.commit()?; + Ok(LoginsDeletionMetrics { + local_deleted: local_deleted as u64, + mirror_deleted: mirror_deleted as u64, + }) + } + + fn mark_mirror_overridden(&self, guid: &str) -> Result<()> { + self.execute_cached( + "UPDATE loginsM SET is_overridden = 1 WHERE guid = :guid", + named_params! { ":guid": guid }, + )?; + Ok(()) + } + + fn ensure_local_overlay_exists(&self, guid: &str) -> Result<()> { + let already_have_local: bool = self.db.query_row( + "SELECT EXISTS(SELECT 1 FROM loginsL WHERE guid = :guid)", + named_params! { ":guid": guid }, + |row| row.get(0), + )?; + + if already_have_local { + return Ok(()); + } + + debug!("No overlay; cloning one for {:?}.", guid); + let changed = self.clone_mirror_to_overlay(guid)?; + if changed == 0 { + report_error!( + "logins-local-overlay-error", + "Failed to create local overlay for GUID {guid:?}." + ); + return Err(Error::NoSuchRecord(guid.to_owned())); + } + Ok(()) + } + + fn clone_mirror_to_overlay(&self, guid: &str) -> Result<usize> { + Ok(self.execute_cached(&CLONE_SINGLE_MIRROR_SQL, &[(":guid", &guid as &dyn ToSql)])?) + } + + /// Wipe all local data, returns the number of rows deleted + pub fn wipe_local(&self) -> Result<usize> { + info!("Executing wipe_local on password engine!"); + let tx = self.unchecked_transaction()?; + let mut row_count = 0; + row_count += self.execute("DELETE FROM loginsL", [])?; + row_count += self.execute("DELETE FROM loginsM", [])?; + row_count += self.execute("DELETE FROM loginsSyncMeta", [])?; + tx.commit()?; + Ok(row_count) + } + + pub fn shutdown(self) -> Result<()> { + self.db.close().map_err(|(_, e)| Error::SqlError(e)) + } +} + +lazy_static! { + static ref GET_ALL_SQL: String = format!( + "SELECT {common_cols} FROM loginsL WHERE is_deleted = 0 + UNION ALL + SELECT {common_cols} FROM loginsM WHERE is_overridden = 0", + common_cols = schema::COMMON_COLS, + ); + static ref COUNT_ALL_SQL: String = format!( + "SELECT COUNT(*) FROM ( + SELECT guid FROM loginsL WHERE is_deleted = 0 + UNION ALL + SELECT guid FROM loginsM WHERE is_overridden = 0 + )" + ); + static ref COUNT_BY_ORIGIN_SQL: String = format!( + "SELECT COUNT(*) FROM ( + SELECT guid FROM loginsL WHERE is_deleted = 0 AND origin = :origin + UNION ALL + SELECT guid FROM loginsM WHERE is_overridden = 0 AND origin = :origin + )" + ); + static ref COUNT_BY_FORM_ACTION_ORIGIN_SQL: String = format!( + "SELECT COUNT(*) FROM ( + SELECT guid FROM loginsL WHERE is_deleted = 0 AND formActionOrigin = :form_action_origin + UNION ALL + SELECT guid FROM loginsM WHERE is_overridden = 0 AND formActionOrigin = :form_action_origin + )" + ); + static ref GET_BY_GUID_SQL: String = format!( + "SELECT {common_cols} + FROM loginsL + WHERE is_deleted = 0 + AND guid = :guid + + UNION ALL + + SELECT {common_cols} + FROM loginsM + WHERE is_overridden IS NOT 1 + AND guid = :guid + ORDER BY origin ASC + + LIMIT 1", + common_cols = schema::COMMON_COLS, + ); + pub static ref CLONE_ENTIRE_MIRROR_SQL: String = format!( + "INSERT OR IGNORE INTO loginsL ({common_cols}, local_modified, is_deleted, sync_status) + SELECT {common_cols}, NULL AS local_modified, 0 AS is_deleted, 0 AS sync_status + FROM loginsM", + common_cols = schema::COMMON_COLS, + ); + static ref CLONE_SINGLE_MIRROR_SQL: String = + format!("{} WHERE guid = :guid", &*CLONE_ENTIRE_MIRROR_SQL,); +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +pub mod test_utils { + use super::*; + use crate::encryption::test_utils::decrypt_struct; + use crate::login::test_utils::enc_login; + use crate::SecureLoginFields; + use sync15::ServerTimestamp; + + // Insert a login into the local and/or mirror tables. + // + // local_login and mirror_login are specified as Some(password_string) + pub fn insert_login( + db: &LoginDb, + guid: &str, + local_login: Option<&str>, + mirror_login: Option<&str>, + ) { + if let Some(password) = mirror_login { + add_mirror( + db, + &enc_login(guid, password), + &ServerTimestamp(util::system_time_ms_i64(std::time::SystemTime::now())), + local_login.is_some(), + ) + .unwrap(); + } + if let Some(password) = local_login { + db.insert_new_login(&enc_login(guid, password)).unwrap(); + } + } + + pub fn insert_encrypted_login( + db: &LoginDb, + local: &EncryptedLogin, + mirror: &EncryptedLogin, + server_modified: &ServerTimestamp, + ) { + db.insert_new_login(local).unwrap(); + add_mirror(db, mirror, server_modified, true).unwrap(); + } + + pub fn add_mirror( + db: &LoginDb, + login: &EncryptedLogin, + server_modified: &ServerTimestamp, + is_overridden: bool, + ) -> Result<()> { + let sql = " + INSERT OR IGNORE INTO loginsM ( + is_overridden, + server_modified, + + httpRealm, + formActionOrigin, + usernameField, + passwordField, + secFields, + origin, + + timesUsed, + timeLastUsed, + timePasswordChanged, + timeCreated, + + guid + ) VALUES ( + :is_overridden, + :server_modified, + + :http_realm, + :form_action_origin, + :username_field, + :password_field, + :sec_fields, + :origin, + + :times_used, + :time_last_used, + :time_password_changed, + :time_created, + + :guid + )"; + let mut stmt = db.prepare_cached(sql)?; + + stmt.execute(named_params! { + ":is_overridden": is_overridden, + ":server_modified": server_modified.as_millis(), + ":http_realm": login.fields.http_realm, + ":form_action_origin": login.fields.form_action_origin, + ":username_field": login.fields.username_field, + ":password_field": login.fields.password_field, + ":origin": login.fields.origin, + ":sec_fields": login.sec_fields, + ":times_used": login.meta.times_used, + ":time_last_used": login.meta.time_last_used, + ":time_password_changed": login.meta.time_password_changed, + ":time_created": login.meta.time_created, + ":guid": login.guid_str(), + })?; + Ok(()) + } + + pub fn get_local_guids(db: &LoginDb) -> Vec<String> { + get_guids(db, "SELECT guid FROM loginsL") + } + + pub fn get_mirror_guids(db: &LoginDb) -> Vec<String> { + get_guids(db, "SELECT guid FROM loginsM") + } + + fn get_guids(db: &LoginDb, sql: &str) -> Vec<String> { + let mut stmt = db.prepare_cached(sql).unwrap(); + let mut res: Vec<String> = stmt + .query_map([], |r| r.get(0)) + .unwrap() + .map(|r| r.unwrap()) + .collect(); + res.sort(); + res + } + + pub fn get_server_modified(db: &LoginDb, guid: &str) -> i64 { + db.conn_ext_query_one(&format!( + "SELECT server_modified FROM loginsM WHERE guid='{}'", + guid + )) + .unwrap() + } + + pub fn check_local_login(db: &LoginDb, guid: &str, password: &str, local_modified_gte: i64) { + let row: (String, i64, bool) = db + .query_row( + "SELECT secFields, local_modified, is_deleted FROM loginsL WHERE guid=?", + [guid], + |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), + ) + .unwrap(); + let enc: SecureLoginFields = decrypt_struct(row.0); + assert_eq!(enc.password, password); + assert!(row.1 >= local_modified_gte); + assert!(!row.2); + } + + pub fn check_mirror_login( + db: &LoginDb, + guid: &str, + password: &str, + server_modified: i64, + is_overridden: bool, + ) { + let row: (String, i64, bool) = db + .query_row( + "SELECT secFields, server_modified, is_overridden FROM loginsM WHERE guid=?", + [guid], + |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), + ) + .unwrap(); + let enc: SecureLoginFields = decrypt_struct(row.0); + assert_eq!(enc.password, password); + assert_eq!(row.1, server_modified); + assert_eq!(row.2, is_overridden); + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod tests { + use super::*; + use crate::db::test_utils::{get_local_guids, get_mirror_guids}; + use crate::encryption::test_utils::TEST_ENCDEC; + use crate::sync::merge::LocalLogin; + use nss::ensure_initialized; + use std::{thread, time}; + + #[test] + fn test_username_dupe_semantics() { + ensure_initialized(); + let mut login = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let db = LoginDb::open_in_memory(); + db.add(login.clone(), &*TEST_ENCDEC) + .expect("should be able to add first login"); + + // We will reject new logins with the same username value... + let exp_err = "Invalid login: Login already exists"; + assert_eq!( + db.add(login.clone(), &*TEST_ENCDEC) + .unwrap_err() + .to_string(), + exp_err + ); + + // Add one with an empty username - not a dupe. + login.username = "".to_string(); + db.add(login.clone(), &*TEST_ENCDEC) + .expect("empty login isn't a dupe"); + + assert_eq!( + db.add(login, &*TEST_ENCDEC).unwrap_err().to_string(), + exp_err + ); + + // one with a username, 1 without. + assert_eq!(db.get_all().unwrap().len(), 2); + } + + #[test] + fn test_add_many() { + ensure_initialized(); + + let login_a = LoginEntry { + origin: "https://a.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let login_b = LoginEntry { + origin: "https://b.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let db = LoginDb::open_in_memory(); + let added = db + .add_many(vec![login_a.clone(), login_b.clone()], &*TEST_ENCDEC) + .expect("should be able to add logins"); + + let [added_a, added_b] = added.as_slice() else { + panic!("there should really be 2") + }; + + let fetched_a = db + .get_by_id(&added_a.as_ref().unwrap().meta.id) + .expect("should work") + .expect("should get a record"); + + assert_eq!(fetched_a.fields.origin, login_a.origin); + + let fetched_b = db + .get_by_id(&added_b.as_ref().unwrap().meta.id) + .expect("should work") + .expect("should get a record"); + + assert_eq!(fetched_b.fields.origin, login_b.origin); + + assert_eq!(db.count_all().unwrap(), 2); + } + + #[test] + fn test_count_by_origin() { + ensure_initialized(); + + let origin_a = "https://a.example.com"; + let login_a = LoginEntry { + origin: origin_a.into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let login_b = LoginEntry { + origin: "https://b.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let db = LoginDb::open_in_memory(); + db.add_many(vec![login_a.clone(), login_b.clone()], &*TEST_ENCDEC) + .expect("should be able to add logins"); + + assert_eq!(db.count_by_origin(origin_a).unwrap(), 1); + } + + #[test] + fn test_count_by_form_action_origin() { + ensure_initialized(); + + let origin_a = "https://a.example.com"; + let login_a = LoginEntry { + origin: origin_a.into(), + form_action_origin: Some(origin_a.into()), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let login_b = LoginEntry { + origin: "https://b.example.com".into(), + form_action_origin: Some("https://b.example.com".into()), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let db = LoginDb::open_in_memory(); + db.add_many(vec![login_a.clone(), login_b.clone()], &*TEST_ENCDEC) + .expect("should be able to add logins"); + + assert_eq!(db.count_by_form_action_origin(origin_a).unwrap(), 1); + } + + #[test] + fn test_add_many_with_failed_constraint() { + ensure_initialized(); + + let login_a = LoginEntry { + origin: "https://example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let login_b = LoginEntry { + // same origin will result in duplicate error + origin: "https://example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + + let db = LoginDb::open_in_memory(); + let added = db + .add_many(vec![login_a.clone(), login_b.clone()], &*TEST_ENCDEC) + .expect("should be able to add logins"); + + let [added_a, added_b] = added.as_slice() else { + panic!("there should really be 2") + }; + + // first entry has been saved successfully + let fetched_a = db + .get_by_id(&added_a.as_ref().unwrap().meta.id) + .expect("should work") + .expect("should get a record"); + + assert_eq!(fetched_a.fields.origin, login_a.origin); + + // second entry failed + assert!(!added_b.is_ok()); + } + + #[test] + fn test_add_with_meta() { + ensure_initialized(); + + let guid = Guid::random(); + let now_ms = util::system_time_ms_i64(SystemTime::now()); + let login = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + let meta = LoginMeta { + id: guid.to_string(), + time_created: now_ms, + time_password_changed: now_ms + 100, + time_last_used: now_ms + 10, + times_used: 42, + }; + + let db = LoginDb::open_in_memory(); + let entry_with_meta = LoginEntryWithMeta { + entry: login.clone(), + meta: meta.clone(), + }; + + db.add_with_meta(entry_with_meta, &*TEST_ENCDEC) + .expect("should be able to add login with record"); + + let fetched = db + .get_by_id(&guid) + .expect("should work") + .expect("should get a record"); + + assert_eq!(fetched.meta, meta); + } + + #[test] + fn test_add_with_meta_deleted() { + ensure_initialized(); + + let guid = Guid::random(); + let now_ms = util::system_time_ms_i64(SystemTime::now()); + let login = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "sekret".into(), + ..LoginEntry::default() + }; + let meta = LoginMeta { + id: guid.to_string(), + time_created: now_ms, + time_password_changed: now_ms + 100, + time_last_used: now_ms + 10, + times_used: 42, + }; + + let db = LoginDb::open_in_memory(); + let entry_with_meta = LoginEntryWithMeta { + entry: login.clone(), + meta: meta.clone(), + }; + + db.add_with_meta(entry_with_meta, &*TEST_ENCDEC) + .expect("should be able to add login with record"); + + db.delete(&guid).expect("should be able to delete login"); + + let entry_with_meta2 = LoginEntryWithMeta { + entry: login.clone(), + meta: meta.clone(), + }; + + db.add_with_meta(entry_with_meta2, &*TEST_ENCDEC) + .expect("should be able to re-add login with record"); + + let fetched = db + .get_by_id(&guid) + .expect("should work") + .expect("should get a record"); + + assert_eq!(fetched.meta, meta); + } + + #[test] + fn test_unicode_submit() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let added = db + .add( + LoginEntry { + form_action_origin: Some("http://😍.com".into()), + origin: "http://😍.com".into(), + http_realm: None, + username_field: "😍".into(), + password_field: "😍".into(), + username: "😍".into(), + password: "😍".into(), + }, + &*TEST_ENCDEC, + ) + .unwrap(); + let fetched = db + .get_by_id(&added.meta.id) + .expect("should work") + .expect("should get a record"); + assert_eq!(added, fetched); + assert_eq!(fetched.fields.origin, "http://xn--r28h.com"); + assert_eq!( + fetched.fields.form_action_origin, + Some("http://xn--r28h.com".to_string()) + ); + assert_eq!(fetched.fields.username_field, "😍"); + assert_eq!(fetched.fields.password_field, "😍"); + let sec_fields = fetched.decrypt_fields(&*TEST_ENCDEC).unwrap(); + assert_eq!(sec_fields.username, "😍"); + assert_eq!(sec_fields.password, "😍"); + } + + #[test] + fn test_unicode_realm() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let added = db + .add( + LoginEntry { + form_action_origin: None, + origin: "http://😍.com".into(), + http_realm: Some("😍😍".into()), + username: "😍".into(), + password: "😍".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + let fetched = db + .get_by_id(&added.meta.id) + .expect("should work") + .expect("should get a record"); + assert_eq!(added, fetched); + assert_eq!(fetched.fields.origin, "http://xn--r28h.com"); + assert_eq!(fetched.fields.http_realm.unwrap(), "😍😍"); + } + + fn check_matches(db: &LoginDb, query: &str, expected: &[&str]) { + let mut results = db + .get_by_base_domain(query) + .unwrap() + .into_iter() + .map(|l| l.fields.origin) + .collect::<Vec<String>>(); + results.sort_unstable(); + let mut sorted = expected.to_owned(); + sorted.sort_unstable(); + assert_eq!(sorted, results); + } + + fn check_good_bad( + good: Vec<&str>, + bad: Vec<&str>, + good_queries: Vec<&str>, + zero_queries: Vec<&str>, + ) { + let db = LoginDb::open_in_memory(); + for h in good.iter().chain(bad.iter()) { + db.add( + LoginEntry { + origin: (*h).into(), + http_realm: Some((*h).into()), + password: "test".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + } + for query in good_queries { + check_matches(&db, query, &good); + } + for query in zero_queries { + check_matches(&db, query, &[]); + } + } + + #[test] + fn test_get_by_base_domain_invalid() { + check_good_bad( + vec!["https://example.com"], + vec![], + vec![], + vec!["invalid query"], + ); + } + + #[test] + fn test_get_by_base_domain() { + check_good_bad( + vec![ + "https://example.com", + "https://www.example.com", + "http://www.example.com", + "http://www.example.com:8080", + "http://sub.example.com:8080", + "https://sub.example.com:8080", + "https://sub.sub.example.com", + "ftp://sub.example.com", + ], + vec![ + "https://badexample.com", + "https://example.co", + "https://example.com.au", + ], + vec!["example.com"], + vec!["foo.com"], + ); + // punycode! This is likely to need adjusting once we normalize + // on insert. + check_good_bad( + vec![ + "http://xn--r28h.com", // punycoded version of "http://😍.com" + ], + vec!["http://💖.com"], + vec!["😍.com", "xn--r28h.com"], + vec![], + ); + } + + #[test] + fn test_get_by_base_domain_ipv4() { + check_good_bad( + vec!["http://127.0.0.1", "https://127.0.0.1:8000"], + vec!["https://127.0.0.0", "https://example.com"], + vec!["127.0.0.1"], + vec!["127.0.0.2"], + ); + } + + #[test] + fn test_get_by_base_domain_ipv6() { + check_good_bad( + vec!["http://[::1]", "https://[::1]:8000"], + vec!["https://[0:0:0:0:0:0:1:1]", "https://example.com"], + vec!["[::1]", "[0:0:0:0:0:0:0:1]"], + vec!["[0:0:0:0:0:0:1:2]"], + ); + } + + #[test] + fn test_add() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let to_add = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }; + let login = db.add(to_add, &*TEST_ENCDEC).unwrap(); + let login2 = db.get_by_id(&login.meta.id).unwrap().unwrap(); + + assert_eq!(login.fields.origin, login2.fields.origin); + assert_eq!(login.fields.http_realm, login2.fields.http_realm); + assert_eq!(login.sec_fields, login2.sec_fields); + } + + #[test] + fn test_update() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = db + .add( + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "user1".into(), + password: "password1".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + db.update( + &login.meta.id, + LoginEntry { + origin: "https://www.example2.com".into(), + http_realm: Some("https://www.example2.com".into()), + username: "user2".into(), + password: "password2".into(), + ..Default::default() // TODO: check and fix if needed + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + let login2 = db.get_by_id(&login.meta.id).unwrap().unwrap(); + + assert_eq!(login2.fields.origin, "https://www.example2.com"); + assert_eq!( + login2.fields.http_realm, + Some("https://www.example2.com".into()) + ); + let sec_fields = login2.decrypt_fields(&*TEST_ENCDEC).unwrap(); + assert_eq!(sec_fields.username, "user2"); + assert_eq!(sec_fields.password, "password2"); + } + + #[test] + fn test_touch() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = db + .add( + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "user1".into(), + password: "password1".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + // Simulate touch happening at another "time" + thread::sleep(time::Duration::from_millis(50)); + db.touch(&login.meta.id).unwrap(); + let login2 = db.get_by_id(&login.meta.id).unwrap().unwrap(); + assert!(login2.meta.time_last_used > login.meta.time_last_used); + assert_eq!(login2.meta.times_used, login.meta.times_used + 1); + } + + #[test] + fn test_delete() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = db + .add( + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + assert!(db.delete(login.guid_str()).unwrap()); + + let local_login = db + .query_row( + "SELECT * FROM loginsL WHERE guid = :guid", + named_params! { ":guid": login.guid_str() }, + |row| Ok(LocalLogin::test_raw_from_row(row).unwrap()), + ) + .unwrap(); + assert_eq!(local_login.fields.http_realm, None); + assert_eq!(local_login.fields.form_action_origin, None); + + assert!(!db.exists(login.guid_str()).unwrap()); + } + + #[test] + fn test_delete_many() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + + let login_a = db + .add( + LoginEntry { + origin: "https://a.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + let login_b = db + .add( + LoginEntry { + origin: "https://b.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + let result = db + .delete_many(vec![login_a.guid_str(), login_b.guid_str()]) + .unwrap(); + assert!(result[0]); + assert!(result[1]); + assert!(!db.exists(login_a.guid_str()).unwrap()); + assert!(!db.exists(login_b.guid_str()).unwrap()); + } + + #[test] + fn test_subsequent_delete_many() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + + let login = db + .add( + LoginEntry { + origin: "https://a.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + let result = db.delete_many(vec![login.guid_str()]).unwrap(); + assert!(result[0]); + assert!(!db.exists(login.guid_str()).unwrap()); + + let result = db.delete_many(vec![login.guid_str()]).unwrap(); + assert!(!result[0]); + } + + #[test] + fn test_delete_many_with_non_existent_id() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + + let result = db.delete_many(vec![&Guid::random()]).unwrap(); + assert!(!result[0]); + } + + #[test] + fn test_delete_local_for_remote_replacement() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = db + .add( + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test_user".into(), + password: "test_password".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + + let result = db + .delete_local_records_for_remote_replacement(vec![login.guid_str()]) + .unwrap(); + + let local_guids = get_local_guids(&db); + assert_eq!(local_guids.len(), 0); + + let mirror_guids = get_mirror_guids(&db); + assert_eq!(mirror_guids.len(), 0); + + assert_eq!(result.local_deleted, 1); + } + + mod test_find_login_to_update { + use super::*; + + fn make_entry(username: &str, password: &str) -> LoginEntry { + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("the website".into()), + username: username.into(), + password: password.into(), + ..Default::default() + } + } + + fn make_saved_login(db: &LoginDb, username: &str, password: &str) -> Login { + db.add(make_entry(username, password), &*TEST_ENCDEC) + .unwrap() + .decrypt(&*TEST_ENCDEC) + .unwrap() + } + + #[test] + fn test_match() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = make_saved_login(&db, "user", "pass"); + assert_eq!( + Some(login), + db.find_login_to_update(make_entry("user", "pass"), &*TEST_ENCDEC) + .unwrap(), + ); + } + + #[test] + fn test_non_matches() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + // Non-match because the username is different + make_saved_login(&db, "other-user", "pass"); + // Non-match because the http_realm is different + db.add( + LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("the other website".into()), + username: "user".into(), + password: "pass".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + // Non-match because it uses form_action_origin instead of http_realm + db.add( + LoginEntry { + origin: "https://www.example.com".into(), + form_action_origin: Some("https://www.example.com/".into()), + username: "user".into(), + password: "pass".into(), + ..Default::default() + }, + &*TEST_ENCDEC, + ) + .unwrap(); + assert_eq!( + None, + db.find_login_to_update(make_entry("user", "pass"), &*TEST_ENCDEC) + .unwrap(), + ); + } + + #[test] + fn test_match_blank_password() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + let login = make_saved_login(&db, "", "pass"); + assert_eq!( + Some(login), + db.find_login_to_update(make_entry("user", "pass"), &*TEST_ENCDEC) + .unwrap(), + ); + } + + #[test] + fn test_username_match_takes_precedence_over_blank_username() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + make_saved_login(&db, "", "pass"); + let username_match = make_saved_login(&db, "user", "pass"); + assert_eq!( + Some(username_match), + db.find_login_to_update(make_entry("user", "pass"), &*TEST_ENCDEC) + .unwrap(), + ); + } + + #[test] + fn test_invalid_login() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + assert!(db + .find_login_to_update( + LoginEntry { + http_realm: None, + form_action_origin: None, + ..LoginEntry::default() + }, + &*TEST_ENCDEC + ) + .is_err()); + } + + #[test] + fn test_update_with_duplicate_login() { + ensure_initialized(); + // If we have duplicate logins in the database, it should be possible to update them + // without triggering a DuplicateLogin error + let db = LoginDb::open_in_memory(); + let login = make_saved_login(&db, "user", "pass"); + let mut dupe = login.clone().encrypt(&*TEST_ENCDEC).unwrap(); + dupe.meta.id = "different-guid".to_string(); + db.insert_new_login(&dupe).unwrap(); + + let mut entry = login.entry(); + entry.password = "pass2".to_string(); + db.update(&login.id, entry, &*TEST_ENCDEC).unwrap(); + + let mut entry = login.entry(); + entry.password = "pass3".to_string(); + db.add_or_update(entry, &*TEST_ENCDEC).unwrap(); + } + } +} diff --git a/third_party/rust/logins/src/encryption.rs b/third_party/rust/logins/src/encryption.rs @@ -0,0 +1,504 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +// This is the *local* encryption support - it has nothing to do with the +// encryption used by sync. + +// For context, what "local encryption" means in this context is: +// * We use regular sqlite, but ensure that sensitive data is encrypted in the DB in the +// `secure_fields` column. The encryption key is managed by the app. +// * The `decrypt_struct` and `encrypt_struct` functions are used to convert between an encrypted +// `secure_fields` string and a decrypted `SecureFields` struct +// * Most API functions return `EncryptedLogin` which has its data encrypted. +// +// This makes life tricky for Sync - sync has its own encryption and its own +// management of sync keys. The entire records are encrypted on the server - +// so the record on the server has the plain-text data (which is then +// encrypted as part of the entire record), so: +// * When transforming a record from the DB into a Sync record, we need to +// *decrypt* the data. +// * When transforming a record from Sync into a DB record, we need to *encrypt* +// the data. +// +// So Sync needs to know the key etc, and that needs to get passed down +// multiple layers, from the app saying "sync now" all the way down to the +// low level sync code. +// To make life a little easier, we do that via a struct. +// +// Consumers of the Login component have 3 options for setting up encryption: +// 1. Implement EncryptorDecryptor directly +// eg `LoginStore::new(MyEncryptorDecryptor)` +// 2. Implement KeyManager and use ManagedEncryptorDecryptor +// eg `LoginStore::new(ManagedEncryptorDecryptor::new(MyKeyManager))` +// 3. Generate a single key and create a StaticKeyManager and use it together with +// ManagedEncryptorDecryptor +// eg `LoginStore::new(ManagedEncryptorDecryptor::new(StaticKeyManager { key: myKey }))` +// +// You can implement EncryptorDecryptor directly to keep full control over the encryption +// algorithm. For example, on the desktop, this could make use of NSS's SecretDecoderRing to +// achieve transparent key management. +// +// If the application wants to keep the current encryption, like Android and iOS, for example, but +// control the key management itself, the KeyManager can be implemented and the encryption can be +// done on the Rust side with the ManagedEncryptorDecryptor. +// +// In tests or some command line tools, it can be practical to use a static key that does not +// change at runtime and is already present when the LoginsStore is initialized. In this case, it +// makes sense to use the provided StaticKeyManager. + +use crate::error::*; +use std::sync::Arc; + +#[cfg(feature = "keydb")] +use futures::executor::block_on; + +#[cfg(feature = "keydb")] +use async_trait::async_trait; + +#[cfg(feature = "keydb")] +use nss::assert_initialized as assert_nss_initialized; +#[cfg(feature = "keydb")] +use nss::pk11::sym_key::{ + authenticate_with_primary_password, authentication_with_primary_password_is_needed, + get_or_create_aes256_key, +}; + +/// This is the generic EncryptorDecryptor trait, as handed over to the Store during initialization. +/// Consumers can implement either this generic trait and bring in their own crypto, or leverage the +/// ManagedEncryptorDecryptor below, which provides encryption algorithms out of the box. +/// +/// Note that EncryptorDecryptor must not call any LoginStore methods. The login store can call out +/// to the EncryptorDecryptor when it's internal mutex is held so calling back in to the LoginStore +/// may deadlock. +pub trait EncryptorDecryptor: Send + Sync { + fn encrypt(&self, cleartext: Vec<u8>) -> ApiResult<Vec<u8>>; + fn decrypt(&self, ciphertext: Vec<u8>) -> ApiResult<Vec<u8>>; +} + +impl<T: EncryptorDecryptor> EncryptorDecryptor for Arc<T> { + fn encrypt(&self, clearbytes: Vec<u8>) -> ApiResult<Vec<u8>> { + (**self).encrypt(clearbytes) + } + + fn decrypt(&self, cipherbytes: Vec<u8>) -> ApiResult<Vec<u8>> { + (**self).decrypt(cipherbytes) + } +} + +/// The ManagedEncryptorDecryptor makes use of the NSS provided cryptographic algorithms. The +/// ManagedEncryptorDecryptor uses a KeyManager for encryption key retrieval. +pub struct ManagedEncryptorDecryptor { + key_manager: Arc<dyn KeyManager>, +} + +impl ManagedEncryptorDecryptor { + #[uniffi::constructor()] + pub fn new(key_manager: Arc<dyn KeyManager>) -> Self { + Self { key_manager } + } +} + +impl EncryptorDecryptor for ManagedEncryptorDecryptor { + fn encrypt(&self, clearbytes: Vec<u8>) -> ApiResult<Vec<u8>> { + let keybytes = self + .key_manager + .get_key() + .map_err(|_| LoginsApiError::MissingKey)?; + let key = std::str::from_utf8(&keybytes).map_err(|_| LoginsApiError::InvalidKey)?; + + let encdec = jwcrypto::EncryptorDecryptor::new(key) + .map_err(|_: jwcrypto::JwCryptoError| LoginsApiError::InvalidKey)?; + + let cleartext = + std::str::from_utf8(&clearbytes).map_err(|e| LoginsApiError::EncryptionFailed { + reason: e.to_string(), + })?; + encdec + .encrypt(cleartext) + .map_err( + |e: jwcrypto::JwCryptoError| LoginsApiError::EncryptionFailed { + reason: e.to_string(), + }, + ) + .map(|text| text.into()) + } + + fn decrypt(&self, cipherbytes: Vec<u8>) -> ApiResult<Vec<u8>> { + let keybytes = self + .key_manager + .get_key() + .map_err(|_| LoginsApiError::MissingKey)?; + let key = std::str::from_utf8(&keybytes).map_err(|_| LoginsApiError::InvalidKey)?; + + let encdec = jwcrypto::EncryptorDecryptor::new(key) + .map_err(|_: jwcrypto::JwCryptoError| LoginsApiError::InvalidKey)?; + + let ciphertext = + std::str::from_utf8(&cipherbytes).map_err(|e| LoginsApiError::DecryptionFailed { + reason: e.to_string(), + })?; + encdec + .decrypt(ciphertext) + .map_err( + |e: jwcrypto::JwCryptoError| LoginsApiError::DecryptionFailed { + reason: e.to_string(), + }, + ) + .map(|text| text.into()) + } +} + +/// Consumers can implement the KeyManager in combination with the ManagedEncryptorDecryptor to hand +/// over the encryption key whenever encryption or decryption happens. +pub trait KeyManager: Send + Sync { + fn get_key(&self) -> ApiResult<Vec<u8>>; +} + +/// Last but not least we provide a StaticKeyManager, which can be +/// used in cases where there is a single key during runtime, for example in tests. +pub struct StaticKeyManager { + key: String, +} + +impl StaticKeyManager { + pub fn new(key: String) -> Self { + Self { key } + } +} + +impl KeyManager for StaticKeyManager { + #[handle_error(Error)] + fn get_key(&self) -> ApiResult<Vec<u8>> { + Ok(self.key.as_bytes().into()) + } +} + +/// `PrimaryPasswordAuthenticator` is used in conjunction with `NSSKeyManager` to provide the +/// primary password and the success or failure actions of the authentication process. +#[cfg(feature = "keydb")] +#[uniffi::export(with_foreign)] +#[async_trait] +pub trait PrimaryPasswordAuthenticator: Send + Sync { + /// Get a primary password for authentication, otherwise return the + /// AuthenticationCancelled error to cancel the authentication process. + async fn get_primary_password(&self) -> ApiResult<String>; + async fn on_authentication_success(&self) -> ApiResult<()>; + async fn on_authentication_failure(&self) -> ApiResult<()>; +} + +/// Use the `NSSKeyManager` to use NSS for key management. +/// +/// NSS stores keys in `key4.db` within the profile and wraps the key with a key derived from the +/// primary password, if set. It defers to the provided `PrimaryPasswordAuthenticator` +/// implementation to handle user authentication. Note that if no primary password is set, the +/// wrapping key is deterministically derived from an empty string. +/// +/// Make sure to initialize NSS using `ensure_initialized_with_profile_dir` before creating a +/// NSSKeyManager. +/// +/// # Examples +/// ```no_run +/// use async_trait::async_trait; +/// use logins::encryption::KeyManager; +/// use logins::{PrimaryPasswordAuthenticator, LoginsApiError, NSSKeyManager}; +/// use std::sync::Arc; +/// +/// struct MyPrimaryPasswordAuthenticator {} +/// +/// #[async_trait] +/// impl PrimaryPasswordAuthenticator for MyPrimaryPasswordAuthenticator { +/// async fn get_primary_password(&self) -> Result<String, LoginsApiError> { +/// // Most likely, you would want to prompt for a password. +/// // let password = prompt_string("primary password").unwrap_or_default(); +/// Ok("secret".to_string()) +/// } +/// +/// async fn on_authentication_success(&self) -> Result<(), LoginsApiError> { +/// println!("success"); +/// Ok(()) +/// } +/// +/// async fn on_authentication_failure(&self) -> Result<(), LoginsApiError> { +/// println!("this did not work, please try again:"); +/// Ok(()) +/// } +/// } +/// let key_manager = NSSKeyManager::new(Arc::new(MyPrimaryPasswordAuthenticator {})); +/// assert_eq!(key_manager.get_key().unwrap().len(), 63); +/// ``` +#[cfg(feature = "keydb")] +#[derive(uniffi::Object)] +pub struct NSSKeyManager { + primary_password_authenticator: Arc<dyn PrimaryPasswordAuthenticator>, +} + +#[cfg(feature = "keydb")] +#[uniffi::export] +impl NSSKeyManager { + /// Initialize new `NSSKeyManager` with a given `PrimaryPasswordAuthenticator`. + /// There must be a previous initializiation of NSS before initializing + /// `NSSKeyManager`, otherwise this panics. + #[uniffi::constructor()] + pub fn new(primary_password_authenticator: Arc<dyn PrimaryPasswordAuthenticator>) -> Self { + assert_nss_initialized(); + Self { + primary_password_authenticator, + } + } + + pub fn into_dyn_key_manager(self: Arc<Self>) -> Arc<dyn KeyManager> { + self + } +} + +/// Identifier for the logins key, under which the key is stored in NSS. +#[cfg(feature = "keydb")] +static KEY_NAME: &str = "as-logins-key"; + +// wrapp `authentication_with_primary_password_is_needed` into an ApiResult +#[cfg(feature = "keydb")] +fn api_authentication_with_primary_password_is_needed() -> ApiResult<bool> { + authentication_with_primary_password_is_needed().map_err(|e: nss::Error| { + LoginsApiError::NSSAuthenticationError { + reason: e.to_string(), + } + }) +} + +// wrapp `authenticate_with_primary_password` into an ApiResult +#[cfg(feature = "keydb")] +fn api_authenticate_with_primary_password(primary_password: &str) -> ApiResult<bool> { + authenticate_with_primary_password(primary_password).map_err(|e: nss::Error| { + LoginsApiError::NSSAuthenticationError { + reason: e.to_string(), + } + }) +} + +#[cfg(feature = "keydb")] +impl KeyManager for NSSKeyManager { + fn get_key(&self) -> ApiResult<Vec<u8>> { + if api_authentication_with_primary_password_is_needed()? { + let primary_password = + block_on(self.primary_password_authenticator.get_primary_password())?; + let mut result = api_authenticate_with_primary_password(&primary_password)?; + + if result { + block_on( + self.primary_password_authenticator + .on_authentication_success(), + )?; + } else { + while !result { + block_on( + self.primary_password_authenticator + .on_authentication_failure(), + )?; + + let primary_password = + block_on(self.primary_password_authenticator.get_primary_password())?; + result = api_authenticate_with_primary_password(&primary_password)?; + } + block_on( + self.primary_password_authenticator + .on_authentication_success(), + )?; + } + } + + let key = get_or_create_aes256_key(KEY_NAME).expect("Could not get or create key via NSS"); + let mut bytes: Vec<u8> = Vec::new(); + serde_json::to_writer( + &mut bytes, + &jwcrypto::Jwk::new_direct_from_bytes(None, &key), + ) + .unwrap(); + Ok(bytes) + } +} + +#[handle_error(Error)] +pub fn create_canary(text: &str, key: &str) -> ApiResult<String> { + Ok(jwcrypto::EncryptorDecryptor::new(key)?.create_canary(text)?) +} + +pub fn check_canary(canary: &str, text: &str, key: &str) -> ApiResult<bool> { + let encdec = jwcrypto::EncryptorDecryptor::new(key) + .map_err(|_: jwcrypto::JwCryptoError| LoginsApiError::InvalidKey)?; + Ok(encdec.check_canary(canary, text).unwrap_or(false)) +} + +#[handle_error(Error)] +pub fn create_key() -> ApiResult<String> { + Ok(jwcrypto::EncryptorDecryptor::create_key()?) +} + +#[cfg(test)] +pub mod test_utils { + use super::*; + use serde::{de::DeserializeOwned, Serialize}; + + lazy_static::lazy_static! { + pub static ref TEST_ENCRYPTION_KEY: String = serde_json::to_string(&jwcrypto::Jwk::new_direct_key(Some("test-key".to_string())).unwrap()).unwrap(); + pub static ref TEST_ENCDEC: Arc<ManagedEncryptorDecryptor> = Arc::new(ManagedEncryptorDecryptor::new(Arc::new(StaticKeyManager { key: TEST_ENCRYPTION_KEY.clone() }))); + } + + pub fn encrypt_struct<T: Serialize>(fields: &T) -> String { + let string = serde_json::to_string(fields).unwrap(); + let cipherbytes = TEST_ENCDEC.encrypt(string.as_bytes().into()).unwrap(); + std::str::from_utf8(&cipherbytes).unwrap().to_owned() + } + pub fn decrypt_struct<T: DeserializeOwned>(ciphertext: String) -> T { + let jsonbytes = TEST_ENCDEC.decrypt(ciphertext.as_bytes().into()).unwrap(); + serde_json::from_str(std::str::from_utf8(&jsonbytes).unwrap()).unwrap() + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod test { + use super::*; + use nss::ensure_initialized; + + #[test] + fn test_static_key_manager() { + ensure_initialized(); + let key = create_key().unwrap(); + let key_manager = StaticKeyManager { key: key.clone() }; + assert_eq!(key.as_bytes(), key_manager.get_key().unwrap()); + } + + #[test] + fn test_managed_encdec_with_invalid_key() { + ensure_initialized(); + let key_manager = Arc::new(StaticKeyManager { + key: "bad_key".to_owned(), + }); + let encdec = ManagedEncryptorDecryptor { key_manager }; + assert!(matches!( + encdec.encrypt("secret".as_bytes().into()).err().unwrap(), + LoginsApiError::InvalidKey + )); + } + + #[test] + fn test_managed_encdec_with_missing_key() { + ensure_initialized(); + struct MyKeyManager {} + impl KeyManager for MyKeyManager { + fn get_key(&self) -> ApiResult<Vec<u8>> { + Err(LoginsApiError::MissingKey) + } + } + let key_manager = Arc::new(MyKeyManager {}); + let encdec = ManagedEncryptorDecryptor { key_manager }; + assert!(matches!( + encdec.encrypt("secret".as_bytes().into()).err().unwrap(), + LoginsApiError::MissingKey + )); + } + + #[test] + fn test_managed_encdec() { + ensure_initialized(); + let key = create_key().unwrap(); + let key_manager = Arc::new(StaticKeyManager { key }); + let encdec = ManagedEncryptorDecryptor { key_manager }; + let cleartext = "secret"; + let ciphertext = encdec.encrypt(cleartext.as_bytes().into()).unwrap(); + assert_eq!( + encdec.decrypt(ciphertext.clone()).unwrap(), + cleartext.as_bytes() + ); + let other_encdec = ManagedEncryptorDecryptor { + key_manager: Arc::new(StaticKeyManager { + key: create_key().unwrap(), + }), + }; + + assert_eq!( + other_encdec.decrypt(ciphertext).err().unwrap().to_string(), + "decryption failed: Crypto error: NSS error: NSS error: -8190 " + ); + } + + #[test] + fn test_key_error() { + let storage_err = jwcrypto::EncryptorDecryptor::new("bad-key").err().unwrap(); + println!("{storage_err:?}"); + assert!(matches!(storage_err, jwcrypto::JwCryptoError::InvalidKey)); + } + + #[test] + fn test_canary_functionality() { + ensure_initialized(); + const CANARY_TEXT: &str = "Arbitrary sequence of text"; + let key = create_key().unwrap(); + let canary = create_canary(CANARY_TEXT, &key).unwrap(); + assert!(check_canary(&canary, CANARY_TEXT, &key).unwrap()); + + let different_key = create_key().unwrap(); + assert!(!check_canary(&canary, CANARY_TEXT, &different_key).unwrap()); + + let bad_key = "bad_key".to_owned(); + assert!(matches!( + check_canary(&canary, CANARY_TEXT, &bad_key).err().unwrap(), + LoginsApiError::InvalidKey + )); + } +} + +#[cfg(feature = "keydb")] +#[cfg(test)] +mod keydb_test { + use super::*; + use nss::ensure_initialized_with_profile_dir; + use std::path::PathBuf; + + struct MockPrimaryPasswordAuthenticator { + password: String, + } + + #[async_trait] + impl PrimaryPasswordAuthenticator for MockPrimaryPasswordAuthenticator { + async fn get_primary_password(&self) -> ApiResult<String> { + Ok(self.password.clone()) + } + async fn on_authentication_success(&self) -> ApiResult<()> { + Ok(()) + } + async fn on_authentication_failure(&self) -> ApiResult<()> { + Ok(()) + } + } + + fn profile_path() -> PathBuf { + std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures/profile") + } + + #[test] + fn test_ensure_initialized_with_profile_dir() { + ensure_initialized_with_profile_dir(profile_path()); + } + + #[test] + fn test_create_key() { + ensure_initialized_with_profile_dir(profile_path()); + let key = create_key().unwrap(); + assert_eq!(key.len(), 63) + } + + #[test] + fn test_nss_key_manager() { + ensure_initialized_with_profile_dir(profile_path()); + let mock_primary_password_authenticator = MockPrimaryPasswordAuthenticator { + password: "password".to_string(), + }; + let nss_key_manager = NSSKeyManager { + primary_password_authenticator: Arc::new(mock_primary_password_authenticator), + }; + assert_eq!(nss_key_manager.get_key().unwrap().len(), 63) + } +} diff --git a/third_party/rust/logins/src/error.rs b/third_party/rust/logins/src/error.rs @@ -0,0 +1,226 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::ffi::OsString; +pub type Result<T> = std::result::Result<T, Error>; +// Functions which are part of the public API should use this Result. +pub type ApiResult<T> = std::result::Result<T, LoginsApiError>; + +pub use error_support::{breadcrumb, handle_error, report_error}; +pub use error_support::{debug, error, info, trace, warn}; + +use error_support::{ErrorHandling, GetErrorHandling}; +use jwcrypto::JwCryptoError; +use sync15::Error as Sync15Error; + +// Errors we return via the public interface. +#[derive(Debug, thiserror::Error)] +pub enum LoginsApiError { + #[error("NSS not initialized")] + NSSUninitialized, + + #[error("NSS error during authentication: {reason}")] + NSSAuthenticationError { reason: String }, + + #[error("error during authentication: {reason}")] + AuthenticationError { reason: String }, + + #[error("authentication cancelled")] + AuthenticationCanceled, + + #[error("Invalid login: {reason}")] + InvalidRecord { reason: String }, + + #[error("No record with guid exists (when one was required): {reason:?}")] + NoSuchRecord { reason: String }, + + #[error("Encryption key is missing.")] + MissingKey, + + #[error("Encryption key is not valid.")] + InvalidKey, + + #[error("encryption failed: {reason}")] + EncryptionFailed { reason: String }, + + #[error("decryption failed: {reason}")] + DecryptionFailed { reason: String }, + + #[error("{reason}")] + Interrupted { reason: String }, + + #[error("SyncAuthInvalid error {reason}")] + SyncAuthInvalid { reason: String }, + + #[error("Unexpected Error: {reason}")] + UnexpectedLoginsApiError { reason: String }, +} + +/// Logins error type +/// These are "internal" errors used by the implementation. This error type +/// is never returned to the consumer. +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Database is closed")] + DatabaseClosed, + + #[error("Malformed incoming record")] + MalformedIncomingRecord, + + #[error("Invalid login: {0}")] + InvalidLogin(#[from] InvalidLogin), + + #[error("The `sync_status` column in DB has an illegal value: {0}")] + BadSyncStatus(u8), + + #[error("No record with guid exists (when one was required): {0:?}")] + NoSuchRecord(String), + + // Fennec import only works on empty logins tables. + #[error("The logins tables are not empty")] + NonEmptyTable, + + #[error("encryption failed: {0:?}")] + EncryptionFailed(String), + + #[error("decryption failed: {0:?}")] + DecryptionFailed(String), + + #[error("Error synchronizing: {0}")] + SyncAdapterError(#[from] sync15::Error), + + #[error("Error parsing JSON data: {0}")] + JsonError(#[from] serde_json::Error), + + #[error("Error executing SQL: {0}")] + SqlError(#[from] rusqlite::Error), + + #[error("Error parsing URL: {0}")] + UrlParseError(#[from] url::ParseError), + + #[error("Invalid path: {0:?}")] + InvalidPath(OsString), + + #[error("CryptoError({0})")] + CryptoError(#[from] JwCryptoError), + + #[error("{0}")] + Interrupted(#[from] interrupt_support::Interrupted), + + #[error("IOError: {0}")] + IOError(#[from] std::io::Error), + + #[error("Migration Error: {0}")] + MigrationError(String), +} + +/// Error::InvalidLogin subtypes +#[derive(Debug, thiserror::Error)] +pub enum InvalidLogin { + // EmptyOrigin error occurs when the login's origin field is empty. + #[error("Origin is empty")] + EmptyOrigin, + #[error("Password is empty")] + EmptyPassword, + #[error("Login already exists")] + DuplicateLogin, + #[error("Both `formActionOrigin` and `httpRealm` are present")] + BothTargets, + #[error("Neither `formActionOrigin` or `httpRealm` are present")] + NoTarget, + // Login has an illegal origin field, split off from IllegalFieldValue since this is a known + // issue with the Desktop logins and we don't want to report it to Sentry (see #5233). + #[error("Login has illegal origin")] + IllegalOrigin, + #[error("Login has illegal field: {field_info}")] + IllegalFieldValue { field_info: String }, +} + +// Define how our internal errors are handled and converted to external errors +// See `support/error/README.md` for how this works, especially the warning about PII. +impl GetErrorHandling for Error { + type ExternalError = LoginsApiError; + + fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> { + match self { + Self::InvalidLogin(why) => ErrorHandling::convert(LoginsApiError::InvalidRecord { + reason: why.to_string(), + }), + Self::MalformedIncomingRecord => { + ErrorHandling::convert(LoginsApiError::InvalidRecord { + reason: "invalid incoming record".to_string(), + }) + } + // Our internal "no such record" error is converted to our public "no such record" error, with no logging and no error reporting. + Self::NoSuchRecord(guid) => ErrorHandling::convert(LoginsApiError::NoSuchRecord { + reason: guid.to_string(), + }), + // NonEmptyTable error is just a sanity check to ensure we aren't asked to migrate into an + // existing DB - consumers should never actually do this, and will never expect to handle this as a specific + // error - so it gets reported to the error reporter and converted to an "internal" error. + Self::NonEmptyTable => { + ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: "must be an empty DB to migrate".to_string(), + }) + .report_error("logins-migration") + } + Self::Interrupted(_) => ErrorHandling::convert(LoginsApiError::Interrupted { + reason: self.to_string(), + }), + Self::SyncAdapterError(e) => match e { + Sync15Error::TokenserverHttpError(401) | Sync15Error::BadKeyLength(..) => { + ErrorHandling::convert(LoginsApiError::SyncAuthInvalid { + reason: e.to_string(), + }) + .log_warning() + } + Sync15Error::RequestError(_) => { + ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: e.to_string(), + }) + .log_warning() + } + _ => ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: self.to_string(), + }) + .report_error("logins-sync"), + }, + Error::SqlError(rusqlite::Error::SqliteFailure(err, _)) => match err.code { + rusqlite::ErrorCode::DatabaseCorrupt => { + ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: self.to_string(), + }) + .report_error("logins-db-corrupt") + } + rusqlite::ErrorCode::DiskFull => { + ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: self.to_string(), + }) + .report_error("logins-db-disk-full") + } + _ => ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: self.to_string(), + }) + .report_error("logins-unexpected"), + }, + // Unexpected errors that we report to Sentry. We should watch the reports for these + // and do one or more of these things if we see them: + // - Fix the underlying issue + // - Add breadcrumbs or other context to help uncover the issue + // - Decide that these are expected errors and move them to the above case + _ => ErrorHandling::convert(LoginsApiError::UnexpectedLoginsApiError { + reason: self.to_string(), + }) + .report_error("logins-unexpected"), + } + } +} + +impl From<uniffi::UnexpectedUniFFICallbackError> for LoginsApiError { + fn from(error: uniffi::UnexpectedUniFFICallbackError) -> Self { + LoginsApiError::UnexpectedLoginsApiError { + reason: error.to_string(), + } + } +} diff --git a/third_party/rust/logins/src/lib.rs b/third_party/rust/logins/src/lib.rs @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![allow(unknown_lints)] +#![warn(rust_2018_idioms)] + +#[macro_use] +mod error; +mod login; + +mod db; +pub mod encryption; +mod schema; +mod store; +mod sync; +mod util; + +use crate::encryption::{ + EncryptorDecryptor, KeyManager, ManagedEncryptorDecryptor, StaticKeyManager, +}; +uniffi::include_scaffolding!("logins"); + +#[cfg(feature = "keydb")] +pub use crate::encryption::{NSSKeyManager, PrimaryPasswordAuthenticator}; + +pub use crate::db::{LoginDb, LoginsDeletionMetrics}; +use crate::encryption::{check_canary, create_canary, create_key}; +pub use crate::error::*; +pub use crate::login::*; +pub use crate::store::*; +pub use crate::sync::LoginsSyncEngine; +use std::sync::Arc; + +// Utility function to create a StaticKeyManager to be used for the time being until support lands +// for [trait implementation of an UniFFI +// interface](https://mozilla.github.io/uniffi-rs/next/proc_macro/index.html#structs-implementing-traits) +// in UniFFI. +pub fn create_static_key_manager(key: String) -> Arc<StaticKeyManager> { + Arc::new(StaticKeyManager::new(key)) +} + +// Similar to create_static_key_manager above, create a +// ManagedEncryptorDecryptor by passing in a KeyManager +pub fn create_managed_encdec(key_manager: Arc<dyn KeyManager>) -> Arc<ManagedEncryptorDecryptor> { + Arc::new(ManagedEncryptorDecryptor::new(key_manager)) +} + +// Create a LoginStore by passing in a db path and a static key +// +// Note this is only temporarily needed until a bug with UniFFI and JavaScript is fixed, which +// prevents passing around traits in JS +pub fn create_login_store_with_static_key_manager(path: String, key: String) -> Arc<LoginStore> { + let encdec: ManagedEncryptorDecryptor = + ManagedEncryptorDecryptor::new(Arc::new(StaticKeyManager::new(key))); + Arc::new(LoginStore::new(path, Arc::new(encdec)).unwrap()) +} + +// Create a LoginStore with NSSKeyManager by passing in a db path and a PrimaryPasswordAuthenticator. +// +// Note this is only temporarily needed until a bug with UniFFI and JavaScript is fixed, which +// prevents passing around traits in JS +#[cfg(feature = "keydb")] +#[uniffi::export] +pub fn create_login_store_with_nss_keymanager( + path: String, + primary_password_authenticator: Arc<dyn PrimaryPasswordAuthenticator>, +) -> Arc<LoginStore> { + let encdec: ManagedEncryptorDecryptor = ManagedEncryptorDecryptor::new(Arc::new( + NSSKeyManager::new(primary_password_authenticator), + )); + Arc::new(LoginStore::new(path, Arc::new(encdec)).unwrap()) +} diff --git a/third_party/rust/logins/src/login.rs b/third_party/rust/logins/src/login.rs @@ -0,0 +1,1299 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// N.B. if you're making a documentation change here, you might also want to make it in: +// +// * The API docs in ../ios/Logins/LoginRecord.swift +// * The API docs in ../android/src/main/java/mozilla/appservices/logins/ServerPassword.kt +// * The android-components docs at +// https://github.com/mozilla-mobile/android-components/tree/master/components/service/sync-logins +// +// We'll figure out a more scalable approach to maintaining all those docs at some point... + +//! # Login Structs +//! +//! This module defines a number of core structs for Logins. They are: +//! * [`LoginEntry`] A login entry by the user. This includes the username/password, the site it +//! was submitted to, etc. [`LoginEntry`] does not store data specific to a DB record. +//! * [`Login`] - A [`LoginEntry`] plus DB record information. This includes the GUID and metadata +//! like time_last_used. +//! * [`EncryptedLogin`] -- A Login above with the username/password data encrypted. +//! * [`LoginFields`], [`SecureLoginFields`], [`LoginMeta`] -- These group the common fields in the +//! structs above. +//! +//! Why so many structs for similar data? Consider some common use cases in a hypothetical browser +//! (currently no browsers act exactly like this, although Fenix/android-components comes close): +//! +//! - User visits a page with a login form. +//! - We inform the user if there are saved logins that can be autofilled. We use the +//! `LoginDb.get_by_base_domain()` which returns a `Vec<EncryptedLogin>`. We don't decrypt the +//! logins because we want to avoid requiring the encryption key at this point, which would +//! force the user to authenticate. Note: this is aspirational at this point, no actual +//! implementations follow this flow. Still, we want application-services to support it. +//! - If the user chooses to autofill, we decrypt the logins into a `Vec<Login>`. We need to +//! decrypt at this point to display the username and autofill the password if they select one. +//! - When the user selects a login, we can use the already decrypted data from `Login` to fill +//! in the form. +//! - User chooses to save a login for autofilling later. +//! - We present the user with a dialog that: +//! - Displays a header that differentiates between different types of save: adding a new +//! login, updating an existing login, filling in a blank username, etc. +//! - Allows the user to tweak the username, in case we failed to detect the form field +//! correctly. This may affect which header should be shown. +//! - Here we use `find_login_to_update()` which returns an `Option<Login>`. Returning a login +//! that has decrypted data avoids forcing the consumer code to decrypt the username again. +//! +//! # Login +//! This has the complete set of data about a login. Very closely related is the +//! "sync payload", defined in sync/payload.rs, which handles all aspects of the JSON serialization. +//! It contains the following fields: +//! - `meta`: A [`LoginMeta`] struct. +//! - fields: A [`LoginFields`] struct. +//! - sec_fields: A [`SecureLoginFields`] struct. +//! +//! # LoginEntry +//! The struct used to add or update logins. This has the plain-text version of the fields that are +//! stored encrypted, so almost all uses of an LoginEntry struct will also require the +//! encryption key to be known and passed in. [LoginDB] methods that save data typically input +//! [LoginEntry] instances. This allows the DB code to handle dupe-checking issues like +//! determining which login record should be updated for a newly submitted [LoginEntry]. +//! It contains the following fields: +//! - fields: A [`LoginFields`] struct. +//! - sec_fields: A [`SecureLoginFields`] struct. +//! +//! # EncryptedLogin +//! Encrypted version of [`Login`]. [LoginDB] methods that return data typically return [EncryptedLogin] +//! this allows deferring decryption, and therefore user authentication, until the secure data is needed. +//! It contains the following fields +//! - `meta`: A [`LoginMeta`] struct. +//! - `fields`: A [`LoginFields`] struct. +//! - `sec_fields`: The secure fields as an encrypted string +//! +//! # SecureLoginFields +//! The struct used to hold the fields which are stored encrypted. It contains: +//! - username: A string. +//! - password: A string. +//! +//! # LoginFields +//! +//! The core set of fields, use by both [`Login`] and [`LoginEntry`] +//! It contains the following fields: +//! +//! - `origin`: The origin at which this login can be used, as a string. +//! +//! The login should only be used on sites that match this origin (for whatever definition +//! of "matches" makes sense at the application level, e.g. eTLD+1 matching). +//! This field is required, must be a valid origin in punycode format, and must not be +//! set to the empty string. +//! +//! Examples of valid `origin` values include: +//! - "https://site.com" +//! - "http://site.com:1234" +//! - "ftp://ftp.site.com" +//! - "moz-proxy://127.0.0.1:8888" +//! - "chrome://MyLegacyExtension" +//! - "file://" +//! - "https://\[::1\]" +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - truncating full URLs to just their origin component, if it is not an opaque origin +//! - converting values with non-ascii characters into punycode +//! +//! **XXX TODO:** +//! - Add a field with the original unicode versions of the URLs instead of punycode? +//! +//! - `sec_fields`: The `username` and `password` for the site, stored as a encrypted JSON +//! representation of an `SecureLoginFields`. +//! +//! This field is required and usually encrypted. There are two different value types: +//! - Plaintext empty string: Used for deleted records +//! - Encrypted value: The credentials associated with the login. +//! +//! - `http_realm`: The challenge string for HTTP Basic authentication, if any. +//! +//! If present, the login should only be used in response to a HTTP Basic Auth +//! challenge that specifies a matching realm. For legacy reasons this string may not +//! contain null bytes, carriage returns or newlines. +//! +//! If this field is set to the empty string, this indicates a wildcard match on realm. +//! +//! This field must not be present if `form_action_origin` is set, since they indicate different types +//! of login (HTTP-Auth based versus form-based). Exactly one of `http_realm` and `form_action_origin` +//! must be present. +//! +//! - `form_action_origin`: The target origin of forms in which this login can be used, if any, as a string. +//! +//! If present, the login should only be used in forms whose target submission URL matches this origin. +//! This field must be a valid origin or one of the following special cases: +//! - An empty string, which is a wildcard match for any origin. +//! - The single character ".", which is equivalent to the empty string +//! - The string "javascript:", which matches any form with javascript target URL. +//! +//! This field must not be present if `http_realm` is set, since they indicate different types of login +//! (HTTP-Auth based versus form-based). Exactly one of `http_realm` and `form_action_origin` must be present. +//! +//! If invalid data is received in this field (either from the application, or via sync) then the +//! logins store will attempt to coerce it into valid data by: +//! - truncating full URLs to just their origin component +//! - converting origins with non-ascii characters into punycode +//! - replacing invalid values with null if a valid 'http_realm' field is present +//! +//! - `username_field`: The name of the form field into which the 'username' should be filled, if any. +//! +//! This value is stored if provided by the application, but does not imply any restrictions on +//! how the login may be used in practice. For legacy reasons this string may not contain null +//! bytes, carriage returns or newlines. This field must be empty unless `form_action_origin` is set. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - setting to the empty string if 'form_action_origin' is not present +//! +//! - `password_field`: The name of the form field into which the 'password' should be filled, if any. +//! +//! This value is stored if provided by the application, but does not imply any restrictions on +//! how the login may be used in practice. For legacy reasons this string may not contain null +//! bytes, carriage returns or newlines. This field must be empty unless `form_action_origin` is set. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - setting to the empty string if 'form_action_origin' is not present +//! +//! # LoginMeta +//! +//! This contains data relating to the login database record -- both on the local instance and +//! synced to other browsers. +//! It contains the following fields: +//! - `id`: A unique string identifier for this record. +//! +//! Consumers may assume that `id` contains only "safe" ASCII characters but should otherwise +//! treat this it as an opaque identifier. These are generated as needed. +//! +//! - `timesUsed`: A lower bound on the number of times the password from this record has been used, as an integer. +//! +//! Applications should use the `touch()` method of the logins store to indicate when a password +//! has been used, and should ensure that they only count uses of the actual `password` field +//! (so for example, copying the `password` field to the clipboard should count as a "use", but +//! copying just the `username` field should not). +//! +//! This number may not record uses that occurred on other devices, since some legacy +//! sync clients do not record this information. It may be zero for records obtained +//! via sync that have never been used locally. +//! +//! When merging duplicate records, the two usage counts are summed. +//! +//! This field is managed internally by the logins store by default and does not need to +//! be set explicitly, although any application-provided value will be preserved when creating +//! a new record. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - replacing missing or negative values with 0 +//! +//! **XXX TODO:** +//! - test that we prevent this counter from moving backwards. +//! - test fixups of missing or negative values +//! - test that we correctly merge dupes +//! +//! - `time_created`: An upper bound on the time of creation of this login, in integer milliseconds from the unix epoch. +//! +//! This is an upper bound because some legacy sync clients do not record this information. +//! +//! Note that this field is typically a timestamp taken from the local machine clock, so it +//! may be wildly inaccurate if the client does not have an accurate clock. +//! +//! This field is managed internally by the logins store by default and does not need to +//! be set explicitly, although any application-provided value will be preserved when creating +//! a new record. +//! +//! When merging duplicate records, the smallest non-zero value is taken. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - replacing missing or negative values with the current time +//! +//! **XXX TODO:** +//! - test that we prevent this timestamp from moving backwards. +//! - test fixups of missing or negative values +//! - test that we correctly merge dupes +//! +//! - `time_last_used`: A lower bound on the time of last use of this login, in integer milliseconds from the unix epoch. +//! +//! This is a lower bound because some legacy sync clients do not record this information; +//! in that case newer clients set `timeLastUsed` when they use the record for the first time. +//! +//! Note that this field is typically a timestamp taken from the local machine clock, so it +//! may be wildly inaccurate if the client does not have an accurate clock. +//! +//! This field is managed internally by the logins store by default and does not need to +//! be set explicitly, although any application-provided value will be preserved when creating +//! a new record. +//! +//! When merging duplicate records, the largest non-zero value is taken. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - removing negative values +//! +//! **XXX TODO:** +//! - test that we prevent this timestamp from moving backwards. +//! - test fixups of missing or negative values +//! - test that we correctly merge dupes +//! +//! - `time_password_changed`: A lower bound on the time that the `password` field was last changed, in integer +//! milliseconds from the unix epoch. +//! +//! Changes to other fields (such as `username`) are not reflected in this timestamp. +//! This is a lower bound because some legacy sync clients do not record this information; +//! in that case newer clients set `time_password_changed` when they change the `password` field. +//! +//! Note that this field is typically a timestamp taken from the local machine clock, so it +//! may be wildly inaccurate if the client does not have an accurate clock. +//! +//! This field is managed internally by the logins store by default and does not need to +//! be set explicitly, although any application-provided value will be preserved when creating +//! a new record. +//! +//! When merging duplicate records, the largest non-zero value is taken. +//! +//! If invalid data is received in this field (either from the application, or via sync) +//! then the logins store will attempt to coerce it into valid data by: +//! - removing negative values +//! +//! **XXX TODO:** +//! - test that we prevent this timestamp from moving backwards. +//! - test that we don't set this for changes to other fields. +//! - test that we correctly merge dupes +//! +//! +//! In order to deal with data from legacy clients in a robust way, it is necessary to be able to build +//! and manipulate all these `Login` structs that contain invalid data. The non-encrypted structs +//! implement the `ValidateAndFixup` trait, providing the following methods which can be used by +//! callers to ensure that they're only working with valid records: +//! +//! - `Login::check_valid()`: Checks validity of a login record, returning `()` if it is valid +//! or an error if it is not. +//! +//! - `Login::fixup()`: Returns either the existing login if it is valid, a clone with invalid fields +//! fixed up if it was safe to do so, or an error if the login is irreparably invalid. + +use crate::{encryption::EncryptorDecryptor, error::*}; +use rusqlite::Row; +use serde_derive::*; +use sync_guid::Guid; +use url::Url; + +// LoginEntry fields that are stored in cleartext +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] +pub struct LoginFields { + pub origin: String, + pub form_action_origin: Option<String>, + pub http_realm: Option<String>, + pub username_field: String, + pub password_field: String, +} + +/// LoginEntry fields that are stored encrypted +#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct SecureLoginFields { + // - Username cannot be null, use the empty string instead + // - Password can't be empty or null (enforced in the ValidateAndFixup code) + // + // This matches the desktop behavior: + // https://searchfox.org/mozilla-central/rev/d3683dbb252506400c71256ef3994cdbdfb71ada/toolkit/components/passwordmgr/LoginManager.jsm#260-267 + + // Because we store the json version of this in the DB, and that's the only place the json + // is used, we rename the fields to short names, just to reduce the overhead in the DB. + #[serde(rename = "u")] + pub username: String, + #[serde(rename = "p")] + pub password: String, +} + +impl SecureLoginFields { + pub fn encrypt(&self, encdec: &dyn EncryptorDecryptor, login_id: &str) -> Result<String> { + let string = serde_json::to_string(&self)?; + let cipherbytes = encdec + .encrypt(string.as_bytes().into()) + .map_err(|e| Error::EncryptionFailed(format!("{e} (encrypting {login_id})")))?; + let ciphertext = std::str::from_utf8(&cipherbytes).map_err(|e| { + Error::EncryptionFailed(format!("{e} (encrypting {login_id}: data not utf8)")) + })?; + Ok(ciphertext.to_owned()) + } + + pub fn decrypt( + ciphertext: &str, + encdec: &dyn EncryptorDecryptor, + login_id: &str, + ) -> Result<Self> { + let jsonbytes = encdec + .decrypt(ciphertext.as_bytes().into()) + .map_err(|e| Error::DecryptionFailed(format!("{e} (decrypting {login_id})")))?; + let json = + std::str::from_utf8(&jsonbytes).map_err(|e| Error::DecryptionFailed(e.to_string()))?; + Ok(serde_json::from_str(json)?) + } +} + +/// Login data specific to database records +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] +pub struct LoginMeta { + pub id: String, + pub time_created: i64, + pub time_password_changed: i64, + pub time_last_used: i64, + pub times_used: i64, +} + +/// A login together with meta fields, handed over to the store API; ie a login persisted +/// elsewhere, useful for migrations +pub struct LoginEntryWithMeta { + pub entry: LoginEntry, + pub meta: LoginMeta, +} + +/// A bulk insert result entry, returned by `add_many` and `add_many_with_records` +pub enum BulkResultEntry { + Success { login: Login }, + Error { message: String }, +} + +/// A login handed over to the store API; ie a login not yet persisted +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] +pub struct LoginEntry { + // login fields + pub origin: String, + pub form_action_origin: Option<String>, + pub http_realm: Option<String>, + pub username_field: String, + pub password_field: String, + + // secure fields + pub username: String, + pub password: String, +} + +impl LoginEntry { + pub fn new(fields: LoginFields, sec_fields: SecureLoginFields) -> Self { + Self { + origin: fields.origin, + form_action_origin: fields.form_action_origin, + http_realm: fields.http_realm, + username_field: fields.username_field, + password_field: fields.password_field, + + username: sec_fields.username, + password: sec_fields.password, + } + } + /// Internal helper for validation and fixups of an "origin" stored as + /// a string. + fn validate_and_fixup_origin(origin: &str) -> Result<Option<String>> { + // Check we can parse the origin, then use the normalized version of it. + match Url::parse(origin) { + Ok(mut u) => { + // Presumably this is a faster path than always setting? + if u.path() != "/" + || u.fragment().is_some() + || u.query().is_some() + || u.username() != "/" + || u.password().is_some() + { + // Not identical - we only want the origin part, so kill + // any other parts which may exist. + // But first special case `file://` URLs which always + // resolve to `file://` + if u.scheme() == "file" { + return Ok(if origin == "file://" { + None + } else { + Some("file://".into()) + }); + } + u.set_path(""); + u.set_fragment(None); + u.set_query(None); + let _ = u.set_username(""); + let _ = u.set_password(None); + let mut href = String::from(u); + // We always store without the trailing "/" which Urls have. + if href.ends_with('/') { + href.pop().expect("url must have a length"); + } + if origin != href { + // Needs to be fixed up. + return Ok(Some(href)); + } + } + Ok(None) + } + Err(e) => { + breadcrumb!( + "Error parsing login origin: {e:?} ({})", + error_support::redact_url(origin) + ); + // We can't fixup completely invalid records, so always throw. + Err(InvalidLogin::IllegalOrigin.into()) + } + } + } +} + +/// A login handed over from the store API, which has been persisted and contains persistence +/// information such as id and time stamps +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] +pub struct Login { + // meta fields + pub id: String, + pub time_created: i64, + pub time_password_changed: i64, + pub time_last_used: i64, + pub times_used: i64, + + // login fields + pub origin: String, + pub form_action_origin: Option<String>, + pub http_realm: Option<String>, + pub username_field: String, + pub password_field: String, + + // secure fields + pub username: String, + pub password: String, +} + +impl Login { + pub fn new(meta: LoginMeta, fields: LoginFields, sec_fields: SecureLoginFields) -> Self { + Self { + id: meta.id, + time_created: meta.time_created, + time_password_changed: meta.time_password_changed, + time_last_used: meta.time_last_used, + times_used: meta.times_used, + + origin: fields.origin, + form_action_origin: fields.form_action_origin, + http_realm: fields.http_realm, + username_field: fields.username_field, + password_field: fields.password_field, + + username: sec_fields.username, + password: sec_fields.password, + } + } + + #[inline] + pub fn guid(&self) -> Guid { + Guid::from_string(self.id.clone()) + } + + pub fn entry(&self) -> LoginEntry { + LoginEntry { + origin: self.origin.clone(), + form_action_origin: self.form_action_origin.clone(), + http_realm: self.http_realm.clone(), + username_field: self.username_field.clone(), + password_field: self.password_field.clone(), + + username: self.username.clone(), + password: self.password.clone(), + } + } + + pub fn encrypt(self, encdec: &dyn EncryptorDecryptor) -> Result<EncryptedLogin> { + let sec_fields = SecureLoginFields { + username: self.username, + password: self.password, + } + .encrypt(encdec, &self.id)?; + Ok(EncryptedLogin { + meta: LoginMeta { + id: self.id, + time_created: self.time_created, + time_password_changed: self.time_password_changed, + time_last_used: self.time_last_used, + times_used: self.times_used, + }, + fields: LoginFields { + origin: self.origin, + form_action_origin: self.form_action_origin, + http_realm: self.http_realm, + username_field: self.username_field, + password_field: self.password_field, + }, + sec_fields, + }) + } +} + +/// A login stored in the database +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] +pub struct EncryptedLogin { + pub meta: LoginMeta, + pub fields: LoginFields, + pub sec_fields: String, +} + +impl EncryptedLogin { + #[inline] + pub fn guid(&self) -> Guid { + Guid::from_string(self.meta.id.clone()) + } + + // TODO: Remove this: https://github.com/mozilla/application-services/issues/4185 + #[inline] + pub fn guid_str(&self) -> &str { + &self.meta.id + } + + pub fn decrypt(self, encdec: &dyn EncryptorDecryptor) -> Result<Login> { + let sec_fields = self.decrypt_fields(encdec)?; + Ok(Login::new(self.meta, self.fields, sec_fields)) + } + + pub fn decrypt_fields(&self, encdec: &dyn EncryptorDecryptor) -> Result<SecureLoginFields> { + SecureLoginFields::decrypt(&self.sec_fields, encdec, &self.meta.id) + } + + pub(crate) fn from_row(row: &Row<'_>) -> Result<EncryptedLogin> { + let login = EncryptedLogin { + meta: LoginMeta { + id: row.get("guid")?, + time_created: row.get("timeCreated")?, + // Might be null + time_last_used: row + .get::<_, Option<i64>>("timeLastUsed")? + .unwrap_or_default(), + + time_password_changed: row.get("timePasswordChanged")?, + times_used: row.get("timesUsed")?, + }, + fields: LoginFields { + origin: row.get("origin")?, + http_realm: row.get("httpRealm")?, + + form_action_origin: row.get("formActionOrigin")?, + + username_field: string_or_default(row, "usernameField")?, + password_field: string_or_default(row, "passwordField")?, + }, + sec_fields: row.get("secFields")?, + }; + // XXX - we used to perform a fixup here, but that seems heavy-handed + // and difficult - we now only do that on add/insert when we have the + // encryption key. + Ok(login) + } +} + +fn string_or_default(row: &Row<'_>, col: &str) -> Result<String> { + Ok(row.get::<_, Option<String>>(col)?.unwrap_or_default()) +} + +pub trait ValidateAndFixup { + // Our validate and fixup functions. + fn check_valid(&self) -> Result<()> + where + Self: Sized, + { + self.validate_and_fixup(false)?; + Ok(()) + } + + fn fixup(self) -> Result<Self> + where + Self: Sized, + { + match self.maybe_fixup()? { + None => Ok(self), + Some(login) => Ok(login), + } + } + + fn maybe_fixup(&self) -> Result<Option<Self>> + where + Self: Sized, + { + self.validate_and_fixup(true) + } + + // validates, and optionally fixes, a struct. If fixup is false and there is a validation + // issue, an `Err` is returned. If fixup is true and a problem was fixed, and `Ok(Some<Self>)` + // is returned with the fixed version. If there was no validation problem, `Ok(None)` is + // returned. + fn validate_and_fixup(&self, fixup: bool) -> Result<Option<Self>> + where + Self: Sized; +} + +impl ValidateAndFixup for LoginEntry { + fn validate_and_fixup(&self, fixup: bool) -> Result<Option<Self>> { + // XXX TODO: we've definitely got more validation and fixups to add here! + + let mut maybe_fixed = None; + + /// A little helper to magic a Some(self.clone()) into existence when needed. + macro_rules! get_fixed_or_throw { + ($err:expr) => { + // This is a block expression returning a local variable, + // entirely so we can give it an explicit type declaration. + { + if !fixup { + return Err($err.into()); + } + warn!("Fixing login record {:?}", $err); + let fixed: Result<&mut Self> = + Ok(maybe_fixed.get_or_insert_with(|| self.clone())); + fixed + } + }; + } + + if self.origin.is_empty() { + return Err(InvalidLogin::EmptyOrigin.into()); + } + + if self.form_action_origin.is_some() && self.http_realm.is_some() { + get_fixed_or_throw!(InvalidLogin::BothTargets)?.http_realm = None; + } + + if self.form_action_origin.is_none() && self.http_realm.is_none() { + return Err(InvalidLogin::NoTarget.into()); + } + + let form_action_origin = self.form_action_origin.clone().unwrap_or_default(); + let http_realm = maybe_fixed + .as_ref() + .unwrap_or(self) + .http_realm + .clone() + .unwrap_or_default(); + + let field_data = [ + ("form_action_origin", &form_action_origin), + ("http_realm", &http_realm), + ("origin", &self.origin), + ("username_field", &self.username_field), + ("password_field", &self.password_field), + ]; + + for (field_name, field_value) in &field_data { + // Nuls are invalid. + if field_value.contains('\0') { + return Err(InvalidLogin::IllegalFieldValue { + field_info: format!("`{}` contains Nul", field_name), + } + .into()); + } + + // Newlines are invalid in Desktop for all the fields here. + if field_value.contains('\n') || field_value.contains('\r') { + return Err(InvalidLogin::IllegalFieldValue { + field_info: format!("`{}` contains newline", field_name), + } + .into()); + } + } + + // Desktop doesn't like fields with the below patterns + if self.username_field == "." { + return Err(InvalidLogin::IllegalFieldValue { + field_info: "`username_field` is a period".into(), + } + .into()); + } + + // Check we can parse the origin, then use the normalized version of it. + if let Some(fixed) = Self::validate_and_fixup_origin(&self.origin)? { + get_fixed_or_throw!(InvalidLogin::IllegalFieldValue { + field_info: "Origin is not normalized".into() + })? + .origin = fixed; + } + + match &maybe_fixed.as_ref().unwrap_or(self).form_action_origin { + None => { + if !self.username_field.is_empty() { + get_fixed_or_throw!(InvalidLogin::IllegalFieldValue { + field_info: "username_field must be empty when form_action_origin is null" + .into() + })? + .username_field + .clear(); + } + if !self.password_field.is_empty() { + get_fixed_or_throw!(InvalidLogin::IllegalFieldValue { + field_info: "password_field must be empty when form_action_origin is null" + .into() + })? + .password_field + .clear(); + } + } + Some(href) => { + // "", ".", and "javascript:" are special cases documented at the top of this file. + if href == "." { + // A bit of a special case - if we are being asked to fixup, we replace + // "." with an empty string - but if not fixing up we don't complain. + if fixup { + maybe_fixed + .get_or_insert_with(|| self.clone()) + .form_action_origin = Some("".into()); + } + } else if !href.is_empty() && href != "javascript:" { + if let Some(fixed) = Self::validate_and_fixup_origin(href)? { + get_fixed_or_throw!(InvalidLogin::IllegalFieldValue { + field_info: "form_action_origin is not normalized".into() + })? + .form_action_origin = Some(fixed); + } + } + } + } + + // secure fields + // + // \r\n chars are valid in desktop for some reason, so we allow them here too. + if self.username.contains('\0') { + return Err(InvalidLogin::IllegalFieldValue { + field_info: "`username` contains Nul".into(), + } + .into()); + } + if self.password.is_empty() { + return Err(InvalidLogin::EmptyPassword.into()); + } + if self.password.contains('\0') { + return Err(InvalidLogin::IllegalFieldValue { + field_info: "`password` contains Nul".into(), + } + .into()); + } + + Ok(maybe_fixed) + } +} + +#[cfg(test)] +pub mod test_utils { + use super::*; + use crate::encryption::test_utils::encrypt_struct; + + // Factory function to make a new login + // + // It uses the guid to create a unique origin/form_action_origin + pub fn enc_login(id: &str, password: &str) -> EncryptedLogin { + let sec_fields = SecureLoginFields { + username: "user".to_string(), + password: password.to_string(), + }; + EncryptedLogin { + meta: LoginMeta { + id: id.to_string(), + ..Default::default() + }, + fields: LoginFields { + form_action_origin: Some(format!("https://{}.example.com", id)), + origin: format!("https://{}.example.com", id), + ..Default::default() + }, + // TODO: fixme + sec_fields: encrypt_struct(&sec_fields), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_url_fixups() -> Result<()> { + // Start with URLs which are all valid and already normalized. + for input in &[ + // The list of valid origins documented at the top of this file. + "https://site.com", + "http://site.com:1234", + "ftp://ftp.site.com", + "moz-proxy://127.0.0.1:8888", + "chrome://MyLegacyExtension", + "file://", + "https://[::1]", + ] { + assert_eq!(LoginEntry::validate_and_fixup_origin(input)?, None); + } + + // And URLs which get normalized. + for (input, output) in &[ + ("https://site.com/", "https://site.com"), + ("http://site.com:1234/", "http://site.com:1234"), + ("http://example.com/foo?query=wtf#bar", "http://example.com"), + ("http://example.com/foo#bar", "http://example.com"), + ( + "http://username:password@example.com/", + "http://example.com", + ), + ("http://😍.com/", "http://xn--r28h.com"), + ("https://[0:0:0:0:0:0:0:1]", "https://[::1]"), + // All `file://` URLs normalize to exactly `file://`. See #2384 for + // why we might consider changing that later. + ("file:///", "file://"), + ("file://foo/bar", "file://"), + ("file://foo/bar/", "file://"), + ("moz-proxy://127.0.0.1:8888/", "moz-proxy://127.0.0.1:8888"), + ( + "moz-proxy://127.0.0.1:8888/foo", + "moz-proxy://127.0.0.1:8888", + ), + ("chrome://MyLegacyExtension/", "chrome://MyLegacyExtension"), + ( + "chrome://MyLegacyExtension/foo", + "chrome://MyLegacyExtension", + ), + ] { + assert_eq!( + LoginEntry::validate_and_fixup_origin(input)?, + Some((*output).into()) + ); + } + Ok(()) + } + + #[test] + fn test_check_valid() { + #[derive(Debug, Clone)] + struct TestCase { + login: LoginEntry, + should_err: bool, + expected_err: &'static str, + } + + let valid_login = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_empty_origin = LoginEntry { + origin: "".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_empty_password = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "".into(), + ..Default::default() + }; + + let login_with_form_submit_and_http_realm = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + form_action_origin: Some("https://www.example.com".into()), + username: "".into(), + password: "test".into(), + ..Default::default() + }; + + let login_without_form_submit_or_http_realm = LoginEntry { + origin: "https://www.example.com".into(), + username: "".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_legacy_form_submit_and_http_realm = LoginEntry { + origin: "https://www.example.com".into(), + form_action_origin: Some("".into()), + username: "".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_null_http_realm = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.\0com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_null_username = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "\0".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_null_password = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "username".into(), + password: "test\0".into(), + ..Default::default() + }; + + let login_with_newline_origin = LoginEntry { + origin: "\rhttps://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_newline_username_field = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username_field: "\n".into(), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_newline_realm = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("foo\nbar".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_newline_password = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test\n".into(), + ..Default::default() + }; + + let login_with_period_username_field = LoginEntry { + origin: "https://www.example.com".into(), + http_realm: Some("https://www.example.com".into()), + username_field: ".".into(), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_period_form_action_origin = LoginEntry { + form_action_origin: Some(".".into()), + origin: "https://www.example.com".into(), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_javascript_form_action_origin = LoginEntry { + form_action_origin: Some("javascript:".into()), + origin: "https://www.example.com".into(), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_malformed_origin_parens = LoginEntry { + origin: " (".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_host_unicode = LoginEntry { + origin: "http://💖.com".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_origin_trailing_slash = LoginEntry { + origin: "https://www.example.com/".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_origin_expanded_ipv6 = LoginEntry { + origin: "https://[0:0:0:0:0:0:1:1]".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_unknown_protocol = LoginEntry { + origin: "moz-proxy://127.0.0.1:8888".into(), + http_realm: Some("https://www.example.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let test_cases = [ + TestCase { + login: valid_login, + should_err: false, + expected_err: "", + }, + TestCase { + login: login_with_empty_origin, + should_err: true, + expected_err: "Invalid login: Origin is empty", + }, + TestCase { + login: login_with_empty_password, + should_err: true, + expected_err: "Invalid login: Password is empty", + }, + TestCase { + login: login_with_form_submit_and_http_realm, + should_err: true, + expected_err: "Invalid login: Both `formActionOrigin` and `httpRealm` are present", + }, + TestCase { + login: login_without_form_submit_or_http_realm, + should_err: true, + expected_err: + "Invalid login: Neither `formActionOrigin` or `httpRealm` are present", + }, + TestCase { + login: login_with_null_http_realm, + should_err: true, + expected_err: "Invalid login: Login has illegal field: `http_realm` contains Nul", + }, + TestCase { + login: login_with_null_username, + should_err: true, + expected_err: "Invalid login: Login has illegal field: `username` contains Nul", + }, + TestCase { + login: login_with_null_password, + should_err: true, + expected_err: "Invalid login: Login has illegal field: `password` contains Nul", + }, + TestCase { + login: login_with_newline_origin, + should_err: true, + expected_err: "Invalid login: Login has illegal field: `origin` contains newline", + }, + TestCase { + login: login_with_newline_realm, + should_err: true, + expected_err: + "Invalid login: Login has illegal field: `http_realm` contains newline", + }, + TestCase { + login: login_with_newline_username_field, + should_err: true, + expected_err: + "Invalid login: Login has illegal field: `username_field` contains newline", + }, + TestCase { + login: login_with_newline_password, + should_err: false, + expected_err: "", + }, + TestCase { + login: login_with_period_username_field, + should_err: true, + expected_err: + "Invalid login: Login has illegal field: `username_field` is a period", + }, + TestCase { + login: login_with_period_form_action_origin, + should_err: false, + expected_err: "", + }, + TestCase { + login: login_with_javascript_form_action_origin, + should_err: false, + expected_err: "", + }, + TestCase { + login: login_with_malformed_origin_parens, + should_err: true, + expected_err: "Invalid login: Login has illegal origin", + }, + TestCase { + login: login_with_host_unicode, + should_err: true, + expected_err: "Invalid login: Login has illegal field: Origin is not normalized", + }, + TestCase { + login: login_with_origin_trailing_slash, + should_err: true, + expected_err: "Invalid login: Login has illegal field: Origin is not normalized", + }, + TestCase { + login: login_with_origin_expanded_ipv6, + should_err: true, + expected_err: "Invalid login: Login has illegal field: Origin is not normalized", + }, + TestCase { + login: login_with_unknown_protocol, + should_err: false, + expected_err: "", + }, + TestCase { + login: login_with_legacy_form_submit_and_http_realm, + should_err: false, + expected_err: "", + }, + ]; + + for tc in &test_cases { + let actual = tc.login.check_valid(); + + if tc.should_err { + assert!(actual.is_err(), "{:#?}", tc); + assert_eq!( + tc.expected_err, + actual.unwrap_err().to_string(), + "{:#?}", + tc, + ); + } else { + assert!(actual.is_ok(), "{:#?}", tc); + assert!( + tc.login.clone().fixup().is_ok(), + "Fixup failed after check_valid passed: {:#?}", + &tc, + ); + } + } + } + + #[test] + fn test_fixup() { + #[derive(Debug, Default)] + struct TestCase { + login: LoginEntry, + fixedup_host: Option<&'static str>, + fixedup_form_action_origin: Option<String>, + } + + // Note that most URL fixups are tested above, but we have one or 2 here. + let login_with_full_url = LoginEntry { + origin: "http://example.com/foo?query=wtf#bar".into(), + form_action_origin: Some("http://example.com/foo?query=wtf#bar".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_host_unicode = LoginEntry { + origin: "http://😍.com".into(), + form_action_origin: Some("http://😍.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_period_fsu = LoginEntry { + origin: "https://example.com".into(), + form_action_origin: Some(".".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + let login_with_empty_fsu = LoginEntry { + origin: "https://example.com".into(), + form_action_origin: Some("".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + + let login_with_form_submit_and_http_realm = LoginEntry { + origin: "https://www.example.com".into(), + form_action_origin: Some("https://www.example.com".into()), + // If both http_realm and form_action_origin are specified, we drop + // the former when fixing up. So for this test we must have an + // invalid value in http_realm to ensure we don't validate a value + // we end up dropping. + http_realm: Some("\n".into()), + username: "".into(), + password: "test".into(), + ..Default::default() + }; + + let test_cases = [ + TestCase { + login: login_with_full_url, + fixedup_host: "http://example.com".into(), + fixedup_form_action_origin: Some("http://example.com".into()), + }, + TestCase { + login: login_with_host_unicode, + fixedup_host: "http://xn--r28h.com".into(), + fixedup_form_action_origin: Some("http://xn--r28h.com".into()), + }, + TestCase { + login: login_with_period_fsu, + fixedup_form_action_origin: Some("".into()), + ..TestCase::default() + }, + TestCase { + login: login_with_form_submit_and_http_realm, + fixedup_form_action_origin: Some("https://www.example.com".into()), + ..TestCase::default() + }, + TestCase { + login: login_with_empty_fsu, + // Should still be empty. + fixedup_form_action_origin: Some("".into()), + ..TestCase::default() + }, + ]; + + for tc in &test_cases { + let login = tc.login.clone().fixup().expect("should work"); + if let Some(expected) = tc.fixedup_host { + assert_eq!(login.origin, expected, "origin not fixed in {:#?}", tc); + } + assert_eq!( + login.form_action_origin, tc.fixedup_form_action_origin, + "form_action_origin not fixed in {:#?}", + tc, + ); + login.check_valid().unwrap_or_else(|e| { + panic!("Fixup produces invalid record: {:#?}", (e, &tc, &login)); + }); + assert_eq!( + login.clone().fixup().unwrap(), + login, + "fixup did not reach fixed point for testcase: {:#?}", + tc, + ); + } + } + + #[test] + fn test_secure_fields_serde() { + let sf = SecureLoginFields { + username: "foo".into(), + password: "pwd".into(), + }; + assert_eq!( + serde_json::to_string(&sf).unwrap(), + r#"{"u":"foo","p":"pwd"}"# + ); + let got: SecureLoginFields = serde_json::from_str(r#"{"u": "user", "p": "p"}"#).unwrap(); + let expected = SecureLoginFields { + username: "user".into(), + password: "p".into(), + }; + assert_eq!(got, expected); + } +} diff --git a/third_party/rust/logins/src/logins.udl b/third_party/rust/logins/src/logins.udl @@ -0,0 +1,276 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace logins { + /// We expose the crypto primitives on the namespace + + /// Create a new, random, encryption key. + [Throws=LoginsApiError] + string create_key(); + + /// Create a "canary" string, which can be used to test if the encryption + //key is still valid for the logins data + [Throws=LoginsApiError] + string create_canary([ByRef]string text, [ByRef]string encryption_key); + + /// Check that key is still valid using the output of `create_canary`. + //`text` much match the text you initially passed to `create_canary()` + [Throws=LoginsApiError] + boolean check_canary([ByRef]string canary, [ByRef]string text, [ByRef]string encryption_key); + + /// Utility function to create a StaticKeyManager to be used for the time + /// being until support lands for [trait implementation of an UniFFI + /// interface](https://mozilla.github.io/uniffi-rs/next/proc_macro/index.html#structs-implementing-traits) + /// in UniFFI. + KeyManager create_static_key_manager(string key); + + /// Similar to create_static_key_manager above, create a + /// ManagedEncryptorDecryptor by passing in a KeyManager + EncryptorDecryptor create_managed_encdec(KeyManager key_manager); + + /// Create a LoginStore with StaticKeyManager by passing in a db path and a + /// static key + LoginStore create_login_store_with_static_key_manager(string path, string key); +}; + +/// A login entry from the user, not linked to any database record. +/// The add/update APIs input these. +dictionary LoginEntry { + // login fields + string origin; + string? http_realm; + string? form_action_origin; + string username_field; + string password_field; + + // secure login fields + string password; + string username; +}; + +/// Login data specific to database records. +/// The add_with_record API inputs this. +dictionary LoginMeta { + string id; + i64 times_used; + i64 time_created; + i64 time_last_used; + i64 time_password_changed; +}; + +/// A login together with record fields, handed over to the store API; ie a login persisted +/// elsewhere, useful for migrations +dictionary LoginEntryWithMeta { + LoginEntry entry; + LoginMeta meta; +}; + +/// A bulk insert result entry, returned by `add_many` and `add_many_with_meta` +[Enum] +interface BulkResultEntry { + Success(Login login); + Error(string message); +}; + +/// A login stored in the database +dictionary Login { + // meta fields + string id; + i64 times_used; + i64 time_created; + i64 time_last_used; + i64 time_password_changed; + + // login fields + string origin; + string? http_realm; + string? form_action_origin; + string username_field; + string password_field; + + // secure login fields + string password; + string username; +}; + +/// Metrics tracking deletion of logins that cannot be decrypted, see `delete_undecryptable_records_for_remote_replacement` +/// for more details +dictionary LoginsDeletionMetrics { + u64 local_deleted; + u64 mirror_deleted; +}; + +/// These are the errors returned by our public API. +[Error] +interface LoginsApiError { + /// NSS not initialized. + NSSUninitialized(); + + /// NSS error during authentication + NSSAuthenticationError(string reason); + + /// error during authentication (in PrimaryPasswordAuthenticator) + AuthenticationError(string reason); + + /// authentication has been cancelled. + AuthenticationCanceled(); + + /// The login data supplied is invalid. The reason will indicate what's wrong with it. + InvalidRecord(string reason); + + /// Asking to do something with a guid which doesn't exist. + NoSuchRecord(string reason); + + /// Encryption key is missing. + MissingKey(); + + /// Encryption key is not valid. + InvalidKey(); + + /// encryption failed + EncryptionFailed(string reason); + + /// decryption failed + DecryptionFailed(string reason); + + /// An operation was interrupted at the request of the consuming app. + Interrupted(string reason); + + /// Sync reported that authentication failed and the user should re-enter their FxA password. + // TODO: remove this at the same time as remove the sync() method in favour of the SyncManager. + SyncAuthInvalid(string reason); + + /// something internal went wrong which doesn't have a public error value + /// because the consuming app can not reasonably take any action to resolve it. + /// The underlying error will have been logged and reported. + /// (ideally would just be `Unexpected`, but that would be a breaking change) + UnexpectedLoginsApiError(string reason); +}; + +[Trait, WithForeign] +interface EncryptorDecryptor { + [Throws=LoginsApiError] + bytes encrypt(bytes cleartext); + + [Throws=LoginsApiError] + bytes decrypt(bytes ciphertext); +}; + +[Trait, WithForeign] +interface KeyManager { + [Throws=LoginsApiError] + bytes get_key(); +}; + +interface StaticKeyManager { + constructor(string key); +}; + +interface ManagedEncryptorDecryptor { + constructor(KeyManager key_manager); +}; + +interface LoginStore { + [Throws=LoginsApiError] + constructor(string path, EncryptorDecryptor encdec); + + [Throws=LoginsApiError] + Login add(LoginEntry login); + + [Throws=LoginsApiError] + sequence<BulkResultEntry> add_many(sequence<LoginEntry> logins); + + [Throws=LoginsApiError] + Login add_with_meta(LoginEntryWithMeta entry_with_meta); + + [Throws=LoginsApiError] + sequence<BulkResultEntry> add_many_with_meta(sequence<LoginEntryWithMeta> entries_with_meta); + + [Throws=LoginsApiError] + Login update([ByRef] string id, LoginEntry login); + + [Throws=LoginsApiError] + Login add_or_update(LoginEntry login); + + [Throws=LoginsApiError] + boolean delete([ByRef] string id); + + [Throws=LoginsApiError, Self=ByArc] + sequence<boolean> delete_many(sequence<string> ids); + + /// Clear out locally stored logins data + /// + /// If sync is enabled, then we will try to recover the data on the next sync. + /// + /// The main reason to call this is when regenerating a new encryption key. + /// In that case, there's no reason to keep around the local data since it can't be decrypted. + /// Calling `wipe_local` is better than keeping around these un-decryptable logins, since we + /// might be able to recover the data via sync. + /// + /// This is a no-op for freshly created databases, so it's safe to call this whenever a key is + /// generated. + [Throws=LoginsApiError] + void wipe_local(); + + [Throws=LoginsApiError, Self=ByArc] + void reset(); + + /// The `delete_undecryptable_records_for_remote_replacement` function locally deletes stored logins + /// that cannot be decrypted and sets the last sync time to 0 so any existing server records can be downloaded + /// and overwrite the locally deleted records. + /// + /// NB: This function was created to unblock iOS logins users who are unable to sync logins and should not be used + /// outside of this use case. + [Throws=LoginsApiError, Self=ByArc] + LoginsDeletionMetrics delete_undecryptable_records_for_remote_replacement(); + + [Throws=LoginsApiError] + void touch([ByRef] string id); + + [Throws=LoginsApiError] + boolean is_empty(); + + [Throws=LoginsApiError] + i64 count(); + + [Throws=LoginsApiError] + i64 count_by_origin([ByRef] string origin); + + [Throws=LoginsApiError] + i64 count_by_form_action_origin([ByRef] string form_action_origin); + + [Throws=LoginsApiError] + sequence<Login> list(); + + [Throws=LoginsApiError] + sequence<Login> get_by_base_domain([ByRef] string base_domain); + + [Throws=LoginsApiError] + boolean has_logins_by_base_domain([ByRef] string base_domain); + + [Throws=LoginsApiError] + Login? find_login_to_update(LoginEntry look); + + [Throws=LoginsApiError] + Login? get([ByRef] string id); + + [Throws=LoginsApiError] + void set_checkpoint([ByRef] string checkpoint); + + [Throws=LoginsApiError] + string? get_checkpoint(); + + /// Run maintenance on the DB + /// + /// This is intended to be run during idle time and will take steps / to clean up / shrink the + /// database. + [Throws=LoginsApiError] + void run_maintenance(); + + [Self=ByArc] + void register_with_sync_manager(); + + [Self=ByArc] + void shutdown(); +}; diff --git a/third_party/rust/logins/src/schema.rs b/third_party/rust/logins/src/schema.rs @@ -0,0 +1,320 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Logins Schema v4 +//! ================ +//! +//! The schema we use is a evolution of the firefox-ios logins database format. +//! There are three tables: +//! +//! - `loginsL`: The local table. +//! - `loginsM`: The mirror table. +//! - `loginsSyncMeta`: The table used to to store various sync metadata. +//! +//! ## `loginsL` +//! +//! This stores local login information, also known as the "overlay". +//! +//! `loginsL` is essentially unchanged from firefox-ios, however note the +//! semantic change v4 makes to timestamp fields (which is explained in more +//! detail in the [COMMON_COLS] documentation). +//! +//! It is important to note that `loginsL` is not guaranteed to be present for +//! all records. Synced records may only exist in `loginsM` (although this is +//! not guaranteed). In either case, queries should read from both `loginsL` and +//! `loginsM`. +//! +//! ### `loginsL` Columns +//! +//! Contains all fields in [COMMON_COLS], as well as the following additional +//! columns: +//! +//! - `local_modified`: A millisecond local timestamp indicating when the record +//! was changed locally, or NULL if the record has never been changed locally. +//! +//! - `is_deleted`: A boolean indicating whether or not this record is a +//! tombstone. +//! +//! - `sync_status`: A `SyncStatus` enum value, one of +//! +//! - `0` (`SyncStatus::Synced`): Indicating that the record has been synced +//! +//! - `1` (`SyncStatus::Changed`): Indicating that the record should be +//! has changed locally and is known to exist on the server. +//! +//! - `2` (`SyncStatus::New`): Indicating that the record has never been +//! synced, or we have been reset since the last time it synced. +//! +//! ## `loginsM` +//! +//! This stores server-side login information, also known as the "mirror". +//! +//! Like `loginsL`, `loginM` has not changed from firefox-ios, beyond the +//! change to store timestamps as milliseconds explained in [COMMON_COLS]. +//! +//! Also like `loginsL`, `loginsM` is not guaranteed to have rows for all +//! records. It should not have rows for records which were not synced! +//! +//! It is important to note that `loginsL` is not guaranteed to be present for +//! all records. Synced records may only exist in `loginsM`! Queries should +//! test against both! +//! +//! ### `loginsM` Columns +//! +//! Contains all fields in [COMMON_COLS], as well as the following additional +//! columns: +//! +//! - `server_modified`: the most recent server-modification timestamp +//! ([sync15::ServerTimestamp]) we've seen for this record. Stored as +//! a millisecond value. +//! +//! - `is_overridden`: A boolean indicating whether or not the mirror contents +//! are invalid, and that we should defer to the data stored in `loginsL`. +//! +//! ## `loginsSyncMeta` +//! +//! This is a simple key-value table based on the `moz_meta` table in places. +//! This table was added (by this rust crate) in version 4, and so is not +//! present in firefox-ios. +//! +//! Currently it is used to store two items: +//! +//! 1. The last sync timestamp is stored under [LAST_SYNC_META_KEY], a +//! `sync15::ServerTimestamp` stored in integer milliseconds. +//! +//! 2. The persisted sync state machine information is stored under +//! [GLOBAL_STATE_META_KEY]. This is a `sync15::GlobalState` stored as +//! JSON. +//! + +use crate::error::*; +use lazy_static::lazy_static; +use rusqlite::Connection; +use sql_support::ConnExt; + +/// Version 1: SQLCipher -> plaintext migration. +/// Version 2: addition of `loginsM.enc_unknown_fields`. +pub(super) const VERSION: i64 = 2; + +/// Every column shared by both tables except for `id` +/// +/// Note: `timeCreated`, `timeLastUsed`, and `timePasswordChanged` are in +/// milliseconds. This is in line with how the server and Desktop handle it, but +/// counter to how firefox-ios handles it (hence needing to fix them up +/// firefox-ios on schema upgrade from 3, the last firefox-ios password schema +/// version). +/// +/// The reason for breaking from how firefox-ios does things is just because it +/// complicates the code to have multiple kinds of timestamps, for very little +/// benefit. It also makes it unclear what's stored on the server, leading to +/// further confusion. +/// +/// However, note that the `local_modified` (of `loginsL`) and `server_modified` +/// (of `loginsM`) are stored as milliseconds as well both on firefox-ios and +/// here (and so they do not need to be updated with the `timeLastUsed`/ +/// `timePasswordChanged`/`timeCreated` timestamps. +pub const COMMON_COLS: &str = " + guid, + secFields, + origin, + httpRealm, + formActionOrigin, + usernameField, + passwordField, + timeCreated, + timeLastUsed, + timePasswordChanged, + timesUsed +"; + +const COMMON_SQL: &str = " + id INTEGER PRIMARY KEY AUTOINCREMENT, + origin TEXT NOT NULL, + -- Exactly one of httpRealm or formActionOrigin should be set + httpRealm TEXT, + formActionOrigin TEXT, + usernameField TEXT, + passwordField TEXT, + timesUsed INTEGER NOT NULL DEFAULT 0, + timeCreated INTEGER NOT NULL, + timeLastUsed INTEGER, + timePasswordChanged INTEGER NOT NULL, + secFields TEXT, + guid TEXT NOT NULL UNIQUE +"; + +lazy_static! { + static ref CREATE_LOCAL_TABLE_SQL: String = format!( + "CREATE TABLE IF NOT EXISTS loginsL ( + {common_sql}, + -- Milliseconds, or NULL if never modified locally. + local_modified INTEGER, + + is_deleted TINYINT NOT NULL DEFAULT 0, + sync_status TINYINT NOT NULL DEFAULT 0 + )", + common_sql = COMMON_SQL + ); + static ref CREATE_MIRROR_TABLE_SQL: String = format!( + "CREATE TABLE IF NOT EXISTS loginsM ( + {common_sql}, + -- Milliseconds (a sync15::ServerTimestamp multiplied by + -- 1000 and truncated) + server_modified INTEGER NOT NULL, + is_overridden TINYINT NOT NULL DEFAULT 0, + -- fields on incoming records we don't know about and roundtrip. + -- a serde_json::Value::Object as an encrypted string. + enc_unknown_fields TEXT + )", + common_sql = COMMON_SQL + ); + static ref SET_VERSION_SQL: String = + format!("PRAGMA user_version = {version}", version = VERSION); +} + +const CREATE_META_TABLE_SQL: &str = " + CREATE TABLE IF NOT EXISTS loginsSyncMeta ( + key TEXT PRIMARY KEY, + value NOT NULL + ) +"; + +const CREATE_OVERRIDE_ORIGIN_INDEX_SQL: &str = " + CREATE INDEX IF NOT EXISTS idx_loginsM_is_overridden_origin + ON loginsM (is_overridden, origin) +"; + +const CREATE_DELETED_ORIGIN_INDEX_SQL: &str = " + CREATE INDEX IF NOT EXISTS idx_loginsL_is_deleted_origin + ON loginsL (is_deleted, origin) +"; + +pub(crate) static LAST_SYNC_META_KEY: &str = "last_sync_time"; +pub(crate) static GLOBAL_STATE_META_KEY: &str = "global_state_v2"; +pub(crate) static GLOBAL_SYNCID_META_KEY: &str = "global_sync_id"; +pub(crate) static COLLECTION_SYNCID_META_KEY: &str = "passwords_sync_id"; +pub(crate) static CHECKPOINT_KEY: &str = "checkpoint"; + +pub(crate) fn init(db: &Connection) -> Result<()> { + let user_version = db.conn_ext_query_one::<i64>("PRAGMA user_version")?; + warn!("user_version: {}", user_version); + if user_version == 0 { + return create(db); + } + if user_version != VERSION { + if user_version < VERSION { + upgrade(db, user_version)?; + } else { + warn!( + "Loaded future schema version {} (we only understand version {}). \ + Optimistically ", + user_version, VERSION + ) + } + } + Ok(()) +} + +// Allow the redundant Ok() here. It will make more sense once we have an actual upgrade function. +#[allow(clippy::unnecessary_wraps)] +fn upgrade(db: &Connection, from: i64) -> Result<()> { + debug!("Upgrading schema from {} to {}", from, VERSION); + if from == VERSION { + return Ok(()); + } + assert_ne!( + from, 0, + "Upgrading from user_version = 0 should already be handled (in `init`)" + ); + + // Schema upgrades. + if from == 1 { + // Just one new nullable column makes this fairly easy + db.execute_batch("ALTER TABLE loginsM ADD enc_unknown_fields TEXT;")?; + } + // XXX - next migration, be sure to: + // from = 2; + // if from == 2 ... + db.execute_batch(&SET_VERSION_SQL)?; + Ok(()) +} + +pub(crate) fn create(db: &Connection) -> Result<()> { + debug!("Creating schema"); + db.execute_all(&[ + &*CREATE_LOCAL_TABLE_SQL, + &*CREATE_MIRROR_TABLE_SQL, + CREATE_OVERRIDE_ORIGIN_INDEX_SQL, + CREATE_DELETED_ORIGIN_INDEX_SQL, + CREATE_META_TABLE_SQL, + &*SET_VERSION_SQL, + ])?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::encryption::test_utils::TEST_ENCDEC; + use crate::LoginDb; + use nss::ensure_initialized; + use rusqlite::Connection; + + #[test] + fn test_create_schema() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + // should be VERSION. + let version = db.conn_ext_query_one::<i64>("PRAGMA user_version").unwrap(); + assert_eq!(version, VERSION); + } + + #[test] + fn test_upgrade_v1() { + ensure_initialized(); + // manually setup a V1 schema. + let connection = Connection::open_in_memory().unwrap(); + connection + .execute_batch( + " + CREATE TABLE IF NOT EXISTS loginsM ( + -- this was common_sql as at v1 + id INTEGER PRIMARY KEY AUTOINCREMENT, + origin TEXT NOT NULL, + httpRealm TEXT, + formActionOrigin TEXT, + usernameField TEXT, + passwordField TEXT, + timesUsed INTEGER NOT NULL DEFAULT 0, + timeCreated INTEGER NOT NULL, + timeLastUsed INTEGER, + timePasswordChanged INTEGER NOT NULL, + secFields TEXT, + guid TEXT NOT NULL UNIQUE, + server_modified INTEGER NOT NULL, + is_overridden TINYINT NOT NULL DEFAULT 0 + -- note enc_unknown_fields missing + ); + ", + ) + .unwrap(); + // Call `create` to create the rest of the schema - the "if not exists" means loginsM + // will remain as v1. + create(&connection).unwrap(); + // but that set the version to VERSION - set it back to 1 so our upgrade code runs. + connection + .execute_batch("PRAGMA user_version = 1;") + .unwrap(); + + // Now open the DB - it will create loginsL for us and migrate loginsM. + let db = LoginDb::with_connection(connection, TEST_ENCDEC.clone()).unwrap(); + // all migrations should have succeeded. + let version = db.conn_ext_query_one::<i64>("PRAGMA user_version").unwrap(); + assert_eq!(version, VERSION); + + // and ensure sql selecting the new column works. + db.execute_batch("SELECT enc_unknown_fields FROM loginsM") + .unwrap(); + } +} diff --git a/third_party/rust/logins/src/store.rs b/third_party/rust/logins/src/store.rs @@ -0,0 +1,548 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use crate::db::{LoginDb, LoginsDeletionMetrics}; +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::login::{BulkResultEntry, EncryptedLogin, Login, LoginEntry, LoginEntryWithMeta}; +use crate::schema; +use crate::LoginsSyncEngine; +use parking_lot::Mutex; +use sql_support::run_maintenance; +use std::path::Path; +use std::sync::{Arc, Weak}; +use sync15::{ + engine::{EngineSyncAssociation, SyncEngine, SyncEngineId}, + ServerTimestamp, +}; + +#[derive(uniffi::Enum)] +pub enum LoginOrErrorMessage { + Login, + String, +} + +// Our "sync manager" will use whatever is stashed here. +lazy_static::lazy_static! { + // Mutex: just taken long enough to update the inner stuff - needed + // to wrap the RefCell as they aren't `Sync` + static ref STORE_FOR_MANAGER: Mutex<Weak<LoginStore>> = Mutex::new(Weak::new()); +} + +/// Called by the sync manager to get a sync engine via the store previously +/// registered with the sync manager. +pub fn get_registered_sync_engine(engine_id: &SyncEngineId) -> Option<Box<dyn SyncEngine>> { + let weak = STORE_FOR_MANAGER.lock(); + match weak.upgrade() { + None => None, + Some(store) => match create_sync_engine(store, engine_id) { + Ok(engine) => Some(engine), + Err(e) => { + report_error!("logins-sync-engine-create-error", "{e}"); + None + } + }, + } +} + +fn create_sync_engine( + store: Arc<LoginStore>, + engine_id: &SyncEngineId, +) -> Result<Box<dyn SyncEngine>> { + match engine_id { + SyncEngineId::Passwords => Ok(Box::new(LoginsSyncEngine::new(Arc::clone(&store))?)), + // panicking here seems reasonable - it's a static error if this + // it hit, not something that runtime conditions can influence. + _ => unreachable!("can't provide unknown engine: {}", engine_id), + } +} + +fn map_bulk_result_entry( + enc_login: Result<EncryptedLogin>, + encdec: &dyn EncryptorDecryptor, +) -> BulkResultEntry { + match enc_login { + Ok(enc_login) => match enc_login.decrypt(encdec) { + Ok(login) => BulkResultEntry::Success { login }, + Err(error) => { + warn!("Login could not be decrypted. This indicates a fundamental problem with the encryption key."); + BulkResultEntry::Error { + message: error.to_string(), + } + } + }, + Err(error) => BulkResultEntry::Error { + message: error.to_string(), + }, + } +} + +pub struct LoginStore { + pub db: Mutex<Option<LoginDb>>, +} + +impl LoginStore { + #[handle_error(Error)] + pub fn new(path: impl AsRef<Path>, encdec: Arc<dyn EncryptorDecryptor>) -> ApiResult<Self> { + let db = Mutex::new(Some(LoginDb::open(path, encdec)?)); + Ok(Self { db }) + } + + pub fn new_from_db(db: LoginDb) -> Self { + let db = Mutex::new(Some(db)); + Self { db } + } + + // Only used for tests, but it's `pub` the `sync-test` crate uses it. + #[cfg(test)] + pub fn new_in_memory() -> Self { + let db = Mutex::new(Some(LoginDb::open_in_memory())); + Self { db } + } + + pub fn lock_db(&self) -> Result<parking_lot::MappedMutexGuard<'_, LoginDb>> { + parking_lot::MutexGuard::try_map(self.db.lock(), |db| db.as_mut()) + .map_err(|_| Error::DatabaseClosed) + } + + #[handle_error(Error)] + pub fn is_empty(&self) -> ApiResult<bool> { + Ok(self.lock_db()?.count_all()? == 0) + } + + #[handle_error(Error)] + pub fn list(&self) -> ApiResult<Vec<Login>> { + let db = self.lock_db()?; + db.get_all().and_then(|logins| { + logins + .into_iter() + .map(|login| login.decrypt(db.encdec.as_ref())) + .collect() + }) + } + + #[handle_error(Error)] + pub fn count(&self) -> ApiResult<i64> { + self.lock_db()?.count_all() + } + + #[handle_error(Error)] + pub fn count_by_origin(&self, origin: &str) -> ApiResult<i64> { + self.lock_db()?.count_by_origin(origin) + } + + #[handle_error(Error)] + pub fn count_by_form_action_origin(&self, form_action_origin: &str) -> ApiResult<i64> { + self.lock_db()? + .count_by_form_action_origin(form_action_origin) + } + + #[handle_error(Error)] + pub fn get(&self, id: &str) -> ApiResult<Option<Login>> { + let db = self.lock_db()?; + match db.get_by_id(id) { + Ok(result) => match result { + Some(enc_login) => enc_login.decrypt(db.encdec.as_ref()).map(Some), + None => Ok(None), + }, + Err(err) => Err(err), + } + } + + #[handle_error(Error)] + pub fn get_by_base_domain(&self, base_domain: &str) -> ApiResult<Vec<Login>> { + let db = self.lock_db()?; + db.get_by_base_domain(base_domain).and_then(|logins| { + logins + .into_iter() + .map(|login| login.decrypt(db.encdec.as_ref())) + .collect() + }) + } + + #[handle_error(Error)] + pub fn has_logins_by_base_domain(&self, base_domain: &str) -> ApiResult<bool> { + self.lock_db()? + .get_by_base_domain(base_domain) + .map(|logins| !logins.is_empty()) + } + + #[handle_error(Error)] + pub fn find_login_to_update(&self, entry: LoginEntry) -> ApiResult<Option<Login>> { + let db = self.lock_db()?; + db.find_login_to_update(entry, db.encdec.as_ref()) + } + + #[handle_error(Error)] + pub fn touch(&self, id: &str) -> ApiResult<()> { + self.lock_db()?.touch(id) + } + + #[handle_error(Error)] + pub fn delete(&self, id: &str) -> ApiResult<bool> { + self.lock_db()?.delete(id) + } + + #[handle_error(Error)] + pub fn delete_many(&self, ids: Vec<String>) -> ApiResult<Vec<bool>> { + // Note we need to receive a vector of String here because `Vec<&str>` is not supported + // with UDL. + let ids: Vec<&str> = ids.iter().map(|id| &**id).collect(); + self.lock_db()?.delete_many(ids) + } + + #[handle_error(Error)] + pub fn delete_undecryptable_records_for_remote_replacement( + self: Arc<Self>, + ) -> ApiResult<LoginsDeletionMetrics> { + // This function was created for the iOS logins verification logic that will + // remove records that prevent logins syncing. Once the verification logic is + // removed from iOS, this function can be removed from the store. + + // Creating an engine requires locking the DB, so make sure to do this first + let engine = LoginsSyncEngine::new(Arc::clone(&self))?; + + let db = self.lock_db()?; + let deletion_stats = + db.delete_undecryptable_records_for_remote_replacement(db.encdec.as_ref())?; + engine.set_last_sync(&db, ServerTimestamp(0))?; + Ok(deletion_stats) + } + + #[handle_error(Error)] + pub fn wipe_local(&self) -> ApiResult<()> { + self.lock_db()?.wipe_local()?; + Ok(()) + } + + #[handle_error(Error)] + pub fn reset(self: Arc<Self>) -> ApiResult<()> { + // Reset should not exist here - all resets should be done via the + // sync manager. It seems that actual consumers don't use this, but + // some tests do, so it remains for now. + let engine = LoginsSyncEngine::new(Arc::clone(&self))?; + engine.do_reset(&EngineSyncAssociation::Disconnected)?; + Ok(()) + } + + #[handle_error(Error)] + pub fn update(&self, id: &str, entry: LoginEntry) -> ApiResult<Login> { + let db = self.lock_db()?; + db.update(id, entry, db.encdec.as_ref()) + .and_then(|enc_login| enc_login.decrypt(db.encdec.as_ref())) + } + + #[handle_error(Error)] + pub fn add(&self, entry: LoginEntry) -> ApiResult<Login> { + let db = self.lock_db()?; + db.add(entry, db.encdec.as_ref()) + .and_then(|enc_login| enc_login.decrypt(db.encdec.as_ref())) + } + + #[handle_error(Error)] + pub fn add_many(&self, entries: Vec<LoginEntry>) -> ApiResult<Vec<BulkResultEntry>> { + let db = self.lock_db()?; + db.add_many(entries, db.encdec.as_ref()).map(|enc_logins| { + enc_logins + .into_iter() + .map(|enc_login| map_bulk_result_entry(enc_login, db.encdec.as_ref())) + .collect() + }) + } + + /// This method is intended to preserve metadata (LoginMeta) during a migration. + /// In normal operation, this method should not be used; instead, + /// use `add(entry)`, which manages the corresponding fields itself. + #[handle_error(Error)] + pub fn add_with_meta(&self, entry_with_meta: LoginEntryWithMeta) -> ApiResult<Login> { + let db = self.lock_db()?; + db.add_with_meta(entry_with_meta, db.encdec.as_ref()) + .and_then(|enc_login| enc_login.decrypt(db.encdec.as_ref())) + } + + #[handle_error(Error)] + pub fn add_many_with_meta( + &self, + entries_with_meta: Vec<LoginEntryWithMeta>, + ) -> ApiResult<Vec<BulkResultEntry>> { + let db = self.lock_db()?; + db.add_many_with_meta(entries_with_meta, db.encdec.as_ref()) + .map(|enc_logins| { + enc_logins + .into_iter() + .map(|enc_login| map_bulk_result_entry(enc_login, db.encdec.as_ref())) + .collect() + }) + } + + #[handle_error(Error)] + pub fn add_or_update(&self, entry: LoginEntry) -> ApiResult<Login> { + let db = self.lock_db()?; + db.add_or_update(entry, db.encdec.as_ref()) + .and_then(|enc_login| enc_login.decrypt(db.encdec.as_ref())) + } + + #[handle_error(Error)] + pub fn set_checkpoint(&self, checkpoint: &str) -> ApiResult<()> { + self.lock_db()? + .put_meta(schema::CHECKPOINT_KEY, &checkpoint) + } + + #[handle_error(Error)] + pub fn get_checkpoint(&self) -> ApiResult<Option<String>> { + self.lock_db()?.get_meta(schema::CHECKPOINT_KEY) + } + + #[handle_error(Error)] + pub fn run_maintenance(&self) -> ApiResult<()> { + let conn = self.lock_db()?; + run_maintenance(&conn)?; + Ok(()) + } + + pub fn shutdown(&self) { + if let Some(db) = self.db.lock().take() { + let _ = db.shutdown(); + } + } + + // This allows the embedding app to say "make this instance available to + // the sync manager". The implementation is more like "offer to sync mgr" + // (thereby avoiding us needing to link with the sync manager) but + // `register_with_sync_manager()` is logically what's happening so that's + // the name it gets. + pub fn register_with_sync_manager(self: Arc<Self>) { + let mut state = STORE_FOR_MANAGER.lock(); + *state = Arc::downgrade(&self); + } + + // this isn't exposed by uniffi - currently the + // only consumer of this is our "example" (and hence why they + // are `pub` and not `pub(crate)`). + // We could probably make the example work with the sync manager - but then + // our example would link with places and logins etc, and it's not a big + // deal really. + #[handle_error(Error)] + pub fn create_logins_sync_engine(self: Arc<Self>) -> ApiResult<Box<dyn SyncEngine>> { + Ok(Box::new(LoginsSyncEngine::new(self)?) as Box<dyn SyncEngine>) + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod test { + use super::*; + use crate::encryption::test_utils::TEST_ENCDEC; + use crate::util; + use nss::ensure_initialized; + use std::cmp::Reverse; + use std::time::SystemTime; + + fn assert_logins_equiv(a: &LoginEntry, b: &Login) { + assert_eq!(a.origin, b.origin); + assert_eq!(a.form_action_origin, b.form_action_origin); + assert_eq!(a.http_realm, b.http_realm); + assert_eq!(a.username_field, b.username_field); + assert_eq!(a.password_field, b.password_field); + assert_eq!(b.username, a.username); + assert_eq!(b.password, a.password); + } + + #[test] + fn test_general() { + ensure_initialized(); + + let store = LoginStore::new_in_memory(); + let list = store.list().expect("Grabbing Empty list to work"); + assert_eq!(list.len(), 0); + let start_us = util::system_time_ms_i64(SystemTime::now()); + + let a = LoginEntry { + origin: "https://www.example.com".into(), + form_action_origin: Some("https://www.example.com".into()), + username_field: "user_input".into(), + password_field: "pass_input".into(), + username: "coolperson21".into(), + password: "p4ssw0rd".into(), + ..Default::default() + }; + + let b = LoginEntry { + origin: "https://www.example2.com".into(), + http_realm: Some("Some String Here".into()), + username: "asdf".into(), + password: "fdsa".into(), + ..Default::default() + }; + let a_id = store.add(a.clone()).expect("added a").id; + let b_id = store.add(b.clone()).expect("added b").id; + + let a_from_db = store + .get(&a_id) + .expect("Not to error getting a") + .expect("a to exist"); + + assert_logins_equiv(&a, &a_from_db); + assert!(a_from_db.time_created >= start_us); + assert!(a_from_db.time_password_changed >= start_us); + assert!(a_from_db.time_last_used >= start_us); + assert_eq!(a_from_db.times_used, 1); + + let b_from_db = store + .get(&b_id) + .expect("Not to error getting b") + .expect("b to exist"); + + assert_logins_equiv(&LoginEntry { ..b.clone() }, &b_from_db); + assert!(b_from_db.time_created >= start_us); + assert!(b_from_db.time_password_changed >= start_us); + assert!(b_from_db.time_last_used >= start_us); + assert_eq!(b_from_db.times_used, 1); + + let mut list = store.list().expect("Grabbing list to work"); + assert_eq!(list.len(), 2); + + let mut expect = vec![a_from_db, b_from_db.clone()]; + + list.sort_by_key(|b| Reverse(b.guid())); + expect.sort_by_key(|b| Reverse(b.guid())); + assert_eq!(list, expect); + + store.delete(&a_id).expect("Successful delete"); + assert!(store + .get(&a_id) + .expect("get after delete should still work") + .is_none()); + + let list = store.list().expect("Grabbing list to work"); + assert_eq!(list.len(), 1); + assert_eq!(list[0], b_from_db); + + let has_logins = store + .has_logins_by_base_domain("example2.com") + .expect("Expect a result for this origin"); + assert!(has_logins); + + let list = store + .get_by_base_domain("example2.com") + .expect("Expect a list for this origin"); + assert_eq!(list.len(), 1); + assert_eq!(list[0], b_from_db); + + let has_logins = store + .has_logins_by_base_domain("www.example.com") + .expect("Expect a result for this origin"); + assert!(!has_logins); + + let list = store + .get_by_base_domain("www.example.com") + .expect("Expect an empty list"); + assert_eq!(list.len(), 0); + + let now_us = util::system_time_ms_i64(SystemTime::now()); + let b2 = LoginEntry { + username: b.username.to_owned(), + password: "newpass".into(), + ..b + }; + + store + .update(&b_id, b2.clone()) + .expect("update b should work"); + + let b_after_update = store + .get(&b_id) + .expect("Not to error getting b") + .expect("b to exist"); + + assert_logins_equiv(&b2, &b_after_update); + assert!(b_after_update.time_created >= start_us); + assert!(b_after_update.time_created <= now_us); + assert!(b_after_update.time_password_changed >= now_us); + assert!(b_after_update.time_last_used >= now_us); + // Should be two even though we updated twice + assert_eq!(b_after_update.times_used, 2); + } + + #[test] + fn test_checkpoint() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + let checkpoint = "a-checkpoint"; + store.set_checkpoint(checkpoint).ok(); + assert_eq!(store.get_checkpoint().unwrap().unwrap(), checkpoint); + } + + #[test] + fn test_sync_manager_registration() { + ensure_initialized(); + let store = Arc::new(LoginStore::new_in_memory()); + assert_eq!(Arc::strong_count(&store), 1); + assert_eq!(Arc::weak_count(&store), 0); + Arc::clone(&store).register_with_sync_manager(); + assert_eq!(Arc::strong_count(&store), 1); + assert_eq!(Arc::weak_count(&store), 1); + let registered = STORE_FOR_MANAGER.lock().upgrade().expect("should upgrade"); + assert!(Arc::ptr_eq(&store, &registered)); + drop(registered); + // should be no new references + assert_eq!(Arc::strong_count(&store), 1); + assert_eq!(Arc::weak_count(&store), 1); + // dropping the registered object should drop the registration. + drop(store); + assert!(STORE_FOR_MANAGER.lock().upgrade().is_none()); + } + + #[test] + fn test_wipe_local_on_a_fresh_database_is_a_noop() { + ensure_initialized(); + // If the database has data, then wipe_local() returns > 0 rows deleted + let db = LoginDb::open_in_memory(); + db.add_or_update( + LoginEntry { + origin: "https://www.example.com".into(), + form_action_origin: Some("https://www.example.com".into()), + username_field: "user_input".into(), + password_field: "pass_input".into(), + username: "coolperson21".into(), + password: "p4ssw0rd".into(), + ..Default::default() + }, + &TEST_ENCDEC.clone(), + ) + .unwrap(); + assert!(db.wipe_local().unwrap() > 0); + + // If the database is empty, then wipe_local() returns 0 rows deleted + let db = LoginDb::open_in_memory(); + assert_eq!(db.wipe_local().unwrap(), 0); + } + + #[test] + fn test_shutdown() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + store.shutdown(); + assert!(matches!( + store.list(), + Err(LoginsApiError::UnexpectedLoginsApiError { reason: _ }) + )); + assert!(store.db.lock().is_none()); + } + + #[test] + fn test_delete_undecryptable_records_for_remote_replacement() { + ensure_initialized(); + let store = Arc::new(LoginStore::new_in_memory()); + // Not much of a test, but let's make sure this doesn't deadlock at least. + store + .delete_undecryptable_records_for_remote_replacement() + .unwrap(); + } +} + +#[test] +fn test_send() { + fn ensure_send<T: Send>() {} + ensure_send::<LoginStore>(); +} diff --git a/third_party/rust/logins/src/sync/engine.rs b/third_party/rust/logins/src/sync/engine.rs @@ -0,0 +1,1188 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use super::merge::{LocalLogin, MirrorLogin, SyncLoginData}; +use super::update_plan::UpdatePlan; +use super::SyncStatus; +use crate::db::CLONE_ENTIRE_MIRROR_SQL; +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::login::EncryptedLogin; +use crate::schema; +use crate::util; +use crate::LoginDb; +use crate::LoginStore; +use interrupt_support::SqlInterruptScope; +use rusqlite::named_params; +use sql_support::ConnExt; +use std::cell::RefCell; +use std::collections::HashSet; +use std::sync::Arc; +use std::time::{Duration, UNIX_EPOCH}; +use sync15::bso::{IncomingBso, OutgoingBso, OutgoingEnvelope}; +use sync15::engine::{CollSyncIds, CollectionRequest, EngineSyncAssociation, SyncEngine}; +use sync15::{telemetry, ServerTimestamp}; +use sync_guid::Guid; + +// The sync engine. +pub struct LoginsSyncEngine { + pub store: Arc<LoginStore>, + pub scope: SqlInterruptScope, + pub encdec: Arc<dyn EncryptorDecryptor>, + pub staged: RefCell<Vec<IncomingBso>>, +} + +impl LoginsSyncEngine { + pub fn new(store: Arc<LoginStore>) -> Result<Self> { + let db = store.lock_db()?; + let scope = db.begin_interrupt_scope()?; + let encdec = db.encdec.clone(); + drop(db); + Ok(Self { + store, + encdec, + scope, + staged: RefCell::new(vec![]), + }) + } + + fn reconcile( + &self, + records: Vec<SyncLoginData>, + server_now: ServerTimestamp, + telem: &mut telemetry::EngineIncoming, + ) -> Result<UpdatePlan> { + let mut plan = UpdatePlan::default(); + + for mut record in records { + self.scope.err_if_interrupted()?; + debug!("Processing remote change {}", record.guid()); + let upstream = if let Some(inbound) = record.inbound.take() { + inbound + } else { + debug!("Processing inbound deletion (always prefer)"); + plan.plan_delete(record.guid.clone()); + continue; + }; + let upstream_time = record.inbound_ts; + match (record.mirror.take(), record.local.take()) { + (Some(mirror), Some(local)) => { + debug!(" Conflict between remote and local, Resolving with 3WM"); + plan.plan_three_way_merge( + local, + mirror, + upstream, + upstream_time, + server_now, + self.encdec.as_ref(), + )?; + telem.reconciled(1); + } + (Some(_mirror), None) => { + debug!(" Forwarding mirror to remote"); + plan.plan_mirror_update(upstream, upstream_time); + telem.applied(1); + } + (None, Some(local)) => { + debug!(" Conflicting record without shared parent, Resolving with 2WM"); + plan.plan_two_way_merge(local, (upstream, upstream_time)); + telem.reconciled(1); + } + (None, None) => { + if let Some(dupe) = self.find_dupe_login(&upstream.login)? { + debug!( + " Incoming record {} was is a dupe of local record {}", + upstream.guid(), + dupe.guid() + ); + let local_modified = UNIX_EPOCH + + Duration::from_millis(dupe.meta.time_password_changed as u64); + let local = LocalLogin::Alive { + login: dupe, + local_modified, + }; + plan.plan_two_way_merge(local, (upstream, upstream_time)); + } else { + debug!(" No dupe found, inserting into mirror"); + plan.plan_mirror_insert(upstream, upstream_time, false); + } + telem.applied(1); + } + } + } + Ok(plan) + } + + fn execute_plan(&self, plan: UpdatePlan) -> Result<()> { + // Because rusqlite want a mutable reference to create a transaction + // (as a way to save us from ourselves), we side-step that by creating + // it manually. + let db = self.store.lock_db()?; + let tx = db.unchecked_transaction()?; + plan.execute(&tx, &self.scope)?; + tx.commit()?; + Ok(()) + } + + // Fetch all the data for the provided IDs. + // TODO: Might be better taking a fn instead of returning all of it... But that func will likely + // want to insert stuff while we're doing this so ugh. + fn fetch_login_data( + &self, + records: Vec<IncomingBso>, + telem: &mut telemetry::EngineIncoming, + ) -> Result<Vec<SyncLoginData>> { + let mut sync_data = Vec::with_capacity(records.len()); + { + let mut seen_ids: HashSet<Guid> = HashSet::with_capacity(records.len()); + for incoming in records.into_iter() { + let id = incoming.envelope.id.clone(); + match SyncLoginData::from_bso(incoming, self.encdec.as_ref()) { + Ok(v) => sync_data.push(v), + Err(e) => { + match e { + // This is a known error with Desktop logins (see #5233), just log it + // rather than reporting to sentry + Error::InvalidLogin(InvalidLogin::IllegalOrigin) => { + warn!("logins-deserialize-error: {e}"); + } + // For all other errors, report them to Sentry + _ => { + report_error!( + "logins-deserialize-error", + "Failed to deserialize record {:?}: {e}", + id + ); + } + }; + // Ideally we'd track new_failed, but it's unclear how + // much value it has. + telem.failed(1); + } + } + seen_ids.insert(id); + } + } + self.scope.err_if_interrupted()?; + + sql_support::each_chunk( + &sync_data + .iter() + .map(|s| s.guid.as_str().to_string()) + .collect::<Vec<String>>(), + |chunk, offset| -> Result<()> { + // pairs the bound parameter for the guid with an integer index. + let values_with_idx = sql_support::repeat_display(chunk.len(), ",", |i, f| { + write!(f, "({},?)", i + offset) + }); + let query = format!( + "WITH to_fetch(guid_idx, fetch_guid) AS (VALUES {vals}) + SELECT + {common_cols}, + is_overridden, + server_modified, + NULL as local_modified, + NULL as is_deleted, + NULL as sync_status, + 1 as is_mirror, + to_fetch.guid_idx as guid_idx + FROM loginsM + JOIN to_fetch + ON loginsM.guid = to_fetch.fetch_guid + + UNION ALL + + SELECT + {common_cols}, + NULL as is_overridden, + NULL as server_modified, + local_modified, + is_deleted, + sync_status, + 0 as is_mirror, + to_fetch.guid_idx as guid_idx + FROM loginsL + JOIN to_fetch + ON loginsL.guid = to_fetch.fetch_guid", + // give each VALUES item 2 entries, an index and the parameter. + vals = values_with_idx, + common_cols = schema::COMMON_COLS, + ); + + let db = &self.store.lock_db()?; + let mut stmt = db.prepare(&query)?; + + let rows = stmt.query_and_then(rusqlite::params_from_iter(chunk), |row| { + let guid_idx_i = row.get::<_, i64>("guid_idx")?; + // Hitting this means our math is wrong... + assert!(guid_idx_i >= 0); + + let guid_idx = guid_idx_i as usize; + let is_mirror: bool = row.get("is_mirror")?; + if is_mirror { + sync_data[guid_idx].set_mirror(MirrorLogin::from_row(row)?)?; + } else { + sync_data[guid_idx].set_local(LocalLogin::from_row(row)?)?; + } + self.scope.err_if_interrupted()?; + Ok(()) + })?; + // `rows` is an Iterator<Item = Result<()>>, so we need to collect to handle the errors. + rows.collect::<Result<()>>()?; + Ok(()) + }, + )?; + Ok(sync_data) + } + + fn fetch_outgoing(&self) -> Result<Vec<OutgoingBso>> { + // Taken from iOS. Arbitrarily large, so that clients that want to + // process deletions first can; for us it doesn't matter. + const TOMBSTONE_SORTINDEX: i32 = 5_000_000; + const DEFAULT_SORTINDEX: i32 = 1; + let db = self.store.lock_db()?; + let mut stmt = db.prepare_cached(&format!( + "SELECT L.*, M.enc_unknown_fields + FROM loginsL L LEFT JOIN loginsM M ON L.guid = M.guid + WHERE sync_status IS NOT {synced}", + synced = SyncStatus::Synced as u8 + ))?; + let bsos = stmt.query_and_then([], |row| { + self.scope.err_if_interrupted()?; + Ok(if row.get::<_, bool>("is_deleted")? { + let envelope = OutgoingEnvelope { + id: row.get::<_, String>("guid")?.into(), + sortindex: Some(TOMBSTONE_SORTINDEX), + ..Default::default() + }; + OutgoingBso::new_tombstone(envelope) + } else { + let unknown = row.get::<_, Option<String>>("enc_unknown_fields")?; + let mut bso = + EncryptedLogin::from_row(row)?.into_bso(self.encdec.as_ref(), unknown)?; + bso.envelope.sortindex = Some(DEFAULT_SORTINDEX); + bso + }) + })?; + bsos.collect::<Result<_>>() + } + + fn do_apply_incoming( + &self, + inbound: Vec<IncomingBso>, + timestamp: ServerTimestamp, + telem: &mut telemetry::Engine, + ) -> Result<Vec<OutgoingBso>> { + let mut incoming_telemetry = telemetry::EngineIncoming::new(); + let data = self.fetch_login_data(inbound, &mut incoming_telemetry)?; + let plan = { + let result = self.reconcile(data, timestamp, &mut incoming_telemetry); + telem.incoming(incoming_telemetry); + result + }?; + self.execute_plan(plan)?; + self.fetch_outgoing() + } + + // Note this receives the db to prevent a deadlock + pub fn set_last_sync(&self, db: &LoginDb, last_sync: ServerTimestamp) -> Result<()> { + debug!("Updating last sync to {}", last_sync); + let last_sync_millis = last_sync.as_millis(); + db.put_meta(schema::LAST_SYNC_META_KEY, &last_sync_millis) + } + + fn get_last_sync(&self, db: &LoginDb) -> Result<Option<ServerTimestamp>> { + let millis = db.get_meta::<i64>(schema::LAST_SYNC_META_KEY)?.unwrap(); + Ok(Some(ServerTimestamp(millis))) + } + + pub fn set_global_state(&self, state: &Option<String>) -> Result<()> { + let to_write = match state { + Some(ref s) => s, + None => "", + }; + let db = self.store.lock_db()?; + db.put_meta(schema::GLOBAL_STATE_META_KEY, &to_write) + } + + pub fn get_global_state(&self) -> Result<Option<String>> { + let db = self.store.lock_db()?; + db.get_meta::<String>(schema::GLOBAL_STATE_META_KEY) + } + + fn mark_as_synchronized(&self, guids: &[&str], ts: ServerTimestamp) -> Result<()> { + let db = self.store.lock_db()?; + let tx = db.unchecked_transaction()?; + sql_support::each_chunk(guids, |chunk, _| -> Result<()> { + db.execute( + &format!( + "DELETE FROM loginsM WHERE guid IN ({vars})", + vars = sql_support::repeat_sql_vars(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + self.scope.err_if_interrupted()?; + + db.execute( + &format!( + "INSERT OR IGNORE INTO loginsM ( + {common_cols}, is_overridden, server_modified + ) + SELECT {common_cols}, 0, {modified_ms_i64} + FROM loginsL + WHERE is_deleted = 0 AND guid IN ({vars})", + common_cols = schema::COMMON_COLS, + modified_ms_i64 = ts.as_millis(), + vars = sql_support::repeat_sql_vars(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + self.scope.err_if_interrupted()?; + + db.execute( + &format!( + "DELETE FROM loginsL WHERE guid IN ({vars})", + vars = sql_support::repeat_sql_vars(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + self.scope.err_if_interrupted()?; + Ok(()) + })?; + self.set_last_sync(&db, ts)?; + tx.commit()?; + Ok(()) + } + + // This exists here as a public function so the store can call it. Ideally + // the store would not do that :) Then it can go back into the sync trait + // and return an anyhow::Result + pub fn do_reset(&self, assoc: &EngineSyncAssociation) -> Result<()> { + info!("Executing reset on password engine!"); + let db = self.store.lock_db()?; + let tx = db.unchecked_transaction()?; + db.execute_all(&[ + &CLONE_ENTIRE_MIRROR_SQL, + "DELETE FROM loginsM", + &format!("UPDATE loginsL SET sync_status = {}", SyncStatus::New as u8), + ])?; + self.set_last_sync(&db, ServerTimestamp(0))?; + match assoc { + EngineSyncAssociation::Disconnected => { + db.delete_meta(schema::GLOBAL_SYNCID_META_KEY)?; + db.delete_meta(schema::COLLECTION_SYNCID_META_KEY)?; + } + EngineSyncAssociation::Connected(ids) => { + db.put_meta(schema::GLOBAL_SYNCID_META_KEY, &ids.global)?; + db.put_meta(schema::COLLECTION_SYNCID_META_KEY, &ids.coll)?; + } + }; + db.delete_meta(schema::GLOBAL_STATE_META_KEY)?; + tx.commit()?; + Ok(()) + } + + // It would be nice if this were a batch-ish api (e.g. takes a slice of records and finds dupes + // for each one if they exist)... I can't think of how to write that query, though. + // This is subtly different from dupe handling by the main API and maybe + // could be consolidated, but for now it remains sync specific. + pub(crate) fn find_dupe_login(&self, l: &EncryptedLogin) -> Result<Option<EncryptedLogin>> { + let form_submit_host_port = l + .fields + .form_action_origin + .as_ref() + .and_then(|s| util::url_host_port(s)); + let enc_fields = l.decrypt_fields(self.encdec.as_ref())?; + let args = named_params! { + ":origin": l.fields.origin, + ":http_realm": l.fields.http_realm, + ":form_submit": form_submit_host_port, + }; + let mut query = format!( + "SELECT {common} + FROM loginsL + WHERE origin IS :origin + AND httpRealm IS :http_realm", + common = schema::COMMON_COLS, + ); + if form_submit_host_port.is_some() { + // Stolen from iOS + query += " AND (formActionOrigin = '' OR (instr(formActionOrigin, :form_submit) > 0))"; + } else { + query += " AND formActionOrigin IS :form_submit" + } + let db = self.store.lock_db()?; + let mut stmt = db.prepare_cached(&query)?; + for login in stmt + .query_and_then(args, EncryptedLogin::from_row)? + .collect::<Result<Vec<EncryptedLogin>>>()? + { + let this_enc_fields = login.decrypt_fields(self.encdec.as_ref())?; + if enc_fields.username == this_enc_fields.username { + return Ok(Some(login)); + } + } + Ok(None) + } +} + +impl SyncEngine for LoginsSyncEngine { + fn collection_name(&self) -> std::borrow::Cow<'static, str> { + "passwords".into() + } + + fn stage_incoming( + &self, + mut inbound: Vec<IncomingBso>, + _telem: &mut telemetry::Engine, + ) -> anyhow::Result<()> { + // We don't have cross-item dependencies like bookmarks does, so we can + // just apply now instead of "staging" + self.staged.borrow_mut().append(&mut inbound); + Ok(()) + } + + fn apply( + &self, + timestamp: ServerTimestamp, + telem: &mut telemetry::Engine, + ) -> anyhow::Result<Vec<OutgoingBso>> { + let inbound = (*self.staged.borrow_mut()).drain(..).collect(); + Ok(self.do_apply_incoming(inbound, timestamp, telem)?) + } + + fn set_uploaded(&self, new_timestamp: ServerTimestamp, ids: Vec<Guid>) -> anyhow::Result<()> { + Ok(self.mark_as_synchronized( + &ids.iter().map(Guid::as_str).collect::<Vec<_>>(), + new_timestamp, + )?) + } + + fn get_collection_request( + &self, + server_timestamp: ServerTimestamp, + ) -> anyhow::Result<Option<CollectionRequest>> { + let db = self.store.lock_db()?; + let since = self.get_last_sync(&db)?.unwrap_or_default(); + Ok(if since == server_timestamp { + None + } else { + Some( + CollectionRequest::new("passwords".into()) + .full() + .newer_than(since), + ) + }) + } + + fn get_sync_assoc(&self) -> anyhow::Result<EngineSyncAssociation> { + let db = self.store.lock_db()?; + let global = db.get_meta(schema::GLOBAL_SYNCID_META_KEY)?; + let coll = db.get_meta(schema::COLLECTION_SYNCID_META_KEY)?; + Ok(if let (Some(global), Some(coll)) = (global, coll) { + EngineSyncAssociation::Connected(CollSyncIds { global, coll }) + } else { + EngineSyncAssociation::Disconnected + }) + } + + fn reset(&self, assoc: &EngineSyncAssociation) -> anyhow::Result<()> { + self.do_reset(assoc)?; + Ok(()) + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod tests { + use super::*; + use crate::db::test_utils::insert_login; + use crate::encryption::test_utils::TEST_ENCDEC; + use crate::login::test_utils::enc_login; + use crate::{LoginEntry, LoginFields, LoginMeta, SecureLoginFields}; + use nss::ensure_initialized; + use std::collections::HashMap; + use std::sync::Arc; + + // Wrap sync functions for easier testing + fn run_fetch_login_data( + engine: &mut LoginsSyncEngine, + records: Vec<IncomingBso>, + ) -> (Vec<SyncLoginData>, telemetry::EngineIncoming) { + let mut telem = sync15::telemetry::EngineIncoming::new(); + (engine.fetch_login_data(records, &mut telem).unwrap(), telem) + } + + fn run_fetch_outgoing(store: LoginStore) -> Vec<OutgoingBso> { + let engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + engine.fetch_outgoing().unwrap() + } + + #[test] + fn test_fetch_login_data() { + ensure_initialized(); + // Test some common cases with fetch_login data + let store = LoginStore::new_in_memory(); + insert_login( + &store.lock_db().unwrap(), + "updated_remotely", + None, + Some("password"), + ); + insert_login( + &store.lock_db().unwrap(), + "deleted_remotely", + None, + Some("password"), + ); + insert_login( + &store.lock_db().unwrap(), + "three_way_merge", + Some("new-local-password"), + Some("password"), + ); + + let mut engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + + let (res, _) = run_fetch_login_data( + &mut engine, + vec![ + IncomingBso::new_test_tombstone(Guid::new("deleted_remotely")), + enc_login("added_remotely", "password") + .into_bso(&*TEST_ENCDEC, None) + .unwrap() + .to_test_incoming(), + enc_login("updated_remotely", "new-password") + .into_bso(&*TEST_ENCDEC, None) + .unwrap() + .to_test_incoming(), + enc_login("three_way_merge", "new-remote-password") + .into_bso(&*TEST_ENCDEC, None) + .unwrap() + .to_test_incoming(), + ], + ); + // For simpler testing, extract/decrypt passwords and put them in a hash map + #[derive(Debug, PartialEq)] + struct SyncPasswords { + local: Option<String>, + mirror: Option<String>, + inbound: Option<String>, + } + let extracted_passwords: HashMap<String, SyncPasswords> = res + .into_iter() + .map(|sync_login_data| { + let mut guids_seen = HashSet::new(); + let passwords = SyncPasswords { + local: sync_login_data.local.map(|local_login| { + guids_seen.insert(local_login.guid_str().to_string()); + let LocalLogin::Alive { login, .. } = local_login else { + unreachable!("this test is not expecting a tombstone"); + }; + login.decrypt_fields(&*TEST_ENCDEC).unwrap().password + }), + mirror: sync_login_data.mirror.map(|mirror_login| { + guids_seen.insert(mirror_login.login.meta.id.clone()); + mirror_login + .login + .decrypt_fields(&*TEST_ENCDEC) + .unwrap() + .password + }), + inbound: sync_login_data.inbound.map(|incoming| { + guids_seen.insert(incoming.login.meta.id.clone()); + incoming + .login + .decrypt_fields(&*TEST_ENCDEC) + .unwrap() + .password + }), + }; + (guids_seen.into_iter().next().unwrap(), passwords) + }) + .collect(); + + assert_eq!(extracted_passwords.len(), 4); + assert_eq!( + extracted_passwords.get("added_remotely").unwrap(), + &SyncPasswords { + local: None, + mirror: None, + inbound: Some("password".into()), + } + ); + assert_eq!( + extracted_passwords.get("updated_remotely").unwrap(), + &SyncPasswords { + local: None, + mirror: Some("password".into()), + inbound: Some("new-password".into()), + } + ); + assert_eq!( + extracted_passwords.get("deleted_remotely").unwrap(), + &SyncPasswords { + local: None, + mirror: Some("password".into()), + inbound: None, + } + ); + assert_eq!( + extracted_passwords.get("three_way_merge").unwrap(), + &SyncPasswords { + local: Some("new-local-password".into()), + mirror: Some("password".into()), + inbound: Some("new-remote-password".into()), + } + ); + } + + #[test] + fn test_sync_local_delete() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + insert_login( + &store.lock_db().unwrap(), + "local-deleted", + Some("password"), + None, + ); + store.lock_db().unwrap().delete("local-deleted").unwrap(); + let changeset = run_fetch_outgoing(store); + let changes: HashMap<String, serde_json::Value> = changeset + .into_iter() + .map(|b| { + ( + b.envelope.id.to_string(), + serde_json::from_str(&b.payload).unwrap(), + ) + }) + .collect(); + assert_eq!(changes.len(), 1); + assert!(changes["local-deleted"].get("deleted").is_some()); + + // hmmm. In theory, we do not need to sync a local-only deletion + } + + #[test] + fn test_sync_local_readd() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + insert_login( + &store.lock_db().unwrap(), + "local-readded", + Some("password"), + None, + ); + store.lock_db().unwrap().delete("local-readded").unwrap(); + insert_login( + &store.lock_db().unwrap(), + "local-readded", + Some("password"), + None, + ); + let changeset = run_fetch_outgoing(store); + let changes: HashMap<String, serde_json::Value> = changeset + .into_iter() + .map(|b| { + ( + b.envelope.id.to_string(), + serde_json::from_str(&b.payload).unwrap(), + ) + }) + .collect(); + assert_eq!(changes.len(), 1); + assert_eq!( + changes["local-readded"].get("password").unwrap(), + "password" + ); + } + + #[test] + fn test_sync_local_readd_of_remote_deletion() { + ensure_initialized(); + let other_store = LoginStore::new_in_memory(); + let mut engine = LoginsSyncEngine::new(Arc::new(other_store)).unwrap(); + let (_res, _telem) = run_fetch_login_data( + &mut engine, + vec![IncomingBso::new_test_tombstone(Guid::new("remote-readded"))], + ); + + let store = LoginStore::new_in_memory(); + insert_login( + &store.lock_db().unwrap(), + "remote-readded", + Some("password"), + None, + ); + let changeset = run_fetch_outgoing(store); + let changes: HashMap<String, serde_json::Value> = changeset + .into_iter() + .map(|b| { + ( + b.envelope.id.to_string(), + serde_json::from_str(&b.payload).unwrap(), + ) + }) + .collect(); + assert_eq!(changes.len(), 1); + assert_eq!( + changes["remote-readded"].get("password").unwrap(), + "password" + ); + } + + #[test] + fn test_sync_local_readd_redelete_of_remote_login() { + ensure_initialized(); + let other_store = LoginStore::new_in_memory(); + let mut engine = LoginsSyncEngine::new(Arc::new(other_store)).unwrap(); + let (_res, _telem) = run_fetch_login_data( + &mut engine, + vec![IncomingBso::from_test_content(serde_json::json!({ + "id": "remote-readded-redeleted", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + }))], + ); + + let store = LoginStore::new_in_memory(); + store + .lock_db() + .unwrap() + .delete("remote-readded-redeleted") + .unwrap(); + insert_login( + &store.lock_db().unwrap(), + "remote-readded-redeleted", + Some("password"), + None, + ); + store + .lock_db() + .unwrap() + .delete("remote-readded-redeleted") + .unwrap(); + let changeset = run_fetch_outgoing(store); + let changes: HashMap<String, serde_json::Value> = changeset + .into_iter() + .map(|b| { + ( + b.envelope.id.to_string(), + serde_json::from_str(&b.payload).unwrap(), + ) + }) + .collect(); + assert_eq!(changes.len(), 1); + assert!(changes["remote-readded-redeleted"].get("deleted").is_some()); + } + + #[test] + fn test_fetch_outgoing() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + insert_login( + &store.lock_db().unwrap(), + "changed", + Some("new-password"), + Some("password"), + ); + insert_login( + &store.lock_db().unwrap(), + "unchanged", + None, + Some("password"), + ); + insert_login(&store.lock_db().unwrap(), "added", Some("password"), None); + insert_login(&store.lock_db().unwrap(), "deleted", None, Some("password")); + store.lock_db().unwrap().delete("deleted").unwrap(); + + let changeset = run_fetch_outgoing(store); + let changes: HashMap<String, serde_json::Value> = changeset + .into_iter() + .map(|b| { + ( + b.envelope.id.to_string(), + serde_json::from_str(&b.payload).unwrap(), + ) + }) + .collect(); + assert_eq!(changes.len(), 3); + assert_eq!(changes["added"].get("password").unwrap(), "password"); + assert_eq!(changes["changed"].get("password").unwrap(), "new-password"); + assert!(changes["deleted"].get("deleted").is_some()); + assert!(changes["added"].get("deleted").is_none()); + assert!(changes["changed"].get("deleted").is_none()); + } + + #[test] + fn test_bad_record() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + let test_ids = ["dummy_000001", "dummy_000002", "dummy_000003"]; + for id in test_ids { + insert_login( + &store.lock_db().unwrap(), + id, + Some("password"), + Some("password"), + ); + } + let mut engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + engine + .mark_as_synchronized(&test_ids, ServerTimestamp::from_millis(100)) + .unwrap(); + let (res, telem) = run_fetch_login_data( + &mut engine, + vec![ + IncomingBso::new_test_tombstone(Guid::new("dummy_000001")), + // invalid + IncomingBso::from_test_content(serde_json::json!({ + "id": "dummy_000002", + "garbage": "data", + "etc": "not a login" + })), + // valid + IncomingBso::from_test_content(serde_json::json!({ + "id": "dummy_000003", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + })), + ], + ); + assert_eq!(telem.get_failed(), 1); + assert_eq!(res.len(), 2); + assert_eq!(res[0].guid, "dummy_000001"); + assert_eq!(res[1].guid, "dummy_000003"); + assert_eq!(engine.fetch_outgoing().unwrap().len(), 0); + } + + fn make_enc_login( + username: &str, + password: &str, + fao: Option<String>, + realm: Option<String>, + ) -> EncryptedLogin { + ensure_initialized(); + let id = Guid::random().to_string(); + let sec_fields = SecureLoginFields { + username: username.into(), + password: password.into(), + } + .encrypt(&*TEST_ENCDEC, &id) + .unwrap(); + EncryptedLogin { + meta: LoginMeta { + id, + ..Default::default() + }, + fields: LoginFields { + form_action_origin: fao, + http_realm: realm, + origin: "http://not-relevant-here.com".into(), + ..Default::default() + }, + sec_fields, + } + } + + #[test] + fn find_dupe_login() { + ensure_initialized(); + let store = LoginStore::new_in_memory(); + + let to_add = LoginEntry { + form_action_origin: Some("https://www.example.com".into()), + origin: "http://not-relevant-here.com".into(), + username: "test".into(), + password: "test".into(), + ..Default::default() + }; + let first_id = store.add(to_add).expect("should insert first").id; + + let to_add = LoginEntry { + form_action_origin: Some("https://www.example1.com".into()), + origin: "http://not-relevant-here.com".into(), + username: "test1".into(), + password: "test1".into(), + ..Default::default() + }; + let second_id = store.add(to_add).expect("should insert second").id; + + let to_add = LoginEntry { + http_realm: Some("http://some-realm.com".into()), + origin: "http://not-relevant-here.com".into(), + username: "test1".into(), + password: "test1".into(), + ..Default::default() + }; + let no_form_origin_id = store.add(to_add).expect("should insert second").id; + + let engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + + let to_find = make_enc_login("test", "test", Some("https://www.example.com".into()), None); + assert_eq!( + engine + .find_dupe_login(&to_find) + .expect("should work") + .expect("should be Some()") + .meta + .id, + first_id + ); + + let to_find = make_enc_login( + "test", + "test", + Some("https://something-else.com".into()), + None, + ); + assert!(engine + .find_dupe_login(&to_find) + .expect("should work") + .is_none()); + + let to_find = make_enc_login( + "test1", + "test1", + Some("https://www.example1.com".into()), + None, + ); + assert_eq!( + engine + .find_dupe_login(&to_find) + .expect("should work") + .expect("should be Some()") + .meta + .id, + second_id + ); + + let to_find = make_enc_login( + "other", + "other", + Some("https://www.example1.com".into()), + None, + ); + assert!(engine + .find_dupe_login(&to_find) + .expect("should work") + .is_none()); + + // no form origin. + let to_find = make_enc_login("test1", "test1", None, Some("http://some-realm.com".into())); + assert_eq!( + engine + .find_dupe_login(&to_find) + .expect("should work") + .expect("should be Some()") + .meta + .id, + no_form_origin_id + ); + } + + #[test] + fn test_roundtrip_unknown() { + ensure_initialized(); + // A couple of helpers + fn apply_incoming_payload(engine: &LoginsSyncEngine, payload: serde_json::Value) { + let bso = IncomingBso::from_test_content(payload); + let mut telem = sync15::telemetry::Engine::new(engine.collection_name()); + engine.stage_incoming(vec![bso], &mut telem).unwrap(); + engine + .apply(ServerTimestamp::from_millis(0), &mut telem) + .unwrap(); + } + + fn get_outgoing_payload(engine: &LoginsSyncEngine) -> serde_json::Value { + // Edit it so it's considered outgoing. + engine + .store + .update( + "dummy_000001", + LoginEntry { + origin: "https://www.example2.com".into(), + http_realm: Some("https://www.example2.com".into()), + username: "test".into(), + password: "test".into(), + ..Default::default() + }, + ) + .unwrap(); + let changeset = engine.fetch_outgoing().unwrap(); + assert_eq!(changeset.len(), 1); + serde_json::from_str::<serde_json::Value>(&changeset[0].payload).unwrap() + } + + // The test itself... + let store = LoginStore::new_in_memory(); + let engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + + apply_incoming_payload( + &engine, + serde_json::json!({ + "id": "dummy_000001", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "unknown1": "?", + "unknown2": {"sub": "object"}, + }), + ); + + let payload = get_outgoing_payload(&engine); + + // The outgoing payload for our item should have the unknown fields. + assert_eq!(payload.get("unknown1").unwrap().as_str().unwrap(), "?"); + assert_eq!( + payload.get("unknown2").unwrap(), + &serde_json::json!({"sub": "object"}) + ); + + // test mirror updates - record is already in our mirror, but now it's + // incoming with different unknown fields. + apply_incoming_payload( + &engine, + serde_json::json!({ + "id": "dummy_000001", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "unknown2": 99, + "unknown3": {"something": "else"}, + }), + ); + let payload = get_outgoing_payload(&engine); + // old unknown values were replaced. + assert!(payload.get("unknown1").is_none()); + assert_eq!(payload.get("unknown2").unwrap().as_u64().unwrap(), 99); + assert_eq!( + payload + .get("unknown3") + .unwrap() + .as_object() + .unwrap() + .get("something") + .unwrap() + .as_str() + .unwrap(), + "else" + ); + } + + fn count(engine: &LoginsSyncEngine, table_name: &str) -> u32 { + ensure_initialized(); + let sql = format!("SELECT COUNT(*) FROM {table_name}"); + engine + .store + .lock_db() + // TODO: get rid of this unwrap + .unwrap() + .try_query_one(&sql, [], false) + .unwrap() + .unwrap() + } + + fn do_test_incoming_with_local_unmirrored_tombstone(local_newer: bool) { + ensure_initialized(); + fn apply_incoming_payload(engine: &LoginsSyncEngine, payload: serde_json::Value) { + let bso = IncomingBso::from_test_content(payload); + let mut telem = sync15::telemetry::Engine::new(engine.collection_name()); + engine.stage_incoming(vec![bso], &mut telem).unwrap(); + engine + .apply(ServerTimestamp::from_millis(0), &mut telem) + .unwrap(); + } + + // The test itself... + let (local_timestamp, remote_timestamp) = if local_newer { (123, 0) } else { (0, 123) }; + + let store = LoginStore::new_in_memory(); + let engine = LoginsSyncEngine::new(Arc::new(store)).unwrap(); + + // apply an incoming record - will be in the mirror. + apply_incoming_payload( + &engine, + serde_json::json!({ + "id": "dummy_000001", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "timePasswordChanged": local_timestamp, + "unknown1": "?", + "unknown2": {"sub": "object"}, + }), + ); + + // Reset the engine - this wipes the mirror. + engine.reset(&EngineSyncAssociation::Disconnected).unwrap(); + // But the local record does still exist. + assert!(engine + .store + .get("dummy_000001") + .expect("should work") + .is_some()); + + // Delete the local record. + engine.store.delete("dummy_000001").unwrap(); + assert!(engine + .store + .get("dummy_000001") + .expect("should work") + .is_none()); + + // double-check our test preconditions - should now have 1 in LoginsL and 0 in LoginsM + assert_eq!(count(&engine, "LoginsL"), 1); + assert_eq!(count(&engine, "LoginsM"), 0); + + // Now we assume we've been reconnected to sync and have an incoming change for the record. + apply_incoming_payload( + &engine, + serde_json::json!({ + "id": "dummy_000001", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test2", + "timePasswordChanged": remote_timestamp, + "unknown1": "?", + "unknown2": {"sub": "object"}, + }), + ); + + // Desktop semantics here are that a local tombstone is treated as though it doesn't exist at all. + // ie, the remote record should be taken whether it is newer or older than the tombstone. + assert!(engine + .store + .get("dummy_000001") + .expect("should work") + .is_some()); + // and there should never be an outgoing record. + // XXX - but there is! But this is exceedingly rare, we + // should fix it :) + // assert_eq!(engine.fetch_outgoing().unwrap().len(), 0); + + // should now be no records in loginsL and 1 in loginsM + assert_eq!(count(&engine, "LoginsL"), 0); + assert_eq!(count(&engine, "LoginsM"), 1); + } + + #[test] + fn test_incoming_non_mirror_tombstone_local_newer() { + do_test_incoming_with_local_unmirrored_tombstone(true); + } + + #[test] + fn test_incoming_non_mirror_tombstone_local_older() { + do_test_incoming_with_local_unmirrored_tombstone(false); + } +} diff --git a/third_party/rust/logins/src/sync/merge.rs b/third_party/rust/logins/src/sync/merge.rs @@ -0,0 +1,432 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Merging for Sync. +use super::{IncomingLogin, LoginPayload}; +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::login::EncryptedLogin; +use crate::util; +use rusqlite::Row; +use std::time::SystemTime; +use sync15::bso::{IncomingBso, IncomingKind}; +use sync15::ServerTimestamp; +use sync_guid::Guid; + +#[derive(Clone, Debug)] +pub(crate) struct MirrorLogin { + pub login: EncryptedLogin, + pub server_modified: ServerTimestamp, +} + +impl MirrorLogin { + #[inline] + pub fn guid_str(&self) -> &str { + &self.login.meta.id + } + + pub(crate) fn from_row(row: &Row<'_>) -> Result<MirrorLogin> { + Ok(MirrorLogin { + login: EncryptedLogin::from_row(row)?, + server_modified: ServerTimestamp(row.get::<_, i64>("server_modified")?), + }) + } +} +#[derive(Clone, Debug)] +pub(crate) enum LocalLogin { + Tombstone { + id: String, + local_modified: SystemTime, + }, + Alive { + login: EncryptedLogin, + local_modified: SystemTime, + }, +} + +impl LocalLogin { + #[inline] + pub fn guid_str(&self) -> &str { + match &self { + LocalLogin::Tombstone { id, .. } => id.as_str(), + LocalLogin::Alive { login, .. } => login.guid_str(), + } + } + + pub fn local_modified(&self) -> SystemTime { + match &self { + LocalLogin::Tombstone { local_modified, .. } + | LocalLogin::Alive { local_modified, .. } => *local_modified, + } + } + + pub(crate) fn from_row(row: &Row<'_>) -> Result<LocalLogin> { + let local_modified = util::system_time_millis_from_row(row, "local_modified")?; + Ok(if row.get("is_deleted")? { + let id = row.get("guid")?; + LocalLogin::Tombstone { id, local_modified } + } else { + let login = EncryptedLogin::from_row(row)?; + if login.sec_fields.is_empty() { + error_support::report_error!("logins-crypto", "empty ciphertext in the db",); + } + LocalLogin::Alive { + login, + local_modified, + } + }) + } + + // Only used by tests where we want to get the "raw" record - ie, a tombstone will still + // be returned here, just with many otherwise invalid empty fields + #[cfg(not(feature = "keydb"))] + #[cfg(test)] + pub(crate) fn test_raw_from_row(row: &Row<'_>) -> Result<EncryptedLogin> { + EncryptedLogin::from_row(row) + } +} + +macro_rules! impl_login { + ($ty:ty { $($fields:tt)* }) => { + impl AsRef<EncryptedLogin> for $ty { + #[inline] + fn as_ref(&self) -> &EncryptedLogin { + &self.login + } + } + + impl AsMut<EncryptedLogin> for $ty { + #[inline] + fn as_mut(&mut self) -> &mut EncryptedLogin { + &mut self.login + } + } + + impl From<$ty> for EncryptedLogin { + #[inline] + fn from(l: $ty) -> Self { + l.login + } + } + + impl From<EncryptedLogin> for $ty { + #[inline] + fn from(login: EncryptedLogin) -> Self { + Self { login, $($fields)* } + } + } + }; +} + +impl_login!(MirrorLogin { + server_modified: ServerTimestamp(0) +}); + +// Stores data needed to do a 3-way merge +#[derive(Debug)] +pub(super) struct SyncLoginData { + pub guid: Guid, + pub local: Option<LocalLogin>, + pub mirror: Option<MirrorLogin>, + // None means it's a deletion + pub inbound: Option<IncomingLogin>, + pub inbound_ts: ServerTimestamp, +} + +impl SyncLoginData { + #[inline] + pub fn guid_str(&self) -> &str { + self.guid.as_str() + } + + #[inline] + pub fn guid(&self) -> &Guid { + &self.guid + } + + pub fn from_bso(bso: IncomingBso, encdec: &dyn EncryptorDecryptor) -> Result<Self> { + let guid = bso.envelope.id.clone(); + let inbound_ts = bso.envelope.modified; + let inbound = match bso.into_content::<LoginPayload>().kind { + IncomingKind::Content(p) => Some(IncomingLogin::from_incoming_payload(p, encdec)?), + IncomingKind::Tombstone => None, + // Before the IncomingKind refactor we returned an error. We could probably just + // treat it as a tombstone but should check that's sane, so for now, we also err. + IncomingKind::Malformed => return Err(Error::MalformedIncomingRecord), + }; + Ok(Self { + guid, + local: None, + mirror: None, + inbound, + inbound_ts, + }) + } +} + +macro_rules! impl_login_setter { + ($setter_name:ident, $field:ident, $Login:ty) => { + impl SyncLoginData { + pub(crate) fn $setter_name(&mut self, record: $Login) -> Result<()> { + // TODO: We probably shouldn't panic in this function! + if self.$field.is_some() { + // Shouldn't be possible (only could happen if UNIQUE fails in sqlite, or if we + // get duplicate guids somewhere,but we check). + panic!( + "SyncLoginData::{} called on object that already has {} data", + stringify!($setter_name), + stringify!($field) + ); + } + + if self.guid_str() != record.guid_str() { + // This is almost certainly a bug in our code. + panic!( + "Wrong guid on login in {}: {:?} != {:?}", + stringify!($setter_name), + self.guid_str(), + record.guid_str() + ); + } + + self.$field = Some(record); + Ok(()) + } + } + }; +} + +impl_login_setter!(set_local, local, LocalLogin); +impl_login_setter!(set_mirror, mirror, MirrorLogin); + +#[derive(Debug, Default, Clone)] +pub(crate) struct LoginDelta { + // "non-commutative" fields + pub origin: Option<String>, + pub password: Option<String>, + pub username: Option<String>, + pub http_realm: Option<String>, + pub form_action_origin: Option<String>, + + pub time_created: Option<i64>, + pub time_last_used: Option<i64>, + pub time_password_changed: Option<i64>, + + // "non-conflicting" fields (which are the same) + pub password_field: Option<String>, + pub username_field: Option<String>, + + // Commutative field + pub times_used: i64, +} + +macro_rules! merge_field { + ($merged:ident, $b:ident, $prefer_b:expr, $field:ident) => { + if let Some($field) = $b.$field.take() { + if $merged.$field.is_some() { + warn!("Collision merging login field {}", stringify!($field)); + if $prefer_b { + $merged.$field = Some($field); + } + } else { + $merged.$field = Some($field); + } + } + }; +} + +impl LoginDelta { + #[allow(clippy::cognitive_complexity)] // Looks like clippy considers this after macro-expansion... + pub fn merge(self, mut b: LoginDelta, b_is_newer: bool) -> LoginDelta { + let mut merged = self; + merge_field!(merged, b, b_is_newer, origin); + merge_field!(merged, b, b_is_newer, password); + merge_field!(merged, b, b_is_newer, username); + merge_field!(merged, b, b_is_newer, http_realm); + merge_field!(merged, b, b_is_newer, form_action_origin); + + merge_field!(merged, b, b_is_newer, time_created); + merge_field!(merged, b, b_is_newer, time_last_used); + merge_field!(merged, b, b_is_newer, time_password_changed); + + merge_field!(merged, b, b_is_newer, password_field); + merge_field!(merged, b, b_is_newer, username_field); + + // commutative fields + merged.times_used += b.times_used; + + merged + } +} + +macro_rules! apply_field { + ($login:ident, $delta:ident, $field:ident) => { + if let Some($field) = $delta.$field.take() { + $login.fields.$field = $field.into(); + } + }; +} + +macro_rules! apply_metadata_field { + ($login:ident, $delta:ident, $field:ident) => { + if let Some($field) = $delta.$field.take() { + $login.meta.$field = $field.into(); + } + }; +} + +impl EncryptedLogin { + pub(crate) fn apply_delta( + &mut self, + mut delta: LoginDelta, + encdec: &dyn EncryptorDecryptor, + ) -> Result<()> { + apply_field!(self, delta, origin); + + apply_metadata_field!(self, delta, time_created); + apply_metadata_field!(self, delta, time_last_used); + apply_metadata_field!(self, delta, time_password_changed); + + apply_field!(self, delta, password_field); + apply_field!(self, delta, username_field); + + let mut sec_fields = self.decrypt_fields(encdec)?; + if let Some(password) = delta.password.take() { + sec_fields.password = password; + } + if let Some(username) = delta.username.take() { + sec_fields.username = username; + } + self.sec_fields = sec_fields.encrypt(encdec, &self.meta.id)?; + + // Use Some("") to indicate that it should be changed to be None (hacky...) + if let Some(realm) = delta.http_realm.take() { + self.fields.http_realm = if realm.is_empty() { None } else { Some(realm) }; + } + + if let Some(url) = delta.form_action_origin.take() { + self.fields.form_action_origin = if url.is_empty() { None } else { Some(url) }; + } + + self.meta.times_used += delta.times_used; + Ok(()) + } + + pub(crate) fn delta( + &self, + older: &EncryptedLogin, + encdec: &dyn EncryptorDecryptor, + ) -> Result<LoginDelta> { + let mut delta = LoginDelta::default(); + + if self.fields.form_action_origin != older.fields.form_action_origin { + delta.form_action_origin = + Some(self.fields.form_action_origin.clone().unwrap_or_default()); + } + + if self.fields.http_realm != older.fields.http_realm { + delta.http_realm = Some(self.fields.http_realm.clone().unwrap_or_default()); + } + + if self.fields.origin != older.fields.origin { + delta.origin = Some(self.fields.origin.clone()); + } + let older_sec_fields = older.decrypt_fields(encdec)?; + let self_sec_fields = self.decrypt_fields(encdec)?; + if self_sec_fields.username != older_sec_fields.username { + delta.username = Some(self_sec_fields.username.clone()); + } + if self_sec_fields.password != older_sec_fields.password { + delta.password = Some(self_sec_fields.password); + } + if self.fields.password_field != older.fields.password_field { + delta.password_field = Some(self.fields.password_field.clone()); + } + if self.fields.username_field != older.fields.username_field { + delta.username_field = Some(self.fields.username_field.clone()); + } + + // We discard zero (and negative numbers) for timestamps so that a + // record that doesn't contain this information (these are + // `#[serde(default)]`) doesn't skew our records. + // + // Arguably, we should also also ignore values later than our + // `time_created`, or earlier than our `time_last_used` or + // `time_password_changed`. Doing this properly would probably require + // a scheme analogous to Desktop's weak-reupload system, so I'm punting + // on it for now. + if self.meta.time_created > 0 && self.meta.time_created != older.meta.time_created { + delta.time_created = Some(self.meta.time_created); + } + if self.meta.time_last_used > 0 && self.meta.time_last_used != older.meta.time_last_used { + delta.time_last_used = Some(self.meta.time_last_used); + } + if self.meta.time_password_changed > 0 + && self.meta.time_password_changed != older.meta.time_password_changed + { + delta.time_password_changed = Some(self.meta.time_password_changed); + } + + if self.meta.times_used > 0 && self.meta.times_used != older.meta.times_used { + delta.times_used = self.meta.times_used - older.meta.times_used; + } + + Ok(delta) + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod tests { + use super::*; + use crate::encryption::test_utils::TEST_ENCDEC; + use nss::ensure_initialized; + + #[test] + fn test_invalid_payload_timestamps() { + ensure_initialized(); + #[allow(clippy::unreadable_literal)] + let bad_timestamp = 18446732429235952000u64; + let bad_payload = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "timeCreated": bad_timestamp, + "timeLastUsed": "some other garbage", + "timePasswordChanged": -30, // valid i64 but negative + })); + let login = SyncLoginData::from_bso(bad_payload, &*TEST_ENCDEC) + .unwrap() + .inbound + .unwrap() + .login; + assert_eq!(login.meta.time_created, 0); + assert_eq!(login.meta.time_last_used, 0); + assert_eq!(login.meta.time_password_changed, 0); + + let now64 = util::system_time_ms_i64(std::time::SystemTime::now()); + let good_payload = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "formSubmitURL": "https://www.example.com/submit", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "timeCreated": now64 - 100, + "timeLastUsed": now64 - 50, + "timePasswordChanged": now64 - 25, + })); + + let login = SyncLoginData::from_bso(good_payload, &*TEST_ENCDEC) + .unwrap() + .inbound + .unwrap() + .login; + + assert_eq!(login.meta.time_created, now64 - 100); + assert_eq!(login.meta.time_last_used, now64 - 50); + assert_eq!(login.meta.time_password_changed, now64 - 25); + } +} diff --git a/third_party/rust/logins/src/sync/mod.rs b/third_party/rust/logins/src/sync/mod.rs @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod engine; +pub(crate) mod merge; +mod payload; +mod update_plan; + +pub use engine::LoginsSyncEngine; +use payload::{IncomingLogin, LoginPayload}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(u8)] +pub(crate) enum SyncStatus { + Synced = 0, + Changed = 1, + New = 2, +} diff --git a/third_party/rust/logins/src/sync/payload.rs b/third_party/rust/logins/src/sync/payload.rs @@ -0,0 +1,436 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Login entry from a server payload +// +// This struct is used for fetching/sending login records to the server. There are a number +// of differences between this and the top-level Login struct; some fields are renamed, some are +// locally encrypted, etc. +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::login::ValidateAndFixup; +use crate::SecureLoginFields; +use crate::{EncryptedLogin, LoginEntry, LoginFields, LoginMeta}; +use serde_derive::*; +use sync15::bso::OutgoingBso; +use sync_guid::Guid; + +type UnknownFields = serde_json::Map<String, serde_json::Value>; + +trait UnknownFieldsExt { + fn encrypt(&self, encdec: &dyn EncryptorDecryptor) -> Result<String>; + fn decrypt(ciphertext: &str, encdec: &dyn EncryptorDecryptor) -> Result<Self> + where + Self: Sized; +} + +impl UnknownFieldsExt for UnknownFields { + fn encrypt(&self, encdec: &dyn EncryptorDecryptor) -> Result<String> { + let string = serde_json::to_string(&self)?; + let cipherbytes = encdec + .encrypt(string.as_bytes().into()) + .map_err(|e| Error::EncryptionFailed(e.to_string()))?; + let ciphertext = std::str::from_utf8(&cipherbytes) + .map_err(|e| Error::EncryptionFailed(e.to_string()))?; + Ok(ciphertext.to_owned()) + } + + fn decrypt(ciphertext: &str, encdec: &dyn EncryptorDecryptor) -> Result<Self> { + let jsonbytes = encdec + .decrypt(ciphertext.as_bytes().into()) + .map_err(|e| Error::DecryptionFailed(e.to_string()))?; + let json = + std::str::from_utf8(&jsonbytes).map_err(|e| Error::DecryptionFailed(e.to_string()))?; + Ok(serde_json::from_str(json)?) + } +} + +/// What we get from the server after parsing the payload. We need to round-trip "unknown" +/// fields, but don't want to carry them around in `EncryptedLogin`. +#[derive(Debug)] +pub(super) struct IncomingLogin { + pub login: EncryptedLogin, + // An encrypted UnknownFields, or None if there are none. + pub unknown: Option<String>, +} + +impl IncomingLogin { + pub fn guid(&self) -> Guid { + self.login.guid() + } + + pub(super) fn from_incoming_payload( + p: LoginPayload, + encdec: &dyn EncryptorDecryptor, + ) -> Result<Self> { + let original_fields = LoginFields { + origin: p.hostname, + form_action_origin: p.form_submit_url, + http_realm: p.http_realm, + username_field: p.username_field, + password_field: p.password_field, + }; + let original_sec_fields = SecureLoginFields { + username: p.username, + password: p.password, + }; + // we do a bit of a dance here to maybe_fixup() the fields via LoginEntry + let original_login_entry = LoginEntry::new(original_fields, original_sec_fields); + let login_entry = original_login_entry + .maybe_fixup()? + .unwrap_or(original_login_entry); + let fields = LoginFields { + origin: login_entry.origin, + form_action_origin: login_entry.form_action_origin, + http_realm: login_entry.http_realm, + username_field: login_entry.username_field, + password_field: login_entry.password_field, + }; + let id = String::from(p.guid); + let sec_fields = SecureLoginFields { + username: login_entry.username, + password: login_entry.password, + } + .encrypt(encdec, &id)?; + + // We handle NULL in the DB for migrated databases and it's wasteful + // to encrypt the common case of an empty map, so... + let unknown = if p.unknown_fields.is_empty() { + None + } else { + Some(p.unknown_fields.encrypt(encdec)?) + }; + + // If we can't fix the parts we keep the invalid bits. + Ok(Self { + login: EncryptedLogin { + meta: LoginMeta { + id, + time_created: p.time_created, + time_password_changed: p.time_password_changed, + time_last_used: p.time_last_used, + times_used: p.times_used, + }, + fields, + sec_fields, + }, + unknown, + }) + } +} + +/// The JSON payload that lives on the storage servers. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct LoginPayload { + #[serde(rename = "id")] + pub guid: Guid, + + // This is 'origin' in our Login struct. + pub hostname: String, + + // This is 'form_action_origin' in our Login struct. + // rename_all = "camelCase" by default will do formSubmitUrl, but we can just + // override this one field. + #[serde(rename = "formSubmitURL")] + #[serde(skip_serializing_if = "Option::is_none")] + pub form_submit_url: Option<String>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub http_realm: Option<String>, + + #[serde(default)] + pub username: String, + + pub password: String, + + #[serde(default)] + pub username_field: String, + + #[serde(default)] + pub password_field: String, + + #[serde(default)] + #[serde(deserialize_with = "deserialize_timestamp")] + pub time_created: i64, + + #[serde(default)] + #[serde(deserialize_with = "deserialize_timestamp")] + pub time_password_changed: i64, + + #[serde(default)] + #[serde(deserialize_with = "deserialize_timestamp")] + pub time_last_used: i64, + + #[serde(default)] + pub times_used: i64, + + // Additional "unknown" round-tripped fields. + #[serde(flatten)] + unknown_fields: UnknownFields, +} + +// These probably should be on the payload itself, but one refactor at a time! +impl EncryptedLogin { + pub fn into_bso( + self, + encdec: &dyn EncryptorDecryptor, + enc_unknown_fields: Option<String>, + ) -> Result<OutgoingBso> { + let unknown_fields = match enc_unknown_fields { + Some(s) => UnknownFields::decrypt(&s, encdec)?, + None => Default::default(), + }; + let sec_fields = SecureLoginFields::decrypt(&self.sec_fields, encdec, &self.meta.id)?; + Ok(OutgoingBso::from_content_with_id( + crate::sync::LoginPayload { + guid: self.guid(), + hostname: self.fields.origin, + form_submit_url: self.fields.form_action_origin, + http_realm: self.fields.http_realm, + username_field: self.fields.username_field, + password_field: self.fields.password_field, + username: sec_fields.username, + password: sec_fields.password, + time_created: self.meta.time_created, + time_password_changed: self.meta.time_password_changed, + time_last_used: self.meta.time_last_used, + times_used: self.meta.times_used, + unknown_fields, + }, + )?) + } +} + +// Quiet clippy, since this function is passed to deserialiaze_with... +#[allow(clippy::unnecessary_wraps)] +fn deserialize_timestamp<'de, D>(deserializer: D) -> std::result::Result<i64, D::Error> +where + D: serde::de::Deserializer<'de>, +{ + use serde::de::Deserialize; + // Invalid and negative timestamps are all replaced with 0. Eventually we + // should investigate replacing values that are unreasonable but still fit + // in an i64 (a date 1000 years in the future, for example), but + // appropriately handling that is complex. + Ok(i64::deserialize(deserializer).unwrap_or_default().max(0)) +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod tests { + use super::*; + use crate::encryption::test_utils::{encrypt_struct, TEST_ENCDEC}; + use crate::sync::merge::SyncLoginData; + use crate::{EncryptedLogin, LoginFields, LoginMeta, SecureLoginFields}; + use sync15::bso::IncomingBso; + + #[test] + fn test_payload_to_login() { + let bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "httpRealm": "test", + "hostname": "https://www.example.com", + "username": "user", + "password": "password", + })); + let login = IncomingLogin::from_incoming_payload( + bso.into_content::<LoginPayload>().content().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap() + .login; + assert_eq!(login.meta.id, "123412341234"); + assert_eq!(login.fields.http_realm, Some("test".to_string())); + assert_eq!(login.fields.origin, "https://www.example.com"); + assert_eq!(login.fields.form_action_origin, None); + let sec_fields = login.decrypt_fields(&*TEST_ENCDEC).unwrap(); + assert_eq!(sec_fields.username, "user"); + assert_eq!(sec_fields.password, "password"); + } + + // formSubmitURL (now formActionOrigin) being an empty string is a valid + // legacy case that is supported on desktop, we should ensure we are as well + // https://searchfox.org/mozilla-central/rev/32c74afbb24dce4b5dd6b33be71197e615631d71/toolkit/components/passwordmgr/test/unit/test_logins_change.js#183-184 + #[test] + fn test_payload_empty_form_action_to_login() { + let bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "formSubmitURL": "", + "hostname": "https://www.example.com", + "username": "user", + "password": "password", + })); + let login = IncomingLogin::from_incoming_payload( + bso.into_content::<LoginPayload>().content().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap() + .login; + assert_eq!(login.meta.id, "123412341234"); + assert_eq!(login.fields.form_action_origin, Some("".to_string())); + assert_eq!(login.fields.http_realm, None); + assert_eq!(login.fields.origin, "https://www.example.com"); + let sec_fields = login.decrypt_fields(&*TEST_ENCDEC).unwrap(); + assert_eq!(sec_fields.username, "user"); + assert_eq!(sec_fields.password, "password"); + + let bso = login.into_bso(&*TEST_ENCDEC, None).unwrap(); + assert_eq!(bso.envelope.id, "123412341234"); + let payload_data: serde_json::Value = serde_json::from_str(&bso.payload).unwrap(); + assert_eq!(payload_data["httpRealm"], serde_json::Value::Null); + assert_eq!(payload_data["formSubmitURL"], "".to_string()); + } + + #[test] + fn test_payload_unknown_fields() { + // No "unknown" fields. + let bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "httpRealm": "test", + "hostname": "https://www.example.com", + "username": "user", + "password": "password", + })); + let payload = bso.into_content::<LoginPayload>().content().unwrap(); + assert!(payload.unknown_fields.is_empty()); + + // An unknown "foo" + let bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "httpRealm": "test", + "hostname": "https://www.example.com", + "username": "user", + "password": "password", + "foo": "bar", + })); + let payload = bso.into_content::<LoginPayload>().content().unwrap(); + assert_eq!(payload.unknown_fields.len(), 1); + assert_eq!( + payload.unknown_fields.get("foo").unwrap().as_str().unwrap(), + "bar" + ); + // re-serialize it. + let unknown = Some(encrypt_struct::<UnknownFields>(&payload.unknown_fields)); + let login = IncomingLogin::from_incoming_payload(payload, &*TEST_ENCDEC) + .unwrap() + .login; + // The raw outgoing payload should have it back. + let outgoing = login.into_bso(&*TEST_ENCDEC, unknown).unwrap(); + let json = + serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(&outgoing.payload) + .unwrap(); + assert_eq!(json.get("foo").unwrap().as_str().unwrap(), "bar"); + } + + #[test] + fn test_form_submit_payload_to_login() { + let bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "hostname": "https://www.example.com", + "formSubmitURL": "https://www.example.com", + "usernameField": "username-field", + "username": "user", + "password": "password", + })); + let login = IncomingLogin::from_incoming_payload( + bso.into_content::<LoginPayload>().content().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap() + .login; + assert_eq!(login.meta.id, "123412341234"); + assert_eq!(login.fields.http_realm, None); + assert_eq!(login.fields.origin, "https://www.example.com"); + assert_eq!( + login.fields.form_action_origin, + Some("https://www.example.com".to_string()) + ); + assert_eq!(login.fields.username_field, "username-field"); + let sec_fields = login.decrypt_fields(&*TEST_ENCDEC).unwrap(); + assert_eq!(sec_fields.username, "user"); + assert_eq!(sec_fields.password, "password"); + } + + #[test] + fn test_login_into_payload() { + let login = EncryptedLogin { + meta: LoginMeta { + id: "123412341234".into(), + ..Default::default() + }, + fields: LoginFields { + http_realm: Some("test".into()), + origin: "https://www.example.com".into(), + ..Default::default() + }, + sec_fields: encrypt_struct(&SecureLoginFields { + username: "user".into(), + password: "password".into(), + }), + }; + let bso = login.into_bso(&*TEST_ENCDEC, None).unwrap(); + assert_eq!(bso.envelope.id, "123412341234"); + let payload_data: serde_json::Value = serde_json::from_str(&bso.payload).unwrap(); + assert_eq!(payload_data["httpRealm"], "test".to_string()); + assert_eq!(payload_data["hostname"], "https://www.example.com"); + assert_eq!(payload_data["username"], "user"); + assert_eq!(payload_data["password"], "password"); + assert!(matches!( + payload_data["formActionOrigin"], + serde_json::Value::Null + )); + } + + #[test] + fn test_username_field_requires_a_form_target() { + let bad_json = serde_json::json!({ + "id": "123412341234", + "httpRealm": "test", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "usernameField": "invalid" + }); + let bad_bso = IncomingBso::from_test_content(bad_json.clone()); + + // Incoming sync data gets fixed automatically. + let login = IncomingLogin::from_incoming_payload( + bad_bso.into_content::<LoginPayload>().content().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap() + .login; + assert_eq!(login.fields.username_field, ""); + + // SyncLoginData::from_payload also fixes up. + let bad_bso = IncomingBso::from_test_content(bad_json); + let login = SyncLoginData::from_bso(bad_bso, &*TEST_ENCDEC) + .unwrap() + .inbound + .unwrap() + .login; + assert_eq!(login.fields.username_field, ""); + } + + #[test] + fn test_password_field_requires_a_form_target() { + let bad_bso = IncomingBso::from_test_content(serde_json::json!({ + "id": "123412341234", + "httpRealm": "test", + "hostname": "https://www.example.com", + "username": "test", + "password": "test", + "passwordField": "invalid" + })); + + let login = IncomingLogin::from_incoming_payload( + bad_bso.into_content::<LoginPayload>().content().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap() + .login; + assert_eq!(login.fields.password_field, ""); + } +} diff --git a/third_party/rust/logins/src/sync/update_plan.rs b/third_party/rust/logins/src/sync/update_plan.rs @@ -0,0 +1,653 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use super::merge::{LocalLogin, MirrorLogin}; +use super::{IncomingLogin, SyncStatus}; +use crate::encryption::EncryptorDecryptor; +use crate::error::*; +use crate::util; +use interrupt_support::SqlInterruptScope; +use rusqlite::{named_params, Connection}; +use std::time::SystemTime; +use sync15::ServerTimestamp; +use sync_guid::Guid; + +#[derive(Default, Debug)] +pub(super) struct UpdatePlan { + pub delete_mirror: Vec<Guid>, + pub delete_local: Vec<Guid>, + pub local_updates: Vec<MirrorLogin>, + // the bool is the `is_overridden` flag, the i64 is ServerTimestamp in millis + pub mirror_inserts: Vec<(IncomingLogin, i64, bool)>, + pub mirror_updates: Vec<(IncomingLogin, i64)>, +} + +impl UpdatePlan { + pub fn plan_two_way_merge( + &mut self, + local: LocalLogin, + upstream: (IncomingLogin, ServerTimestamp), + ) { + match &local { + LocalLogin::Tombstone { .. } => { + debug!(" ignoring local tombstone, inserting into mirror"); + self.delete_local.push(upstream.0.guid()); + self.plan_mirror_insert(upstream.0, upstream.1, false); + } + LocalLogin::Alive { login, .. } => { + debug!(" Conflicting record without shared parent, using newer"); + let is_override = + login.meta.time_password_changed > upstream.0.login.meta.time_password_changed; + self.plan_mirror_insert(upstream.0, upstream.1, is_override); + if !is_override { + self.delete_local.push(login.guid()); + } + } + } + } + + pub fn plan_three_way_merge( + &mut self, + local: LocalLogin, + shared: MirrorLogin, + upstream: IncomingLogin, + upstream_time: ServerTimestamp, + server_now: ServerTimestamp, + encdec: &dyn EncryptorDecryptor, + ) -> Result<()> { + let local_age = SystemTime::now() + .duration_since(local.local_modified()) + .unwrap_or_default(); + let remote_age = server_now.duration_since(upstream_time).unwrap_or_default(); + + let delta = { + let upstream_delta = upstream.login.delta(&shared.login, encdec)?; + match local { + LocalLogin::Tombstone { .. } => { + // If the login was deleted locally, the merged delta is the + // upstream delta. We do this because a user simultaneously deleting their + // login and updating it has two possible outcomes: + // - A login that was intended to be deleted remains because another update was + // there + // - A login that was intended to be updated got deleted + // + // The second case is arguably worse, where a user could lose their login + // indefinitely + // So, just like desktop, this acts as though the local login doesn't exist at all. + upstream_delta + } + LocalLogin::Alive { login, .. } => { + let local_delta = login.delta(&shared.login, encdec)?; + local_delta.merge(upstream_delta, remote_age < local_age) + } + } + }; + + // Update mirror to upstream + self.mirror_updates + .push((upstream, upstream_time.as_millis())); + let mut new = shared; + + new.login.apply_delta(delta, encdec)?; + new.server_modified = upstream_time; + self.local_updates.push(new); + Ok(()) + } + + pub fn plan_delete(&mut self, id: Guid) { + self.delete_local.push(id.clone()); + self.delete_mirror.push(id); + } + + pub fn plan_mirror_update(&mut self, upstream: IncomingLogin, time: ServerTimestamp) { + self.mirror_updates.push((upstream, time.as_millis())); + } + + pub fn plan_mirror_insert( + &mut self, + upstream: IncomingLogin, + time: ServerTimestamp, + is_override: bool, + ) { + self.mirror_inserts + .push((upstream, time.as_millis(), is_override)); + } + + fn perform_deletes(&self, conn: &Connection, scope: &SqlInterruptScope) -> Result<()> { + sql_support::each_chunk(&self.delete_local, |chunk, _| -> Result<()> { + conn.execute( + &format!( + "DELETE FROM loginsL WHERE guid IN ({vars})", + vars = sql_support::repeat_sql_vars(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + scope.err_if_interrupted()?; + Ok(()) + })?; + + sql_support::each_chunk(&self.delete_mirror, |chunk, _| { + conn.execute( + &format!( + "DELETE FROM loginsM WHERE guid IN ({vars})", + vars = sql_support::repeat_sql_vars(chunk.len()) + ), + rusqlite::params_from_iter(chunk), + )?; + Ok(()) + }) + } + + // These aren't batched but probably should be. + fn perform_mirror_updates(&self, conn: &Connection, scope: &SqlInterruptScope) -> Result<()> { + let sql = " + UPDATE loginsM + SET server_modified = :server_modified, + enc_unknown_fields = :enc_unknown_fields, + httpRealm = :http_realm, + formActionOrigin = :form_action_origin, + usernameField = :username_field, + passwordField = :password_field, + origin = :origin, + secFields = :sec_fields, + -- Avoid zeroes if the remote has been overwritten by an older client. + timesUsed = coalesce(nullif(:times_used, 0), timesUsed), + timeLastUsed = coalesce(nullif(:time_last_used, 0), timeLastUsed), + timePasswordChanged = coalesce(nullif(:time_password_changed, 0), timePasswordChanged), + timeCreated = coalesce(nullif(:time_created, 0), timeCreated) + WHERE guid = :guid + "; + let mut stmt = conn.prepare_cached(sql)?; + for (upstream, timestamp) in &self.mirror_updates { + let login = &upstream.login; + trace!("Updating mirror {:?}", login.guid_str()); + stmt.execute(named_params! { + ":server_modified": *timestamp, + ":enc_unknown_fields": upstream.unknown, + ":http_realm": login.fields.http_realm, + ":form_action_origin": login.fields.form_action_origin, + ":username_field": login.fields.username_field, + ":password_field": login.fields.password_field, + ":origin": login.fields.origin, + ":times_used": login.meta.times_used, + ":time_last_used": login.meta.time_last_used, + ":time_password_changed": login.meta.time_password_changed, + ":time_created": login.meta.time_created, + ":guid": login.guid_str(), + ":sec_fields": login.sec_fields, + })?; + scope.err_if_interrupted()?; + } + Ok(()) + } + + fn perform_mirror_inserts(&self, conn: &Connection, scope: &SqlInterruptScope) -> Result<()> { + let sql = " + INSERT OR IGNORE INTO loginsM ( + is_overridden, + server_modified, + enc_unknown_fields, + + httpRealm, + formActionOrigin, + usernameField, + passwordField, + origin, + secFields, + + timesUsed, + timeLastUsed, + timePasswordChanged, + timeCreated, + + guid + ) VALUES ( + :is_overridden, + :server_modified, + :enc_unknown_fields, + + :http_realm, + :form_action_origin, + :username_field, + :password_field, + :origin, + :sec_fields, + + :times_used, + :time_last_used, + :time_password_changed, + :time_created, + + :guid + )"; + let mut stmt = conn.prepare_cached(sql)?; + + for (upstream, timestamp, is_overridden) in &self.mirror_inserts { + let login = &upstream.login; + trace!("Inserting mirror {:?}", login.guid_str()); + stmt.execute(named_params! { + ":is_overridden": *is_overridden, + ":server_modified": *timestamp, + ":enc_unknown_fields": upstream.unknown, + ":http_realm": login.fields.http_realm, + ":form_action_origin": login.fields.form_action_origin, + ":username_field": login.fields.username_field, + ":password_field": login.fields.password_field, + ":origin": login.fields.origin, + ":times_used": login.meta.times_used, + ":time_last_used": login.meta.time_last_used, + ":time_password_changed": login.meta.time_password_changed, + ":time_created": login.meta.time_created, + ":guid": login.guid_str(), + ":sec_fields": login.sec_fields, + })?; + scope.err_if_interrupted()?; + } + Ok(()) + } + + fn perform_local_updates(&self, conn: &Connection, scope: &SqlInterruptScope) -> Result<()> { + let sql = format!( + "UPDATE loginsL + SET local_modified = :local_modified, + httpRealm = :http_realm, + formActionOrigin = :form_action_origin, + usernameField = :username_field, + passwordField = :password_field, + timeLastUsed = :time_last_used, + timePasswordChanged = :time_password_changed, + timesUsed = :times_used, + origin = :origin, + secFields = :sec_fields, + sync_status = {changed}, + is_deleted = 0 + WHERE guid = :guid", + changed = SyncStatus::Changed as u8 + ); + let mut stmt = conn.prepare_cached(&sql)?; + // XXX OutgoingChangeset should no longer have timestamp. + let local_ms: i64 = util::system_time_ms_i64(SystemTime::now()); + for l in &self.local_updates { + trace!("Updating local {:?}", l.guid_str()); + stmt.execute(named_params! { + ":local_modified": local_ms, + ":http_realm": l.login.fields.http_realm, + ":form_action_origin": l.login.fields.form_action_origin, + ":username_field": l.login.fields.username_field, + ":password_field": l.login.fields.password_field, + ":origin": l.login.fields.origin, + ":time_last_used": l.login.meta.time_last_used, + ":time_password_changed": l.login.meta.time_password_changed, + ":times_used": l.login.meta.times_used, + ":guid": l.guid_str(), + ":sec_fields": l.login.sec_fields, + })?; + scope.err_if_interrupted()?; + } + Ok(()) + } + + pub fn execute(&self, conn: &Connection, scope: &SqlInterruptScope) -> Result<()> { + debug!( + "UpdatePlan: deleting {} records...", + self.delete_local.len() + ); + self.perform_deletes(conn, scope)?; + debug!( + "UpdatePlan: Updating {} existing mirror records...", + self.mirror_updates.len() + ); + self.perform_mirror_updates(conn, scope)?; + debug!( + "UpdatePlan: Inserting {} new mirror records...", + self.mirror_inserts.len() + ); + self.perform_mirror_inserts(conn, scope)?; + debug!( + "UpdatePlan: Updating {} reconciled local records...", + self.local_updates.len() + ); + self.perform_local_updates(conn, scope)?; + Ok(()) + } +} + +#[cfg(not(feature = "keydb"))] +#[cfg(test)] +mod tests { + use nss::ensure_initialized; + use std::time::Duration; + + use super::*; + use crate::db::test_utils::{ + check_local_login, check_mirror_login, get_local_guids, get_mirror_guids, + get_server_modified, insert_encrypted_login, insert_login, + }; + use crate::db::LoginDb; + use crate::encryption::test_utils::TEST_ENCDEC; + use crate::login::test_utils::enc_login; + + fn inc_login(id: &str, password: &str) -> crate::sync::IncomingLogin { + IncomingLogin { + login: enc_login(id, password), + unknown: Default::default(), + } + } + + #[test] + fn test_deletes() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + insert_login(&db, "login1", Some("password"), Some("password")); + insert_login(&db, "login2", Some("password"), Some("password")); + insert_login(&db, "login3", Some("password"), Some("password")); + insert_login(&db, "login4", Some("password"), Some("password")); + + UpdatePlan { + delete_mirror: vec![Guid::new("login1"), Guid::new("login2")], + delete_local: vec![Guid::new("login2"), Guid::new("login3")], + ..UpdatePlan::default() + } + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + + assert_eq!(get_local_guids(&db), vec!["login1", "login4"]); + assert_eq!(get_mirror_guids(&db), vec!["login3", "login4"]); + } + + #[test] + fn test_mirror_updates() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + insert_login(&db, "unchanged", None, Some("password")); + insert_login(&db, "changed", None, Some("password")); + insert_login( + &db, + "changed2", + Some("new-local-password"), + Some("password"), + ); + let initial_modified = get_server_modified(&db, "unchanged"); + + UpdatePlan { + mirror_updates: vec![ + (inc_login("changed", "new-password"), 20000), + (inc_login("changed2", "new-password2"), 21000), + ], + ..UpdatePlan::default() + } + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + check_mirror_login(&db, "unchanged", "password", initial_modified, false); + check_mirror_login(&db, "changed", "new-password", 20000, false); + check_mirror_login(&db, "changed2", "new-password2", 21000, true); + } + + #[test] + fn test_mirror_inserts() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + UpdatePlan { + mirror_inserts: vec![ + (inc_login("login1", "new-password"), 20000, false), + (inc_login("login2", "new-password2"), 21000, true), + ], + ..UpdatePlan::default() + } + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + check_mirror_login(&db, "login1", "new-password", 20000, false); + check_mirror_login(&db, "login2", "new-password2", 21000, true); + } + + #[test] + fn test_local_updates() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + insert_login(&db, "login", Some("password"), Some("password")); + let before_update = util::system_time_ms_i64(SystemTime::now()); + + UpdatePlan { + local_updates: vec![MirrorLogin { + login: enc_login("login", "new-password"), + server_modified: ServerTimestamp(10000), + }], + ..UpdatePlan::default() + } + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + check_local_login(&db, "login", "new-password", before_update); + } + + #[test] + fn test_plan_three_way_merge_server_wins() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + // First we create our expected logins + let login = enc_login("login", "old local password"); + let mirror_login = enc_login("login", "mirror password"); + let server_login = enc_login("login", "new upstream password"); + + // Then, we create a new, empty update plan + let mut update_plan = UpdatePlan::default(); + // Here, we define all the timestamps, remember, if difference between the + // upstream record timestamp and the server timestamp is less than the + // difference between the local record timestamp and time **now** then the server wins. + // + // In other words, if server_time - upstream_time < now - local_record_time then the server + // wins. This is because we determine which record to "prefer" based on the "age" of the + // update + let now = SystemTime::now(); + // local record's timestamps is now - 100 second, so the local age is 100 + let local_modified = now.checked_sub(Duration::from_secs(100)).unwrap(); + // mirror timestamp is not too relevant here, but we set it for completeness + let mirror_timestamp = now.checked_sub(Duration::from_secs(1000)).unwrap(); + // Server's timestamp is now + let server_timestamp = now; + // Server's record timestamp is now - 1 second, so the server age is: 1 + // And since the local age is 100, then the server should win. + let server_record_timestamp = now.checked_sub(Duration::from_secs(1)).unwrap(); + let local_login = LocalLogin::Alive { + login: login.clone(), + local_modified, + }; + + let mirror_login = MirrorLogin { + login: mirror_login, + server_modified: mirror_timestamp.try_into().unwrap(), + }; + + // Lets make sure our local login is in the database, so that it can be updated later + insert_encrypted_login( + &db, + &login, + &mirror_login.login, + &mirror_login.server_modified, + ); + let upstream_login = IncomingLogin { + login: server_login, + unknown: None, + }; + + update_plan + .plan_three_way_merge( + local_login, + mirror_login, + upstream_login, + server_record_timestamp.try_into().unwrap(), + server_timestamp.try_into().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap(); + update_plan + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + + check_local_login(&db, "login", "new upstream password", 0); + } + + #[test] + fn test_plan_three_way_merge_local_wins() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + // First we create our expected logins + let login = enc_login("login", "new local password"); + let mirror_login = enc_login("login", "mirror password"); + let server_login = enc_login("login", "old upstream password"); + + // Then, we create a new, empty update plan + let mut update_plan = UpdatePlan::default(); + // Here, we define all the timestamps, remember, if difference between the + // upstream record timestamp and the server timestamp is less than the + // difference between the local record timestamp and time **now** then the server wins. + // + // In other words, if server_time - upstream_time < now - local_record_time then the server + // wins. This is because we determine which record to "prefer" based on the "age" of the + // update + let now = SystemTime::now(); + // local record's timestamps is now - 1 second, so the local age is 1 + let local_modified = now.checked_sub(Duration::from_secs(1)).unwrap(); + // mirror timestamp is not too relevant here, but we set it for completeness + let mirror_timestamp = now.checked_sub(Duration::from_secs(1000)).unwrap(); + // Server's timestamp is now + let server_timestamp = now; + // Server's record timestamp is now - 500 second, so the server age is: 500 + // And since the local age is 1, the local record should win! + let server_record_timestamp = now.checked_sub(Duration::from_secs(500)).unwrap(); + let local_login = LocalLogin::Alive { + login: login.clone(), + local_modified, + }; + let mirror_login = MirrorLogin { + login: mirror_login, + server_modified: mirror_timestamp.try_into().unwrap(), + }; + + // Lets make sure our local login is in the database, so that it can be updated later + insert_encrypted_login( + &db, + &login, + &mirror_login.login, + &mirror_login.server_modified, + ); + + let upstream_login = IncomingLogin { + login: server_login, + unknown: None, + }; + + update_plan + .plan_three_way_merge( + local_login, + mirror_login, + upstream_login, + server_record_timestamp.try_into().unwrap(), + server_timestamp.try_into().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap(); + update_plan + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + + check_local_login(&db, "login", "new local password", 0); + } + + #[test] + fn test_plan_three_way_merge_local_tombstone_loses() { + ensure_initialized(); + let db = LoginDb::open_in_memory(); + // First we create our expected logins + let login = enc_login("login", "new local password"); + let mirror_login = enc_login("login", "mirror password"); + let server_login = enc_login("login", "old upstream password"); + + // Then, we create a new, empty update plan + let mut update_plan = UpdatePlan::default(); + // Here, we define all the timestamps, remember, if difference between the + // upstream record timestamp and the server timestamp is less than the + // difference between the local record timestamp and time **now** then the server wins. + // + // In other words, if server_time - upstream_time < now - local_record_time then the server + // wins. This is because we determine which record to "prefer" based on the "age" of the + // update + let now = SystemTime::now(); + // local record's timestamps is now - 1 second, so the local age is 1 + let local_modified = now.checked_sub(Duration::from_secs(1)).unwrap(); + // mirror timestamp is not too relevant here, but we set it for completeness + let mirror_timestamp = now.checked_sub(Duration::from_secs(1000)).unwrap(); + // Server's timestamp is now + let server_timestamp = now; + // Server's record timestamp is now - 500 second, so the server age is: 500 + // And since the local age is 1, the local record should win! + let server_record_timestamp = now.checked_sub(Duration::from_secs(500)).unwrap(); + let mirror_login = MirrorLogin { + login: mirror_login, + server_modified: mirror_timestamp.try_into().unwrap(), + }; + + // Lets make sure our local login is in the database, so that it can be updated later + insert_encrypted_login( + &db, + &login, + &mirror_login.login, + &mirror_login.server_modified, + ); + + // Now, lets delete our local login + db.delete("login").unwrap(); + + // Then, lets set our tombstone + let local_login = LocalLogin::Tombstone { + id: login.meta.id.clone(), + local_modified, + }; + + let upstream_login = IncomingLogin { + login: server_login, + unknown: None, + }; + + update_plan + .plan_three_way_merge( + local_login, + mirror_login, + upstream_login, + server_record_timestamp.try_into().unwrap(), + server_timestamp.try_into().unwrap(), + &*TEST_ENCDEC, + ) + .unwrap(); + update_plan + .execute(&db, &db.begin_interrupt_scope().unwrap()) + .unwrap(); + + // Now we verify that even though our login deletion was "younger" + // then the upstream modification, the upstream modification wins because + // modifications always beat tombstones + check_local_login(&db, "login", "old upstream password", 0); + } + + #[test] + fn test_plan_two_way_merge_local_tombstone_loses() { + ensure_initialized(); + let mut update_plan = UpdatePlan::default(); + // Ensure the local tombstone is newer than the incoming - it still loses. + let local = LocalLogin::Tombstone { + id: "login-id".to_string(), + local_modified: SystemTime::now(), + }; + let incoming = IncomingLogin { + login: enc_login("login-id", "new local password"), + unknown: None, + }; + + update_plan.plan_two_way_merge(local, (incoming, ServerTimestamp::from_millis(1234))); + + // Plan should be to apply the incoming. + assert_eq!(update_plan.mirror_inserts.len(), 1); + assert_eq!(update_plan.delete_local.len(), 1); + assert_eq!(update_plan.delete_mirror.len(), 0); + } +} diff --git a/third_party/rust/logins/src/util.rs b/third_party/rust/logins/src/util.rs @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use rusqlite::Row; +use std::time; +use url::Url; + +pub fn url_host_port(url_str: &str) -> Option<String> { + let url = Url::parse(url_str).ok()?; + let host = url.host_str()?; + Some(if let Some(p) = url.port() { + format!("{}:{}", host, p) + } else { + host.to_string() + }) +} + +pub fn system_time_millis_from_row(row: &Row<'_>, col_name: &str) -> Result<time::SystemTime> { + let time_ms = row.get::<_, Option<i64>>(col_name)?.unwrap_or_default() as u64; + Ok(time::UNIX_EPOCH + time::Duration::from_millis(time_ms)) +} + +pub fn duration_ms_i64(d: time::Duration) -> i64 { + (d.as_secs() as i64) * 1000 + (i64::from(d.subsec_nanos()) / 1_000_000) +} + +pub fn system_time_ms_i64(t: time::SystemTime) -> i64 { + duration_ms_i64(t.duration_since(time::UNIX_EPOCH).unwrap_or_default()) +} + +#[cfg(test)] +pub(crate) fn init_test_logging() { + use std::sync::Once; + static INIT_LOGGING: Once = Once::new(); + INIT_LOGGING.call_once(|| { + error_support::init_for_tests_with_level(error_support::Level::Trace); + }); +} diff --git a/third_party/rust/logins/uniffi.toml b/third_party/rust/logins/uniffi.toml @@ -0,0 +1,6 @@ +[bindings.kotlin] +package_name = "mozilla.appservices.logins" + +[bindings.swift] +ffi_module_name = "MozillaRustComponents" +ffi_module_filename = "loginsFFI" diff --git a/third_party/rust/nss/.cargo-checksum.json b/third_party/rust/nss/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"a02789df36131f32a60b54968c08b6cb77b75735011d2d4a8932b4f538ddd139","README.md":"14dd59e435d179c21c3b4b880bbe3cc6e5999b9f9ac9431f3f9aa3f43902e3fa","src/aes.rs":"bf3b115fecfc445fed978f43fed4076249c99d72db203acacd8297f418c347e5","src/cert.rs":"8195da7dc86bb9f60306106be08e622d0a116dabdbd31967e227435933ee50d0","src/ec.rs":"c495042a6f92254b7c9941ef0e253340922b0c1d1c43c7d3e725aa1068ae5d0b","src/ecdh.rs":"4acddfaebbc43f4e59c9dd0df56e582f5d0db65c4fd15dcc634c2e27d84efc2c","src/error.rs":"58a923bb8651160bb17c582cf876046792e79f3a190c8572f836b218f16cee74","src/lib.rs":"862ae2d8dbbe29f83579209286198b19bdccdcd81b99e55646d25de874a76d13","src/pbkdf2.rs":"40d5facfdc434571455283265823dd2b0334d2a8db0a09b50ee05d5b1f2a02d7","src/pk11/context.rs":"b4927fe401ed113d79f03aed1c0d9a007d3ce3b3706921ebc3e239e1f472dad6","src/pk11/mod.rs":"d78368654f9a8bc12f1403c4a096b63cf9834820ea6ed48418b9afaa0fc2299e","src/pk11/slot.rs":"99cb603b6d561b86d7655ca33da4aa0e4fb355d065f56d1bfc22b0778a745989","src/pk11/sym_key.rs":"28c01518126a2460c14266fad3dfcbbf50a6bbf4d40bfbf66d1b9d9ae47b47da","src/pk11/types.rs":"010e926224d29c9fe12d8804add17e2130f4c383bc8186ac1dad08d16678ae4e","src/pkixc.rs":"939fd8bd84be5eef57c6e9a970e1509e8cb94566ad42f1427a3beaaa214cc62b","src/secport.rs":"99a2c5112939bda2558dd7f0760f1092ab42052871448181083f92ce56f73f05","src/util.rs":"5d19265429cb707dc51a7b712ae6f5dd013db0975d215a314a31e8110902f4a5"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/nss/Cargo.toml b/third_party/rust/nss/Cargo.toml @@ -0,0 +1,51 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "nss" +version = "0.1.0" +authors = ["Sync Team <sync-team@mozilla.com>"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = "README.md" +license = "MPL-2.0" + +[features] +backtrace = ["error-support/backtrace"] +default = [] +gecko = ["nss_sys/gecko"] +keydb = ["dep:once_cell"] + +[lib] +name = "nss" +crate-type = ["lib"] +path = "src/lib.rs" + +[dependencies] +base64 = "0.21" +serde = "1" +serde_derive = "1" +thiserror = "2" + +[dependencies.error-support] +path = "../../error" + +[dependencies.nss_sys] +path = "nss_sys" + +[dependencies.once_cell] +version = "1.20.2" +optional = true diff --git a/third_party/rust/nss/README.md b/third_party/rust/nss/README.md @@ -0,0 +1,21 @@ +## nss + +This crate provides various cryptographic routines backed by +[NSS](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS). + +The API is designed to operate at approximately the same level of abstraction as the +[`crypto.subtle`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) API, although the details are obviously +different given the different host language. It provides: + +* Cryptographically secure [pseudorandom number generation](./src/pk11/slot.rs). +* Cryptographic [digests](./src/pk11/context.rs) and [hkdf](./src/pk11/sym_key.rs). +* [AES encryption and decryption](./src/aes.rs) in various modes. +* Generation, import and export of [elliptic-curve keys](./src/ec.rs). +* ECDH [key agreement](./src/ecdh.rs). +* Constant-time [string comparison](./src/secport.rs). + +Like the `crypto.subtle` API, these primitives are quite low-level and involve some subtlety in order to use correctly. +Consumers should prefer the higher-level abstractions offered by the [rc_crypto](../) crate where possible. + +These features are in turn built on even-lower-level bindings to the raw NSS API, provided by the [nss_sys](./nss_sys) +crate. diff --git a/third_party/rust/nss/src/aes.rs b/third_party/rust/nss/src/aes.rs @@ -0,0 +1,116 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + error::*, + pk11::sym_key::import_sym_key, + util::{assert_nss_initialized, map_nss_secstatus, ScopedPtr}, +}; +use std::{ + mem, + os::raw::{c_uchar, c_uint}, +}; + +const AES_GCM_TAG_LENGTH: usize = 16; + +#[derive(Debug, Copy, Clone)] +pub enum Operation { + Encrypt, + Decrypt, +} + +pub fn aes_gcm_crypt( + key: &[u8], + nonce: &[u8], + aad: &[u8], + data: &[u8], + operation: Operation, +) -> Result<Vec<u8>> { + let mut gcm_params = nss_sys::CK_GCM_PARAMS { + pIv: nonce.as_ptr() as nss_sys::CK_BYTE_PTR, + ulIvLen: nss_sys::CK_ULONG::try_from(nonce.len())?, + ulIvBits: nss_sys::CK_ULONG::try_from( + nonce.len().checked_mul(8).ok_or(ErrorKind::InternalError)?, + )?, + pAAD: aad.as_ptr() as nss_sys::CK_BYTE_PTR, + ulAADLen: nss_sys::CK_ULONG::try_from(aad.len())?, + ulTagBits: nss_sys::CK_ULONG::try_from(AES_GCM_TAG_LENGTH * 8)?, + }; + let mut params = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: &mut gcm_params as *mut _ as *mut c_uchar, + len: c_uint::try_from(mem::size_of::<nss_sys::CK_GCM_PARAMS>())?, + }; + common_crypt( + nss_sys::CKM_AES_GCM.into(), + key, + data, + AES_GCM_TAG_LENGTH, + &mut params, + operation, + ) +} + +pub fn aes_cbc_crypt( + key: &[u8], + nonce: &[u8], + data: &[u8], + operation: Operation, +) -> Result<Vec<u8>> { + let mut params = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: nonce.as_ptr() as *mut c_uchar, + len: c_uint::try_from(nonce.len())?, + }; + common_crypt( + nss_sys::CKM_AES_CBC_PAD.into(), + key, + data, + usize::try_from(nss_sys::AES_BLOCK_SIZE)?, // CBC mode might pad the result. + &mut params, + operation, + ) +} + +pub fn common_crypt( + mech: nss_sys::CK_MECHANISM_TYPE, + key: &[u8], + data: &[u8], + extra_data_len: usize, + params: &mut nss_sys::SECItem, + operation: Operation, +) -> Result<Vec<u8>> { + assert_nss_initialized(); + // Most of the following code is inspired by the Firefox WebCrypto implementation: + // https://searchfox.org/mozilla-central/rev/f46e2bf881d522a440b30cbf5cf8d76fc212eaf4/dom/crypto/WebCryptoTask.cpp#566 + // CKA_ENCRYPT always is fine. + let sym_key = import_sym_key(mech, nss_sys::CKA_ENCRYPT.into(), key)?; + // Initialize the output buffer (enough space for padding / a full tag). + let result_max_len = data + .len() + .checked_add(extra_data_len) + .ok_or(ErrorKind::InternalError)?; + let mut out_len: c_uint = 0; + let mut out = vec![0u8; result_max_len]; + let result_max_len_uint = c_uint::try_from(result_max_len)?; + let data_len = c_uint::try_from(data.len())?; + let f = match operation { + Operation::Decrypt => nss_sys::PK11_Decrypt, + Operation::Encrypt => nss_sys::PK11_Encrypt, + }; + map_nss_secstatus(|| unsafe { + f( + sym_key.as_mut_ptr(), + mech, + params, + out.as_mut_ptr(), + &mut out_len, + result_max_len_uint, + data.as_ptr(), + data_len, + ) + })?; + out.truncate(usize::try_from(out_len)?); + Ok(out) +} diff --git a/third_party/rust/nss/src/cert.rs b/third_party/rust/nss/src/cert.rs @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use crate::pk11::types::{Certificate, PublicKey}; +use crate::util::{assert_nss_initialized, sec_item_as_slice, ScopedPtr}; +use nss_sys::{CERT_ExtractPublicKey, CERT_GetDefaultCertDB, CERT_NewTempCertificate}; + +pub fn extract_ec_public_key(der: &[u8]) -> Result<Vec<u8>> { + assert_nss_initialized(); + + let certdb = unsafe { CERT_GetDefaultCertDB() }; + let mut data = nss_sys::SECItem { + len: u32::try_from(der.len())?, + data: der.as_ptr() as *mut u8, + type_: nss_sys::SECItemType::siBuffer as u32, + }; + + let cert = unsafe { + Certificate::from_ptr(CERT_NewTempCertificate( + certdb, + &mut data, + std::ptr::null_mut(), + nss_sys::PR_FALSE, + nss_sys::PR_TRUE, + ))? + }; + + let pub_key = unsafe { PublicKey::from_ptr(CERT_ExtractPublicKey(cert.as_mut_ptr()))? }; + let pub_key_raw = unsafe { &*pub_key.as_ptr() }; + + if pub_key_raw.keyType != nss_sys::KeyType::ecKey as u32 { + return Err( + ErrorKind::InputError("public key is not of type EC (Elliptic Curve).".into()).into(), + ); + } + + let mut pub_key_data = unsafe { pub_key_raw.u.ec.publicValue }; + let pub_key_data_raw = unsafe { sec_item_as_slice(&mut pub_key_data)? }; + + Ok(pub_key_data_raw.to_vec()) +} diff --git a/third_party/rust/nss/src/ec.rs b/third_party/rust/nss/src/ec.rs @@ -0,0 +1,422 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + error::*, + pk11::{ + self, + context::HashAlgorithm, + slot, + types::{Pkcs11Object, PrivateKey as PK11PrivateKey, PublicKey as PK11PublicKey}, + }, + util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr}, +}; +use serde_derive::{Deserialize, Serialize}; +use std::{ + mem, + ops::Deref, + os::raw::{c_uchar, c_uint, c_void}, + ptr, +}; + +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Curve { + P256, + P384, +} + +impl Curve { + pub fn get_field_len(&self) -> u32 { + match &self { + Curve::P256 => 32, + Curve::P384 => 48, + } + } +} + +const CRV_P256: &str = "P-256"; +const CRV_P384: &str = "P-384"; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EcKey { + curve: String, + // The `d` value of the EC Key. + private_key: Vec<u8>, + // The uncompressed x,y-representation of the public component of the EC Key. + public_key: Vec<u8>, +} + +impl EcKey { + pub fn new(curve: Curve, private_key: &[u8], public_key: &[u8]) -> Self { + let curve = match curve { + Curve::P256 => CRV_P256, + Curve::P384 => CRV_P384, + }; + Self { + curve: curve.to_owned(), + private_key: private_key.to_vec(), + public_key: public_key.to_vec(), + } + } + + pub fn from_coordinates(curve: Curve, d: &[u8], x: &[u8], y: &[u8]) -> Result<Self> { + let ec_point = create_ec_point_for_coordinates(x, y)?; + Ok(EcKey::new(curve, d, &ec_point)) + } + + pub fn curve(&self) -> Curve { + if self.curve == CRV_P256 { + return Curve::P256; + } else if self.curve == CRV_P384 { + return Curve::P384; + } + unimplemented!("It is impossible to create a curve object with a different CRV.") + } + + pub fn public_key(&self) -> &[u8] { + &self.public_key + } + + pub fn private_key(&self) -> &[u8] { + &self.private_key + } +} + +fn create_ec_point_for_coordinates(x: &[u8], y: &[u8]) -> Result<Vec<u8>> { + if x.len() != y.len() { + return Err(ErrorKind::InternalError.into()); + } + let mut buf = vec![0u8; x.len() + y.len() + 1]; + buf[0] = u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)?; + let mut offset = 1; + buf[offset..offset + x.len()].copy_from_slice(x); + offset += x.len(); + buf[offset..offset + y.len()].copy_from_slice(y); + Ok(buf) +} + +pub fn generate_keypair(curve: Curve) -> Result<(PrivateKey, PublicKey)> { + assert_nss_initialized(); + // 1. Create EC params + let params_buf = create_ec_params_for_curve(curve)?; + let mut params = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: params_buf.as_ptr() as *mut c_uchar, + len: c_uint::try_from(params_buf.len())?, + }; + + // 2. Generate the key pair + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/f46e2bf881d522a440b30cbf5cf8d76fc212eaf4/dom/crypto/WebCryptoTask.cpp#2389 + let mech = nss_sys::CKM_EC_KEY_PAIR_GEN; + let slot = slot::get_internal_slot()?; + let mut pub_key: *mut nss_sys::SECKEYPublicKey = ptr::null_mut(); + let prv_key = PrivateKey::from(curve, unsafe { + PK11PrivateKey::from_ptr(nss_sys::PK11_GenerateKeyPair( + slot.as_mut_ptr(), + mech.into(), + &mut params as *mut _ as *mut c_void, + &mut pub_key, + nss_sys::PR_FALSE, + nss_sys::PR_FALSE, + ptr::null_mut(), + ))? + }); + let pub_key = PublicKey::from(curve, unsafe { PK11PublicKey::from_ptr(pub_key)? }); + Ok((prv_key, pub_key)) +} + +pub struct PrivateKey { + curve: Curve, + wrapped: PK11PrivateKey, +} + +impl Deref for PrivateKey { + type Target = PK11PrivateKey; + #[inline] + fn deref(&self) -> &PK11PrivateKey { + &self.wrapped + } +} + +impl PrivateKey { + pub fn convert_to_public_key(&self) -> Result<PublicKey> { + let mut pub_key = self.wrapped.convert_to_public_key()?; + + // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1562046. + let field_len = self.curve.get_field_len(); + let expected_len = 2 * field_len + 1; + let mut pub_value = unsafe { (*pub_key.as_ptr()).u.ec.publicValue }; + if pub_value.len == expected_len - 2 { + let old_pub_value_raw = unsafe { sec_item_as_slice(&mut pub_value)?.to_vec() }; + let mut new_pub_value_raw = vec![0u8; usize::try_from(expected_len)?]; + new_pub_value_raw[0] = u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)?; + new_pub_value_raw[1] = u8::try_from(old_pub_value_raw.len())?; + new_pub_value_raw[2..].copy_from_slice(&old_pub_value_raw); + pub_key = PublicKey::from_bytes(self.curve, &new_pub_value_raw)?.wrapped; + } + Ok(PublicKey { + wrapped: pub_key, + curve: self.curve, + }) + } + + #[inline] + pub(crate) fn from(curve: Curve, key: PK11PrivateKey) -> Self { + Self { + curve, + wrapped: key, + } + } + + pub fn curve(&self) -> Curve { + self.curve + } + + pub fn private_value(&self) -> Result<Vec<u8>> { + let mut private_value = self.read_raw_attribute(nss_sys::CKA_VALUE.into()).unwrap(); + let private_key = unsafe { sec_item_as_slice(private_value.as_mut_ref())?.to_vec() }; + Ok(private_key) + } + + fn from_nss_params( + curve: Curve, + ec_params: &[u8], + ec_point: &[u8], + private_value: &[u8], + ) -> Result<Self> { + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/444ee13e14fe30451651c0f62b3979c76766ada4/dom/crypto/CryptoKey.cpp#322 + // These explicit variable type declarations are *VERY* important, as we pass to NSS a pointer to them + // and we need these variables to be of the right size! + let mut private_key_value: nss_sys::CK_OBJECT_CLASS = nss_sys::CKO_PRIVATE_KEY.into(); + let mut false_value: nss_sys::CK_BBOOL = nss_sys::CK_FALSE; + let mut ec_value: nss_sys::CK_KEY_TYPE = nss_sys::CKK_EC.into(); + let bbool_size = mem::size_of::<nss_sys::CK_BBOOL>(); + let key_template = vec![ + ck_attribute( + nss_sys::CKA_CLASS.into(), + &mut private_key_value as *mut _ as *mut c_void, + mem::size_of::<nss_sys::CK_OBJECT_CLASS>(), + )?, + ck_attribute( + nss_sys::CKA_KEY_TYPE.into(), + &mut ec_value as *mut _ as *mut c_void, + mem::size_of::<nss_sys::CK_KEY_TYPE>(), + )?, + ck_attribute( + nss_sys::CKA_TOKEN.into(), + &mut false_value as *mut _ as *mut c_void, + bbool_size, + )?, + ck_attribute( + nss_sys::CKA_SENSITIVE.into(), + &mut false_value as *mut _ as *mut c_void, + bbool_size, + )?, + ck_attribute( + nss_sys::CKA_PRIVATE.into(), + &mut false_value as *mut _ as *mut c_void, + bbool_size, + )?, + // PrivateKeyFromPrivateKeyTemplate sets the ID. + ck_attribute(nss_sys::CKA_ID.into(), ptr::null_mut(), 0)?, + ck_attribute( + nss_sys::CKA_EC_PARAMS.into(), + ec_params.as_ptr() as *mut c_void, + ec_params.len(), + )?, + ck_attribute( + nss_sys::CKA_EC_POINT.into(), + ec_point.as_ptr() as *mut c_void, + ec_point.len(), + )?, + ck_attribute( + nss_sys::CKA_VALUE.into(), + private_value.as_ptr() as *mut c_void, + private_value.len(), + )?, + ]; + Ok(Self::from( + curve, + PK11PrivateKey::from_private_key_template(key_template)?, + )) + } + + pub fn import(ec_key: &EcKey) -> Result<Self> { + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/66086345467c69685434dd1c5177b30a7511b1a5/dom/crypto/CryptoKey.cpp#652 + assert_nss_initialized(); + let curve = ec_key.curve(); + let ec_params = create_ec_params_for_curve(curve)?; + Self::from_nss_params(curve, &ec_params, &ec_key.public_key, &ec_key.private_key) + } + + pub fn export(&self) -> Result<EcKey> { + let public_key = self.convert_to_public_key()?; + let public_key_bytes = public_key.to_bytes()?; + let private_key_bytes = self.private_value()?; + Ok(EcKey::new( + self.curve, + &private_key_bytes, + &public_key_bytes, + )) + } +} + +#[inline] +fn ck_attribute( + r#type: nss_sys::CK_ATTRIBUTE_TYPE, + p_value: nss_sys::CK_VOID_PTR, + value_len: usize, +) -> Result<nss_sys::CK_ATTRIBUTE> { + Ok(nss_sys::CK_ATTRIBUTE { + type_: r#type, + pValue: p_value, + ulValueLen: nss_sys::CK_ULONG::try_from(value_len)?, + }) +} + +pub struct PublicKey { + curve: Curve, + wrapped: PK11PublicKey, +} + +impl Deref for PublicKey { + type Target = PK11PublicKey; + #[inline] + fn deref(&self) -> &PK11PublicKey { + &self.wrapped + } +} + +impl PublicKey { + #[inline] + pub(crate) fn from(curve: Curve, key: PK11PublicKey) -> Self { + Self { + curve, + wrapped: key, + } + } + + pub fn curve(&self) -> Curve { + self.curve + } + + /// ECDSA verify operation + pub fn verify( + &self, + message: &[u8], + signature: &[u8], + hash_algorithm: HashAlgorithm, + ) -> Result<()> { + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/b2716c233e9b4398fc5923cbe150e7f83c7c6c5b/dom/crypto/WebCryptoTask.cpp#1144 + let signature = nss_sys::SECItem { + len: u32::try_from(signature.len())?, + data: signature.as_ptr() as *mut u8, + type_: 0, + }; + let hash = pk11::context::hash_buf(&hash_algorithm, message)?; + let hash = nss_sys::SECItem { + len: u32::try_from(hash.len())?, + data: hash.as_ptr() as *mut u8, + type_: 0, + }; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_VerifyWithMechanism( + self.as_mut_ptr(), + nss_sys::PK11_MapSignKeyType((*self.wrapped.as_ptr()).keyType), + ptr::null(), + &signature, + &hash, + ptr::null_mut(), + ) + })?; + Ok(()) + } + + pub fn to_bytes(&self) -> Result<Vec<u8>> { + // Some public keys we create do not have an associated PCKS#11 slot + // therefore we cannot use `read_raw_attribute(CKA_EC_POINT)` + // so we read the `publicValue` field directly instead. + let mut ec_point = unsafe { (*self.as_ptr()).u.ec.publicValue }; + let public_key = unsafe { sec_item_as_slice(&mut ec_point)?.to_vec() }; + check_pub_key_bytes(&public_key, self.curve)?; + Ok(public_key) + } + + pub fn from_bytes(curve: Curve, bytes: &[u8]) -> Result<PublicKey> { + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/ec489aa170b6486891cf3625717d6fa12bcd11c1/dom/crypto/CryptoKey.cpp#1078 + check_pub_key_bytes(bytes, curve)?; + let key_data = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: bytes.as_ptr() as *mut c_uchar, + len: c_uint::try_from(bytes.len())?, + }; + let params_buf = create_ec_params_for_curve(curve)?; + let params = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: params_buf.as_ptr() as *mut c_uchar, + len: c_uint::try_from(params_buf.len())?, + }; + + let pub_key = nss_sys::SECKEYPublicKey { + arena: ptr::null_mut(), + keyType: nss_sys::KeyType::ecKey as u32, + pkcs11Slot: ptr::null_mut(), + pkcs11ID: nss_sys::CK_INVALID_HANDLE.into(), + u: nss_sys::SECKEYPublicKeyStr_u { + ec: nss_sys::SECKEYECPublicKey { + DEREncodedParams: params, + publicValue: key_data, + encoding: nss_sys::ECPointEncoding::ECPoint_Uncompressed as u32, + size: 0, + }, + }, + }; + Ok(Self::from(curve, unsafe { + PK11PublicKey::from_ptr(nss_sys::SECKEY_CopyPublicKey(&pub_key))? + })) + } +} + +fn check_pub_key_bytes(bytes: &[u8], curve: Curve) -> Result<()> { + let field_len = curve.get_field_len(); + // Check length of uncompressed point coordinates. There are 2 field elements + // and a leading "point form" octet (which must be EC_POINT_FORM_UNCOMPRESSED). + if bytes.len() != usize::try_from(2 * field_len + 1)? { + return Err(ErrorKind::InternalError.into()); + } + // No support for compressed points. + if bytes[0] != u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)? { + return Err(ErrorKind::InternalError.into()); + } + Ok(()) +} + +fn create_ec_params_for_curve(curve: Curve) -> Result<Vec<u8>> { + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/ec489aa170b6486891cf3625717d6fa12bcd11c1/dom/crypto/WebCryptoCommon.h#299 + let curve_oid_tag = match curve { + Curve::P256 => nss_sys::SECOidTag::SEC_OID_SECG_EC_SECP256R1, + Curve::P384 => nss_sys::SECOidTag::SEC_OID_SECG_EC_SECP384R1, + }; + // Retrieve curve data by OID tag. + let oid_data = unsafe { nss_sys::SECOID_FindOIDByTag(curve_oid_tag as u32) }; + if oid_data.is_null() { + return Err(ErrorKind::InternalError.into()); + } + // Set parameters + let oid_data_len = unsafe { (*oid_data).oid.len }; + let mut buf = vec![0u8; usize::try_from(oid_data_len)? + 2]; + buf[0] = c_uchar::try_from(nss_sys::SEC_ASN1_OBJECT_ID)?; + buf[1] = c_uchar::try_from(oid_data_len)?; + let oid_data_data = + unsafe { std::slice::from_raw_parts((*oid_data).oid.data, usize::try_from(oid_data_len)?) }; + buf[2..].copy_from_slice(oid_data_data); + Ok(buf) +} diff --git a/third_party/rust/nss/src/ecdh.rs b/third_party/rust/nss/src/ecdh.rs @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + ec::{PrivateKey, PublicKey}, + error::*, + pk11::types::SymKey, + util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr}, +}; + +pub fn ecdh_agreement(priv_key: &PrivateKey, pub_key: &PublicKey) -> Result<Vec<u8>> { + assert_nss_initialized(); + if priv_key.curve() != pub_key.curve() { + return Err(ErrorKind::InternalError.into()); + } + // The following code is adapted from: + // https://searchfox.org/mozilla-central/rev/444ee13e14fe30451651c0f62b3979c76766ada4/dom/crypto/WebCryptoTask.cpp#2835 + + // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the + // derived symmetric key and don't matter because we ignore them anyway. + let sym_key = unsafe { + SymKey::from_ptr(nss_sys::PK11_PubDeriveWithKDF( + priv_key.as_mut_ptr(), + pub_key.as_mut_ptr(), + nss_sys::PR_FALSE, + std::ptr::null_mut(), + std::ptr::null_mut(), + nss_sys::CKM_ECDH1_DERIVE.into(), + nss_sys::CKM_SHA512_HMAC.into(), + nss_sys::CKA_SIGN.into(), + 0, + nss_sys::CKD_NULL.into(), + std::ptr::null_mut(), + std::ptr::null_mut(), + ))? + }; + + map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?; + + // This doesn't leak, because the SECItem* returned by PK11_GetKeyData + // just refers to a buffer managed by `sym_key` which we copy into `buf`. + let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) }; + let buf = unsafe { sec_item_as_slice(&mut key_data)? }; + Ok(buf.to_vec()) +} diff --git a/third_party/rust/nss/src/error.rs b/third_party/rust/nss/src/error.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[derive(Debug, thiserror::Error)] +pub enum ErrorKind { + #[error("NSS error: {0} {1}")] + NSSError(i32, String), + #[error("SSL error: {0} {1}")] + SSLError(i32, String), + #[error("PKIX error: {0} {1}")] + PKIXError(i32, String), + #[error("Input or format error: {0}")] + InputError(String), + #[error("Internal crypto error")] + InternalError, + #[error("invalid key length")] + InvalidKeyLength, + #[error("Interior nul byte was found")] + NulError, + #[error("Conversion error: {0}")] + ConversionError(#[from] std::num::TryFromIntError), + #[error("Base64 decode error: {0}")] + Base64Decode(#[from] base64::DecodeError), + #[error("Certificate issuer does not match")] + CertificateIssuerError, + #[error("Certificate subject does not match")] + CertificateSubjectError, + #[error("Certificate not yet valid or expired")] + CertificateValidityError, +} + +error_support::define_error! { + ErrorKind { + (Base64Decode, base64::DecodeError), + (ConversionError, std::num::TryFromIntError), + } +} diff --git a/third_party/rust/nss/src/lib.rs b/third_party/rust/nss/src/lib.rs @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![allow(unknown_lints)] +#![warn(rust_2018_idioms)] +#[macro_use] +mod util; +pub mod aes; +pub mod cert; +pub mod ec; +pub mod ecdh; +mod error; +pub mod pbkdf2; +pub mod pk11; +pub mod pkixc; +pub mod secport; +pub use crate::error::{Error, ErrorKind, Result}; +pub use util::assert_nss_initialized as assert_initialized; +pub use util::ensure_nss_initialized as ensure_initialized; + +#[cfg(feature = "keydb")] +pub use util::ensure_nss_initialized_with_profile_dir as ensure_initialized_with_profile_dir; diff --git a/third_party/rust/nss/src/pbkdf2.rs b/third_party/rust/nss/src/pbkdf2.rs @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr}; +use crate::{ + error::*, + pk11::{ + slot::get_internal_slot, + types::{AlgorithmID, SymKey}, + }, +}; + +// Expose for consumers to choose the hashing algorithm +// Currently only SHA256 supported +pub use crate::pk11::context::HashAlgorithm; +use nss_sys::SECOidTag; + +// ***** BASED ON THE FOLLOWING IMPLEMENTATION ***** +// https://searchfox.org/mozilla-central/rev/8ccea36c4fb09412609fb738c722830d7098602b/dom/crypto/WebCryptoTask.cpp#2567 + +pub fn pbkdf2_key_derive( + password: &[u8], + salt: &[u8], + iterations: u32, + hash_algorithm: HashAlgorithm, + out: &mut [u8], +) -> Result<()> { + assert_nss_initialized(); + let oid_tag = match hash_algorithm { + HashAlgorithm::SHA256 => SECOidTag::SEC_OID_HMAC_SHA256 as u32, + HashAlgorithm::SHA384 => SECOidTag::SEC_OID_HMAC_SHA384 as u32, + }; + let mut sec_salt = nss_sys::SECItem { + len: u32::try_from(salt.len())?, + data: salt.as_ptr() as *mut u8, + type_: 0, + }; + let alg_id = unsafe { + AlgorithmID::from_ptr(nss_sys::PK11_CreatePBEV2AlgorithmID( + SECOidTag::SEC_OID_PKCS5_PBKDF2 as u32, + SECOidTag::SEC_OID_HMAC_SHA1 as u32, + oid_tag, + i32::try_from(out.len())?, + i32::try_from(iterations)?, + &mut sec_salt as *mut nss_sys::SECItem, + ))? + }; + + let slot = get_internal_slot()?; + let mut sec_pw = nss_sys::SECItem { + len: u32::try_from(password.len())?, + data: password.as_ptr() as *mut u8, + type_: 0, + }; + let sym_key = unsafe { + SymKey::from_ptr(nss_sys::PK11_PBEKeyGen( + slot.as_mut_ptr(), + alg_id.as_mut_ptr(), + &mut sec_pw as *mut nss_sys::SECItem, + nss_sys::PR_FALSE, + std::ptr::null_mut(), + ))? + }; + map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?; + + // This doesn't leak, because the SECItem* returned by PK11_GetKeyData + // just refers to a buffer managed by `sym_key` which we copy into `buf` + let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) }; + let buf = unsafe { sec_item_as_slice(&mut key_data)? }; + // Stop panic in swap_with_slice by returning an error if the sizes mismatch + if buf.len() != out.len() { + return Err(ErrorKind::InternalError.into()); + } + out.swap_with_slice(buf); + Ok(()) +} diff --git a/third_party/rust/nss/src/pk11/context.rs b/third_party/rust/nss/src/pk11/context.rs @@ -0,0 +1,123 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + error::*, + pk11::{ + sym_key::import_sym_key, + types::{Context, SymKey}, + }, + util::{assert_nss_initialized, map_nss_secstatus, ScopedPtr}, +}; +use std::ptr; + +#[derive(Copy, Clone, Debug)] +#[repr(u8)] +pub enum HashAlgorithm { + SHA256, + SHA384, +} + +impl HashAlgorithm { + fn result_len(&self) -> u32 { + match self { + HashAlgorithm::SHA256 => nss_sys::SHA256_LENGTH, + HashAlgorithm::SHA384 => nss_sys::SHA384_LENGTH, + } + } + + fn as_hmac_mechanism(&self) -> u32 { + match self { + HashAlgorithm::SHA256 => nss_sys::CKM_SHA256_HMAC, + HashAlgorithm::SHA384 => nss_sys::CKM_SHA384_HMAC, + } + } + + pub(crate) fn as_hkdf_mechanism(&self) -> u32 { + match self { + HashAlgorithm::SHA256 => nss_sys::CKM_NSS_HKDF_SHA256, + HashAlgorithm::SHA384 => nss_sys::CKM_NSS_HKDF_SHA384, + } + } +} + +impl From<&HashAlgorithm> for nss_sys::SECOidTag { + fn from(alg: &HashAlgorithm) -> Self { + match alg { + HashAlgorithm::SHA256 => nss_sys::SECOidTag::SEC_OID_SHA256, + HashAlgorithm::SHA384 => nss_sys::SECOidTag::SEC_OID_SHA384, + } + } +} + +pub fn hash_buf(algorithm: &HashAlgorithm, data: &[u8]) -> Result<Vec<u8>> { + assert_nss_initialized(); + let result_len = usize::try_from(algorithm.result_len())?; + let mut out = vec![0u8; result_len]; + let data_len = i32::try_from(data.len())?; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_HashBuf( + Into::<nss_sys::SECOidTag>::into(algorithm) as u32, + out.as_mut_ptr(), + data.as_ptr(), + data_len, + ) + })?; + Ok(out) +} + +pub fn hmac_sign(digest_alg: &HashAlgorithm, sym_key_bytes: &[u8], data: &[u8]) -> Result<Vec<u8>> { + let mech = digest_alg.as_hmac_mechanism(); + let sym_key = import_sym_key(mech.into(), nss_sys::CKA_SIGN.into(), sym_key_bytes)?; + let context = create_context_by_sym_key(mech.into(), nss_sys::CKA_SIGN.into(), &sym_key)?; + hash_buf_with_context(&context, data) +} + +/// Similar to hash_buf except the consumer has to provide the digest context. +fn hash_buf_with_context(context: &Context, data: &[u8]) -> Result<Vec<u8>> { + assert_nss_initialized(); + map_nss_secstatus(|| unsafe { nss_sys::PK11_DigestBegin(context.as_mut_ptr()) })?; + let data_len = u32::try_from(data.len())?; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_DigestOp(context.as_mut_ptr(), data.as_ptr(), data_len) + })?; + // We allocate the maximum possible length for the out buffer then we'll + // slice it after nss fills `out_len`. + let mut out_len: u32 = 0; + let mut out = vec![0u8; nss_sys::HASH_LENGTH_MAX as usize]; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_DigestFinal( + context.as_mut_ptr(), + out.as_mut_ptr(), + &mut out_len, + nss_sys::HASH_LENGTH_MAX, + ) + })?; + out.truncate(usize::try_from(out_len)?); + Ok(out) +} + +/// Safe wrapper around PK11_CreateContextBySymKey that +/// de-allocates memory when the context goes out of +/// scope. +pub fn create_context_by_sym_key( + mechanism: nss_sys::CK_MECHANISM_TYPE, + operation: nss_sys::CK_ATTRIBUTE_TYPE, + sym_key: &SymKey, +) -> Result<Context> { + assert_nss_initialized(); + let param = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: ptr::null_mut(), + len: 0, + }; + unsafe { + Context::from_ptr(nss_sys::PK11_CreateContextBySymKey( + mechanism, + operation, + sym_key.as_mut_ptr(), + &param, + )) + } +} diff --git a/third_party/rust/nss/src/pk11/mod.rs b/third_party/rust/nss/src/pk11/mod.rs @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub mod context; +pub mod slot; +pub mod sym_key; +pub mod types; diff --git a/third_party/rust/nss/src/pk11/slot.rs b/third_party/rust/nss/src/pk11/slot.rs @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + error::*, + pk11::types::Slot, + util::{assert_nss_initialized, map_nss_secstatus, ScopedPtr}, +}; + +pub fn generate_random(data: &mut [u8]) -> Result<()> { + // `NSS_Init` will initialize the RNG with data from `/dev/urandom`. + assert_nss_initialized(); + let len = i32::try_from(data.len())?; + map_nss_secstatus(|| unsafe { nss_sys::PK11_GenerateRandom(data.as_mut_ptr(), len) })?; + Ok(()) +} + +/// Safe wrapper around `PK11_GetInternalSlot` that +/// de-allocates memory when the slot goes out of +/// scope. +pub(crate) fn get_internal_slot() -> Result<Slot> { + unsafe { Slot::from_ptr(nss_sys::PK11_GetInternalSlot()) } +} + +/// Safe wrapper around `PK11_GetInternalKeySlot` that +/// de-allocates memory when the slot goes out of +/// scope. +#[cfg(feature = "keydb")] +pub(crate) fn get_internal_key_slot() -> Result<Slot> { + unsafe { Slot::from_ptr(nss_sys::PK11_GetInternalKeySlot()) } +} diff --git a/third_party/rust/nss/src/pk11/sym_key.rs b/third_party/rust/nss/src/pk11/sym_key.rs @@ -0,0 +1,277 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[cfg(feature = "keydb")] +use crate::util::get_last_error; +use crate::{ + error::*, + pk11::{context::HashAlgorithm, slot, types::SymKey}, + util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr}, +}; +#[cfg(feature = "keydb")] +use std::ffi::{c_char, CString}; +use std::{ + mem, + os::raw::{c_uchar, c_uint, c_ulong}, + ptr, +}; + +pub fn hkdf_expand( + digest_alg: &HashAlgorithm, + key_bytes: &[u8], + info: &[u8], + len: usize, +) -> Result<Vec<u8>> { + assert_nss_initialized(); + let mech = digest_alg.as_hkdf_mechanism(); + // Most of the following code is inspired by the Firefox WebCrypto implementation: + // https://searchfox.org/mozilla-central/rev/ee3905439acbf81e9c829ece0b46d09d2fa26c5c/dom/crypto/WebCryptoTask.cpp#2530-2597 + // Except that we only do the expand part, which explains why we use null pointers below. + let mut hkdf_params = nss_sys::CK_NSS_HKDFParams { + bExtract: nss_sys::CK_FALSE, + pSalt: ptr::null_mut(), + ulSaltLen: 0, + bExpand: nss_sys::CK_TRUE, + pInfo: info.as_ptr() as *mut u8, + ulInfoLen: c_ulong::try_from(info.len())?, + }; + let mut params = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: &mut hkdf_params as *mut _ as *mut c_uchar, + len: u32::try_from(mem::size_of::<nss_sys::CK_NSS_HKDFParams>())?, + }; + let base_key = import_sym_key(mech.into(), nss_sys::CKA_WRAP.into(), key_bytes)?; + let derived_len = i32::try_from(len)?; + let sym_key = unsafe { + SymKey::from_ptr( + // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the + // derived symmetric key and don't matter because we ignore them anyway. + nss_sys::PK11_Derive( + base_key.as_mut_ptr(), + mech.into(), + &mut params, + nss_sys::CKM_SHA512_HMAC.into(), + nss_sys::CKA_SIGN.into(), + derived_len, + ), + )? + }; + map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?; + // SAFETY: This doesn't leak, because the SECItem* returned by PK11_GetKeyData just refers to a + // buffer managed by `sym_key` which we copy into `out`. + let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) }; + if u32::try_from(len)? > key_data.len { + return Err(ErrorKind::InternalError.into()); + } + let buf = unsafe { sec_item_as_slice(&mut key_data)? }; + Ok(buf.to_vec()) +} + +/// Safe wrapper around PK11_ImportSymKey that +/// de-allocates memory when the key goes out of +/// scope. +pub(crate) fn import_sym_key( + mechanism: nss_sys::CK_MECHANISM_TYPE, + operation: nss_sys::CK_ATTRIBUTE_TYPE, + buf: &[u8], +) -> Result<SymKey> { + assert_nss_initialized(); + let mut item = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: buf.as_ptr() as *mut c_uchar, + len: c_uint::try_from(buf.len())?, + }; + let slot = slot::get_internal_slot()?; + unsafe { + SymKey::from_ptr(nss_sys::PK11_ImportSymKey( + slot.as_mut_ptr(), + mechanism, + nss_sys::PK11Origin::PK11_OriginUnwrap as u32, + operation, + &mut item, + ptr::null_mut(), + )) + } +} + +/// Check weather a primary password has been set and NSS needs to be authenticated. +/// Only available with the `keydb` feature. +#[cfg(feature = "keydb")] +pub fn authentication_with_primary_password_is_needed() -> Result<bool> { + let slot = slot::get_internal_key_slot()?; + + unsafe { + Ok( + nss_sys::PK11_NeedLogin(slot.as_mut_ptr()) == nss_sys::PR_TRUE + && nss_sys::PK11_IsLoggedIn(slot.as_mut_ptr(), ptr::null_mut()) != nss_sys::PR_TRUE, + ) + } +} + +/// Authorize NSS key store against a user-provided primary password. +/// Only available with the `keydb` feature. +#[cfg(feature = "keydb")] +pub fn authenticate_with_primary_password(primary_password: &str) -> Result<bool> { + let slot = slot::get_internal_key_slot()?; + + let password_cstr = CString::new(primary_password).map_err(|_| ErrorKind::NulError)?; + unsafe { + Ok( + nss_sys::PK11_CheckUserPassword(slot.as_mut_ptr(), password_cstr.as_ptr()) + == nss_sys::SECStatus::SECSuccess, + ) + } +} + +/// Retrieve a key, identified by `name`, from the internal NSS key store. If none exists, create +/// one, persist, and return. +/// Only available with the `keydb` feature. +#[cfg(feature = "keydb")] +pub fn get_or_create_aes256_key(name: &str) -> Result<Vec<u8>> { + let sym_key = match get_aes256_key(name) { + Ok(sym_key) => sym_key, + Err(_) => create_aes256_key(name)?, + }; + let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) }; + if key_data.len != nss_sys::AES_256_KEY_LENGTH { + return Err(ErrorKind::InvalidKeyLength.into()); + } + let buf = unsafe { sec_item_as_slice(&mut key_data)? }; + // SAFETY: `to_vec` copies the data out before there's any chance for `sym_key` to be + // destroyed. + Ok(buf.to_vec()) +} + +#[cfg(feature = "keydb")] +fn get_aes256_key(name: &str) -> Result<SymKey> { + let slot = slot::get_internal_key_slot()?; + let name = CString::new(name).map_err(|_| ErrorKind::NulError)?; + let sym_key = unsafe { + SymKey::from_ptr(nss_sys::PK11_ListFixedKeysInSlot( + slot.as_mut_ptr(), + name.as_ptr() as *mut c_char, + ptr::null_mut(), + )) + }; + match sym_key { + Ok(sym_key) => { + // See + // https://searchfox.org/mozilla-central/source/security/manager/ssl/NSSKeyStore.cpp#163-201 + // Unfortunately we can't use PK11_ExtractKeyValue(symKey.get()) here because softoken + // marks all token objects of type CKO_SECRET_KEY as sensitive. So we have to wrap and + // unwrap symKey to obtain a non-sensitive copy of symKey as a session object. + let wrapping_key = unsafe { + SymKey::from_ptr(nss_sys::PK11_KeyGen( + slot.as_mut_ptr(), + nss_sys::CKM_AES_KEY_GEN, + ptr::null_mut(), + 16, + ptr::null_mut(), + )) + .map_err(|_| get_last_error())? + }; + let mut wrap_len = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: ptr::null_mut(), + len: 0, + }; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_WrapSymKey( + nss_sys::CKM_AES_KEY_WRAP_KWP, + ptr::null_mut(), + wrapping_key.as_mut_ptr(), + sym_key.as_mut_ptr(), + &mut wrap_len, + ) + }) + .map_err(|_| get_last_error())?; + // PK11_UnwrapSymKey takes an int keySize + if wrap_len.len > u32::MAX - 8 { + return Err(ErrorKind::InvalidKeyLength.into()); + } + // Allocate an extra 8 bytes for CKM_AES_KEY_WRAP_KWP overhead. + let wrapped_key = unsafe { + nss_sys::SECITEM_AllocItem(ptr::null_mut(), ptr::null_mut(), wrap_len.len + 8) + }; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_WrapSymKey( + nss_sys::CKM_AES_KEY_WRAP_KWP, + ptr::null_mut(), + wrapping_key.as_mut_ptr(), + sym_key.as_mut_ptr(), + wrapped_key, + ) + }) + .map_err(|_| get_last_error())?; + let sym_key = unsafe { + SymKey::from_ptr(nss_sys::PK11_UnwrapSymKey( + wrapping_key.as_mut_ptr(), + nss_sys::CKM_AES_KEY_WRAP_KWP, + ptr::null_mut(), + wrapped_key, + nss_sys::CKM_AES_GCM.into(), + (nss_sys::CKA_ENCRYPT | nss_sys::CKA_DECRYPT).into(), + wrap_len.len as i32, + )) + } + .map_err(|_| get_last_error())?; + + map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?; + Ok(sym_key) + } + Err(e) => Err(e), + } +} + +#[cfg(feature = "keydb")] +fn create_aes256_key(name: &str) -> Result<SymKey> { + let mut key_bytes: [u8; nss_sys::AES_256_KEY_LENGTH as usize] = + [0; nss_sys::AES_256_KEY_LENGTH as usize]; + map_nss_secstatus(|| unsafe { + nss_sys::PK11_GenerateRandom(key_bytes.as_mut_ptr(), nss_sys::AES_256_KEY_LENGTH as i32) + })?; + match import_and_persist_sym_key( + nss_sys::CKM_AES_GCM.into(), + nss_sys::PK11Origin::PK11_OriginGenerated, + (nss_sys::CKA_ENCRYPT | nss_sys::CKA_DECRYPT).into(), + &key_bytes, + ) { + Ok(sym_key) => { + let name = CString::new(name).map_err(|_| ErrorKind::NulError)?; + unsafe { nss_sys::PK11_SetSymKeyNickname(sym_key.as_mut_ptr(), name.as_ptr()) }; + Ok(sym_key) + } + Err(e) => Err(e), + } +} + +/// Safe wrapper around PK11_ImportSymKey that +/// de-allocates memory when the key goes out of +/// scope, and persists key in key4.db. +#[cfg(feature = "keydb")] +fn import_and_persist_sym_key( + mechanism: nss_sys::CK_MECHANISM_TYPE, + origin: nss_sys::PK11Origin, + operation: nss_sys::CK_ATTRIBUTE_TYPE, + buf: &[u8], +) -> Result<SymKey> { + let mut item = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: buf.as_ptr() as *mut c_uchar, + len: c_uint::try_from(buf.len())?, + }; + let slot = slot::get_internal_key_slot()?; + unsafe { + SymKey::from_ptr(nss_sys::PK11_ImportSymKeyWithFlags( + slot.as_mut_ptr(), + mechanism, + origin as u32, + operation, + &mut item, + nss_sys::CK_FLAGS::default(), + nss_sys::PR_TRUE, + ptr::null_mut(), + )) + } +} diff --git a/third_party/rust/nss/src/pk11/types.rs b/third_party/rust/nss/src/pk11/types.rs @@ -0,0 +1,229 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + error::*, + pk11::slot::{generate_random, get_internal_slot}, + util::{map_nss_secstatus, ScopedPtr}, +}; +use std::{ + ops::Deref, + os::raw::{c_int, c_uchar, c_uint, c_void}, + ptr, +}; + +scoped_ptr!(SymKey, nss_sys::PK11SymKey, nss_sys::PK11_FreeSymKey); +scoped_ptr!( + PrivateKey, + nss_sys::SECKEYPrivateKey, + nss_sys::SECKEY_DestroyPrivateKey +); +scoped_ptr!( + PublicKey, + nss_sys::SECKEYPublicKey, + nss_sys::SECKEY_DestroyPublicKey +); +scoped_ptr!( + GenericObject, + nss_sys::PK11GenericObject, + nss_sys::PK11_DestroyGenericObject +); + +scoped_ptr!( + Certificate, + nss_sys::CERTCertificate, + nss_sys::CERT_DestroyCertificate +); + +scoped_ptr!(Context, nss_sys::PK11Context, pk11_destroy_context_true); +scoped_ptr!(Slot, nss_sys::PK11SlotInfo, nss_sys::PK11_FreeSlot); + +scoped_ptr!( + AlgorithmID, + nss_sys::SECAlgorithmID, + secoid_destroy_algorithm_id_true +); + +#[inline] +unsafe fn secoid_destroy_algorithm_id_true(alg_id: *mut nss_sys::SECAlgorithmID) { + nss_sys::SECOID_DestroyAlgorithmID(alg_id, nss_sys::PR_TRUE); +} + +#[inline] +unsafe fn pk11_destroy_context_true(context: *mut nss_sys::PK11Context) { + nss_sys::PK11_DestroyContext(context, nss_sys::PR_TRUE); +} + +// Trait for types that have PCKS#11 attributes that are readable. See +// https://searchfox.org/mozilla-central/rev/8ed8474757695cdae047150a0eaf94a5f1c96dbe/security/nss/lib/pk11wrap/pk11pub.h#842-864 +/// # Safety +/// Unsafe since it needs to call [`nss_sys::PK11_ReadRawAttribute`] which is +/// a C NSS function, and thus inherently unsafe to call +pub(crate) unsafe trait Pkcs11Object: ScopedPtr { + const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType; + fn read_raw_attribute( + &self, + attribute_type: nss_sys::CK_ATTRIBUTE_TYPE, + ) -> Result<ScopedSECItem> { + let mut out_sec = ScopedSECItem::empty(nss_sys::SECItemType::siBuffer); + map_nss_secstatus(|| unsafe { + nss_sys::PK11_ReadRawAttribute( + Self::PK11_OBJECT_TYPE as u32, + self.as_mut_ptr() as *mut c_void, + attribute_type, + out_sec.as_mut_ref(), + ) + })?; + Ok(out_sec) + } +} + +unsafe impl Pkcs11Object for GenericObject { + const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypeGeneric; +} +unsafe impl Pkcs11Object for PrivateKey { + const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypePrivKey; +} +unsafe impl Pkcs11Object for PublicKey { + const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypePubKey; +} +unsafe impl Pkcs11Object for SymKey { + const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypeSymKey; +} + +// From https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/NSS_API_Guidelines#Thread_Safety: +// "Data structures that are read only, like SECKEYPublicKeys or PK11SymKeys, need not be protected." +unsafe impl Send for PrivateKey {} +unsafe impl Send for PublicKey {} + +impl PrivateKey { + pub fn convert_to_public_key(&self) -> Result<PublicKey> { + Ok(unsafe { PublicKey::from_ptr(nss_sys::SECKEY_ConvertToPublicKey(self.as_mut_ptr()))? }) + } + + // To protect against key ID collisions, PrivateKeyFromPrivateKeyTemplate + // generates a random ID for each key. The given template must contain an + // attribute slot for a key ID, but it must consist of a null pointer and have a + // length of 0. + pub(crate) fn from_private_key_template( + mut template: Vec<nss_sys::CK_ATTRIBUTE>, + ) -> Result<Self> { + // Generate a random 160-bit object ID. This ID must be unique. + let mut obj_id_buf = vec![0u8; 160 / 8]; + generate_random(&mut obj_id_buf)?; + let mut obj_id = nss_sys::SECItem { + type_: nss_sys::SECItemType::siBuffer as u32, + data: obj_id_buf.as_ptr() as *mut c_uchar, + len: c_uint::try_from(obj_id_buf.len())?, + }; + let slot = get_internal_slot()?; + let mut pre_existing_key = unsafe { + nss_sys::PK11_FindKeyByKeyID(slot.as_mut_ptr(), &mut obj_id, std::ptr::null_mut()) + }; + if !pre_existing_key.is_null() { + // Note that we can't just call SECKEY_DestroyPrivateKey here because that + // will destroy the PKCS#11 object that is backing a preexisting key (that + // we still have a handle on somewhere else in memory). If that object were + // destroyed, cryptographic operations performed by that other key would + // fail. + unsafe { + destroy_private_key_without_destroying_pkcs11_object(pre_existing_key); + } + // Try again with a new ID (but only once - collisions are very unlikely). + generate_random(&mut obj_id_buf)?; + pre_existing_key = unsafe { + nss_sys::PK11_FindKeyByKeyID(slot.as_mut_ptr(), &mut obj_id, std::ptr::null_mut()) + }; + if !pre_existing_key.is_null() { + unsafe { + destroy_private_key_without_destroying_pkcs11_object(pre_existing_key); + } + return Err(ErrorKind::InternalError.into()); + } + } + let template_len = c_int::try_from(template.len())?; + let id_attr: &mut nss_sys::CK_ATTRIBUTE = template + .iter_mut() + .find(|&&mut attr| { + attr.type_ == (nss_sys::CKA_ID as nss_sys::CK_ATTRIBUTE_TYPE) + && attr.pValue.is_null() + && attr.ulValueLen == 0 + }) + .ok_or(ErrorKind::InternalError)?; + id_attr.pValue = obj_id_buf.as_mut_ptr() as *mut c_void; + id_attr.ulValueLen = nss_sys::CK_ULONG::try_from(obj_id_buf.len())?; + // We use `PK11_CreateGenericObject` instead of `PK11_CreateManagedGenericObject` + // to leak the reference on purpose because `PK11_FindKeyByKeyID` will take + // ownership of it. + let _obj = unsafe { + GenericObject::from_ptr(nss_sys::PK11_CreateGenericObject( + slot.as_mut_ptr(), + template.as_mut_ptr(), + template_len, + nss_sys::PR_FALSE, + ))? + }; + // Have NSS translate the object to a private key. + Ok(unsafe { + PrivateKey::from_ptr(nss_sys::PK11_FindKeyByKeyID( + slot.as_mut_ptr(), + &mut obj_id, + std::ptr::null_mut(), + ))? + }) + } +} + +// This is typically used by functions receiving a pointer to an `out SECItem`, +// where we allocate the struct, but NSS allocates the elements it points to. +pub(crate) struct ScopedSECItem { + wrapped: nss_sys::SECItem, +} + +impl ScopedSECItem { + pub(crate) fn empty(r#type: nss_sys::SECItemType) -> Self { + ScopedSECItem { + wrapped: nss_sys::SECItem { + type_: r#type as u32, + data: ptr::null_mut(), + len: 0, + }, + } + } + + pub(crate) fn as_mut_ref(&mut self) -> &mut nss_sys::SECItem { + &mut self.wrapped + } +} + +impl Deref for ScopedSECItem { + type Target = nss_sys::SECItem; + #[inline] + fn deref(&self) -> &nss_sys::SECItem { + &self.wrapped + } +} + +impl Drop for ScopedSECItem { + fn drop(&mut self) { + unsafe { + // PR_FALSE asks the NSS allocator not to free the SECItem + // itself, and just the pointee of `self.wrapped.data`. + nss_sys::SECITEM_FreeItem(&mut self.wrapped, nss_sys::PR_FALSE); + } + } +} + +// This helper function will release the memory backing a SECKEYPrivateKey and +// any resources acquired in its creation. It will leave the backing PKCS#11 +// object untouched, however. This should only be called from +// PrivateKeyFromPrivateKeyTemplate. +// From: https://searchfox.org/mozilla-central/rev/444ee13e14fe30451651c0f62b3979c76766ada4/dom/crypto/CryptoKey.cpp#80 +unsafe fn destroy_private_key_without_destroying_pkcs11_object( + key: *mut nss_sys::SECKEYPrivateKey, +) { + assert!(!key.is_null()); + nss_sys::PK11_FreeSlot((*key).pkcs11Slot); + nss_sys::PORT_FreeArena((*key).arena, nss_sys::PR_TRUE); +} diff --git a/third_party/rust/nss/src/pkixc.rs b/third_party/rust/nss/src/pkixc.rs @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use crate::util::assert_nss_initialized; + +use nss_sys::PRErrorCode; + +// NSS error codes. +// https://searchfox.org/mozilla-central/rev/352b525/security/nss/lib/util/secerr.h#29 +const SEC_ERROR_BASE: i32 = -0x2000; // -8192 +const SEC_ERROR_EXPIRED_CERTIFICATE: i32 = SEC_ERROR_BASE + 11; +const SEC_ERROR_UNKNOWN_ISSUER: i32 = SEC_ERROR_BASE + 13; +const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: i32 = SEC_ERROR_BASE + 30; + +// SSL error codes. +// https://searchfox.org/mozilla-central/rev/352b525/security/nss/lib/ssl/sslerr.h#42 +const SSL_ERROR_BASE: i32 = -0x3000; // -12288 +const SSL_ERROR_BAD_CERT_DOMAIN: i32 = SSL_ERROR_BASE + 12; + +// PKIX error codes. +// https://searchfox.org/mozilla-central/rev/352b525/security/nss/lib/mozpkix/include/pkix/pkixnss.h#81 +const PKIX_ERROR_BASE: i32 = -0x4000; // -16384 +const PKIX_ERROR_NOT_YET_VALID_CERTIFICATE: i32 = PKIX_ERROR_BASE + 5; +const PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE: i32 = PKIX_ERROR_BASE + 6; + +const ROOT_HASH_LENGTH: usize = 32; + +pub fn verify_code_signing_certificate_chain( + certificates: Vec<&[u8]>, + seconds_since_epoch: u64, + root_sha256_hash: &[u8], + hostname: &str, +) -> Result<()> { + assert_nss_initialized(); + + let mut cert_lens: Vec<u16> = vec![]; + for certificate in &certificates { + match u16::try_from(certificate.len()) { + Ok(v) => cert_lens.push(v), + Err(e) => { + return Err(ErrorKind::InputError(format!( + "certificate length is more than 65536 bytes: {}", + e + )) + .into()); + } + } + } + + let mut p_certificates: Vec<_> = certificates.iter().map(|c| c.as_ptr()).collect(); + + if root_sha256_hash.len() != ROOT_HASH_LENGTH { + return Err(ErrorKind::InputError(format!( + "root hash contains {} bytes instead of {}", + root_sha256_hash.len(), + ROOT_HASH_LENGTH + )) + .into()); + } + + let mut out: PRErrorCode = 0; + + let result = unsafe { + nss_sys::VerifyCodeSigningCertificateChain( + p_certificates.as_mut_ptr(), // Ideally the exposed API should not require mutability here. + cert_lens.as_ptr(), + certificates.len(), + seconds_since_epoch, + root_sha256_hash.as_ptr(), + hostname.as_ptr(), + hostname.len(), + &mut out, + ) + }; + + if !result { + let kind = match out { + SEC_ERROR_UNKNOWN_ISSUER => ErrorKind::CertificateIssuerError, + SEC_ERROR_EXPIRED_CERTIFICATE => ErrorKind::CertificateValidityError, + SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE => ErrorKind::CertificateValidityError, + PKIX_ERROR_NOT_YET_VALID_CERTIFICATE => ErrorKind::CertificateValidityError, + PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE => ErrorKind::CertificateValidityError, + SSL_ERROR_BAD_CERT_DOMAIN => ErrorKind::CertificateSubjectError, + _ => { + let msg = "invalid chain of trust".to_string(); + if SSL_ERROR_BASE < out && out < SSL_ERROR_BASE + 1000 { + ErrorKind::SSLError(out, msg) + } else if PKIX_ERROR_BASE < out && out < PKIX_ERROR_BASE + 1000 { + ErrorKind::PKIXError(out, msg) + } else { + ErrorKind::NSSError(out, msg) + } + } + }; + return Err(kind.into()); + } + + Ok(()) +} diff --git a/third_party/rust/nss/src/secport.rs b/third_party/rust/nss/src/secport.rs @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use crate::util::assert_nss_initialized; +use std::os::raw::c_void; + +pub fn secure_memcmp(a: &[u8], b: &[u8]) -> Result<bool> { + assert_nss_initialized(); + // NSS_SecureMemcmp will compare N elements fron our slices, + // so make sure they are the same length first. + if a.len() != b.len() { + return Ok(false); + } + let result = unsafe { + nss_sys::NSS_SecureMemcmp( + a.as_ptr() as *const c_void, + b.as_ptr() as *const c_void, + a.len(), + ) + }; + Ok(result == 0) +} diff --git a/third_party/rust/nss/src/util.rs b/third_party/rust/nss/src/util.rs @@ -0,0 +1,282 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use nss_sys::*; +use std::{ffi::CString, os::raw::c_char}; + +use std::path::PathBuf; +use std::sync::OnceLock; + +#[cfg(feature = "keydb")] +use crate::pk11::slot; + +// This is the NSS version that this crate is claiming to be compatible with. +// We check it at runtime using `NSS_VersionCheck`. +pub const COMPATIBLE_NSS_VERSION: &str = "3.26"; + +// Expect NSS has been initialized. This is usually be done via `init_rust_components`, see +// components/init_rust_components/README.md. +pub fn assert_nss_initialized() { + INITIALIZED.get().expect( + "NSS has not initialized. + Please ensure you include the initialization component and call it early in your code. See + https://mozilla.github.io/application-services/book/rust-docs/init_rust_components/index.html", + ); +} + +// This and many other nss init code were either taken directly from or are inspired by +// https://github.com/mozilla/neqo/blob/b931a289eee7d62c0815535f01cfa34c5a929f9d/neqo-crypto/src/lib.rs#L73-L77 +enum NssLoaded { + External, + NoDb, + #[cfg(feature = "keydb")] + Db, +} + +static INITIALIZED: OnceLock<NssLoaded> = OnceLock::new(); + +fn assert_compatible_version() { + let min_ver = CString::new(COMPATIBLE_NSS_VERSION).unwrap(); + if unsafe { NSS_VersionCheck(min_ver.as_ptr()) } == PR_FALSE { + panic!("Incompatible NSS version!") + } +} + +fn init_once(profile_path: Option<PathBuf>) -> NssLoaded { + assert_compatible_version(); + + if unsafe { NSS_IsInitialized() != PR_FALSE } { + return NssLoaded::External; + } + + match profile_path { + #[cfg(feature = "keydb")] + Some(path) => { + if !path.is_dir() { + panic!("missing profile directory {:?}", path); + } + let pathstr = path.to_str().expect("invalid path"); + let dircstr = CString::new(pathstr).expect("could not build CString from path"); + let empty = CString::new("").expect("could not build empty CString"); + let flags = NSS_INIT_FORCEOPEN | NSS_INIT_OPTIMIZESPACE; + + let context = unsafe { + NSS_InitContext( + dircstr.as_ptr(), + empty.as_ptr(), + empty.as_ptr(), + empty.as_ptr(), + std::ptr::null_mut(), + flags, + ) + }; + if context.is_null() { + let error = get_last_error(); + panic!("could not initialize context: {}", error); + } + + let slot = slot::get_internal_key_slot().expect("could not get internal key slot"); + + if unsafe { PK11_NeedUserInit(slot.as_mut_ptr()) } == nss_sys::PR_TRUE { + let result = unsafe { + PK11_InitPin( + slot.as_mut_ptr(), + std::ptr::null_mut(), + std::ptr::null_mut(), + ) + }; + if result != SECStatus::SECSuccess { + let error = get_last_error(); + panic!("could not initialize context: {}", error); + } + } + + NssLoaded::Db + } + + #[cfg(not(feature = "keydb"))] + Some(_) => panic!("Use the keydb feature to enable nss initialization with profile path"), + + None => { + let empty = CString::default(); + let flags = NSS_INIT_READONLY + | NSS_INIT_NOCERTDB + | NSS_INIT_NOMODDB + | NSS_INIT_FORCEOPEN + | NSS_INIT_OPTIMIZESPACE; + let context = unsafe { + NSS_InitContext( + empty.as_ptr(), + empty.as_ptr(), + empty.as_ptr(), + empty.as_ptr(), + std::ptr::null_mut(), + flags, + ) + }; + if context.is_null() { + let error = get_last_error(); + panic!("Could not initialize NSS: {}", error); + } + + NssLoaded::NoDb + } + } +} + +/// Initialize NSS. This only executes the initialization routines once, so if there is any chance +/// that this is invoked twice, that's OK. +/// +/// # Errors +/// +/// When NSS initialization fails. +pub fn ensure_nss_initialized() { + INITIALIZED.get_or_init(|| init_once(None)); +} + +/// Use this function to initialize NSS if you want to manage keys with NSS. +/// ensure_initialized_with_profile_dir initializes NSS with a profile directory (where key4.db +/// will be stored) and appropriate flags to persist keys (and certificates) in its internal PKCS11 +/// software implementation. +/// If it has been called previously with a different path, it will fail. +/// If `ensure_initialized` has been called before, it will also fail. +#[cfg(feature = "keydb")] +pub fn ensure_nss_initialized_with_profile_dir<P: Into<PathBuf>>(dir: P) { + INITIALIZED.get_or_init(|| init_once(Some(dir.into()))); +} + +pub fn map_nss_secstatus<F>(callback: F) -> Result<()> +where + F: FnOnce() -> SECStatus, +{ + if callback() == SECStatus::SECSuccess { + return Ok(()); + } + Err(get_last_error()) +} + +/// Retrieve and wrap the last NSS/NSPR error in the current thread. +#[cold] +pub fn get_last_error() -> Error { + let error_code = unsafe { PR_GetError() }; + let error_text: String = usize::try_from(unsafe { PR_GetErrorTextLength() }) + .map(|error_text_len| { + let mut out_str = vec![0u8; error_text_len + 1]; + unsafe { PR_GetErrorText(out_str.as_mut_ptr() as *mut c_char) }; + CString::new(&out_str[0..error_text_len]) + .unwrap_or_else(|_| CString::default()) + .to_str() + .unwrap_or("") + .to_owned() + }) + .unwrap_or_else(|_| "".to_string()); + ErrorKind::NSSError(error_code, error_text).into() +} + +pub(crate) trait ScopedPtr +where + Self: std::marker::Sized, +{ + type RawType; + unsafe fn from_ptr(ptr: *mut Self::RawType) -> Result<Self>; + fn as_ptr(&self) -> *const Self::RawType; + fn as_mut_ptr(&self) -> *mut Self::RawType; +} + +// The macro defines a wrapper around pointers referring to types allocated by NSS, +// calling their NSS destructor method when they go out of scope to avoid memory leaks. +// The `as_ptr`/`as_mut_ptr` are provided to retrieve the raw pointers to pass to +// NSS functions that consume them. +#[macro_export] +macro_rules! scoped_ptr { + ($scoped:ident, $target:ty, $dtor:path) => { + pub struct $scoped { + ptr: *mut $target, + } + + impl $crate::util::ScopedPtr for $scoped { + type RawType = $target; + + #[allow(dead_code)] + unsafe fn from_ptr(ptr: *mut $target) -> $crate::error::Result<$scoped> { + if !ptr.is_null() { + Ok($scoped { ptr }) + } else { + Err($crate::error::ErrorKind::InternalError.into()) + } + } + + #[inline] + fn as_ptr(&self) -> *const $target { + self.ptr + } + + #[inline] + fn as_mut_ptr(&self) -> *mut $target { + self.ptr + } + } + + impl Drop for $scoped { + fn drop(&mut self) { + assert!(!self.ptr.is_null()); + unsafe { $dtor(self.ptr) }; + } + } + }; +} + +/// Copies a SECItem into a slice +/// +/// # Safety +/// +/// The returned reference must not outlive the `sym_key`, since that owns the `SecItem` buffer. +pub(crate) unsafe fn sec_item_as_slice(sec_item: &mut SECItem) -> Result<&mut [u8]> { + let sec_item_buf_len = usize::try_from(sec_item.len)?; + let buf = std::slice::from_raw_parts_mut(sec_item.data, sec_item_buf_len); + Ok(buf) +} + +#[cfg(test)] +mod test { + use super::*; + use std::thread; + + #[test] + fn test_assert_initialized() { + ensure_nss_initialized(); + assert_nss_initialized(); + } + + #[cfg(feature = "keydb")] + #[test] + fn test_assert_initialized_with_profile_dir() { + ensure_nss_initialized_with_profile_dir("./"); + assert_nss_initialized(); + } + + #[test] + fn test_ensure_initialized_multithread() { + let threads: Vec<_> = (0..2) + .map(|_| thread::spawn(ensure_nss_initialized)) + .collect(); + + for handle in threads { + handle.join().unwrap(); + } + } + + #[cfg(feature = "keydb")] + #[test] + fn test_ensure_initialized_with_profile_dir_multithread() { + let threads: Vec<_> = (0..2) + .map(|_| thread::spawn(move || ensure_nss_initialized_with_profile_dir("./"))) + .collect(); + + for handle in threads { + handle.join().unwrap(); + } + } +} diff --git a/third_party/rust/nss_build_common/.cargo-checksum.json b/third_party/rust/nss_build_common/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"59bb44e9fda258667a117c29c7ebe563eba3a69dd5aa63b04a8303e311f0c5c6","src/lib.rs":"0086dca9a1c0f0b3ea67bcb5881583fd877912bfc3657620544d52982d3ebf2d"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/nss_build_common/Cargo.toml b/third_party/rust/nss_build_common/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "nss_build_common" +version = "0.1.0" +authors = ["Thom Chiovoloni <tchiovoloni@mozilla.com>"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = false +license = "MPL-2.0" + +[lib] +name = "nss_build_common" +path = "src/lib.rs" + +[dependencies] diff --git a/third_party/rust/nss_build_common/src/lib.rs b/third_party/rust/nss_build_common/src/lib.rs @@ -0,0 +1,193 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! This shouldn't exist, but does because if something isn't going to link +//! against `nss` but has an `nss`-enabled `sqlcipher` turned on (for example, +//! by a `cargo` feature activated by something else in the workspace). +//! it might need to issue link commands for NSS. + +use std::{ + env, + ffi::OsString, + path::{Path, PathBuf}, +}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum LinkingKind { + Dynamic { folded_libs: bool }, + Static, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct NoNssDir; + +pub fn link_nss() -> Result<(), NoNssDir> { + let is_gecko = env::var_os("MOZ_TOPOBJDIR").is_some(); + if !is_gecko { + let (lib_dir, include_dir) = get_nss()?; + println!( + "cargo:rustc-link-search=native={}", + lib_dir.to_string_lossy() + ); + println!("cargo:include={}", include_dir.to_string_lossy()); + let kind = determine_kind(); + link_nss_libs(kind); + } else { + let libs = match env::var("CARGO_CFG_TARGET_OS") + .as_ref() + .map(std::string::String::as_str) + { + Ok("android") | Ok("macos") => vec!["nss3"], + _ => vec!["nssutil3", "nss3", "plds4", "plc4", "nspr4"], + }; + for lib in &libs { + println!("cargo:rustc-link-lib=dylib={}", lib); + } + } + Ok(()) +} + +fn get_nss() -> Result<(PathBuf, PathBuf), NoNssDir> { + let nss_dir = env("NSS_DIR").ok_or(NoNssDir)?; + let nss_dir = Path::new(&nss_dir); + if !nss_dir.exists() { + println!( + "NSS_DIR path (obtained via `env`) does not exist: {}", + nss_dir.display() + ); + panic!("It looks like NSS is not built. Please run `libs/verify-[platform]-environment.sh` first!"); + } + let lib_dir = nss_dir.join("lib"); + let include_dir = nss_dir.join("include"); + Ok((lib_dir, include_dir)) +} + +fn determine_kind() -> LinkingKind { + if env_flag("NSS_STATIC") { + LinkingKind::Static + } else { + let folded_libs = env_flag("NSS_USE_FOLDED_LIBS"); + LinkingKind::Dynamic { folded_libs } + } +} + +fn link_nss_libs(kind: LinkingKind) { + let libs = get_nss_libs(kind); + // Emit -L flags + let kind_str = match kind { + LinkingKind::Dynamic { .. } => "dylib", + LinkingKind::Static => "static", + }; + for lib in libs { + println!("cargo:rustc-link-lib={}={}", kind_str, lib); + } + // Link against C++ stdlib (for mozpkix) + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + if target_os == "android" || target_os == "linux" { + println!("cargo:rustc-link-lib=stdc++"); + } else { + println!("cargo:rustc-link-lib=c++"); + } + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if target_arch == "x86_64" && target_os == "android" { + let android_home = env::var("ANDROID_HOME").expect("ANDROID_HOME not set"); + const ANDROID_NDK_VERSION: &str = "28.2.13676358"; + // One of these will exist, depending on the host platform. + const DARWIN_X86_64_LIB_DIR: &str = + "/toolchains/llvm/prebuilt/darwin-x86_64/lib/clang/19/lib/linux/"; + println!("cargo:rustc-link-search={android_home}/ndk/{ANDROID_NDK_VERSION}/{DARWIN_X86_64_LIB_DIR}"); + const LINUX_X86_64_LIB_DIR: &str = + "/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/19/lib/linux/"; + println!("cargo:rustc-link-search={android_home}/ndk/{ANDROID_NDK_VERSION}/{LINUX_X86_64_LIB_DIR}"); + println!("cargo:rustc-link-lib=static=clang_rt.builtins-x86_64-android"); + } +} + +fn get_nss_libs(kind: LinkingKind) -> Vec<&'static str> { + match kind { + LinkingKind::Static => { + let mut static_libs = vec![ + "certdb", + "certhi", + "cryptohi", + "freebl_static", + "mozpkix", + "nspr4", + "nss_static", + "nssb", + "nssdev", + "nsspki", + "nssutil", + "pk11wrap_static", + "plc4", + "plds4", + "softokn_static", + ]; + // Hardware specific libs. + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + // https://searchfox.org/nss/rev/0d5696b3edce5124353f03159d2aa15549db8306/lib/freebl/freebl.gyp#508-542 + if target_arch == "arm" || target_arch == "aarch64" { + static_libs.push("armv8_c_lib"); + } + if target_arch == "x86_64" || target_arch == "x86" { + static_libs.push("gcm-aes-x86_c_lib"); + static_libs.push("sha-x86_c_lib"); + } + if target_arch == "arm" { + static_libs.push("gcm-aes-arm32-neon_c_lib") + } + if target_arch == "aarch64" { + static_libs.push("gcm-aes-aarch64_c_lib"); + } + if target_arch == "x86_64" { + static_libs.push("hw-acc-crypto-avx"); + static_libs.push("hw-acc-crypto-avx2"); + } + // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#315-324 + if ((target_os == "android" || target_os == "linux") && target_arch == "x86_64") + || target_os == "windows" + { + static_libs.push("intel-gcm-wrap_c_lib"); + // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#43-47 + if (target_os == "android" || target_os == "linux") && target_arch == "x86_64" { + static_libs.push("intel-gcm-s_lib"); + } + } + static_libs + } + LinkingKind::Dynamic { folded_libs } => { + let mut dylibs = vec!["freebl3", "nss3", "nssckbi", "softokn3"]; + if !folded_libs { + dylibs.append(&mut vec!["nspr4", "nssutil3", "plc4", "plds4"]); + } + dylibs + } + } +} + +pub fn env(name: &str) -> Option<OsString> { + println!("cargo:rerun-if-env-changed={}", name); + env::var_os(name) +} + +pub fn env_str(name: &str) -> Option<String> { + println!("cargo:rerun-if-env-changed={}", name); + env::var(name).ok() +} + +pub fn env_flag(name: &str) -> bool { + match env_str(name).as_ref().map(String::as_ref) { + Some("1") => true, + Some("0") => false, + Some(s) => { + println!( + "cargo:warning=unknown value for environment var {:?}: {:?}. Ignoring", + name, s + ); + false + } + None => false, + } +} diff --git a/third_party/rust/nss_sys/.cargo-checksum.json b/third_party/rust/nss_sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fadb4d4c210bd6bfb89552c4421f22151acdbbc1fc72f4eb97c7bceb271385e8","README.md":"5f931f614978589f2343ad2ae405e21ccf49496d4593f3fec818b1a9bc2f194b","build.rs":"b541496d108a9e85545b9ee28c84790aa5b361805f691a082403233588423fd0","src/bindings/blapit.rs":"9f83f4d66c7164f75d714ea569714a36c2d2e9fda981e3aa1b890c54567c9e79","src/bindings/certdb.rs":"00411907215d7b427952a0200f91e4c564158fc5883cdb7332d92afcb424375b","src/bindings/keyhi.rs":"cdf9c3735343a718f86cfe5f822530dc7c7e4fc2c36e2a11797d9054dd0bfd05","src/bindings/keythi.rs":"ea9a1a8c33c3f2b8b78bd58d8d627d9f8d8c22ee4e1cd26c78701106bf0db69f","src/bindings/mod.rs":"c5cefb78172bd7bc1650123edf92f7005bb5e74ed090beaa73772c1b2fd26cf6","src/bindings/nss.rs":"c221cfcdaf00e9e024b335ff137d4df5feca5d3e30af0fe680e6feac33450ed7","src/bindings/pk11pub.rs":"c49d433cc87a9039ee5a278ca0a1e8d90c2406f1d05bc0001be2eb9e34b6ca53","src/bindings/pkcs11n.rs":"bc1ba0d903891d5331aeb6b1921fde7c2cd31cbbe75338e145b5aaff5c94c147","src/bindings/pkcs11t.rs":"5d84bfd36df100b026b6ddf4c48b75f2b0f3475108ba309985341c228f9e6955","src/bindings/pkixc.rs":"61d2bf93ad07ada57338dbf4f3418f782502e76a316759044ab20e80c284016d","src/bindings/plarena.rs":"8de09e3c378df457988729ca4d58e1ef1f2883dfa68e62acb79a55fb19a9d6f5","src/bindings/prerror.rs":"b7bda8a6511c43f59351a17f4311ceb272231a55473895b999a34e3a3ff76722","src/bindings/prtypes.rs":"5afd17e4d24880609320f8cc5a9c06f57ac766524ca5f6cbc5edc65195974c6e","src/bindings/secasn1t.rs":"5a79f0a4057fb934786ef9407c7b134c7bc2f3560f9af0d58dd27ede62c66391","src/bindings/seccomon.rs":"1538dc6226e3c731e3028b6e3859de7f51c7bf996b0a48e9019c766187c61576","src/bindings/secitem.rs":"7a1593f87dcbb4d9ef462fda9932486d169bea9f12b4ed83e3a7102d0b33127e","src/bindings/seckey.rs":"dd7b90e263c19855e38f6df657d60c532a509a3a9180acddc8f5f612da76889b","src/bindings/secmodt.rs":"f1c002df25b598e6fbed5285c98c0d8cfe4188254ca31f829cb993d321a4f6d0","src/bindings/secoid.rs":"1a1e3d8106c26d081daa56b22f6214b6b2456e14f6d5b34db77bb428e7dc4525","src/bindings/secoidt.rs":"d3841fa00100d081fd355ef65d8ff10e2341440715c937017d795fc7efd0d31d","src/bindings/secport.rs":"6b9c691f7a80467ad2db76e2168d9dceee781e5edaadd48b76e66852f632db12","src/lib.rs":"3081488f34b747cbe852e6692389db5df3dae65b180558aa7af9bf6ae809faa2"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/nss_sys/Cargo.toml b/third_party/rust/nss_sys/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "nss_sys" +version = "0.1.0" +authors = ["Sync Team <sync-team@mozilla.com>"] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = "README.md" +license = "MPL-2.0" + +[features] +default = [] +gecko = [] + +[lib] +name = "nss_sys" +crate-type = ["lib"] +path = "src/lib.rs" + +[dependencies.libsqlite3-sys] +version = "0.35.0" +features = ["bundled"] + +[build-dependencies.nss_build_common] +path = "../nss_build_common" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(__appsvc_ci_hack)"] diff --git a/third_party/rust/nss_sys/README.md b/third_party/rust/nss_sys/README.md @@ -0,0 +1,18 @@ +## nss_sys + +Low-level NSS bindings for Rust. + +This crate defines low-level FFI bindings for NSS. They are maintained by hand. + +The directory structure of this crate is meant to mirror that of NSS itself. +For each header file provided by NSS, there should be a corresponding `.rs` file +in the `nss_sys::bindings` module that declares the corresponding functions and +data types. + +To add new bindings in this crate, you'll need to: + +* Identify the NSS header file that contains the functionality of interest. +* Edit the Rust file of the corresponding name under `./src/bindings`. + * If one doesn't currently exist then create it. +* Add `#[recpr(C)]` structs and `pub extern "C"` functions as necessary to make the + new functionality visible to Rust. diff --git a/third_party/rust/nss_sys/build.rs b/third_party/rust/nss_sys/build.rs @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +fn main() { + nss_build_common::link_nss().unwrap(); +} diff --git a/third_party/rust/nss_sys/src/bindings/blapit.rs b/third_party/rust/nss_sys/src/bindings/blapit.rs @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub const EC_POINT_FORM_UNCOMPRESSED: u32 = 4; +pub const SHA256_LENGTH: u32 = 32; +pub const SHA384_LENGTH: u32 = 48; +pub const HASH_LENGTH_MAX: u32 = 64; +pub const AES_BLOCK_SIZE: u32 = 16; +pub const AES_256_KEY_LENGTH: u32 = 32; diff --git a/third_party/rust/nss_sys/src/bindings/certdb.rs b/third_party/rust/nss_sys/src/bindings/certdb.rs @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; +use std::os::raw::c_char; + +// Opaque types +pub type CERTCertDBHandle = u8; +pub type CERTCertificate = u8; + +extern "C" { + pub fn CERT_GetDefaultCertDB() -> *mut CERTCertDBHandle; + + pub fn CERT_NewTempCertificate( + handle: *mut CERTCertDBHandle, + derCert: *mut SECItem, + nickname: *mut c_char, + isperm: PRBool, + copyDER: PRBool, + ) -> *mut CERTCertificate; + + pub fn CERT_DestroyCertificate(cert: *mut CERTCertificate); +} diff --git a/third_party/rust/nss_sys/src/bindings/keyhi.rs b/third_party/rust/nss_sys/src/bindings/keyhi.rs @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; + +extern "C" { + pub fn SECKEY_CopyPublicKey(pubKey: *const SECKEYPublicKey) -> *mut SECKEYPublicKey; + pub fn SECKEY_ConvertToPublicKey(privateKey: *mut SECKEYPrivateKey) -> *mut SECKEYPublicKey; + pub fn SECKEY_DestroyPrivateKey(key: *mut SECKEYPrivateKey); + pub fn SECKEY_DestroyPublicKey(key: *mut SECKEYPublicKey); +} diff --git a/third_party/rust/nss_sys/src/bindings/keythi.rs b/third_party/rust/nss_sys/src/bindings/keythi.rs @@ -0,0 +1,140 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; +use std::os::raw::{c_int, c_uchar, c_void}; + +pub type SECKEYPublicKey = SECKEYPublicKeyStr; +#[repr(C)] +pub struct SECKEYPublicKeyStr { + pub arena: *mut PLArenaPool, + pub keyType: u32, /* KeyType */ + pub pkcs11Slot: *mut PK11SlotInfo, + pub pkcs11ID: CK_OBJECT_HANDLE, + pub u: SECKEYPublicKeyStr_u, +} + +#[repr(C)] +pub union SECKEYPublicKeyStr_u { + pub rsa: SECKEYRSAPublicKey, + pub dsa: SECKEYDSAPublicKey, + pub dh: SECKEYDHPublicKey, + pub kea: SECKEYKEAPublicKey, + pub fortezza: SECKEYFortezzaPublicKey, + pub ec: SECKEYECPublicKey, +} + +pub type SECKEYPrivateKey = SECKEYPrivateKeyStr; +#[repr(C)] +pub struct SECKEYPrivateKeyStr { + pub arena: *mut PLArenaPool, + pub keyType: u32, /* KeyType */ + pub pkcs11Slot: *mut PK11SlotInfo, + pub pkcs11ID: CK_OBJECT_HANDLE, + pub pkcs11IsTemp: PRBool, + pub wincx: *mut c_void, + pub staticflags: PRUint32, +} + +#[repr(u32)] +pub enum KeyType { + nullKey = 0, + rsaKey = 1, + dsaKey = 2, + fortezzaKey = 3, + dhKey = 4, + keaKey = 5, + ecKey = 6, + rsaPssKey = 7, + rsaOaepKey = 8, +} + +pub type SECKEYRSAPublicKey = SECKEYRSAPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYRSAPublicKeyStr { + pub arena: *mut PLArenaPool, + pub modulus: SECItem, + pub publicExponent: SECItem, +} + +pub type SECKEYDSAPublicKey = SECKEYDSAPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYDSAPublicKeyStr { + pub params: SECKEYPQGParams, + pub publicValue: SECItem, +} + +pub type SECKEYPQGParams = SECKEYPQGParamsStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYPQGParamsStr { + pub arena: *mut PLArenaPool, + pub prime: SECItem, + pub subPrime: SECItem, + pub base: SECItem, +} + +pub type SECKEYDHPublicKey = SECKEYDHPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYDHPublicKeyStr { + pub arena: *mut PLArenaPool, + pub prime: SECItem, + pub base: SECItem, + pub publicValue: SECItem, +} + +pub type SECKEYKEAPublicKey = SECKEYKEAPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYKEAPublicKeyStr { + pub params: SECKEYKEAParams, + pub publicValue: SECItem, +} + +pub type SECKEYKEAParams = SECKEYKEAParamsStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYKEAParamsStr { + pub arena: *mut PLArenaPool, + pub hash: SECItem, +} + +pub type SECKEYFortezzaPublicKey = SECKEYFortezzaPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYFortezzaPublicKeyStr { + pub KEAversion: c_int, + pub DSSversion: c_int, + pub KMID: [c_uchar; 8usize], + pub clearance: SECItem, + pub KEApriviledge: SECItem, + pub DSSpriviledge: SECItem, + pub KEAKey: SECItem, + pub DSSKey: SECItem, + pub params: SECKEYPQGParams, + pub keaParams: SECKEYPQGParams, +} + +pub type SECKEYECPublicKey = SECKEYECPublicKeyStr; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECKEYECPublicKeyStr { + pub DEREncodedParams: SECKEYECParams, + pub size: c_int, + pub publicValue: SECItem, + pub encoding: u32, /* ECPointEncoding */ +} + +pub type SECKEYECParams = SECItem; + +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum ECPointEncoding { + ECPoint_Uncompressed = 0, + ECPoint_XOnly = 1, + ECPoint_Undefined = 2, +} diff --git a/third_party/rust/nss_sys/src/bindings/mod.rs b/third_party/rust/nss_sys/src/bindings/mod.rs @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod blapit; +pub use blapit::*; +mod certdb; +pub use certdb::*; +mod keyhi; +pub use keyhi::*; +mod keythi; +pub use keythi::*; +mod nss; +pub use nss::*; +mod pk11pub; +pub use pk11pub::*; +mod pkcs11n; +pub use pkcs11n::*; +mod pkcs11t; +pub use pkcs11t::*; +mod pkixc; +pub use pkixc::*; +mod plarena; +pub use plarena::*; +mod prerror; +pub use prerror::*; +mod prtypes; +pub use prtypes::*; +mod secasn1t; +pub use secasn1t::*; +mod seccomon; +pub use seccomon::*; +mod secitem; +pub use secitem::*; +mod seckey; +pub use seckey::*; +mod secmodt; +pub use secmodt::*; +mod secoid; +pub use secoid::*; +mod secoidt; +pub use secoidt::*; +mod secport; +pub use secport::*; diff --git a/third_party/rust/nss_sys/src/bindings/nss.rs b/third_party/rust/nss_sys/src/bindings/nss.rs @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; +use std::os::raw::c_char; + +extern "C" { + pub fn NSS_VersionCheck(importedVersion: *const c_char) -> PRBool; + pub fn NSS_InitContext( + configdir: *const c_char, + certPrefix: *const c_char, + keyPrefix: *const c_char, + secmodName: *const c_char, + initParams: *mut NSSInitParameters, + flags: PRUint32, + ) -> *mut NSSInitContext; + pub fn NSS_IsInitialized() -> PRBool; +} + +pub const NSS_INIT_READONLY: u32 = 1; +pub const NSS_INIT_NOCERTDB: u32 = 2; +pub const NSS_INIT_NOMODDB: u32 = 4; +pub const NSS_INIT_FORCEOPEN: u32 = 8; +pub const NSS_INIT_OPTIMIZESPACE: u32 = 32; + +// Opaque types +pub type NSSInitContext = u8; +pub type NSSInitParameters = [u64; 10usize]; diff --git a/third_party/rust/nss_sys/src/bindings/pk11pub.rs b/third_party/rust/nss_sys/src/bindings/pk11pub.rs @@ -0,0 +1,191 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; +use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_void}; + +extern "C" { + pub fn PK11_FreeSlot(slot: *mut PK11SlotInfo); + pub fn PK11_GetInternalSlot() -> *mut PK11SlotInfo; + pub fn PK11_GetInternalKeySlot() -> *mut PK11SlotInfo; + pub fn PK11_NeedUserInit(slot: *mut PK11SlotInfo) -> PRBool; + pub fn PK11_NeedLogin(slot: *mut PK11SlotInfo) -> PRBool; + pub fn PK11_IsLoggedIn(slot: *mut PK11SlotInfo, wincx: *mut c_void) -> PRBool; + pub fn PK11_CheckUserPassword(slot: *mut PK11SlotInfo, password: *const c_char) -> SECStatus; + pub fn PK11_GenerateRandom(data: *mut c_uchar, len: c_int) -> SECStatus; + pub fn PK11_FreeSymKey(key: *mut PK11SymKey); + pub fn PK11_InitPin( + slot: *mut PK11SlotInfo, + ssopw: *const c_char, + pk11_userpwd: *const c_char, + ) -> SECStatus; + pub fn PK11_KeyGen( + slot: *mut PK11SlotInfo, + type_: CK_MECHANISM_TYPE, + param: *mut SECItem, + keySize: c_int, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn PK11_ImportSymKey( + slot: *mut PK11SlotInfo, + type_: CK_MECHANISM_TYPE, + origin: u32, /* PK11Origin */ + operation: CK_ATTRIBUTE_TYPE, + key: *mut SECItem, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn PK11_ImportSymKeyWithFlags( + slot: *mut PK11SlotInfo, + type_: CK_MECHANISM_TYPE, + origin: u32, /* PK11Origin */ + operation: CK_ATTRIBUTE_TYPE, + key: *mut SECItem, + flags: CK_FLAGS, + isPerm: PRBool, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn PK11_SetSymKeyNickname(key: *mut PK11SymKey, name: *const c_char) -> SECStatus; + pub fn PK11_Derive( + baseKey: *mut PK11SymKey, + mechanism: CK_MECHANISM_TYPE, + param: *mut SECItem, + target: CK_MECHANISM_TYPE, + operation: CK_ATTRIBUTE_TYPE, + keySize: c_int, + ) -> *mut PK11SymKey; + pub fn PK11_PubDeriveWithKDF( + privKey: *mut SECKEYPrivateKey, + pubKey: *mut SECKEYPublicKey, + isSender: PRBool, + randomA: *mut SECItem, + randomB: *mut SECItem, + derive: CK_MECHANISM_TYPE, + target: CK_MECHANISM_TYPE, + operation: CK_ATTRIBUTE_TYPE, + keySize: c_int, + kdf: CK_ULONG, + sharedData: *mut SECItem, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn PK11_WrapSymKey( + type_: CK_MECHANISM_TYPE, + param: *mut SECItem, + wrappingKey: *mut PK11SymKey, + symKey: *mut PK11SymKey, + wrappedKey: *mut SECItem, + ) -> SECStatus; + pub fn PK11_UnwrapSymKey( + wrappingKey: *mut PK11SymKey, + wrapType: CK_MECHANISM_TYPE, + param: *mut SECItem, + wrappedKey: *mut SECItem, + target: CK_MECHANISM_TYPE, + operation: CK_ATTRIBUTE_TYPE, + keySize: c_int, + ) -> *mut PK11SymKey; + pub fn PK11_ExtractKeyValue(symKey: *mut PK11SymKey) -> SECStatus; + pub fn PK11_GetKeyData(symKey: *mut PK11SymKey) -> *mut SECItem; + pub fn PK11_GenerateKeyPair( + slot: *mut PK11SlotInfo, + type_: CK_MECHANISM_TYPE, + param: *mut c_void, + pubk: *mut *mut SECKEYPublicKey, + isPerm: PRBool, + isSensitive: PRBool, + wincx: *mut c_void, + ) -> *mut SECKEYPrivateKey; + pub fn PK11_FindKeyByKeyID( + slot: *mut PK11SlotInfo, + keyID: *mut SECItem, + wincx: *mut c_void, + ) -> *mut SECKEYPrivateKey; + pub fn PK11_ListFixedKeysInSlot( + slot: *mut PK11SlotInfo, + nickname: *mut c_char, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn PK11_Decrypt( + symkey: *mut PK11SymKey, + mechanism: CK_MECHANISM_TYPE, + param: *mut SECItem, + out: *mut c_uchar, + outLen: *mut c_uint, + maxLen: c_uint, + enc: *const c_uchar, + encLen: c_uint, + ) -> SECStatus; + pub fn PK11_Encrypt( + symKey: *mut PK11SymKey, + mechanism: CK_MECHANISM_TYPE, + param: *mut SECItem, + out: *mut c_uchar, + outLen: *mut c_uint, + maxLen: c_uint, + data: *const c_uchar, + dataLen: c_uint, + ) -> SECStatus; + pub fn PK11_VerifyWithMechanism( + key: *mut SECKEYPublicKey, + mechanism: CK_MECHANISM_TYPE, + param: *const SECItem, + sig: *const SECItem, + hash: *const SECItem, + wincx: *mut c_void, + ) -> SECStatus; + pub fn PK11_MapSignKeyType(keyType: u32 /* KeyType */) -> CK_MECHANISM_TYPE; + pub fn PK11_DestroyContext(context: *mut PK11Context, freeit: PRBool); + pub fn PK11_CreateContextBySymKey( + type_: CK_MECHANISM_TYPE, + operation: CK_ATTRIBUTE_TYPE, + symKey: *mut PK11SymKey, + param: *const SECItem, + ) -> *mut PK11Context; + pub fn PK11_DigestBegin(cx: *mut PK11Context) -> SECStatus; + pub fn PK11_HashBuf( + hashAlg: u32, /* SECOidTag */ + out: *mut c_uchar, + in_: *const c_uchar, + len: PRInt32, + ) -> SECStatus; + pub fn PK11_DigestOp(context: *mut PK11Context, in_: *const c_uchar, len: c_uint) -> SECStatus; + pub fn PK11_DigestFinal( + context: *mut PK11Context, + data: *mut c_uchar, + outLen: *mut c_uint, + length: c_uint, + ) -> SECStatus; + pub fn PK11_DestroyGenericObject(object: *mut PK11GenericObject) -> SECStatus; + pub fn PK11_CreateGenericObject( + slot: *mut PK11SlotInfo, + pTemplate: *const CK_ATTRIBUTE, + count: c_int, + token: PRBool, + ) -> *mut PK11GenericObject; + pub fn PK11_ReadRawAttribute( + type_: u32, /* PK11ObjectType */ + object: *mut c_void, + attr: CK_ATTRIBUTE_TYPE, + item: *mut SECItem, + ) -> SECStatus; + pub fn PK11_CreatePBEV2AlgorithmID( + pbeAlgTag: u32, /* SECOidTag */ + cipherAlgTag: u32, /* SECOidTag */ + prfAlgTag: u32, /* SECOidTag */ + keyLength: c_int, + iteration: c_int, + salt: *mut SECItem, + ) -> *mut SECAlgorithmID; + pub fn PK11_PBEKeyGen( + slot: *mut PK11SlotInfo, + algid: *mut SECAlgorithmID, + pwitem: *mut SECItem, + faulty3DES: PRBool, + wincx: *mut c_void, + ) -> *mut PK11SymKey; + pub fn SECITEM_AllocItem( + arena: *mut PLArenaPool, + item: *mut SECItem, + len: c_uint, + ) -> *mut SECItem; +} diff --git a/third_party/rust/nss_sys/src/bindings/pkcs11n.rs b/third_party/rust/nss_sys/src/bindings/pkcs11n.rs @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; + +// https://searchfox.org/nss/rev/4d480919bbf204df5e199b9fdedec8f2a6295778/lib/util/pkcs11n.h#27 +pub const NSSCK_VENDOR_NSS: u32 = 0x4E534350; + +pub const CKM_NSS: u32 = CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS; +pub const CKM_NSS_HKDF_SHA256: u32 = CKM_NSS + 4; +pub const CKM_NSS_HKDF_SHA384: u32 = CKM_NSS + 5; + +pub type CK_GCM_PARAMS = CK_GCM_PARAMS_V3; +#[repr(C)] +pub struct CK_GCM_PARAMS_V3 { + pub pIv: CK_BYTE_PTR, + pub ulIvLen: CK_ULONG, + pub ulIvBits: CK_ULONG, + pub pAAD: CK_BYTE_PTR, + pub ulAADLen: CK_ULONG, + pub ulTagBits: CK_ULONG, +} +#[repr(C)] +pub struct CK_NSS_HKDFParams { + pub bExtract: CK_BBOOL, + pub pSalt: CK_BYTE_PTR, + pub ulSaltLen: CK_ULONG, + pub bExpand: CK_BBOOL, + pub pInfo: CK_BYTE_PTR, + pub ulInfoLen: CK_ULONG, +} diff --git a/third_party/rust/nss_sys/src/bindings/pkcs11t.rs b/third_party/rust/nss_sys/src/bindings/pkcs11t.rs @@ -0,0 +1,55 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::os::raw::{c_uchar, c_ulong, c_void}; + +pub const CK_TRUE: CK_BBOOL = 1; +pub const CK_FALSE: CK_BBOOL = 0; +pub type CK_BYTE = c_uchar; +pub type CK_BBOOL = CK_BYTE; +pub type CK_ULONG = c_ulong; +pub type CK_BYTE_PTR = *mut CK_BYTE; +pub type CK_VOID_PTR = *mut c_void; +pub type CK_OBJECT_HANDLE = CK_ULONG; +pub type CK_OBJECT_CLASS = CK_ULONG; +pub type CK_KEY_TYPE = CK_ULONG; +pub type CK_ATTRIBUTE_TYPE = CK_ULONG; +pub type CK_FLAGS = CK_ULONG; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CK_ATTRIBUTE { + pub type_: CK_ATTRIBUTE_TYPE, + pub pValue: CK_VOID_PTR, + pub ulValueLen: CK_ULONG, +} +pub type CK_MECHANISM_TYPE = CK_ULONG; + +pub const CK_INVALID_HANDLE: u32 = 0; +pub const CKO_PRIVATE_KEY: u32 = 3; +pub const CKK_EC: u32 = 3; +pub const CKA_CLASS: u32 = 0; +pub const CKA_TOKEN: u32 = 1; +pub const CKA_PRIVATE: u32 = 2; +pub const CKA_VALUE: u32 = 17; +pub const CKA_KEY_TYPE: u32 = 256; +pub const CKA_ID: u32 = 258; +pub const CKA_SENSITIVE: u32 = 259; +pub const CKA_ENCRYPT: u32 = 260; +pub const CKA_DECRYPT: u32 = 261; +pub const CKA_WRAP: u32 = 262; +pub const CKA_SIGN: u32 = 264; +pub const CKA_EC_PARAMS: u32 = 384; +pub const CKA_EC_POINT: u32 = 385; +// https://searchfox.org/nss/rev/4d480919bbf204df5e199b9fdedec8f2a6295778/lib/util/pkcs11t.h#1244 +pub const CKM_VENDOR_DEFINED: u32 = 0x80000000; +pub const CKM_SHA256_HMAC: u32 = 593; +pub const CKM_SHA384_HMAC: u32 = 609; +pub const CKM_SHA512_HMAC: u32 = 625; +pub const CKM_EC_KEY_PAIR_GEN: u32 = 4160; +pub const CKM_ECDH1_DERIVE: u32 = 4176; +pub const CKM_AES_CBC_PAD: u32 = 4229; +pub const CKM_AES_GCM: u32 = 4231; +pub const CKM_AES_KEY_GEN: CK_ULONG = 0x00001080; +pub const CKM_AES_KEY_WRAP_KWP: CK_ULONG = 0x0000210B; +pub const CKD_NULL: u32 = 1; diff --git a/third_party/rust/nss_sys/src/bindings/pkixc.rs b/third_party/rust/nss_sys/src/bindings/pkixc.rs @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; + +extern "C" { + pub fn VerifyCodeSigningCertificateChain( + certificates: *mut *const u8, + certificateLengths: *const u16, + numCertificates: size_t, + secondsSinceEpoch: u64, + rootSHA256Hash: *const u8, + hostname: *const u8, + hostnameLength: size_t, + error: *mut PRErrorCode, + ) -> bool; +} diff --git a/third_party/rust/nss_sys/src/bindings/plarena.rs b/third_party/rust/nss_sys/src/bindings/plarena.rs @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PLArena { + pub next: *mut PLArena, + pub base: PRUword, + pub limit: PRUword, + pub avail: PRUword, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PLArenaPool { + pub first: PLArena, + pub current: *mut PLArena, + pub arenasize: PRUint32, + pub mask: PRUword, +} diff --git a/third_party/rust/nss_sys/src/bindings/prerror.rs b/third_party/rust/nss_sys/src/bindings/prerror.rs @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; +use std::os::raw::c_char; + +extern "C" { + pub fn PR_GetError() -> PRErrorCode; + pub fn PR_GetErrorTextLength() -> PRInt32; + pub fn PR_GetErrorText(text: *mut c_char) -> PRInt32; +} + +pub type PRErrorCode = PRInt32; diff --git a/third_party/rust/nss_sys/src/bindings/prtypes.rs b/third_party/rust/nss_sys/src/bindings/prtypes.rs @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::os::raw::{c_int, c_uint}; + +pub type PRIntn = c_int; +pub type PRBool = PRIntn; +pub type PRUword = usize; +pub type PRInt32 = c_int; +pub type PRUint32 = c_uint; +pub const PR_FALSE: PRBool = 0; +pub const PR_TRUE: PRBool = 1; diff --git a/third_party/rust/nss_sys/src/bindings/secasn1t.rs b/third_party/rust/nss_sys/src/bindings/secasn1t.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub const SEC_ASN1_OBJECT_ID: u32 = 6; diff --git a/third_party/rust/nss_sys/src/bindings/seccomon.rs b/third_party/rust/nss_sys/src/bindings/seccomon.rs @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::os::raw::{c_uchar, c_uint}; + +#[repr(u32)] +pub enum SECItemType { + siBuffer = 0, + siClearDataBuffer = 1, + siCipherDataBuffer = 2, + siDERCertBuffer = 3, + siEncodedCertBuffer = 4, + siDERNameBuffer = 5, + siEncodedNameBuffer = 6, + siAsciiNameString = 7, + siAsciiString = 8, + siDEROID = 9, + siUnsignedInteger = 10, + siUTCTime = 11, + siGeneralizedTime = 12, + siVisibleString = 13, + siUTF8String = 14, + siBMPString = 15, +} + +pub type SECItem = SECItemStr; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SECItemStr { + pub type_: u32, /* SECItemType */ + pub data: *mut c_uchar, + pub len: c_uint, +} + +#[repr(i32)] +#[derive(PartialEq, Eq)] +pub enum _SECStatus { + SECWouldBlock = -2, + SECFailure = -1, + SECSuccess = 0, +} +pub use _SECStatus as SECStatus; diff --git a/third_party/rust/nss_sys/src/bindings/secitem.rs b/third_party/rust/nss_sys/src/bindings/secitem.rs @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; + +extern "C" { + pub fn SECITEM_FreeItem(zap: *mut SECItem, freeit: PRBool); +} diff --git a/third_party/rust/nss_sys/src/bindings/seckey.rs b/third_party/rust/nss_sys/src/bindings/seckey.rs @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; + +extern "C" { + pub fn CERT_ExtractPublicKey(cert: *mut CERTCertificate) -> *mut SECKEYPublicKey; +} diff --git a/third_party/rust/nss_sys/src/bindings/secmodt.rs b/third_party/rust/nss_sys/src/bindings/secmodt.rs @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Opaque pointers as these types are giant. +pub type PK11SlotInfo = u8; +pub type PK11SymKey = u8; +pub type PK11Context = u8; + +#[repr(u32)] +pub enum PK11Origin { + PK11_OriginNULL = 0, + PK11_OriginDerive = 1, + PK11_OriginGenerated = 2, + PK11_OriginFortezzaHack = 3, + PK11_OriginUnwrap = 4, +} + +#[repr(u32)] +pub enum PK11ObjectType { + PK11_TypeGeneric = 0, + PK11_TypePrivKey = 1, + PK11_TypePubKey = 2, + PK11_TypeCert = 3, + PK11_TypeSymKey = 4, +} + +// #[repr(C)] +// #[derive(Copy, Clone)] +// pub struct PK11GenericObjectStr { +// _unused: [u8; 0], +// } +pub type PK11GenericObject = u8; diff --git a/third_party/rust/nss_sys/src/bindings/secoid.rs b/third_party/rust/nss_sys/src/bindings/secoid.rs @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; + +extern "C" { + pub fn SECOID_FindOIDByTag(tagnum: u32 /* SECOidTag */) -> *mut SECOidData; + pub fn SECOID_DestroyAlgorithmID(aid: *mut SECAlgorithmID, freeit: PRBool); +} diff --git a/third_party/rust/nss_sys/src/bindings/secoidt.rs b/third_party/rust/nss_sys/src/bindings/secoidt.rs @@ -0,0 +1,401 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use crate::*; +use std::os::raw::{c_char, c_ulong}; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECAlgorithmIDStr { + pub algorithm: SECItem, + pub parameters: SECItem, +} + +pub type SECAlgorithmID = SECAlgorithmIDStr; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SECOidDataStr { + pub oid: SECItem, + pub offset: u32, /* SECOidTag */ + pub desc: *const c_char, + pub mechanism: c_ulong, + pub supportedExtension: u32, /* SECSupportExtenTag */ +} +pub type SECOidData = SECOidDataStr; + +pub enum SECSupportExtenTag { + INVALID_CERT_EXTENSION = 0, + UNSUPPORTED_CERT_EXTENSION = 1, + SUPPORTED_CERT_EXTENSION = 2, +} + +#[repr(u32)] +pub enum SECOidTag { + SEC_OID_UNKNOWN = 0, + SEC_OID_MD2 = 1, + SEC_OID_MD4 = 2, + SEC_OID_MD5 = 3, + SEC_OID_SHA1 = 4, + SEC_OID_RC2_CBC = 5, + SEC_OID_RC4 = 6, + SEC_OID_DES_EDE3_CBC = 7, + SEC_OID_RC5_CBC_PAD = 8, + SEC_OID_DES_ECB = 9, + SEC_OID_DES_CBC = 10, + SEC_OID_DES_OFB = 11, + SEC_OID_DES_CFB = 12, + SEC_OID_DES_MAC = 13, + SEC_OID_DES_EDE = 14, + SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE = 15, + SEC_OID_PKCS1_RSA_ENCRYPTION = 16, + SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION = 17, + SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION = 18, + SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION = 19, + SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION = 20, + SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC = 21, + SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC = 22, + SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC = 23, + SEC_OID_PKCS7 = 24, + SEC_OID_PKCS7_DATA = 25, + SEC_OID_PKCS7_SIGNED_DATA = 26, + SEC_OID_PKCS7_ENVELOPED_DATA = 27, + SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA = 28, + SEC_OID_PKCS7_DIGESTED_DATA = 29, + SEC_OID_PKCS7_ENCRYPTED_DATA = 30, + SEC_OID_PKCS9_EMAIL_ADDRESS = 31, + SEC_OID_PKCS9_UNSTRUCTURED_NAME = 32, + SEC_OID_PKCS9_CONTENT_TYPE = 33, + SEC_OID_PKCS9_MESSAGE_DIGEST = 34, + SEC_OID_PKCS9_SIGNING_TIME = 35, + SEC_OID_PKCS9_COUNTER_SIGNATURE = 36, + SEC_OID_PKCS9_CHALLENGE_PASSWORD = 37, + SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS = 38, + SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES = 39, + SEC_OID_PKCS9_SMIME_CAPABILITIES = 40, + SEC_OID_AVA_COMMON_NAME = 41, + SEC_OID_AVA_COUNTRY_NAME = 42, + SEC_OID_AVA_LOCALITY = 43, + SEC_OID_AVA_STATE_OR_PROVINCE = 44, + SEC_OID_AVA_ORGANIZATION_NAME = 45, + SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME = 46, + SEC_OID_AVA_DN_QUALIFIER = 47, + SEC_OID_AVA_DC = 48, + SEC_OID_NS_TYPE_GIF = 49, + SEC_OID_NS_TYPE_JPEG = 50, + SEC_OID_NS_TYPE_URL = 51, + SEC_OID_NS_TYPE_HTML = 52, + SEC_OID_NS_TYPE_CERT_SEQUENCE = 53, + SEC_OID_MISSI_KEA_DSS_OLD = 54, + SEC_OID_MISSI_DSS_OLD = 55, + SEC_OID_MISSI_KEA_DSS = 56, + SEC_OID_MISSI_DSS = 57, + SEC_OID_MISSI_KEA = 58, + SEC_OID_MISSI_ALT_KEA = 59, + SEC_OID_NS_CERT_EXT_NETSCAPE_OK = 60, + SEC_OID_NS_CERT_EXT_ISSUER_LOGO = 61, + SEC_OID_NS_CERT_EXT_SUBJECT_LOGO = 62, + SEC_OID_NS_CERT_EXT_CERT_TYPE = 63, + SEC_OID_NS_CERT_EXT_BASE_URL = 64, + SEC_OID_NS_CERT_EXT_REVOCATION_URL = 65, + SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL = 66, + SEC_OID_NS_CERT_EXT_CA_CRL_URL = 67, + SEC_OID_NS_CERT_EXT_CA_CERT_URL = 68, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL = 69, + SEC_OID_NS_CERT_EXT_CA_POLICY_URL = 70, + SEC_OID_NS_CERT_EXT_HOMEPAGE_URL = 71, + SEC_OID_NS_CERT_EXT_ENTITY_LOGO = 72, + SEC_OID_NS_CERT_EXT_USER_PICTURE = 73, + SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME = 74, + SEC_OID_NS_CERT_EXT_COMMENT = 75, + SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL = 76, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME = 77, + SEC_OID_NS_KEY_USAGE_GOVT_APPROVED = 78, + SEC_OID_X509_SUBJECT_DIRECTORY_ATTR = 79, + SEC_OID_X509_SUBJECT_KEY_ID = 80, + SEC_OID_X509_KEY_USAGE = 81, + SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD = 82, + SEC_OID_X509_SUBJECT_ALT_NAME = 83, + SEC_OID_X509_ISSUER_ALT_NAME = 84, + SEC_OID_X509_BASIC_CONSTRAINTS = 85, + SEC_OID_X509_NAME_CONSTRAINTS = 86, + SEC_OID_X509_CRL_DIST_POINTS = 87, + SEC_OID_X509_CERTIFICATE_POLICIES = 88, + SEC_OID_X509_POLICY_MAPPINGS = 89, + SEC_OID_X509_POLICY_CONSTRAINTS = 90, + SEC_OID_X509_AUTH_KEY_ID = 91, + SEC_OID_X509_EXT_KEY_USAGE = 92, + SEC_OID_X509_AUTH_INFO_ACCESS = 93, + SEC_OID_X509_CRL_NUMBER = 94, + SEC_OID_X509_REASON_CODE = 95, + SEC_OID_X509_INVALID_DATE = 96, + SEC_OID_X500_RSA_ENCRYPTION = 97, + SEC_OID_RFC1274_UID = 98, + SEC_OID_RFC1274_MAIL = 99, + SEC_OID_PKCS12 = 100, + SEC_OID_PKCS12_MODE_IDS = 101, + SEC_OID_PKCS12_ESPVK_IDS = 102, + SEC_OID_PKCS12_BAG_IDS = 103, + SEC_OID_PKCS12_CERT_BAG_IDS = 104, + SEC_OID_PKCS12_OIDS = 105, + SEC_OID_PKCS12_PBE_IDS = 106, + SEC_OID_PKCS12_SIGNATURE_IDS = 107, + SEC_OID_PKCS12_ENVELOPING_IDS = 108, + SEC_OID_PKCS12_PKCS8_KEY_SHROUDING = 109, + SEC_OID_PKCS12_KEY_BAG_ID = 110, + SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID = 111, + SEC_OID_PKCS12_SECRET_BAG_ID = 112, + SEC_OID_PKCS12_X509_CERT_CRL_BAG = 113, + SEC_OID_PKCS12_SDSI_CERT_BAG = 114, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4 = 115, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4 = 116, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC = 117, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 118, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 119, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4 = 120, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4 = 121, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES = 122, + SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST = 123, + SEC_OID_ANSIX9_DSA_SIGNATURE = 124, + SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST = 125, + SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST = 126, + SEC_OID_VERISIGN_USER_NOTICES = 127, + SEC_OID_PKIX_CPS_POINTER_QUALIFIER = 128, + SEC_OID_PKIX_USER_NOTICE_QUALIFIER = 129, + SEC_OID_PKIX_OCSP = 130, + SEC_OID_PKIX_OCSP_BASIC_RESPONSE = 131, + SEC_OID_PKIX_OCSP_NONCE = 132, + SEC_OID_PKIX_OCSP_CRL = 133, + SEC_OID_PKIX_OCSP_RESPONSE = 134, + SEC_OID_PKIX_OCSP_NO_CHECK = 135, + SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF = 136, + SEC_OID_PKIX_OCSP_SERVICE_LOCATOR = 137, + SEC_OID_PKIX_REGCTRL_REGTOKEN = 138, + SEC_OID_PKIX_REGCTRL_AUTHENTICATOR = 139, + SEC_OID_PKIX_REGCTRL_PKIPUBINFO = 140, + SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS = 141, + SEC_OID_PKIX_REGCTRL_OLD_CERT_ID = 142, + SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY = 143, + SEC_OID_PKIX_REGINFO_UTF8_PAIRS = 144, + SEC_OID_PKIX_REGINFO_CERT_REQUEST = 145, + SEC_OID_EXT_KEY_USAGE_SERVER_AUTH = 146, + SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH = 147, + SEC_OID_EXT_KEY_USAGE_CODE_SIGN = 148, + SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT = 149, + SEC_OID_EXT_KEY_USAGE_TIME_STAMP = 150, + SEC_OID_OCSP_RESPONDER = 151, + SEC_OID_NETSCAPE_SMIME_KEA = 152, + SEC_OID_FORTEZZA_SKIPJACK = 153, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4 = 154, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4 = 155, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC = 156, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC = 157, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 158, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 159, + SEC_OID_PKCS12_SAFE_CONTENTS_ID = 160, + SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID = 161, + SEC_OID_PKCS12_V1_KEY_BAG_ID = 162, + SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID = 163, + SEC_OID_PKCS12_V1_CERT_BAG_ID = 164, + SEC_OID_PKCS12_V1_CRL_BAG_ID = 165, + SEC_OID_PKCS12_V1_SECRET_BAG_ID = 166, + SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID = 167, + SEC_OID_PKCS9_X509_CERT = 168, + SEC_OID_PKCS9_SDSI_CERT = 169, + SEC_OID_PKCS9_X509_CRL = 170, + SEC_OID_PKCS9_FRIENDLY_NAME = 171, + SEC_OID_PKCS9_LOCAL_KEY_ID = 172, + SEC_OID_BOGUS_KEY_USAGE = 173, + SEC_OID_X942_DIFFIE_HELMAN_KEY = 174, + SEC_OID_NETSCAPE_NICKNAME = 175, + SEC_OID_NETSCAPE_RECOVERY_REQUEST = 176, + SEC_OID_CERT_RENEWAL_LOCATOR = 177, + SEC_OID_NS_CERT_EXT_SCOPE_OF_USE = 178, + SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN = 179, + SEC_OID_CMS_3DES_KEY_WRAP = 180, + SEC_OID_CMS_RC2_KEY_WRAP = 181, + SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE = 182, + SEC_OID_AES_128_ECB = 183, + SEC_OID_AES_128_CBC = 184, + SEC_OID_AES_192_ECB = 185, + SEC_OID_AES_192_CBC = 186, + SEC_OID_AES_256_ECB = 187, + SEC_OID_AES_256_CBC = 188, + SEC_OID_SDN702_DSA_SIGNATURE = 189, + SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE = 190, + SEC_OID_SHA256 = 191, + SEC_OID_SHA384 = 192, + SEC_OID_SHA512 = 193, + SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION = 194, + SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION = 195, + SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION = 196, + SEC_OID_AES_128_KEY_WRAP = 197, + SEC_OID_AES_192_KEY_WRAP = 198, + SEC_OID_AES_256_KEY_WRAP = 199, + SEC_OID_ANSIX962_EC_PUBLIC_KEY = 200, + SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE = 201, + SEC_OID_ANSIX962_EC_PRIME192V1 = 202, + SEC_OID_ANSIX962_EC_PRIME192V2 = 203, + SEC_OID_ANSIX962_EC_PRIME192V3 = 204, + SEC_OID_ANSIX962_EC_PRIME239V1 = 205, + SEC_OID_ANSIX962_EC_PRIME239V2 = 206, + SEC_OID_ANSIX962_EC_PRIME239V3 = 207, + SEC_OID_SECG_EC_SECP256R1 = 208, + SEC_OID_SECG_EC_SECP112R1 = 209, + SEC_OID_SECG_EC_SECP112R2 = 210, + SEC_OID_SECG_EC_SECP128R1 = 211, + SEC_OID_SECG_EC_SECP128R2 = 212, + SEC_OID_SECG_EC_SECP160K1 = 213, + SEC_OID_SECG_EC_SECP160R1 = 214, + SEC_OID_SECG_EC_SECP160R2 = 215, + SEC_OID_SECG_EC_SECP192K1 = 216, + SEC_OID_SECG_EC_SECP224K1 = 217, + SEC_OID_SECG_EC_SECP224R1 = 218, + SEC_OID_SECG_EC_SECP256K1 = 219, + SEC_OID_SECG_EC_SECP384R1 = 220, + SEC_OID_SECG_EC_SECP521R1 = 221, + SEC_OID_ANSIX962_EC_C2PNB163V1 = 222, + SEC_OID_ANSIX962_EC_C2PNB163V2 = 223, + SEC_OID_ANSIX962_EC_C2PNB163V3 = 224, + SEC_OID_ANSIX962_EC_C2PNB176V1 = 225, + SEC_OID_ANSIX962_EC_C2TNB191V1 = 226, + SEC_OID_ANSIX962_EC_C2TNB191V2 = 227, + SEC_OID_ANSIX962_EC_C2TNB191V3 = 228, + SEC_OID_ANSIX962_EC_C2ONB191V4 = 229, + SEC_OID_ANSIX962_EC_C2ONB191V5 = 230, + SEC_OID_ANSIX962_EC_C2PNB208W1 = 231, + SEC_OID_ANSIX962_EC_C2TNB239V1 = 232, + SEC_OID_ANSIX962_EC_C2TNB239V2 = 233, + SEC_OID_ANSIX962_EC_C2TNB239V3 = 234, + SEC_OID_ANSIX962_EC_C2ONB239V4 = 235, + SEC_OID_ANSIX962_EC_C2ONB239V5 = 236, + SEC_OID_ANSIX962_EC_C2PNB272W1 = 237, + SEC_OID_ANSIX962_EC_C2PNB304W1 = 238, + SEC_OID_ANSIX962_EC_C2TNB359V1 = 239, + SEC_OID_ANSIX962_EC_C2PNB368W1 = 240, + SEC_OID_ANSIX962_EC_C2TNB431R1 = 241, + SEC_OID_SECG_EC_SECT113R1 = 242, + SEC_OID_SECG_EC_SECT113R2 = 243, + SEC_OID_SECG_EC_SECT131R1 = 244, + SEC_OID_SECG_EC_SECT131R2 = 245, + SEC_OID_SECG_EC_SECT163K1 = 246, + SEC_OID_SECG_EC_SECT163R1 = 247, + SEC_OID_SECG_EC_SECT163R2 = 248, + SEC_OID_SECG_EC_SECT193R1 = 249, + SEC_OID_SECG_EC_SECT193R2 = 250, + SEC_OID_SECG_EC_SECT233K1 = 251, + SEC_OID_SECG_EC_SECT233R1 = 252, + SEC_OID_SECG_EC_SECT239K1 = 253, + SEC_OID_SECG_EC_SECT283K1 = 254, + SEC_OID_SECG_EC_SECT283R1 = 255, + SEC_OID_SECG_EC_SECT409K1 = 256, + SEC_OID_SECG_EC_SECT409R1 = 257, + SEC_OID_SECG_EC_SECT571K1 = 258, + SEC_OID_SECG_EC_SECT571R1 = 259, + SEC_OID_NETSCAPE_AOLSCREENNAME = 260, + SEC_OID_AVA_SURNAME = 261, + SEC_OID_AVA_SERIAL_NUMBER = 262, + SEC_OID_AVA_STREET_ADDRESS = 263, + SEC_OID_AVA_TITLE = 264, + SEC_OID_AVA_POSTAL_ADDRESS = 265, + SEC_OID_AVA_POSTAL_CODE = 266, + SEC_OID_AVA_POST_OFFICE_BOX = 267, + SEC_OID_AVA_GIVEN_NAME = 268, + SEC_OID_AVA_INITIALS = 269, + SEC_OID_AVA_GENERATION_QUALIFIER = 270, + SEC_OID_AVA_HOUSE_IDENTIFIER = 271, + SEC_OID_AVA_PSEUDONYM = 272, + SEC_OID_PKIX_CA_ISSUERS = 273, + SEC_OID_PKCS9_EXTENSION_REQUEST = 274, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST = 275, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST = 276, + SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE = 277, + SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278, + SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279, + SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280, + SEC_OID_X509_HOLD_INSTRUCTION_CODE = 281, + SEC_OID_X509_DELTA_CRL_INDICATOR = 282, + SEC_OID_X509_ISSUING_DISTRIBUTION_POINT = 283, + SEC_OID_X509_CERT_ISSUER = 284, + SEC_OID_X509_FRESHEST_CRL = 285, + SEC_OID_X509_INHIBIT_ANY_POLICY = 286, + SEC_OID_X509_SUBJECT_INFO_ACCESS = 287, + SEC_OID_CAMELLIA_128_CBC = 288, + SEC_OID_CAMELLIA_192_CBC = 289, + SEC_OID_CAMELLIA_256_CBC = 290, + SEC_OID_PKCS5_PBKDF2 = 291, + SEC_OID_PKCS5_PBES2 = 292, + SEC_OID_PKCS5_PBMAC1 = 293, + SEC_OID_HMAC_SHA1 = 294, + SEC_OID_HMAC_SHA224 = 295, + SEC_OID_HMAC_SHA256 = 296, + SEC_OID_HMAC_SHA384 = 297, + SEC_OID_HMAC_SHA512 = 298, + SEC_OID_PKIX_TIMESTAMPING = 299, + SEC_OID_PKIX_CA_REPOSITORY = 300, + SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE = 301, + SEC_OID_SEED_CBC = 302, + SEC_OID_X509_ANY_POLICY = 303, + SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION = 304, + SEC_OID_PKCS1_MGF1 = 305, + SEC_OID_PKCS1_PSPECIFIED = 306, + SEC_OID_PKCS1_RSA_PSS_SIGNATURE = 307, + SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION = 308, + SEC_OID_SHA224 = 309, + SEC_OID_EV_INCORPORATION_LOCALITY = 310, + SEC_OID_EV_INCORPORATION_STATE = 311, + SEC_OID_EV_INCORPORATION_COUNTRY = 312, + SEC_OID_BUSINESS_CATEGORY = 313, + SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST = 314, + SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST = 315, + SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING = 316, + SEC_OID_AVA_NAME = 317, + SEC_OID_AES_128_GCM = 318, + SEC_OID_AES_192_GCM = 319, + SEC_OID_AES_256_GCM = 320, + SEC_OID_IDEA_CBC = 321, + SEC_OID_RC2_40_CBC = 322, + SEC_OID_DES_40_CBC = 323, + SEC_OID_RC4_40 = 324, + SEC_OID_RC4_56 = 325, + SEC_OID_NULL_CIPHER = 326, + SEC_OID_HMAC_MD5 = 327, + SEC_OID_TLS_RSA = 328, + SEC_OID_TLS_DHE_RSA = 329, + SEC_OID_TLS_DHE_DSS = 330, + SEC_OID_TLS_DH_RSA = 331, + SEC_OID_TLS_DH_DSS = 332, + SEC_OID_TLS_DH_ANON = 333, + SEC_OID_TLS_ECDHE_ECDSA = 334, + SEC_OID_TLS_ECDHE_RSA = 335, + SEC_OID_TLS_ECDH_ECDSA = 336, + SEC_OID_TLS_ECDH_RSA = 337, + SEC_OID_TLS_ECDH_ANON = 338, + SEC_OID_TLS_RSA_EXPORT = 339, + SEC_OID_TLS_DHE_RSA_EXPORT = 340, + SEC_OID_TLS_DHE_DSS_EXPORT = 341, + SEC_OID_TLS_DH_RSA_EXPORT = 342, + SEC_OID_TLS_DH_DSS_EXPORT = 343, + SEC_OID_TLS_DH_ANON_EXPORT = 344, + SEC_OID_APPLY_SSL_POLICY = 345, + SEC_OID_CHACHA20_POLY1305 = 346, + SEC_OID_TLS_ECDHE_PSK = 347, + SEC_OID_TLS_DHE_PSK = 348, + SEC_OID_TLS_FFDHE_2048 = 349, + SEC_OID_TLS_FFDHE_3072 = 350, + SEC_OID_TLS_FFDHE_4096 = 351, + SEC_OID_TLS_FFDHE_6144 = 352, + SEC_OID_TLS_FFDHE_8192 = 353, + SEC_OID_TLS_DHE_CUSTOM = 354, + SEC_OID_CURVE25519 = 355, + SEC_OID_TLS13_KEA_ANY = 356, + SEC_OID_X509_ANY_EXT_KEY_USAGE = 357, + SEC_OID_EXT_KEY_USAGE_IPSEC_IKE = 358, + SEC_OID_IPSEC_IKE_END = 359, + SEC_OID_IPSEC_IKE_INTERMEDIATE = 360, + SEC_OID_EXT_KEY_USAGE_IPSEC_END = 361, + SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL = 362, + SEC_OID_EXT_KEY_USAGE_IPSEC_USER = 363, + SEC_OID_TOTAL = 364, +} diff --git a/third_party/rust/nss_sys/src/bindings/secport.rs b/third_party/rust/nss_sys/src/bindings/secport.rs @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::*; +use std::os::raw::{c_int, c_void}; + +pub type size_t = usize; + +extern "C" { + pub fn PORT_FreeArena(arena: *mut PLArenaPool, zero: PRBool); + pub fn NSS_SecureMemcmp(a: *const c_void, b: *const c_void, n: size_t) -> c_int; +} diff --git a/third_party/rust/nss_sys/src/lib.rs b/third_party/rust/nss_sys/src/lib.rs @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![allow(unknown_lints)] +#![warn(rust_2018_idioms)] +#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] + +mod bindings; +pub use bindings::*; + +// So we link against the SQLite lib imported by parent crates +// such as places and logins. +#[allow(unused_extern_crates)] +#[cfg(any(not(feature = "gecko"), __appsvc_ci_hack))] +extern crate libsqlite3_sys; diff --git a/third_party/rust/rc_crypto/.cargo-checksum.json b/third_party/rust/rc_crypto/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"4cb5761465758109551f7e58fbb94b423d8230a8c3200e022b297b69d5c176c2","README.md":"110e6647522bf94adb22a8659ac93b5f5213b0832d3610acc8f137964962311a","src/aead.rs":"056c58687489347442411a407600a4917c4c044ec8208215280c3d5b3a28acc1","src/aead/aes_cbc.rs":"a8de38ba4288c21662faceb0985ada899314ea242845146d40905801718b4fa6","src/aead/aes_gcm.rs":"161e05df2cd51261a188edc476ec0a6d7888731f94e661a48ee6e6299e39a2d2","src/agreement.rs":"3efd9e5df1559f716952cd31690f62a778930c09a33c116fa9d6431a07f94d14","src/constant_time.rs":"8856965601d0a4705b68d7ff87e35d57a2f59b007b2d6f519dac624efc7a0ff5","src/contentsignature.rs":"bd2378f965a0d8f99694f6efcff9a807862b8665e4963ef4016a10c3d14272e5","src/digest.rs":"8b0de193c351decd34245ceecb6b25ddd2a15e94bc50d720a6a3ca17a94c2c53","src/ece_crypto.rs":"8aff8da0e64d87e6707bc46bc0028d9aea5c6d3aa456aec74e2e05fe4f04a622","src/error.rs":"2e0ab278977fe511ac75d56517a67d1961f63acc5aa27d4140ae7eec07e9cf21","src/hawk_crypto.rs":"0c5408c303fd71feb2285ff31ccff121ce976ceb4cc3544ba356b1946d1dd50f","src/hkdf.rs":"0ee1f7992b9a491b176af335ee10f5cf38d3f3638a5b2649576db8ab57108d9e","src/hmac.rs":"8d521acd0b7b5c9373a1318213fbab0a3a469c0c175449d86f3160edbfbc789c","src/lib.rs":"40d9906485880f1b677967eb430b7b6d4941d56dfe5c9a77c34e49e4fd3956f8","src/pbkdf2.rs":"7dd3321b49e072046302020d0dacc924465f0cb9e431c10c51f55801c3bfe829","src/rand.rs":"ccdd1051d06e1a40b577a907702394e286c3e4825356a3666738187cb57f661e","src/signature.rs":"f8185f0586f6edec1dd1966c38f3dc6c0778bb50d488e671051fd55afe4d2ff8"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/rc_crypto/Cargo.toml b/third_party/rust/rc_crypto/Cargo.toml @@ -0,0 +1,64 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "rc_crypto" +version = "0.1.0" +authors = ["Sync Team <sync-team@mozilla.com>"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +readme = "README.md" +license = "MPL-2.0" + +[features] +backtrace = ["error-support/backtrace"] +default = [] +gecko = ["nss/gecko"] + +[lib] +name = "rc_crypto" +crate-type = ["lib"] +path = "src/lib.rs" + +[dependencies] +base64 = "0.21" +hex = "0.4" +thiserror = "2" + +[dependencies.ece] +version = "2.3" +features = ["serializable-keys"] +optional = true +default-features = false + +[dependencies.error-support] +path = "../error" + +[dependencies.hawk] +version = "5" +optional = true +default-features = false + +[dependencies.nss] +path = "nss" + +[dev-dependencies.ece] +version = "2.0" +features = [ + "serializable-keys", + "backend-test-helper", +] +default-features = false diff --git a/third_party/rust/rc_crypto/README.md b/third_party/rust/rc_crypto/README.md @@ -0,0 +1,27 @@ +# rc_crypto + +The `rc_crypto` crate, like its name implies, handles all of our cryptographic needs. + +For consumers, it pretty much follows the very rust-idiomatic [ring crate API](https://briansmith.org/rustdoc/ring/) and +offers the following functionality: + +* Cryptographically secure [pseudorandom number generation](./src/rand.rs). +* Cryptographic [digests](./src/digest.rs), [hmac](./src/hmac.rs), and [hkdf](./src/hkdf.rs). +* Authenticated encryption ([AEAD](./src/aead.rs)) routines. +* ECDH [key agreement](./src/agreement.rs). +* ECDSA [signature verification](./src/signature.rs). +* Constant-time [string comparison](./src/constant_time.rs). +* HTTP [Hawk Authentication](./src/hawk_crypto.rs) through the [rust-hawk crate](https://github.com/taskcluster/rust-hawk/). +* HTTP [Encrypted Content-Encoding](./src/ece.rs) through the [ece crate](https://github.com/mozilla/rust-ece). + +Under the hood, it is backed by Mozilla's [NSS](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS) library, +through bindings in the [nss](./nss/) crate. This has a number of advantages for our use-case: + +* Uses Mozilla-owned-and-audited crypto primitives. +* Decouples us from ring's fast-moving [versioning and stability + policy](https://github.com/briansmith/ring#versioning--stability). + + +## Rust features + +- `gecko` will avoid linking against libsqlite3_sys's libsqlite. See [#2882](https://github.com/mozilla/application-services/issues/2882) for context. diff --git a/third_party/rust/rc_crypto/src/aead.rs b/third_party/rust/rc_crypto/src/aead.rs @@ -0,0 +1,324 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +mod aes_cbc; +mod aes_gcm; + +use crate::error::*; +pub use aes_cbc::LEGACY_SYNC_AES_256_CBC_HMAC_SHA256; +pub use aes_gcm::{AES_128_GCM, AES_256_GCM}; +use nss::aes; + +pub fn open( + key: &OpeningKey, + nonce: Nonce, + aad: Aad<'_>, + ciphertext_and_tag: &[u8], +) -> Result<Vec<u8>> { + (key.algorithm().open)(&key.key, nonce, &aad, ciphertext_and_tag) +} + +pub fn seal(key: &SealingKey, nonce: Nonce, aad: Aad<'_>, plaintext: &[u8]) -> Result<Vec<u8>> { + (key.algorithm().seal)(&key.key, nonce, &aad, plaintext) +} + +/// The additional authenticated data (AAD) for an opening or sealing +/// operation. This data is authenticated but is **not** encrypted. +/// This is a type-safe wrapper around the raw bytes designed to encourage +/// correct use of the API. +#[repr(transparent)] +pub struct Aad<'a>(&'a [u8]); + +impl<'a> Aad<'a> { + /// Construct the `Aad` by borrowing a contiguous sequence of bytes. + #[inline] + pub fn from(aad: &'a [u8]) -> Self { + Aad(aad) + } +} + +impl Aad<'static> { + /// Construct an empty `Aad`. + pub fn empty() -> Self { + Self::from(&[]) + } +} + +/// The nonce for an opening or sealing operation. +/// This is a type-safe wrapper around the raw bytes designed to encourage +/// correct use of the API. +pub struct Nonce(Vec<u8>); + +impl Nonce { + #[inline] + pub fn try_assume_unique_for_key(algorithm: &'static Algorithm, value: &[u8]) -> Result<Self> { + if value.len() != algorithm.nonce_len() { + return Err(ErrorKind::InternalError.into()); + } + Ok(Self(value.to_vec())) + } +} + +pub struct OpeningKey { + key: Key, +} + +impl OpeningKey { + /// Create a new opening key. + /// + /// `key_bytes` must be exactly `algorithm.key_len` bytes long. + #[inline] + pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self> { + Ok(Self { + key: Key::new(algorithm, key_bytes)?, + }) + } + + /// The key's AEAD algorithm. + #[inline] + pub fn algorithm(&self) -> &'static Algorithm { + self.key.algorithm() + } +} + +pub struct SealingKey { + key: Key, +} + +impl SealingKey { + /// Create a new sealing key. + /// + /// `key_bytes` must be exactly `algorithm.key_len` bytes long. + #[inline] + pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self> { + Ok(Self { + key: Key::new(algorithm, key_bytes)?, + }) + } + + /// The key's AEAD algorithm. + #[inline] + pub fn algorithm(&self) -> &'static Algorithm { + self.key.algorithm() + } +} + +/// `OpeningKey` and `SealingKey` are type-safety wrappers around `Key`. +pub(crate) struct Key { + key_value: Vec<u8>, + algorithm: &'static Algorithm, +} + +impl Key { + fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self> { + if key_bytes.len() != algorithm.key_len() { + return Err(ErrorKind::InternalError.into()); + } + Ok(Key { + key_value: key_bytes.to_vec(), + algorithm, + }) + } + + #[inline] + pub fn algorithm(&self) -> &'static Algorithm { + self.algorithm + } +} + +// An AEAD algorithm. +#[allow(clippy::type_complexity)] +pub struct Algorithm { + tag_len: usize, + key_len: usize, + nonce_len: usize, + open: fn(key: &Key, nonce: Nonce, aad: &Aad<'_>, ciphertext_and_tag: &[u8]) -> Result<Vec<u8>>, + seal: fn(key: &Key, nonce: Nonce, aad: &Aad<'_>, plaintext: &[u8]) -> Result<Vec<u8>>, +} + +impl Algorithm { + /// The length of the key. + #[inline] + pub const fn key_len(&self) -> usize { + self.key_len + } + + /// The length of a tag. + #[inline] + pub const fn tag_len(&self) -> usize { + self.tag_len + } + + /// The length of the nonces. + #[inline] + pub const fn nonce_len(&self) -> usize { + self.nonce_len + } +} + +pub(crate) enum Direction { + Opening, + Sealing, +} + +impl Direction { + fn to_nss_operation(&self) -> aes::Operation { + match self { + Direction::Opening => aes::Operation::Decrypt, + Direction::Sealing => aes::Operation::Encrypt, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use nss::ensure_initialized; + + static ALL_ALGORITHMS: &[&Algorithm] = &[ + &LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, + &AES_128_GCM, + &AES_256_GCM, + ]; + static ALL_ALGORITHMS_THAT_SUPPORT_AAD: &[&Algorithm] = &[&AES_128_GCM, &AES_256_GCM]; + + #[test] + fn test_roundtrip() { + ensure_initialized(); + for algorithm in ALL_ALGORITHMS { + let mut cleartext_bytes = vec![0u8; 127]; + crate::rand::fill(&mut cleartext_bytes).unwrap(); + + let mut key_bytes = vec![0u8; algorithm.key_len()]; + crate::rand::fill(&mut key_bytes).unwrap(); + + let nonce_bytes = vec![0u8; algorithm.nonce_len()]; + + let key = SealingKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let ciphertext_bytes = seal(&key, nonce, Aad::empty(), &cleartext_bytes).unwrap(); + + let key = OpeningKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let roundtriped_cleartext_bytes = + open(&key, nonce, Aad::empty(), &ciphertext_bytes).unwrap(); + assert_eq!(roundtriped_cleartext_bytes, cleartext_bytes); + } + } + + #[test] + fn test_cant_open_with_mismatched_key() { + ensure_initialized(); + let mut key_bytes_1 = vec![0u8; AES_256_GCM.key_len()]; + crate::rand::fill(&mut key_bytes_1).unwrap(); + + let mut key_bytes_2 = vec![0u8; AES_128_GCM.key_len()]; + crate::rand::fill(&mut key_bytes_2).unwrap(); + + let nonce_bytes = vec![0u8; AES_256_GCM.nonce_len()]; + + let key = SealingKey::new(&AES_256_GCM, &key_bytes_1).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(&AES_256_GCM, &nonce_bytes).unwrap(); + let ciphertext_bytes = seal(&key, nonce, Aad::empty(), &[0u8; 0]).unwrap(); + + let key = OpeningKey::new(&AES_128_GCM, &key_bytes_2).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(&AES_128_GCM, &nonce_bytes).unwrap(); + let result = open(&key, nonce, Aad::empty(), &ciphertext_bytes); + assert!(result.is_err()); + } + + #[test] + fn test_cant_open_modified_ciphertext() { + ensure_initialized(); + for algorithm in ALL_ALGORITHMS { + let mut key_bytes = vec![0u8; algorithm.key_len()]; + crate::rand::fill(&mut key_bytes).unwrap(); + + let nonce_bytes = vec![0u8; algorithm.nonce_len()]; + + let key = SealingKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let ciphertext_bytes = seal(&key, nonce, Aad::empty(), &[0u8; 0]).unwrap(); + + for i in 0..ciphertext_bytes.len() { + let mut modified_ciphertext = ciphertext_bytes.clone(); + modified_ciphertext[i] = modified_ciphertext[i].wrapping_add(1); + + let key = OpeningKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let result = open(&key, nonce, Aad::empty(), &modified_ciphertext); + assert!(result.is_err()); + } + } + } + + #[test] + fn test_cant_open_with_incorrect_associated_data() { + ensure_initialized(); + for algorithm in ALL_ALGORITHMS_THAT_SUPPORT_AAD { + let mut key_bytes = vec![0u8; algorithm.key_len()]; + crate::rand::fill(&mut key_bytes).unwrap(); + + let nonce_bytes = vec![0u8; algorithm.nonce_len()]; + + let key = SealingKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let ciphertext_bytes = seal(&key, nonce, Aad::from(&[1, 2, 3]), &[0u8; 0]).unwrap(); + + let key = OpeningKey::new(algorithm, &key_bytes).unwrap(); + let nonce = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes).unwrap(); + let result = open(&key, nonce, Aad::empty(), &ciphertext_bytes); + assert!(result.is_err()); + + let nonce = Nonce::try_assume_unique_for_key(&AES_256_GCM, &nonce_bytes).unwrap(); + let result = open(&key, nonce, Aad::from(&[2, 3, 4]), &ciphertext_bytes); + assert!(result.is_err()); + } + } + + #[test] + fn test_cant_use_incorrectly_sized_key() { + ensure_initialized(); + for algorithm in ALL_ALGORITHMS { + let key_bytes = vec![0u8; algorithm.key_len() - 1]; + let result = Key::new(algorithm, &key_bytes); + assert!(result.is_err()); + + let key_bytes = vec![0u8; algorithm.key_len() + 1]; + let result = Key::new(algorithm, &key_bytes); + assert!(result.is_err()); + } + } + + #[test] + fn test_cant_use_incorrectly_sized_nonce() { + ensure_initialized(); + for algorithm in ALL_ALGORITHMS { + let nonce_bytes = vec![0u8; algorithm.nonce_len() - 1]; + let result = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes); + assert!(result.is_err()); + + let nonce_bytes = vec![0u8; algorithm.nonce_len() + 1]; + let result = Nonce::try_assume_unique_for_key(algorithm, &nonce_bytes); + assert!(result.is_err()); + } + } +} diff --git a/third_party/rust/rc_crypto/src/aead/aes_cbc.rs b/third_party/rust/rc_crypto/src/aead/aes_cbc.rs @@ -0,0 +1,268 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::{aead, digest, error::*, hmac}; +use base64::{engine::general_purpose::STANDARD, Engine}; +use nss::aes; + +/// AES-256 in CBC mode with HMAC-SHA256 tags and 128 bit nonces. +/// This is a Sync 1.5 specific encryption scheme, do not use for new +/// applications, there are better options out there nowadays. +/// Important note: The HMAC tag verification is done against the +/// base64 representation of the ciphertext. +/// More details here: https://mozilla-services.readthedocs.io/en/latest/sync/storageformat5.html#record-encryption +pub static LEGACY_SYNC_AES_256_CBC_HMAC_SHA256: aead::Algorithm = aead::Algorithm { + key_len: 64, // 32 bytes for the AES key, 32 bytes for the HMAC key. + tag_len: 32, + nonce_len: 128 / 8, + open, + seal, +}; + +// Warning: This does not run in constant time (which is fine for our usage). +pub(crate) fn open( + key: &aead::Key, + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + ciphertext_and_tag: &[u8], +) -> Result<Vec<u8>> { + let ciphertext_len = ciphertext_and_tag + .len() + .checked_sub(key.algorithm().tag_len()) + .ok_or(ErrorKind::InternalError)?; + let (ciphertext, hmac_signature) = ciphertext_and_tag.split_at(ciphertext_len); + let (aes_key, hmac_key_bytes) = extract_keys(key); + // 1. Tag (HMAC signature) check. + let hmac_key = hmac::VerificationKey::new(&digest::SHA256, hmac_key_bytes); + hmac::verify( + &hmac_key, + STANDARD.encode(ciphertext).as_bytes(), + hmac_signature, + )?; + // 2. Decryption. + aes_cbc(aes_key, nonce, aad, ciphertext, aead::Direction::Opening) +} + +pub(crate) fn seal( + key: &aead::Key, + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + plaintext: &[u8], +) -> Result<Vec<u8>> { + let (aes_key, hmac_key_bytes) = extract_keys(key); + // 1. Encryption. + let mut ciphertext = aes_cbc(aes_key, nonce, aad, plaintext, aead::Direction::Sealing)?; + // 2. Tag (HMAC signature) generation. + let hmac_key = hmac::SigningKey::new(&digest::SHA256, hmac_key_bytes); + let signature = hmac::sign(&hmac_key, STANDARD.encode(&ciphertext).as_bytes())?; + ciphertext.extend(&signature.0.value); + Ok(ciphertext) +} + +fn extract_keys(key: &aead::Key) -> (&[u8], &[u8]) { + // Always split at 32 since we only do AES 256 w/ HMAC 256 tag. + let (aes_key, hmac_key_bytes) = key.key_value.split_at(32); + (aes_key, hmac_key_bytes) +} + +fn aes_cbc( + aes_key: &[u8], + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + data: &[u8], + direction: aead::Direction, +) -> Result<Vec<u8>> { + if !aad.0.is_empty() { + // CBC mode does not support AAD. + return Err(ErrorKind::InternalError.into()); + } + Ok(aes::aes_cbc_crypt( + aes_key, + &nonce.0, + data, + direction.to_nss_operation(), + )?) +} + +#[cfg(test)] +mod test { + use super::*; + use nss::ensure_initialized; + + // These are the test vectors used by the sync15 crate, but concatenated + // together rather than split into individual pieces. + const IV_B64: &str = "GX8L37AAb2FZJMzIoXlX8w=="; + + const KEY_B64: &str = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYHqeg3KW9+m6Qwye0R+62At\ + NzwWVMtAWazz/Ew+YKV2o+Wr9BBcSPHvQ=="; + + const CIPHERTEXT_AND_TAG_B64: &str = + "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn80QhbD80l0HEcZGCynh45qIbeYBik0lgcHbKm\ + lIxTJNwU+OeqipN+/j7MqhjKOGIlvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQzyGGkSYM2xU\ + Ft06aNivoQTvU2GgGmUK6MvadoY38hhW2LCMkoZcNfgCqJ26lO1O0sEO6zHsk3IVz6vsK\ + iJ2Hq6VCo7hu123wNegmujHWQSGyf8JeudZjKzfi0OFRRvvm4QAKyBWf0MgrW1F8SFDnV\ + fkq8amCB7NhdwhgLWbN+21NitNwWYknoEWe1m6hmGZDgDT32uxzWxCV8QqqrpH/ZggViE\ + r9uMgoy4lYaWqP7G5WKvvechc62aqnsNEYhH26A5QgzmlNyvB+KPFvPsYzxDnSCjOoRSL\ + x7GG86wT59QZyx5sGKww3rcCNrwNZaRvek3OO4sOAs+SGCuRTjr6XuvA=="; + + const CLEARTEXT_B64: &str = + "eyJpZCI6IjVxUnNnWFdSSlpYciIsImhpc3RVcmkiOiJmaWxlOi8vL1VzZXJzL2phc29u\ + L0xpYnJhcnkvQXBwbGljYXRpb24lMjBTdXBwb3J0L0ZpcmVmb3gvUHJvZmlsZXMva3Nn\ + ZDd3cGsuTG9jYWxTeW5jU2VydmVyL3dlYXZlL2xvZ3MvIiwidGl0bGUiOiJJbmRleCBv\ + ZiBmaWxlOi8vL1VzZXJzL2phc29uL0xpYnJhcnkvQXBwbGljYXRpb24gU3VwcG9ydC9G\ + aXJlZm94L1Byb2ZpbGVzL2tzZ2Q3d3BrLkxvY2FsU3luY1NlcnZlci93ZWF2ZS9sb2dz\ + LyIsInZpc2l0cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3MjQyNSwidHlwZSI6MX1dfQ=="; + + #[test] + fn test_decrypt() { + ensure_initialized(); + let key_bytes = STANDARD.decode(KEY_B64).unwrap(); + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let ciphertext_and_tag = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + let cleartext_bytes = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap(); + + let expected_cleartext_bytes = STANDARD.decode(CLEARTEXT_B64).unwrap(); + assert_eq!(&expected_cleartext_bytes, &cleartext_bytes); + } + + #[test] + fn test_encrypt() { + ensure_initialized(); + let key_bytes = STANDARD.decode(KEY_B64).unwrap(); + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let cleartext = STANDARD.decode(CLEARTEXT_B64).unwrap(); + + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap(); + + let expected_ciphertext_bytes = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + assert_eq!(&expected_ciphertext_bytes, &ciphertext_bytes); + } + + #[test] + fn test_roundtrip() { + ensure_initialized(); + let key_bytes = STANDARD.decode(KEY_B64).unwrap(); + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let cleartext = STANDARD.decode(CLEARTEXT_B64).unwrap(); + + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + let roundtriped_cleartext_bytes = + open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap(); + assert_eq!(roundtriped_cleartext_bytes, cleartext); + } + + #[test] + fn test_decrypt_fails_with_wrong_aes_key() { + ensure_initialized(); + let mut key_bytes = STANDARD.decode(KEY_B64).unwrap(); + key_bytes[1] = b'X'; + + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let ciphertext_and_tag = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + + let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err(); + match err.kind() { + ErrorKind::NSSError(_) | ErrorKind::InternalError => {} + _ => panic!("unexpected error kind"), + } + } + + #[test] + fn test_decrypt_fails_with_wrong_hmac_key() { + ensure_initialized(); + let mut key_bytes = STANDARD.decode(KEY_B64).unwrap(); + key_bytes[60] = b'X'; + + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let ciphertext_and_tag = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + + let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err(); + match err.kind() { + ErrorKind::InternalError => {} + _ => panic!("unexpected error kind"), + } + } + + #[test] + fn test_decrypt_fails_with_modified_ciphertext() { + ensure_initialized(); + let key_bytes = STANDARD.decode(KEY_B64).unwrap(); + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + + let mut ciphertext_and_tag = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + ciphertext_and_tag[4] = b'Z'; + + let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err(); + match err.kind() { + ErrorKind::InternalError => {} + _ => panic!("unexpected error kind"), + } + } + + #[test] + fn test_decrypt_fails_with_modified_tag() { + ensure_initialized(); + let key_bytes = STANDARD.decode(KEY_B64).unwrap(); + let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap(); + let iv = STANDARD.decode(IV_B64).unwrap(); + let nonce = + aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv) + .unwrap(); + + let mut ciphertext_and_tag = STANDARD.decode(CIPHERTEXT_AND_TAG_B64).unwrap(); + let end = ciphertext_and_tag.len(); + ciphertext_and_tag[end - 4] = b'Z'; + + let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err(); + match err.kind() { + ErrorKind::InternalError => {} + _ => panic!("unexpected error kind"), + } + } +} diff --git a/third_party/rust/rc_crypto/src/aead/aes_gcm.rs b/third_party/rust/rc_crypto/src/aead/aes_gcm.rs @@ -0,0 +1,150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::{aead, error::*}; +use nss::aes; + +/// AES-128 in GCM mode with 128-bit tags and 96 bit nonces. +pub static AES_128_GCM: aead::Algorithm = aead::Algorithm { + key_len: 16, + tag_len: 16, + nonce_len: 96 / 8, + open, + seal, +}; + +/// AES-256 in GCM mode with 128-bit tags and 96 bit nonces. +pub static AES_256_GCM: aead::Algorithm = aead::Algorithm { + key_len: 32, + tag_len: 16, + nonce_len: 96 / 8, + open, + seal, +}; + +pub(crate) fn open( + key: &aead::Key, + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + ciphertext_and_tag: &[u8], +) -> Result<Vec<u8>> { + aes_gcm( + key, + nonce, + aad, + ciphertext_and_tag, + aead::Direction::Opening, + ) +} + +pub(crate) fn seal( + key: &aead::Key, + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + plaintext: &[u8], +) -> Result<Vec<u8>> { + aes_gcm(key, nonce, aad, plaintext, aead::Direction::Sealing) +} + +fn aes_gcm( + key: &aead::Key, + nonce: aead::Nonce, + aad: &aead::Aad<'_>, + data: &[u8], + direction: aead::Direction, +) -> Result<Vec<u8>> { + Ok(aes::aes_gcm_crypt( + &key.key_value, + &nonce.0, + aad.0, + data, + direction.to_nss_operation(), + )?) +} + +#[cfg(test)] +mod test { + use super::*; + use nss::ensure_initialized; + + // Test vector from the AES-GCM spec. + const NONCE_HEX: &str = "cafebabefacedbaddecaf888"; + const KEY_HEX: &str = "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308"; + const AAD_HEX: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2"; + const TAG_HEX: &str = "76fc6ece0f4e1768cddf8853bb2d551b"; + const CIPHERTEXT_HEX: &str = + "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662"; + const CLEARTEXT_HEX: &str = + "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"; + + #[test] + fn test_decrypt() { + ensure_initialized(); + let key_bytes = hex::decode(KEY_HEX).unwrap(); + let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap(); + let mut ciphertext_and_tag = hex::decode(CIPHERTEXT_HEX).unwrap(); + let tag = hex::decode(TAG_HEX).unwrap(); + ciphertext_and_tag.extend(&tag); + + let iv = hex::decode(NONCE_HEX).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap(); + let aad_bytes = hex::decode(AAD_HEX).unwrap(); + let aad = aead::Aad::from(&aad_bytes); + let cleartext_bytes = open(&key, nonce, &aad, &ciphertext_and_tag).unwrap(); + let encoded_cleartext = hex::encode(cleartext_bytes); + assert_eq!(&CLEARTEXT_HEX, &encoded_cleartext); + } + + #[test] + fn test_encrypt() { + ensure_initialized(); + let key_bytes = hex::decode(KEY_HEX).unwrap(); + let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap(); + let cleartext = hex::decode(CLEARTEXT_HEX).unwrap(); + + let iv = hex::decode(NONCE_HEX).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap(); + let aad_bytes = hex::decode(AAD_HEX).unwrap(); + let aad = aead::Aad::from(&aad_bytes); + let ciphertext_bytes = seal(&key, nonce, &aad, &cleartext).unwrap(); + + let expected_tag = hex::decode(TAG_HEX).unwrap(); + let mut expected_ciphertext = hex::decode(CIPHERTEXT_HEX).unwrap(); + expected_ciphertext.extend(&expected_tag); + assert_eq!(&expected_ciphertext, &ciphertext_bytes); + } + + #[test] + fn test_roundtrip() { + ensure_initialized(); + let key_bytes = hex::decode(KEY_HEX).unwrap(); + let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap(); + let cleartext = hex::decode(CLEARTEXT_HEX).unwrap(); + + let iv = hex::decode(NONCE_HEX).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap(); + let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap(); + let roundtriped_cleartext_bytes = + open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap(); + assert_eq!(roundtriped_cleartext_bytes, cleartext); + } +} diff --git a/third_party/rust/rc_crypto/src/agreement.rs b/third_party/rust/rc_crypto/src/agreement.rs @@ -0,0 +1,417 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::error::*; +use core::marker::PhantomData; + +pub use ec::{Curve, EcKey}; +use nss::{ec, ecdh}; + +pub type EphemeralKeyPair = KeyPair<Ephemeral>; + +/// A key agreement algorithm. +#[derive(PartialEq, Eq)] +pub struct Algorithm { + pub(crate) curve_id: ec::Curve, +} + +pub static ECDH_P256: Algorithm = Algorithm { + curve_id: ec::Curve::P256, +}; + +pub static ECDH_P384: Algorithm = Algorithm { + curve_id: ec::Curve::P384, +}; + +/// How many times the key may be used. +pub trait Lifetime {} + +/// The key may be used at most once. +pub struct Ephemeral {} +impl Lifetime for Ephemeral {} + +/// The key may be used more than once. +pub struct Static {} +impl Lifetime for Static {} + +/// A key pair for key agreement. +pub struct KeyPair<U: Lifetime> { + private_key: PrivateKey<U>, + public_key: PublicKey, +} + +impl<U: Lifetime> KeyPair<U> { + /// Generate a new key pair for the given algorithm. + pub fn generate(alg: &'static Algorithm) -> Result<Self> { + let (prv_key, pub_key) = ec::generate_keypair(alg.curve_id)?; + Ok(Self { + private_key: PrivateKey { + alg, + wrapped: prv_key, + usage: PhantomData, + }, + public_key: PublicKey { + alg, + wrapped: pub_key, + }, + }) + } + + pub fn from_private_key(private_key: PrivateKey<U>) -> Result<Self> { + let public_key = private_key + .compute_public_key() + .map_err(|_| ErrorKind::InternalError)?; + Ok(Self { + private_key, + public_key, + }) + } + + /// The private key. + pub fn private_key(&self) -> &PrivateKey<U> { + &self.private_key + } + + /// The public key. + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } + + /// Split the key pair apart. + pub fn split(self) -> (PrivateKey<U>, PublicKey) { + (self.private_key, self.public_key) + } +} + +impl KeyPair<Static> { + pub fn from(private_key: PrivateKey<Static>) -> Result<Self> { + Self::from_private_key(private_key) + } +} + +/// A public key for key agreement. +pub struct PublicKey { + wrapped: ec::PublicKey, + alg: &'static Algorithm, +} + +impl PublicKey { + #[inline] + pub fn to_bytes(&self) -> Result<Vec<u8>> { + Ok(self.wrapped.to_bytes()?) + } + + #[inline] + pub fn algorithm(&self) -> &'static Algorithm { + self.alg + } +} + +/// An unparsed public key for key agreement. +pub struct UnparsedPublicKey<'a> { + alg: &'static Algorithm, + bytes: &'a [u8], +} + +impl<'a> UnparsedPublicKey<'a> { + pub fn new(algorithm: &'static Algorithm, bytes: &'a [u8]) -> Self { + Self { + alg: algorithm, + bytes, + } + } + + pub fn algorithm(&self) -> &'static Algorithm { + self.alg + } + + pub fn bytes(&self) -> &'a [u8] { + self.bytes + } +} + +/// A private key for key agreement. +pub struct PrivateKey<U: Lifetime> { + wrapped: ec::PrivateKey, + alg: &'static Algorithm, + usage: PhantomData<U>, +} + +impl<U: Lifetime> PrivateKey<U> { + #[inline] + pub fn algorithm(&self) -> &'static Algorithm { + self.alg + } + + pub fn compute_public_key(&self) -> Result<PublicKey> { + let pub_key = self.wrapped.convert_to_public_key()?; + Ok(PublicKey { + wrapped: pub_key, + alg: self.alg, + }) + } + + /// Ephemeral agreement. + /// This consumes `self`, ensuring that the private key can + /// only be used for a single agreement operation. + pub fn agree(self, peer_public_key: &UnparsedPublicKey<'_>) -> Result<InputKeyMaterial> { + agree_(&self.wrapped, self.alg, peer_public_key) + } +} + +impl PrivateKey<Static> { + /// Static agreement. + /// This borrows `self`, allowing the private key to + /// be used for a multiple agreement operations. + pub fn agree_static( + &self, + peer_public_key: &UnparsedPublicKey<'_>, + ) -> Result<InputKeyMaterial> { + agree_(&self.wrapped, self.alg, peer_public_key) + } + + pub fn import(ec_key: &EcKey) -> Result<Self> { + // XXX: we should just let ec::PrivateKey own alg. + let alg = match ec_key.curve() { + Curve::P256 => &ECDH_P256, + Curve::P384 => &ECDH_P384, + }; + let private_key = ec::PrivateKey::import(ec_key)?; + Ok(Self { + wrapped: private_key, + alg, + usage: PhantomData, + }) + } + + pub fn export(&self) -> Result<EcKey> { + Ok(self.wrapped.export()?) + } + + /// The whole point of having `Ephemeral` and `Static` lifetimes is to use the type + /// system to avoid re-using the same ephemeral key. However for tests we might need + /// to create a "static" ephemeral key. + pub fn _tests_only_dangerously_convert_to_ephemeral(self) -> PrivateKey<Ephemeral> { + PrivateKey::<Ephemeral> { + wrapped: self.wrapped, + alg: self.alg, + usage: PhantomData, + } + } +} + +fn agree_( + my_private_key: &ec::PrivateKey, + my_alg: &Algorithm, + peer_public_key: &UnparsedPublicKey<'_>, +) -> Result<InputKeyMaterial> { + let alg = &my_alg; + if peer_public_key.algorithm() != *alg { + return Err(ErrorKind::InternalError.into()); + } + let pub_key = ec::PublicKey::from_bytes(my_private_key.curve(), peer_public_key.bytes())?; + let value = ecdh::ecdh_agreement(my_private_key, &pub_key)?; + Ok(InputKeyMaterial { value }) +} + +/// The result of a key agreement operation, to be fed into a KDF. +#[must_use] +pub struct InputKeyMaterial { + value: Vec<u8>, +} + +impl InputKeyMaterial { + /// Calls `kdf` with the raw key material and then returns what `kdf` + /// returns, consuming `Self` so that the key material can only be used + /// once. + pub fn derive<F, R>(self, kdf: F) -> R + where + F: FnOnce(&[u8]) -> R, + { + kdf(&self.value) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; + use nss::ensure_initialized; + + // Test vectors copied from: + // https://chromium.googlesource.com/chromium/src/+/56f1232/components/test/data/webcrypto/ecdh.json#5 + + const PUB_KEY_1_B64: &str = + "BLunVoWkR67xRdAohVblFBWn1Oosb3kH_baxw1yfIYFfthSm4LIY35vDD-5LE454eB7TShn919DVVGZ_7tWdjTE"; + const PRIV_KEY_1_JWK_D: &str = "CQ8uF_-zB1NftLO6ytwKM3Cnuol64PQw5qOuCzQJeFU"; + const PRIV_KEY_1_JWK_X: &str = "u6dWhaRHrvFF0CiFVuUUFafU6ixveQf9trHDXJ8hgV8"; + const PRIV_KEY_1_JWK_Y: &str = "thSm4LIY35vDD-5LE454eB7TShn919DVVGZ_7tWdjTE"; + + const PRIV_KEY_2_JWK_D: &str = "uN2YSQvxuxhQQ9Y1XXjYi1vr2ZTdzuoDX18PYu4LU-0"; + const PRIV_KEY_2_JWK_X: &str = "S2S3tjygMB0DkM-N9jYUgGLt_9_H6km5P9V6V_KS4_4"; + const PRIV_KEY_2_JWK_Y: &str = "03j8Tyqgrc4R4FAUV2C7-im96yMmfmO_5Om6Kr8YP3o"; + + const SHARED_SECRET_HEX: &str = + "163FAA3FC4815D47345C8E959F707B2F1D3537E7B2EA1DAEC23CA8D0A242CFF3"; + + fn load_priv_key_1() -> PrivateKey<Static> { + let private_key = URL_SAFE_NO_PAD.decode(PRIV_KEY_1_JWK_D).unwrap(); + let x = URL_SAFE_NO_PAD.decode(PRIV_KEY_1_JWK_X).unwrap(); + let y = URL_SAFE_NO_PAD.decode(PRIV_KEY_1_JWK_Y).unwrap(); + PrivateKey::<Static>::import( + &EcKey::from_coordinates(Curve::P256, &private_key, &x, &y).unwrap(), + ) + .unwrap() + } + + fn load_priv_key_2() -> PrivateKey<Static> { + let private_key = URL_SAFE_NO_PAD.decode(PRIV_KEY_2_JWK_D).unwrap(); + let x = URL_SAFE_NO_PAD.decode(PRIV_KEY_2_JWK_X).unwrap(); + let y = URL_SAFE_NO_PAD.decode(PRIV_KEY_2_JWK_Y).unwrap(); + PrivateKey::<Static>::import( + &EcKey::from_coordinates(Curve::P256, &private_key, &x, &y).unwrap(), + ) + .unwrap() + } + + #[test] + fn test_static_agreement() { + ensure_initialized(); + let pub_key_raw = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap(); + let peer_pub_key = UnparsedPublicKey::new(&ECDH_P256, &pub_key_raw); + let prv_key = load_priv_key_2(); + let ikm = prv_key.agree_static(&peer_pub_key).unwrap(); + let secret = ikm + .derive(|z| -> Result<Vec<u8>> { Ok(z.to_vec()) }) + .unwrap(); + let secret_b64 = hex::encode_upper(secret); + assert_eq!(secret_b64, *SHARED_SECRET_HEX); + } + + #[test] + fn test_ephemeral_agreement_roundtrip() { + ensure_initialized(); + let (our_prv_key, our_pub_key) = + KeyPair::<Ephemeral>::generate(&ECDH_P256).unwrap().split(); + let (their_prv_key, their_pub_key) = + KeyPair::<Ephemeral>::generate(&ECDH_P256).unwrap().split(); + let their_pub_key_raw = their_pub_key.to_bytes().unwrap(); + let peer_public_key_1 = UnparsedPublicKey::new(&ECDH_P256, &their_pub_key_raw); + let ikm_1 = our_prv_key.agree(&peer_public_key_1).unwrap(); + let secret_1 = ikm_1 + .derive(|z| -> Result<Vec<u8>> { Ok(z.to_vec()) }) + .unwrap(); + let our_pub_key_raw = our_pub_key.to_bytes().unwrap(); + let peer_public_key_2 = UnparsedPublicKey::new(&ECDH_P256, &our_pub_key_raw); + let ikm_2 = their_prv_key.agree(&peer_public_key_2).unwrap(); + let secret_2 = ikm_2 + .derive(|z| -> Result<Vec<u8>> { Ok(z.to_vec()) }) + .unwrap(); + assert_eq!(secret_1, secret_2); + } + + #[test] + fn test_compute_public_key() { + ensure_initialized(); + let (prv_key, pub_key) = KeyPair::<Static>::generate(&ECDH_P256).unwrap().split(); + let computed_pub_key = prv_key.compute_public_key().unwrap(); + assert_eq!( + computed_pub_key.to_bytes().unwrap(), + pub_key.to_bytes().unwrap() + ); + } + + #[test] + fn test_compute_public_key_known_values() { + ensure_initialized(); + let prv_key = load_priv_key_1(); + let pub_key = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap(); + let computed_pub_key = prv_key.compute_public_key().unwrap(); + assert_eq!(computed_pub_key.to_bytes().unwrap(), pub_key.as_slice()); + + let prv_key = load_priv_key_2(); + let computed_pub_key = prv_key.compute_public_key().unwrap(); + assert_ne!(computed_pub_key.to_bytes().unwrap(), pub_key.as_slice()); + } + + #[test] + fn test_keys_byte_representations_roundtrip() { + ensure_initialized(); + let key_pair = KeyPair::<Static>::generate(&ECDH_P256).unwrap(); + let prv_key = key_pair.private_key; + let extracted_pub_key = prv_key.compute_public_key().unwrap(); + let ec_key = prv_key.export().unwrap(); + let prv_key_reconstructed = PrivateKey::<Static>::import(&ec_key).unwrap(); + let extracted_pub_key_reconstructed = prv_key.compute_public_key().unwrap(); + let ec_key_reconstructed = prv_key_reconstructed.export().unwrap(); + assert_eq!(ec_key.curve(), ec_key_reconstructed.curve()); + assert_eq!(ec_key.public_key(), ec_key_reconstructed.public_key()); + assert_eq!(ec_key.private_key(), ec_key_reconstructed.private_key()); + assert_eq!( + extracted_pub_key.to_bytes().unwrap(), + extracted_pub_key_reconstructed.to_bytes().unwrap() + ); + } + + #[test] + fn test_agreement_rejects_invalid_pubkeys() { + ensure_initialized(); + let prv_key = load_priv_key_2(); + + let mut invalid_pub_key = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap(); + invalid_pub_key[0] = invalid_pub_key[0].wrapping_add(1); + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + + let mut invalid_pub_key = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap(); + invalid_pub_key[0] = 0x02; + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + + let mut invalid_pub_key = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap(); + invalid_pub_key[64] = invalid_pub_key[0].wrapping_add(1); + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + + let mut invalid_pub_key = [0u8; 65]; + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + invalid_pub_key[0] = 0x04; + + let mut invalid_pub_key = URL_SAFE_NO_PAD.decode(PUB_KEY_1_B64).unwrap().to_vec(); + invalid_pub_key = invalid_pub_key[0..64].to_vec(); + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + + // From FxA tests at https://github.com/mozilla/fxa-crypto-relier/blob/04f61dc/test/deriver/DeriverUtils.js#L78 + // We trust that NSS will do the right thing here, but it seems worthwhile to confirm for completeness. + let invalid_pub_key_b64 = "BEogZ-rnm44oJkKsOE6Tc7NwFMgmntf7Btm_Rc4atxcqq99Xq1RWNTFpk99pdQOSjUvwELss51PkmAGCXhLfMV0"; + let invalid_pub_key = URL_SAFE_NO_PAD.decode(invalid_pub_key_b64).unwrap(); + assert!(prv_key + .agree_static(&UnparsedPublicKey::new(&ECDH_P256, &invalid_pub_key)) + .is_err()); + } +} diff --git a/third_party/rust/rc_crypto/src/constant_time.rs b/third_party/rust/rc_crypto/src/constant_time.rs @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::error::*; + +/// Returns `Ok(())` if `a == b` and `Error` otherwise. +/// The comparison of `a` and `b` is done in constant time with respect to the +/// contents of each, but NOT in constant time with respect to the lengths of +/// `a` and `b`. +pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<()> { + if nss::secport::secure_memcmp(a, b)? { + Ok(()) + } else { + Err(ErrorKind::InternalError.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use nss::ensure_initialized; + + #[test] + fn does_compare() { + ensure_initialized(); + assert!(verify_slices_are_equal(b"bobo", b"bobo").is_ok()); + assert!(verify_slices_are_equal(b"bobo", b"obob").is_err()); + assert!(verify_slices_are_equal(b"bobo", b"notbobo").is_err()); + } +} diff --git a/third_party/rust/rc_crypto/src/contentsignature.rs b/third_party/rust/rc_crypto/src/contentsignature.rs @@ -0,0 +1,430 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::str; + +use base64::{ + engine::general_purpose::{STANDARD, URL_SAFE}, + Engine, +}; + +use crate::error::*; +use crate::signature; + +/// Verify content signatures, with the ECDSA P384 curve and SHA-384 hashing (NIST384p / secp384r1). +/// +/// These signatures are typically used to guarantee integrity of data between our servers and clients. +/// This is a critical part of systems like Remote Settings or the experiment platform. +/// +/// The equivalent implementation for Gecko is ``security/manager/ssl/nsIContentSignatureVerifier.idl``. +/// +/// Decode a string with colon separated hexadecimal pairs into an array of bytes +/// (eg. "3C:01:44" -> [60, 1, 68]). +fn decode_root_hash(input: &str) -> Result<Vec<u8>> { + let bytes_hex = input.split(':'); + + let mut result: Vec<u8> = vec![]; + for byte_hex in bytes_hex { + let byte = match hex::decode(byte_hex) { + Ok(v) => v, + Err(_) => return Err(ErrorKind::RootHashFormatError(input.to_string()).into()), + }; + result.extend(byte); + } + + Ok(result) +} + +/// Split a certificate chain in PEM format into a list of certificates bytes, +/// decoded from base64. +fn split_pem(pem_content: &[u8]) -> Result<Vec<Vec<u8>>> { + let pem_str = match str::from_utf8(pem_content) { + Ok(v) => v, + Err(e) => { + return Err(ErrorKind::PEMFormatError(e.to_string()).into()); + } + }; + + let pem_lines = pem_str.split('\n'); + + let mut blocks: Vec<Vec<u8>> = vec![]; + let mut block: Vec<u8> = vec![]; + let mut read = false; + for line in pem_lines { + if line.contains("-----BEGIN CERTIFICATE") { + read = true; + } else if line.contains("-----END CERTIFICATE") { + read = false; + let decoded = match STANDARD.decode(&block) { + Ok(v) => v, + Err(e) => return Err(ErrorKind::PEMFormatError(e.to_string()).into()), + }; + blocks.push(decoded); + block.clear(); + } else if read { + block.extend_from_slice(line.as_bytes()); + } + } + if read { + return Err(ErrorKind::PEMFormatError("Missing end header".into()).into()); + } + if blocks.is_empty() { + return Err(ErrorKind::PEMFormatError("Missing PEM data".into()).into()); + } + + Ok(blocks) +} + +/// Verify that the signature matches the input data. +/// +/// The data must be prefixed with ``Content-Signature:\u{0}``. +/// The signature must be provided as base 64 url-safe encoded. +/// The certificate chain, provided as PEM, must be valid at the provided current time. +/// The root certificate content must match the provided root hash, and the leaf +/// subject name must match the provided hostname. +pub fn verify( + input: &[u8], + signature: &[u8], + pem_bytes: &[u8], + seconds_since_epoch: u64, + root_sha256_hash: &str, + hostname: &str, +) -> Result<()> { + let certificates = split_pem(pem_bytes)?; + + let mut certificates_slices: Vec<&[u8]> = vec![]; + for certificate in &certificates { + certificates_slices.push(certificate); + } + + let root_hash_bytes = decode_root_hash(root_sha256_hash)?; + + nss::pkixc::verify_code_signing_certificate_chain( + certificates_slices, + seconds_since_epoch, + &root_hash_bytes, + hostname, + ) + .map_err(|err| match err.kind() { + nss::ErrorKind::CertificateIssuerError => ErrorKind::CertificateIssuerError, + nss::ErrorKind::CertificateValidityError => ErrorKind::CertificateValidityError, + nss::ErrorKind::CertificateSubjectError => ErrorKind::CertificateSubjectError, + _ => ErrorKind::CertificateChainError(err.to_string()), + })?; + + let leaf_cert = certificates.first().unwrap(); // PEM parse fails if len == 0. + + let public_key_bytes = match nss::cert::extract_ec_public_key(leaf_cert) { + Ok(bytes) => bytes, + Err(err) => return Err(ErrorKind::CertificateContentError(err.to_string()).into()), + }; + + let signature_bytes = match URL_SAFE.decode(signature) { + Ok(b) => b, + Err(err) => return Err(ErrorKind::SignatureContentError(err.to_string()).into()), + }; + + // Since signature is NIST384p / secp384r1, we can perform a few safety checks. + if signature_bytes.len() != 96 { + return Err(ErrorKind::SignatureContentError(format!( + "signature contains {} bytes instead of {}", + signature_bytes.len(), + 96 + )) + .into()); + } + if public_key_bytes.len() != 96 + 1 { + // coordinates with x04 prefix. + return Err(ErrorKind::CertificateContentError(format!( + "public key contains {} bytes instead of {}", + public_key_bytes.len(), + 97 + )) + .into()); + } + + let signature_alg = &signature::ECDSA_P384_SHA384; + let public_key = signature::UnparsedPublicKey::new(signature_alg, &public_key_bytes); + // Note that if the provided key type or curve is incorrect here, the signature will + // be considered as invalid. + match public_key.verify(input, &signature_bytes) { + Ok(_) => Ok(()), + Err(err) => Err(ErrorKind::SignatureMismatchError(err.to_string()).into()), + } +} + +#[cfg(test)] +mod test { + use super::*; + + const ROOT_HASH: &str = "3C:01:44:6A:BE:90:36:CE:A9:A0:9A:CA:A3:A5:20:AC:62:8F:20:A7:AE:32:CE:86:1C:B2:EF:B7:0F:A0:C7:45"; + const VALID_CERT_CHAIN: &[u8] = b"\ +-----BEGIN CERTIFICATE----- +MIIDBjCCAougAwIBAgIIFml6g0ldRGowCgYIKoZIzj0EAwMwgaMxCzAJBgNVBAYT +AlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3pp +bGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTFFMEMGA1UEAww8Q29u +dGVudCBTaWduaW5nIEludGVybWVkaWF0ZS9lbWFpbEFkZHJlc3M9Zm94c2VjQG1v +emlsbGEuY29tMB4XDTIxMDIwMzE1MDQwNVoXDTIxMDQyNDE1MDQwNVowgakxCzAJ +BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFp +biBWaWV3MRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMRcwFQYDVQQLEw5D +bG91ZCBTZXJ2aWNlczE2MDQGA1UEAxMtcmVtb3RlLXNldHRpbmdzLmNvbnRlbnQt +c2lnbmF0dXJlLm1vemlsbGEub3JnMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8pKb +HX4IiD0SCy+NO7gwKqRRZ8IhGd8PTaIHIBgM6RDLRyDeswXgV+2kGUoHyzkbNKZt +zlrS3AhqeUCtl1g6ECqSmZBbRTjCpn/UCpCnMLL0T0goxtAB8Rmi3CdM0cBUo4GD +MIGAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSME +GDAWgBQlZawrqt0eUz/t6OdN45oKfmzy6DA4BgNVHREEMTAvgi1yZW1vdGUtc2V0 +dGluZ3MuY29udGVudC1zaWduYXR1cmUubW96aWxsYS5vcmcwCgYIKoZIzj0EAwMD +aQAwZgIxAPh43Bxl4MxPT6Ra1XvboN5O2OvIn2r8rHvZPWR/jJ9vcTwH9X3F0aLJ +9FiresnsLAIxAOoAcREYB24gFBeWxbiiXaG7TR/yM1/MXw4qxbN965FFUaoB+5Bc +fS8//SQGTlCqKQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIEAQAAADANBgkqhkiG9w0BAQsFADCBqTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRwwGgYDVQQK +ExNBZGRvbnMgVGVzdCBTaWduaW5nMSQwIgYDVQQDExt0ZXN0LmFkZG9ucy5zaWdu +aW5nLnJvb3QuY2ExMTAvBgkqhkiG9w0BCQEWInNlY29wcytzdGFnZXJvb3RhZGRv +bnNAbW96aWxsYS5jb20wHhcNMjEwMTExMDAwMDAwWhcNMjQxMTE0MjA0ODU5WjCB +ozELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xLzAt +BgNVBAsTJk1vemlsbGEgQU1PIFByb2R1Y3Rpb24gU2lnbmluZyBTZXJ2aWNlMUUw +QwYDVQQDDDxDb250ZW50IFNpZ25pbmcgSW50ZXJtZWRpYXRlL2VtYWlsQWRkcmVz +cz1mb3hzZWNAbW96aWxsYS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARw1dyE +xV5aNiHJPa/fVHO6kxJn3oZLVotJ0DzFZA9r1sQf8i0+v78Pg0/c3nTAyZWfkULz +vOpKYK/GEGBtisxCkDJ+F3NuLPpSIg3fX25pH0LE15fvASBVcr8tKLVHeOmjggG6 +MIIBtjAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSUBAf8EDDAK +BggrBgEFBQcDAzAdBgNVHQ4EFgQUJWWsK6rdHlM/7ejnTeOaCn5s8ugwgdkGA1Ud +IwSB0TCBzoAUhtg0HE5Y0RNcmV/YQpjtFA8Z8l2hga+kgawwgakxCzAJBgNVBAYT +AlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEcMBoGA1UE +ChMTQWRkb25zIFRlc3QgU2lnbmluZzEkMCIGA1UEAxMbdGVzdC5hZGRvbnMuc2ln +bmluZy5yb290LmNhMTEwLwYJKoZIhvcNAQkBFiJzZWNvcHMrc3RhZ2Vyb290YWRk +b25zQG1vemlsbGEuY29tggRgJZg7MDMGCWCGSAGG+EIBBAQmFiRodHRwOi8vYWRk +b25zLmFsbGl6b20ub3JnL2NhL2NybC5wZW0wTgYDVR0eBEcwRaBDMCCCHi5jb250 +ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzAfgh1jb250ZW50LXNpZ25hdHVyZS5t +b3ppbGxhLm9yZzANBgkqhkiG9w0BAQsFAAOCAgEAtGTTzcPzpcdf07kIeRs9vPMx +qiF8ylW5L/IQ2NzT3sFFAvPW1vW1wZC0xAHMsuVyo+BTGrv+4mlD0AUR9acRfiTZ +9qyZ3sJbyhQwJAXLKU4YpnzuFOf58T/yOnOdwpH2ky/0FuHskMyfXaAz2Az4JXJH +TCgggqfdZNvsZ5eOnQlKoC5NadMa8oTI5sd4SyR5ANUPAtYok931MvVSz3IMbwTr +v4PPWXdl9SGXuOknSqdY6/bS1LGvC2KprsT+PBlvVtS6YgZOH0uCgTTLpnrco87O +ErzC2PJBA1Ftn3Mbaou6xy7O+YX+reJ6soNUV+0JHOuKj0aTXv0c+lXEAh4Y8nea +UGhW6+MRGYMOP2NuKv8s2+CtNH7asPq3KuTQpM5RerjdouHMIedX7wpNlNk0CYbg +VMJLxZfAdwcingLWda/H3j7PxMoAm0N+eA24TGDQPC652ZakYk4MQL/45lm0A5f0 +xLGKEe6JMZcTBQyO7ANWcrpVjKMiwot6bY6S2xU17mf/h7J32JXZJ23OPOKpMS8d +mljj4nkdoYDT35zFuS1z+5q6R5flLca35vRHzC3XA0H/XJvgOKUNLEW/IiJIqLNi +ab3Ao0RubuX+CAdFML5HaJmkyuJvL3YtwIOwe93RGcGRZSKZsnMS+uY5QN8+qKQz +LC4GzWQGSCGDyD+JCVw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHbDCCBVSgAwIBAgIEYCWYOzANBgkqhkiG9w0BAQwFADCBqTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRwwGgYDVQQK +ExNBZGRvbnMgVGVzdCBTaWduaW5nMSQwIgYDVQQDExt0ZXN0LmFkZG9ucy5zaWdu +aW5nLnJvb3QuY2ExMTAvBgkqhkiG9w0BCQEWInNlY29wcytzdGFnZXJvb3RhZGRv +bnNAbW96aWxsYS5jb20wHhcNMjEwMjExMjA0ODU5WhcNMjQxMTE0MjA0ODU5WjCB +qTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBW +aWV3MRwwGgYDVQQKExNBZGRvbnMgVGVzdCBTaWduaW5nMSQwIgYDVQQDExt0ZXN0 +LmFkZG9ucy5zaWduaW5nLnJvb3QuY2ExMTAvBgkqhkiG9w0BCQEWInNlY29wcytz +dGFnZXJvb3RhZGRvbnNAbW96aWxsYS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDKRVty/FRsO4Ech6EYleyaKgAueaLYfMSsAIyPC/N8n/P8QcH8 +rjoiMJrKHRlqiJmMBSmjUZVzZAP0XJku0orLKWPKq7cATt+xhGY/RJtOzenMMsr5 +eN02V3GzUd1jOShUpERjzXdaO3pnfZqhdqNYqP9ocqQpyno7bZ3FZQ2vei+bF52k +51uPioTZo+1zduoR/rT01twGtZm3QpcwU4mO74ysyxxgqEy3kpojq8Nt6haDwzrj +khV9M6DGPLHZD71QaUiz5lOhD9CS8x0uqXhBhwMUBBkHsUDSxbN4ZhjDDWpCmwaD +OtbJMUJxDGPCr9qj49QESccb367OeXLrfZ2Ntu/US2Bw9EDfhyNsXr9dg9NHj5yf +4sDUqBHG0W8zaUvJx5T2Ivwtno1YZLyJwQW5pWeWn8bEmpQKD2KS/3y2UjlDg+YM +NdNASjFe0fh6I5NCFYmFWA73DpDGlUx0BtQQU/eZQJ+oLOTLzp8d3dvenTBVnKF+ +uwEmoNfZwc4TTWJOhLgwxA4uK+Paaqo4Ap2RGS2ZmVkPxmroB3gL5n3k3QEXvULh +7v8Psk4+MuNWnxudrPkN38MGJo7ju7gDOO8h1jLD4tdfuAqbtQLduLXzT4DJPA4y +JBTFIRMIpMqP9CovaS8VPtMFLTrYlFh9UnEGpCeLPanJr+VEj7ae5sc8YwIDAQAB +o4IBmDCCAZQwDAYDVR0TBAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0lAQH/ +BAwwCgYIKwYBBQUHAwMwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk +IENlcnRpZmljYXRlMDMGCWCGSAGG+EIBBAQmFiRodHRwOi8vYWRkb25zLm1vemls +bGEub3JnL2NhL2NybC5wZW0wHQYDVR0OBBYEFIbYNBxOWNETXJlf2EKY7RQPGfJd +MIHZBgNVHSMEgdEwgc6AFIbYNBxOWNETXJlf2EKY7RQPGfJdoYGvpIGsMIGpMQsw +CQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx +HDAaBgNVBAoTE0FkZG9ucyBUZXN0IFNpZ25pbmcxJDAiBgNVBAMTG3Rlc3QuYWRk +b25zLnNpZ25pbmcucm9vdC5jYTExMC8GCSqGSIb3DQEJARYic2Vjb3BzK3N0YWdl +cm9vdGFkZG9uc0Btb3ppbGxhLmNvbYIEYCWYOzANBgkqhkiG9w0BAQwFAAOCAgEA +nowyJv8UaIV7NA0B3wkWratq6FgA1s/PzetG/ZKZDIW5YtfUvvyy72HDAwgKbtap +Eog6zGI4L86K0UGUAC32fBjE5lWYEgsxNM5VWlQjbgTG0dc3dYiufxfDFeMbAPmD +DzpIgN3jHW2uRqa/MJ+egHhv7kGFL68uVLboqk/qHr+SOCc1LNeSMCuQqvHwwM0+ +AU1GxhzBWDkealTS34FpVxF4sT5sKLODdIS5HXJr2COHHfYkw2SW/Sfpt6fsOwaF +2iiDaK4LPWHWhhIYa6yaynJ+6O6KPlpvKYCChaTOVdc+ikyeiSO6AakJykr5Gy7d +PkkK7MDCxuY6psHj7iJQ59YK7ujQB8QYdzuXBuLLo5hc5gBcq3PJs0fLT2YFcQHA +dj+olGaDn38T0WI8ycWaFhQfKwATeLWfiQepr8JfoNlC2vvSDzGUGfdAfZfsJJZ8 +5xZxahHoTFGS0mDRfXqzKH5uD578GgjOZp0fULmzkcjWsgzdpDhadGjExRZFKlAy +iKv8cXTONrGY0fyBDKennuX0uAca3V0Qm6v2VRp+7wG/pywWwc5n+04qgxTQPxgO +6pPB9UUsNbaLMDR5QPYAWrNhqJ7B07XqIYJZSwGP5xB9NqUZLF4z+AOMYgWtDpmg +IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= +-----END CERTIFICATE-----"; + const VALID_INPUT: &[u8] = + b"Content-Signature:\x00{\"data\":[],\"last_modified\":\"1603992731957\"}"; + const VALID_SIGNATURE: &[u8] = b"fJJcOpwdnkjEWFeHXfdOJN6GaGLuDTPGzQOxA2jn6ldIleIk6KqMhZcy2GZv2uYiGwl6DERWwpaoUfQFLyCAOcVjck1qlaaEFZGY1BQba9p99xEc9FNQ3YPPfvSSZqsw"; + const VALID_HOSTNAME: &str = "remote-settings.content-signature.mozilla.org"; + + const INVALID_CERTIFICATE: &[u8] = b"\ + -----BEGIN CERTIFICATE----- + invalidCertificategIFiJLFfdxFlYwCgYIKoZIzj0EAwMwgaMxCzAJBgNVBAYT + AlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3pp + bGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTFFMEMGA1UEAww8Q29u + dGVudCBTaWduaW5nIEludGVybWVkaWF0ZS9lbWFpbEFkZHJlc3M9Zm94c2VjQG1v + emlsbGEuY29tMB4XDTIwMDYxNjE3MTYxNVoXDTIwMDkwNDE3MTYxNVowgakxCzAJ + BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFp + biBWaWV3MRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMRcwFQYDVQQLEw5D + bG91ZCBTZXJ2aWNlczE2MDQGA1UEAxMtcmVtb3RlLXNldHRpbmdzLmNvbnRlbnQt + c2lnbmF0dXJlLm1vemlsbGEub3JnMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDmOX + N5IGlUqCvu6xkOKr020Eo3kY2uPdJO0ZihVUoglk1ktQPss184OajFOMKm/BJX4W + IsZUzQoRL8NgGfZDwBjT95Q87lhOWEWs5AU/nMXIYwDp7rpUPaUqw0QLMikdo4GD + MIGAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSME + GDAWgBSgHUoXT4zCKzVF8WPx2nBwp8744TA4BgNVHREEMTAvgi1yZW1vdGUtc2V0 + dGluZ3MuY29udGVudC1zaWduYXR1cmUubW96aWxsYS5vcmcwCgYIKoZIzj0EAwMD + aQAwZgIxAJvyynyPqRmRMqf95FPH5xfcoT3jb/2LOkUifGDtjtZ338ScpT2glUK8 + HszKVANqXQIxAIygMaeTiD9figEusmHMthBdFoIoHk31x4MHukAy+TWZ863X6/V2 + 6/ZrZMpinvalid== + -----END CERTIFICATE-----"; + + #[test] + fn test_decode_root_hash() { + nss::ensure_initialized(); + assert!(decode_root_hash("meh!").is_err()); + assert!(decode_root_hash("3C:rr:44").is_err()); + + let result = decode_root_hash(ROOT_HASH).unwrap(); + assert_eq!( + result, + vec![ + 60, 1, 68, 106, 190, 144, 54, 206, 169, 160, 154, 202, 163, 165, 32, 172, 98, 143, + 32, 167, 174, 50, 206, 134, 28, 178, 239, 183, 15, 160, 199, 69 + ] + ); + } + + #[test] + fn test_split_pem() { + assert!(split_pem(b"meh!").is_err()); + + assert!(split_pem( + b"-----BEGIN CERTIFICATE----- +invalidCertificate +-----END CERTIFICATE-----" + ) + .is_err()); + + assert!(split_pem( + b"-----BEGIN CERTIFICATE----- +bGxhIEFNTyBQcm9kdWN0aW9uIFNp +-----BEGIN CERTIFICATE-----" + ) + .is_err()); + + let result = split_pem( + b"-----BEGIN CERTIFICATE----- +AQID +BAUG +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +/f7/ +-----END CERTIFICATE-----", + ) + .unwrap(); + assert_eq!(result, vec![vec![1, 2, 3, 4, 5, 6], vec![253, 254, 255]]); + } + + #[test] + fn test_verify_fails_if_invalid() { + nss::ensure_initialized(); + assert!(verify( + b"msg", + b"sig", + b"-----BEGIN CERTIFICATE----- +fdfeff +-----END CERTIFICATE-----", + 42, + ROOT_HASH, + "remotesettings.firefox.com", + ) + .is_err()); + } + + #[test] + fn test_verify_fails_if_cert_has_expired() { + nss::ensure_initialized(); + assert!(verify( + VALID_INPUT, + VALID_SIGNATURE, + VALID_CERT_CHAIN, + 1215559719, // July 9, 2008 + ROOT_HASH, + VALID_HOSTNAME, + ) + .is_err()); + } + + #[test] + fn test_verify_fails_if_bad_certificate_chain() { + nss::ensure_initialized(); + assert!(verify( + VALID_INPUT, + VALID_SIGNATURE, + INVALID_CERTIFICATE, + 1615559719, // March 12, 2021 + ROOT_HASH, + VALID_HOSTNAME, + ) + .is_err()); + } + + #[test] + fn test_verify_fails_if_mismatch() { + nss::ensure_initialized(); + assert!(verify( + b"msg", + VALID_SIGNATURE, + VALID_CERT_CHAIN, + 1615559719, // March 12, 2021 + ROOT_HASH, + VALID_HOSTNAME, + ) + .is_err()); + } + + #[test] + fn test_verify_fails_if_bad_hostname() { + nss::ensure_initialized(); + assert!(verify( + VALID_INPUT, + VALID_SIGNATURE, + VALID_CERT_CHAIN, + 1615559719, // March 12, 2021 + ROOT_HASH, + "some.hostname.org", + ) + .is_err()); + } + + #[test] + fn test_verify_fails_if_bad_root_hash() { + nss::ensure_initialized(); + assert!(verify( + VALID_INPUT, + VALID_SIGNATURE, + VALID_CERT_CHAIN, + 1615559719, // March 12, 2021 + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00", + VALID_HOSTNAME, + ) + .is_err()); + } + + #[test] + fn test_verify_succeeds_if_valid() { + nss::ensure_initialized(); + verify( + VALID_INPUT, + VALID_SIGNATURE, + VALID_CERT_CHAIN, + 1615559719, // March 12, 2021 + ROOT_HASH, + VALID_HOSTNAME, + ) + .unwrap(); + } +} diff --git a/third_party/rust/rc_crypto/src/digest.rs b/third_party/rust/rc_crypto/src/digest.rs @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::error::*; + +pub use nss::pk11::context::HashAlgorithm::{self as Algorithm, *}; + +/// A calculated digest value. +#[derive(Clone)] +pub struct Digest { + pub(crate) value: Vec<u8>, + pub(crate) algorithm: Algorithm, +} + +impl Digest { + pub fn algorithm(&self) -> &Algorithm { + &self.algorithm + } +} + +impl AsRef<[u8]> for Digest { + fn as_ref(&self) -> &[u8] { + self.value.as_ref() + } +} + +/// Returns the digest of data using the given digest algorithm. +pub fn digest(algorithm: &Algorithm, data: &[u8]) -> Result<Digest> { + let value = nss::pk11::context::hash_buf(algorithm, data)?; + Ok(Digest { + value, + algorithm: *algorithm, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + const MESSAGE: &[u8] = b"bobo"; + const DIGEST_HEX: &str = "bf0c97708b849de696e7373508b13c5ea92bafa972fc941d694443e494a4b84d"; + + #[test] + fn sha256_digest() { + nss::ensure_initialized(); + assert_eq!(hex::encode(digest(&SHA256, MESSAGE).unwrap()), DIGEST_HEX); + assert_ne!( + hex::encode(digest(&SHA256, b"notbobo").unwrap()), + DIGEST_HEX + ); + } + + #[test] + fn digest_cleanly_rejects_gigantic_messages() { + nss::ensure_initialized(); + let message = vec![0; (i32::MAX as usize) + 1]; + assert!(digest(&SHA256, &message).is_err()); + } +} diff --git a/third_party/rust/rc_crypto/src/ece_crypto.rs b/third_party/rust/rc_crypto/src/ece_crypto.rs @@ -0,0 +1,188 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + aead, + agreement::{self, Curve, EcKey, UnparsedPublicKey}, + digest, hkdf, hmac, rand, +}; +use ece::crypto::{Cryptographer, EcKeyComponents, LocalKeyPair, RemotePublicKey}; + +impl From<crate::Error> for ece::Error { + fn from(_: crate::Error) -> Self { + ece::Error::CryptoError + } +} + +pub struct RcCryptoLocalKeyPair { + wrapped: agreement::KeyPair<agreement::Static>, +} +// SECKEYPrivateKeyStr and SECKEYPublicKeyStr are Sync. +unsafe impl Sync for RcCryptoLocalKeyPair {} + +impl RcCryptoLocalKeyPair { + pub fn from_raw_components(components: &EcKeyComponents) -> Result<Self, ece::Error> { + let ec_key = EcKey::new( + Curve::P256, + components.private_key(), + components.public_key(), + ); + let priv_key = agreement::PrivateKey::<agreement::Static>::import(&ec_key)?; + let wrapped = agreement::KeyPair::<agreement::Static>::from_private_key(priv_key)?; + Ok(RcCryptoLocalKeyPair { wrapped }) + } + + pub fn generate_random() -> Result<Self, ece::Error> { + let wrapped = agreement::KeyPair::<agreement::Static>::generate(&agreement::ECDH_P256)?; + Ok(RcCryptoLocalKeyPair { wrapped }) + } + + fn agree(&self, peer: &RcCryptoRemotePublicKey) -> Result<Vec<u8>, ece::Error> { + let peer_public_key_raw_bytes = &peer.as_raw()?; + let peer_public_key = + UnparsedPublicKey::new(&agreement::ECDH_P256, peer_public_key_raw_bytes); + self.wrapped + .private_key() + .agree_static(&peer_public_key)? + .derive(|z| Ok(z.to_vec())) + } +} + +impl LocalKeyPair for RcCryptoLocalKeyPair { + fn raw_components(&self) -> Result<EcKeyComponents, ece::Error> { + let ec_key = self.wrapped.private_key().export()?; + Ok(EcKeyComponents::new( + ec_key.private_key(), + ec_key.public_key(), + )) + } + + fn pub_as_raw(&self) -> Result<Vec<u8>, ece::Error> { + let bytes = self.wrapped.public_key().to_bytes()?; + Ok(bytes.to_vec()) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} +pub struct RcCryptoRemotePublicKey { + raw: Vec<u8>, +} + +impl RcCryptoRemotePublicKey { + pub fn from_raw(bytes: &[u8]) -> Result<RcCryptoRemotePublicKey, ece::Error> { + Ok(RcCryptoRemotePublicKey { + raw: bytes.to_owned(), + }) + } +} + +impl RemotePublicKey for RcCryptoRemotePublicKey { + fn as_raw(&self) -> Result<Vec<u8>, ece::Error> { + Ok(self.raw.to_vec()) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + +pub(crate) struct RcCryptoCryptographer; + +impl Cryptographer for RcCryptoCryptographer { + fn generate_ephemeral_keypair(&self) -> Result<Box<dyn LocalKeyPair>, ece::Error> { + Ok(Box::new(RcCryptoLocalKeyPair::generate_random()?)) + } + + fn import_key_pair( + &self, + components: &EcKeyComponents, + ) -> Result<Box<dyn LocalKeyPair>, ece::Error> { + Ok(Box::new(RcCryptoLocalKeyPair::from_raw_components( + components, + )?)) + } + + fn import_public_key(&self, raw: &[u8]) -> Result<Box<dyn RemotePublicKey>, ece::Error> { + Ok(Box::new(RcCryptoRemotePublicKey::from_raw(raw)?)) + } + + fn compute_ecdh_secret( + &self, + remote: &dyn RemotePublicKey, + local: &dyn LocalKeyPair, + ) -> Result<Vec<u8>, ece::Error> { + let local_any = local.as_any(); + let local = local_any.downcast_ref::<RcCryptoLocalKeyPair>().unwrap(); + let remote_any = remote.as_any(); + let remote = remote_any + .downcast_ref::<RcCryptoRemotePublicKey>() + .unwrap(); + local.agree(remote) + } + + fn hkdf_sha256( + &self, + salt: &[u8], + secret: &[u8], + info: &[u8], + len: usize, + ) -> Result<Vec<u8>, ece::Error> { + let salt = hmac::SigningKey::new(&digest::SHA256, salt); + let mut out = vec![0u8; len]; + hkdf::extract_and_expand(&salt, secret, info, &mut out)?; + Ok(out) + } + + fn aes_gcm_128_encrypt( + &self, + key: &[u8], + iv: &[u8], + data: &[u8], + ) -> Result<Vec<u8>, ece::Error> { + let key = aead::SealingKey::new(&aead::AES_128_GCM, key)?; + let nonce = aead::Nonce::try_assume_unique_for_key(&aead::AES_128_GCM, iv)?; + Ok(aead::seal(&key, nonce, aead::Aad::empty(), data)?) + } + + fn aes_gcm_128_decrypt( + &self, + key: &[u8], + iv: &[u8], + ciphertext_and_tag: &[u8], + ) -> Result<Vec<u8>, ece::Error> { + let key = aead::OpeningKey::new(&aead::AES_128_GCM, key)?; + let nonce = aead::Nonce::try_assume_unique_for_key(&aead::AES_128_GCM, iv)?; + Ok(aead::open( + &key, + nonce, + aead::Aad::empty(), + ciphertext_and_tag, + )?) + } + + fn random_bytes(&self, dest: &mut [u8]) -> Result<(), ece::Error> { + Ok(rand::fill(dest)?) + } +} + +// Please call `rc_crypto::ensure_initialized()` instead of calling +// this function directly. +pub(crate) fn init() { + ece::crypto::set_cryptographer(&crate::ece_crypto::RcCryptoCryptographer) + .expect("Failed to initialize `ece` cryptographer!") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cryptographer_backend() { + nss::ensure_initialized(); + crate::ensure_initialized(); + ece::crypto::test_cryptographer(RcCryptoCryptographer); + } +} diff --git a/third_party/rust/rc_crypto/src/error.rs b/third_party/rust/rc_crypto/src/error.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[derive(Debug, thiserror::Error)] +pub enum ErrorKind { + #[error("NSS error: {0}")] + NSSError(#[from] nss::Error), + #[error("Internal crypto error")] + InternalError, + #[error("Conversion error: {0}")] + ConversionError(#[from] std::num::TryFromIntError), + #[error("Root hash format error: {0}")] + RootHashFormatError(String), + #[error("PEM content format error: {0}")] + PEMFormatError(String), + #[error("Certificate content error: {0}")] + CertificateContentError(String), + #[error("Certificate not yet valid or expired")] + CertificateValidityError, + #[error("Certificate subject mismatch")] + CertificateSubjectError, + #[error("Certificate issuer mismatch")] + CertificateIssuerError, + #[error("Certificate chain of trust error: {0}")] + CertificateChainError(String), + #[error("Signature content error: {0}")] + SignatureContentError(String), + #[error("Content signature mismatch error: {0}")] + SignatureMismatchError(String), +} + +error_support::define_error! { + ErrorKind { + (ConversionError, std::num::TryFromIntError), + (NSSError, nss::Error), + } +} diff --git a/third_party/rust/rc_crypto/src/hawk_crypto.rs b/third_party/rust/rc_crypto/src/hawk_crypto.rs @@ -0,0 +1,161 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{digest, hmac, rand}; +use hawk::crypto as hc; + +impl From<crate::Error> for hc::CryptoError { + // Our errors impl `Fail`, so we can do this. + fn from(e: crate::Error) -> Self { + hc::CryptoError::Other(e.into()) + } +} + +pub(crate) struct RcCryptoCryptographer; + +impl hc::HmacKey for crate::hmac::SigningKey { + fn sign(&self, data: &[u8]) -> Result<Vec<u8>, hc::CryptoError> { + let digest = hmac::sign(self, data)?; + Ok(digest.as_ref().into()) + } +} + +// I don't really see a reason to bother doing incremental hashing here. A +// one-shot is going to be faster in many cases anyway, and the higher memory +// usage probably doesn't matter given our usage. +struct NssHasher { + buffer: Vec<u8>, + algorithm: &'static digest::Algorithm, +} + +impl hc::Hasher for NssHasher { + fn update(&mut self, data: &[u8]) -> Result<(), hc::CryptoError> { + self.buffer.extend_from_slice(data); + Ok(()) + } + + fn finish(&mut self) -> Result<Vec<u8>, hc::CryptoError> { + let digest = digest::digest(self.algorithm, &self.buffer)?; + let bytes: &[u8] = digest.as_ref(); + Ok(bytes.to_owned()) + } +} + +impl hc::Cryptographer for RcCryptoCryptographer { + fn rand_bytes(&self, output: &mut [u8]) -> Result<(), hc::CryptoError> { + rand::fill(output)?; + Ok(()) + } + + fn new_key( + &self, + algorithm: hawk::DigestAlgorithm, + key: &[u8], + ) -> Result<Box<dyn hc::HmacKey>, hc::CryptoError> { + let k = hmac::SigningKey::new(to_rc_crypto_algorithm(algorithm)?, key); + Ok(Box::new(k)) + } + + fn constant_time_compare(&self, a: &[u8], b: &[u8]) -> bool { + crate::constant_time::verify_slices_are_equal(a, b).is_ok() + } + + fn new_hasher( + &self, + algorithm: hawk::DigestAlgorithm, + ) -> Result<Box<dyn hc::Hasher>, hc::CryptoError> { + Ok(Box::new(NssHasher { + algorithm: to_rc_crypto_algorithm(algorithm)?, + buffer: vec![], + })) + } +} + +fn to_rc_crypto_algorithm( + algorithm: hawk::DigestAlgorithm, +) -> Result<&'static digest::Algorithm, hc::CryptoError> { + match algorithm { + hawk::DigestAlgorithm::Sha256 => Ok(&digest::SHA256), + algo => Err(hc::CryptoError::UnsupportedDigest(algo)), + } +} + +// Note: this doesn't initialize NSS! +pub(crate) fn init() { + hawk::crypto::set_cryptographer(&crate::hawk_crypto::RcCryptoCryptographer) + .expect("Failed to initialize `hawk` cryptographer!") +} + +#[cfg(test)] +mod test { + + // Based on rust-hawk's hash_consistency. This fails if we've messed up the hashing. + #[test] + fn test_hawk_hashing() { + nss::ensure_initialized(); + crate::ensure_initialized(); + + let mut hasher1 = hawk::PayloadHasher::new("text/plain", hawk::SHA256).unwrap(); + hasher1.update("pày").unwrap(); + hasher1.update("load").unwrap(); + let hash1 = hasher1.finish().unwrap(); + + let mut hasher2 = hawk::PayloadHasher::new("text/plain", hawk::SHA256).unwrap(); + hasher2.update("pàyload").unwrap(); + let hash2 = hasher2.finish().unwrap(); + + let hash3 = hawk::PayloadHasher::hash("text/plain", hawk::SHA256, "pàyload").unwrap(); + + let hash4 = // "pàyload" as utf-8 bytes + hawk::PayloadHasher::hash("text/plain", hawk::SHA256, [112, 195, 160, 121, 108, 111, 97, 100]).unwrap(); + + assert_eq!( + hash1, + &[ + 228, 238, 241, 224, 235, 114, 158, 112, 211, 254, 118, 89, 25, 236, 87, 176, 181, + 54, 61, 135, 42, 223, 188, 103, 194, 59, 83, 36, 136, 31, 198, 50 + ] + ); + assert_eq!(hash2, hash1); + assert_eq!(hash3, hash1); + assert_eq!(hash4, hash1); + } + + // Based on rust-hawk's test_make_mac. This fails if we've messed up the signing. + #[test] + fn test_hawk_signing() { + nss::ensure_initialized(); + crate::ensure_initialized(); + + let key = hawk::Key::new( + [ + 11u8, 19, 228, 209, 79, 189, 200, 59, 166, 47, 86, 254, 235, 184, 120, 197, 75, + 152, 201, 79, 115, 61, 111, 242, 219, 187, 173, 14, 227, 108, 60, 232, + ], + hawk::SHA256, + ) + .unwrap(); + + let mac = hawk::mac::Mac::new( + hawk::mac::MacType::Header, + &key, + std::time::UNIX_EPOCH + std::time::Duration::new(1000, 100), + "nonny", + "POST", + "mysite.com", + 443, + "/v1/api", + None, + None, + ) + .unwrap(); + assert_eq!( + mac.as_ref(), + &[ + 192, 227, 235, 121, 157, 185, 197, 79, 189, 214, 235, 139, 9, 232, 99, 55, 67, 30, + 68, 0, 150, 187, 192, 238, 21, 200, 209, 107, 245, 159, 243, 178 + ] + ); + } +} diff --git a/third_party/rust/rc_crypto/src/hkdf.rs b/third_party/rust/rc_crypto/src/hkdf.rs @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::{error::*, hmac}; + +pub fn extract_and_expand( + salt: &hmac::SigningKey, + secret: &[u8], + info: &[u8], + out: &mut [u8], +) -> Result<()> { + let prk = extract(salt, secret)?; + expand(&prk, info, out)?; + Ok(()) +} + +pub fn extract(salt: &hmac::SigningKey, secret: &[u8]) -> Result<hmac::SigningKey> { + let prk = hmac::sign(salt, secret)?; + Ok(hmac::SigningKey::new(salt.digest_algorithm(), prk.as_ref())) +} + +pub fn expand(prk: &hmac::SigningKey, info: &[u8], out: &mut [u8]) -> Result<()> { + let mut derived = + nss::pk11::sym_key::hkdf_expand(prk.digest_alg, &prk.key_value, info, out.len())?; + out.swap_with_slice(&mut derived[0..out.len()]); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::digest; + use nss::ensure_initialized; + + #[test] + fn hkdf_produces_correct_result() { + ensure_initialized(); + let secret = hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap(); + let salt = hex::decode("000102030405060708090a0b0c").unwrap(); + let info = hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap(); + let expected_out = hex::decode( + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", + ) + .unwrap(); + let salt = hmac::SigningKey::new(&digest::SHA256, &salt); + let mut out = vec![0u8; expected_out.len()]; + extract_and_expand(&salt, &secret, &info, &mut out).unwrap(); + assert_eq!(out, expected_out); + } + + #[test] + fn hkdf_rejects_gigantic_salt() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let salt_bytes = vec![0; (u32::MAX as usize) + 1]; + let salt = hmac::SigningKey { + digest_alg: &digest::SHA256, + key_value: salt_bytes, + }; + let mut out = vec![0u8; 8]; + assert!(extract_and_expand(&salt, b"secret", b"info", &mut out).is_err()); + } + } + + #[test] + fn hkdf_rejects_gigantic_secret() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let salt = hmac::SigningKey::new(&digest::SHA256, b"salt"); + let secret = vec![0; (u32::MAX as usize) + 1]; + let mut out = vec![0u8; 8]; + assert!(extract_and_expand(&salt, secret.as_slice(), b"info", &mut out).is_err()); + } + } + + // N.B. the `info `parameter is a `c_ulong`, and I can't figure out how to check whether + // `c_ulong` is smaller than `usize` in order to write a `hkdf_rejects_gigantic_info` test. + + #[test] + fn hkdf_rejects_gigantic_output_buffers() { + ensure_initialized(); + let salt = hmac::SigningKey::new(&digest::SHA256, b"salt"); + let mut out = vec![0u8; 8160 + 1]; // RFC maximum (hashlen * 255) + 1 + assert!(extract_and_expand(&salt, b"secret", b"info", &mut out).is_err()); + } + + #[test] + fn hkdf_rejects_zero_length_output_buffer() { + ensure_initialized(); + let salt = hmac::SigningKey::new(&digest::SHA256, b"salt"); + let mut out = vec![0u8; 0]; + assert!(extract_and_expand(&salt, b"secret", b"info", &mut out).is_err()); + } + + #[test] + fn hkdf_can_produce_small_output() { + ensure_initialized(); + let salt = hmac::SigningKey::new(&digest::SHA256, b"salt"); + let mut out = vec![0u8; 1]; + assert!(extract_and_expand(&salt, b"secret", b"info", &mut out).is_ok()); + } + + #[test] + fn hkdf_accepts_zero_length_info() { + ensure_initialized(); + let salt = hmac::SigningKey::new(&digest::SHA256, b"salt"); + let mut out = vec![0u8; 32]; + assert!(extract_and_expand(&salt, b"secret", b"", &mut out).is_ok()); + } + + #[test] + fn hkdf_expand_rejects_short_prk() { + ensure_initialized(); + let prk = hmac::SigningKey::new(&digest::SHA256, b"too short"); // must be >= HashLen + let mut out = vec![0u8; 8]; + assert!(expand(&prk, b"info", &mut out).is_ok()); + } +} diff --git a/third_party/rust/rc_crypto/src/hmac.rs b/third_party/rust/rc_crypto/src/hmac.rs @@ -0,0 +1,210 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::{constant_time, digest, error::*}; + +/// A calculated signature value. +/// This is a type-safe wrappper that discourages attempts at comparing signatures +/// for equality, which might naively be done using a non-constant-time comparison. +#[derive(Clone)] +pub struct Signature(pub(crate) digest::Digest); + +impl AsRef<[u8]> for Signature { + #[inline] + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +/// A key to use for HMAC signing. +pub struct SigningKey { + pub(crate) digest_alg: &'static digest::Algorithm, + pub(crate) key_value: Vec<u8>, +} + +impl SigningKey { + pub fn new(digest_alg: &'static digest::Algorithm, key_value: &[u8]) -> Self { + SigningKey { + digest_alg, + key_value: key_value.to_vec(), + } + } + + #[inline] + pub fn digest_algorithm(&self) -> &'static digest::Algorithm { + self.digest_alg + } +} + +/// A key to use for HMAC authentication. +pub struct VerificationKey { + wrapped: SigningKey, +} + +impl VerificationKey { + pub fn new(digest_alg: &'static digest::Algorithm, key_value: &[u8]) -> Self { + VerificationKey { + wrapped: SigningKey::new(digest_alg, key_value), + } + } + + #[inline] + pub fn digest_algorithm(&self) -> &'static digest::Algorithm { + self.wrapped.digest_algorithm() + } +} + +/// Calculate the HMAC of `data` using `key` and verify it corresponds to the provided signature. +pub fn verify(key: &VerificationKey, data: &[u8], signature: &[u8]) -> Result<()> { + verify_with_own_key(&key.wrapped, data, signature) +} + +/// Equivalent to `verify` but allows the consumer to pass a `SigningKey`. +pub fn verify_with_own_key(key: &SigningKey, data: &[u8], signature: &[u8]) -> Result<()> { + constant_time::verify_slices_are_equal(sign(key, data)?.as_ref(), signature) +} + +/// Calculate the HMAC of `data` using `key`. +pub fn sign(key: &SigningKey, data: &[u8]) -> Result<Signature> { + let value = nss::pk11::context::hmac_sign(key.digest_alg, &key.key_value, data)?; + Ok(Signature(digest::Digest { + value, + algorithm: *key.digest_alg, + })) +} + +#[cfg(test)] +mod tests { + use super::*; + use nss::ensure_initialized; + + const KEY: &[u8] = b"key"; + const MESSAGE: &[u8] = b"The quick brown fox jumps over the lazy dog"; + const SIGNATURE_HEX: &str = "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"; + + #[test] + fn hmac_sign() { + ensure_initialized(); + let key = SigningKey::new(&digest::SHA256, KEY); + let signature = sign(&key, MESSAGE).unwrap(); + let expected_signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert_eq!(signature.as_ref(), expected_signature.as_slice()); + assert!(verify_with_own_key(&key, MESSAGE, &expected_signature).is_ok()); + } + + #[test] + fn hmac_sign_gives_different_signatures_for_different_keys() { + ensure_initialized(); + let key = SigningKey::new(&digest::SHA256, b"another key"); + let signature = sign(&key, MESSAGE).unwrap(); + let expected_signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert_ne!(signature.as_ref(), expected_signature.as_slice()); + } + + #[test] + fn hmac_sign_gives_different_signatures_for_different_messages() { + ensure_initialized(); + let key = SigningKey::new(&digest::SHA256, KEY); + let signature = sign(&key, b"a different message").unwrap(); + let expected_signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert_ne!(signature.as_ref(), expected_signature.as_slice()); + } + + #[test] + fn hmac_verify() { + ensure_initialized(); + let key = VerificationKey::new(&digest::SHA256, KEY); + let expected_signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert!(verify(&key, MESSAGE, &expected_signature).is_ok()); + } + + #[test] + fn hmac_verify_fails_with_incorrect_signature() { + ensure_initialized(); + let key = VerificationKey::new(&digest::SHA256, KEY); + let signature = hex::decode(SIGNATURE_HEX).unwrap(); + for i in 0..signature.len() { + let mut wrong_signature = signature.clone(); + wrong_signature[i] = wrong_signature[i].wrapping_add(1); + assert!(verify(&key, MESSAGE, &wrong_signature).is_err()); + } + } + + #[test] + fn hmac_verify_fails_with_incorrect_key() { + ensure_initialized(); + let key = VerificationKey::new(&digest::SHA256, b"wrong key"); + let signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert!(verify(&key, MESSAGE, &signature).is_err()); + } + + #[test] + fn hmac_sign_cleanly_rejects_gigantic_keys() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let key_bytes = vec![0; (u32::MAX as usize) + 1]; + // Direct construction of SigningKey to avoid instantiating the array. + let key = SigningKey { + digest_alg: &digest::SHA256, + key_value: key_bytes, + }; + assert!(sign(&key, MESSAGE).is_err()); + } + } + + #[test] + fn hmac_verify_cleanly_rejects_gigantic_keys() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let key_bytes = vec![0; (u32::MAX as usize) + 1]; + // Direct construction of VerificationKey to avoid instantiating the array. + let key = VerificationKey { + wrapped: SigningKey { + digest_alg: &digest::SHA256, + key_value: key_bytes, + }, + }; + let signature = hex::decode(SIGNATURE_HEX).unwrap(); + assert!(verify(&key, MESSAGE, &signature).is_err()); + } + } + + #[test] + fn hmac_sign_cleanly_rejects_gigantic_messages() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let key = SigningKey::new(&digest::SHA256, KEY); + let message = vec![0; (u32::MAX as usize) + 1]; + assert!(sign(&key, &message).is_err()); + } + } + + #[test] + fn hmac_verify_cleanly_rejects_gigantic_messages() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let key = VerificationKey::new(&digest::SHA256, KEY); + let signature = hex::decode(SIGNATURE_HEX).unwrap(); + let message = vec![0; (u32::MAX as usize) + 1]; + assert!(verify(&key, &message, &signature).is_err()); + } + } +} diff --git a/third_party/rust/rc_crypto/src/lib.rs b/third_party/rust/rc_crypto/src/lib.rs @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#![allow(unknown_lints)] +#![warn(rust_2018_idioms)] +/// This crate provides all the cryptographic primitives required by +/// this workspace, backed by the NSS library. +/// The exposed API is pretty much the same as the `ring` crate. +pub mod aead; +pub mod agreement; +pub mod constant_time; +pub mod contentsignature; +pub mod digest; +#[cfg(feature = "ece")] +pub mod ece_crypto; +mod error; +#[cfg(feature = "hawk")] +mod hawk_crypto; +pub mod hkdf; +pub mod hmac; +pub mod pbkdf2; +pub mod rand; +pub mod signature; + +// Expose `hawk` if the hawk feature is on. This avoids consumers needing to +// configure this separately, which is more or less trivial to do incorrectly. +#[cfg(feature = "hawk")] +pub use hawk; + +// Expose `ece` if the ece feature is on. This avoids consumers needing to +// configure this separately, which is more or less trivial to do incorrectly. +#[cfg(feature = "ece")] +pub use ece; + +pub use crate::error::{Error, ErrorKind, Result}; + +/// Only required to be called if you intend to use this library in conjunction +/// with the `hawk` or the `ece` crate. +pub fn ensure_initialized() { + nss::assert_initialized(); + + #[cfg(any(feature = "hawk", feature = "ece"))] + { + static INIT_ONCE: std::sync::Once = std::sync::Once::new(); + INIT_ONCE.call_once(|| { + #[cfg(feature = "hawk")] + crate::hawk_crypto::init(); + #[cfg(feature = "ece")] + crate::ece_crypto::init(); + }); + } +} diff --git a/third_party/rust/rc_crypto/src/pbkdf2.rs b/third_party/rust/rc_crypto/src/pbkdf2.rs @@ -0,0 +1,208 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::error::*; +use nss::pbkdf2::pbkdf2_key_derive; +pub use nss::pbkdf2::HashAlgorithm; +/// Extend passwords using pbkdf2, based on the following [rfc](https://www.ietf.org/rfc/rfc2898.txt) it runs the NSS implementation +/// # Arguments +/// +/// * `passphrase` - The password to stretch +/// * `salt` - A salt to use in the generation process +/// * `iterations` - The number of iterations the hashing algorithm will run on each section of the key +/// * `hash_algorithm` - The hash algorithm to use +/// * `out` - The slice the algorithm will populate +/// +/// # Examples +/// +/// ``` +/// use rc_crypto::pbkdf2; +/// use nss::ensure_initialized; +/// ensure_initialized(); +/// let password = b"password"; +/// let salt = b"salt"; +/// let mut out = vec![0u8; 32]; +/// let iterations = 2; // Real code should have a MUCH higher number of iterations (Think 1000+) +/// pbkdf2::derive(password, salt, iterations, pbkdf2::HashAlgorithm::SHA256, &mut out).unwrap(); // Oh oh should handle the error! +/// assert_eq!(hex::encode(out), "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"); +// +///``` +/// +/// # Errors +/// +/// Could possibly return an error if the HMAC algorithm fails, or if the NSS algorithm returns an error +pub fn derive( + passphrase: &[u8], + salt: &[u8], + iterations: u32, + hash_algorithm: HashAlgorithm, + out: &mut [u8], +) -> Result<()> { + pbkdf2_key_derive(passphrase, salt, iterations, hash_algorithm, out)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use nss::ensure_initialized; + + #[test] + fn test_generate_correct_out() { + ensure_initialized(); + let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"; + let mut out = vec![0u8; 32]; + let password = b"password"; + let salt = b"salt"; + derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_longer_key() { + ensure_initialized(); + let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c"; + let password = b"password"; + let salt = b"salt"; + let mut out = vec![0u8; 64]; + derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_more_iterations() { + ensure_initialized(); + let expected = "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"; + let password = b"password"; + let salt = b"salt"; + let mut out = vec![0u8; 32]; + derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_odd_length() { + ensure_initialized(); + let expected = "ad35240ac683febfaf3cd49d845473fbbbaa2437f5f82d5a415ae00ac76c6bfccf"; + let password = b"password"; + let salt = b"salt"; + let mut out = vec![0u8; 33]; + derive(password, salt, 3, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_nulls() { + ensure_initialized(); + let expected = "e25d526987819f966e324faa4a"; + let password = b"passw\x00rd"; + let salt = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + let mut out = vec![0u8; 13]; + derive(password, salt, 5, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_password_null() { + ensure_initialized(); + let expected = "62384466264daadc4144018c6bd864648272b34da8980d31521ffcce92ae003b"; + let password = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + let salt = b"salt"; + let mut out = vec![0u8; 32]; + derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_empty_password() { + ensure_initialized(); + let expected = "f135c27993baf98773c5cdb40a5706ce6a345cde61b000a67858650cd6a324d7"; + let mut out = vec![0u8; 32]; + let password = b""; + let salt = b"salt"; + derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_empty_salt() { + ensure_initialized(); + let expected = "c1232f10f62715fda06ae7c0a2037ca19b33cf103b727ba56d870c11f290a2ab"; + let mut out = vec![0u8; 32]; + let password = b"password"; + let salt = b""; + derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_tiny_out() { + ensure_initialized(); + let expected = "12"; + let mut out = vec![0u8; 1]; + let password = b"password"; + let salt = b"salt"; + derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap(); + assert_eq!(expected, hex::encode(out)); + } + + #[test] + fn test_rejects_zero_iterations() { + ensure_initialized(); + let mut out = vec![0u8; 32]; + let password = b"password"; + let salt = b"salt"; + assert!(derive(password, salt, 0, HashAlgorithm::SHA256, &mut out).is_err()); + } + + #[test] + fn test_rejects_empty_out() { + ensure_initialized(); + let mut out = vec![0u8; 0]; + let password = b"password"; + let salt = b"salt"; + assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err()); + } + + #[test] + fn test_rejects_gaigantic_salt() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let salt = vec![0; (u32::MAX as usize) + 1]; + let mut out = vec![0u8; 1]; + let password = b"password"; + assert!(derive(password, &salt, 1, HashAlgorithm::SHA256, &mut out).is_err()); + } + } + #[test] + fn test_rejects_gaigantic_password() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let password = vec![0; (u32::MAX as usize) + 1]; + let mut out = vec![0u8; 1]; + let salt = b"salt"; + assert!(derive(&password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err()); + } + } + + #[test] + fn test_rejects_gaigantic_out() { + ensure_initialized(); + if (u32::MAX as usize) < usize::MAX { + let password = b"password"; + let mut out = vec![0; (u32::MAX as usize) + 1]; + let salt = b"salt"; + assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err()); + } + } + + #[test] + fn test_rejects_gaigantic_iterations() { + ensure_initialized(); + let password = b"password"; + let mut out = vec![0; 32]; + let salt = b"salt"; + assert!(derive(password, salt, u32::MAX, HashAlgorithm::SHA256, &mut out).is_err()); + } +} diff --git a/third_party/rust/rc_crypto/src/rand.rs b/third_party/rust/rc_crypto/src/rand.rs @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::error::*; + +/// Fill a buffer with cryptographically secure pseudo-random data. +pub fn fill(dest: &mut [u8]) -> Result<()> { + Ok(nss::pk11::slot::generate_random(dest)?) +} + +#[cfg(test)] +mod tests { + use super::*; + use nss::ensure_initialized; + + #[test] + fn random_fill() { + ensure_initialized(); + + let mut out = vec![0u8; 64]; + assert!(fill(&mut out).is_ok()); + // This check could *in theory* fail if we randomly generate all zeroes + // but we're treating that probability as negligible in practice. + assert_ne!(out, vec![0u8; 64]); + + let mut out2 = vec![0u8; 64]; + assert!(fill(&mut out2).is_ok()); + assert_ne!(out, vec![0u8; 64]); + assert_ne!(out2, out); + } + + #[test] + fn random_fill_empty() { + ensure_initialized(); + + let mut out = vec![0u8; 0]; + assert!(fill(&mut out).is_ok()); + assert_eq!(out, vec![0u8; 0]); + } + + #[test] + fn random_fill_oddly_sized_arrays() { + ensure_initialized(); + + let sizes: [usize; 4] = [61, 63, 65, 67]; + for size in &sizes { + let mut out = vec![0u8; *size]; + assert!(fill(&mut out).is_ok()); + assert_ne!(out, vec![0u8; *size]); + } + } + + #[test] + fn random_fill_rejects_attempts_to_fill_gigantic_arrays() { + ensure_initialized(); + + let max_size: usize = i32::MAX as usize; + let mut out = vec![0u8; max_size + 1]; + assert!(fill(&mut out).is_err()); + } +} diff --git a/third_party/rust/rc_crypto/src/signature.rs b/third_party/rust/rc_crypto/src/signature.rs @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains code that was copied from the ring crate which is under +// the ISC license, reproduced below: + +// Copyright 2015-2017 Brian Smith. + +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::Result; +use nss::{ec::Curve, ec::PublicKey, pbkdf2::HashAlgorithm}; + +/// A signature verification algorithm. +pub struct VerificationAlgorithm { + curve: Curve, + digest_alg: HashAlgorithm, +} + +pub static ECDSA_P256_SHA256: VerificationAlgorithm = VerificationAlgorithm { + curve: Curve::P256, + digest_alg: HashAlgorithm::SHA256, +}; + +pub static ECDSA_P384_SHA384: VerificationAlgorithm = VerificationAlgorithm { + curve: Curve::P384, + digest_alg: HashAlgorithm::SHA384, +}; + +/// An unparsed public key for signature operations. +pub struct UnparsedPublicKey<'a> { + alg: &'static VerificationAlgorithm, + bytes: &'a [u8], +} + +impl<'a> UnparsedPublicKey<'a> { + pub fn new(algorithm: &'static VerificationAlgorithm, bytes: &'a [u8]) -> Self { + Self { + alg: algorithm, + bytes, + } + } + + pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<()> { + let pub_key = PublicKey::from_bytes(self.alg.curve, self.bytes)?; + Ok(pub_key.verify(message, signature, self.alg.digest_alg)?) + } + + pub fn algorithm(&self) -> &'static VerificationAlgorithm { + self.alg + } + + pub fn bytes(&self) -> &'a [u8] { + self.bytes + } +} + +#[cfg(test)] +mod tests { + use super::*; + use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; + use nss::ensure_initialized; + + #[test] + fn test_ecdsa_p384_sha384_verify() { + ensure_initialized(); + // Test generated with JS DOM's WebCrypto. + let pub_key_bytes = URL_SAFE_NO_PAD.decode( + "BMZj_xHOfLQn5DIEQcYUkyASDWo8O30gWdkWXHHHWN5owKhGWplYHEb4PLf3DkFTg_smprr-ApdULy3NV10x8IZ0EfVaUZdXvTquH1kiw2PxD7fhqiozMXUaSuZI5KBE6w", + ).unwrap(); + let message = URL_SAFE_NO_PAD.decode( + "F9MQDmEEdvOfm-NkCRrXqG-aVA9kq0xqtjvtWLndmmt6bO2gfLE2CVDDLzJYds0n88uz27c5JkzdsLpm5HP3aLFgD8bgnGm-EgdBpm99CRiIm7mAMbb0-NRAyUxeoGmdgJPVQLWFNoHRwzKV2wZ0Bk-Bq7jkeDHmDfnx-CJKVMQ", + ) + .unwrap(); + let signature = URL_SAFE_NO_PAD.decode( + "XLZmtJweW4qx0u0l6EpfmB5z-S-CNj4mrl9d7U0MuftdNPhmlNacV4AKR-i4uNn0TUIycU7GsfIjIqxuiL9WdAnfq_KH_SJ95mduqXgWNKlyt8JgMLd4h-jKOllh4erh", + ) + .unwrap(); + let public_key = + crate::signature::UnparsedPublicKey::new(&ECDSA_P384_SHA384, &pub_key_bytes); + + // Failure case: Wrong key algorithm. + let public_key_wrong_alg = + crate::signature::UnparsedPublicKey::new(&ECDSA_P256_SHA256, &pub_key_bytes); + assert!(public_key_wrong_alg.verify(&message, &signature).is_err()); + + // Failure case: Add garbage to signature. + let mut garbage_signature = signature.clone(); + garbage_signature.push(42); + assert!(public_key.verify(&message, &garbage_signature).is_err()); + + // Failure case: Flip a bit in message. + let mut garbage_message = message.clone(); + garbage_message[42] = 42; + assert!(public_key.verify(&garbage_message, &signature).is_err()); + + // Happy case. + assert!(public_key.verify(&message, &signature).is_ok()); + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustInitRustComponents.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustInitRustComponents.sys.mjs @@ -0,0 +1,63 @@ +// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate. +// Trust me, you don't want to mess with it! + +import { + ArrayBufferDataStream, + FfiConverter, + FfiConverterArrayBuffer, + FfiConverterInt8, + FfiConverterUInt8, + FfiConverterInt16, + FfiConverterUInt16, + FfiConverterInt32, + FfiConverterUInt32, + FfiConverterInt64, + FfiConverterUInt64, + FfiConverterFloat32, + FfiConverterFloat64, + FfiConverterBoolean, + FfiConverterBytes, + FfiConverterString, + UniFFICallbackHandler, + UniFFICallbackMethodHandler, + UniFFIError, + UniFFIInternalError, + UniFFITypeError, + constructUniffiObject, + handleRustResult, + uniffiObjectPtr, +} from "moz-src:///toolkit/components/uniffi-js/js/UniFFI.sys.mjs"; + +// Objects intended to be used in the unit tests +export var UnitTestObjs = { + uniffiObjectPtr, +}; +/** + * Global initialization routines for Rust components, when `logins/keydb` feature is activated. Must be + * called before any other calls to Rust components. + * + * Receives the path to the profile directory. + * + * For adding additional initialization code: Note that this function is called very early in the + * app lifetime and therefore affects the startup time. Only the most necessary things should be + * done here. + * @param {string} profilePath + */ +export async function initialize( + profilePath) { + +FfiConverterString.checkType(profilePath); +const result = await UniFFIScaffolding.callAsyncWrapper( + 7, // uniffi_init_rust_components_fn_func_initialize + FfiConverterString.lower(profilePath), +) +return handleRustResult( + result, + (result) => undefined, + null, +) +} + + + + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustLogins.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustLogins.sys.mjs @@ -0,0 +1,3668 @@ +// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate. +// Trust me, you don't want to mess with it! + +import { + ArrayBufferDataStream, + FfiConverter, + FfiConverterArrayBuffer, + FfiConverterInt8, + FfiConverterUInt8, + FfiConverterInt16, + FfiConverterUInt16, + FfiConverterInt32, + FfiConverterUInt32, + FfiConverterInt64, + FfiConverterUInt64, + FfiConverterFloat32, + FfiConverterFloat64, + FfiConverterBoolean, + FfiConverterBytes, + FfiConverterString, + UniFFICallbackHandler, + UniFFICallbackMethodHandler, + UniFFIError, + UniFFIInternalError, + UniFFITypeError, + constructUniffiObject, + handleRustResult, + uniffiObjectPtr, +} from "moz-src:///toolkit/components/uniffi-js/js/UniFFI.sys.mjs"; + +// Objects intended to be used in the unit tests +export var UnitTestObjs = { + uniffiObjectPtr, +}; +/** + * Check that key is still valid using the output of `create_canary`. + * @param {string} canary + * @param {string} text + * @param {string} encryptionKey + * @returns {boolean} + */ +export function checkCanary( + canary, + text, + encryptionKey) { + +FfiConverterString.checkType(canary); +FfiConverterString.checkType(text); +FfiConverterString.checkType(encryptionKey); +const result = UniFFIScaffolding.callSync( + 8, // uniffi_logins_fn_func_check_canary + FfiConverterString.lower(canary), + FfiConverterString.lower(text), + FfiConverterString.lower(encryptionKey), +) +return handleRustResult( + result, + FfiConverterBoolean.lift.bind(FfiConverterBoolean), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), +) +} + +/** + * Create a "canary" string, which can be used to test if the encryption + * @param {string} text + * @param {string} encryptionKey + * @returns {string} + */ +export function createCanary( + text, + encryptionKey) { + +FfiConverterString.checkType(text); +FfiConverterString.checkType(encryptionKey); +const result = UniFFIScaffolding.callSync( + 9, // uniffi_logins_fn_func_create_canary + FfiConverterString.lower(text), + FfiConverterString.lower(encryptionKey), +) +return handleRustResult( + result, + FfiConverterString.lift.bind(FfiConverterString), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), +) +} + +/** + * We expose the crypto primitives on the namespace + * Create a new, random, encryption key. + * @returns {string} + */ +export function createKey() { + +const result = UniFFIScaffolding.callSync( + 10, // uniffi_logins_fn_func_create_key +) +return handleRustResult( + result, + FfiConverterString.lift.bind(FfiConverterString), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), +) +} + +/** + * createLoginStoreWithNssKeymanager + * @param {string} path + * @param {PrimaryPasswordAuthenticator} primaryPasswordAuthenticator + * @returns {LoginStore} + */ +export function createLoginStoreWithNssKeymanager( + path, + primaryPasswordAuthenticator) { + +FfiConverterString.checkType(path); +FfiConverterTypePrimaryPasswordAuthenticator.checkType(primaryPasswordAuthenticator); +const result = UniFFIScaffolding.callSync( + 11, // uniffi_logins_fn_func_create_login_store_with_nss_keymanager + FfiConverterString.lower(path), + FfiConverterTypePrimaryPasswordAuthenticator.lower(primaryPasswordAuthenticator), +) +return handleRustResult( + result, + FfiConverterTypeLoginStore.lift.bind(FfiConverterTypeLoginStore), + null, +) +} + +/** + * Create a LoginStore with StaticKeyManager by passing in a db path and a + * static key + * @param {string} path + * @param {string} key + * @returns {LoginStore} + */ +export function createLoginStoreWithStaticKeyManager( + path, + key) { + +FfiConverterString.checkType(path); +FfiConverterString.checkType(key); +const result = UniFFIScaffolding.callSync( + 12, // uniffi_logins_fn_func_create_login_store_with_static_key_manager + FfiConverterString.lower(path), + FfiConverterString.lower(key), +) +return handleRustResult( + result, + FfiConverterTypeLoginStore.lift.bind(FfiConverterTypeLoginStore), + null, +) +} + +/** + * Similar to create_static_key_manager above, create a + * ManagedEncryptorDecryptor by passing in a KeyManager + * @param {KeyManager} keyManager + * @returns {EncryptorDecryptor} + */ +export function createManagedEncdec( + keyManager) { + +FfiConverterTypeKeyManager.checkType(keyManager); +const result = UniFFIScaffolding.callSync( + 13, // uniffi_logins_fn_func_create_managed_encdec + FfiConverterTypeKeyManager.lower(keyManager), +) +return handleRustResult( + result, + FfiConverterTypeEncryptorDecryptor.lift.bind(FfiConverterTypeEncryptorDecryptor), + null, +) +} + +/** + * Utility function to create a StaticKeyManager to be used for the time + * being until support lands for [trait implementation of an UniFFI + * interface](https://mozilla.github.io/uniffi-rs/next/proc_macro/index.html#structs-implementing-traits) + * in UniFFI. + * @param {string} key + * @returns {KeyManager} + */ +export function createStaticKeyManager( + key) { + +FfiConverterString.checkType(key); +const result = UniFFIScaffolding.callSync( + 14, // uniffi_logins_fn_func_create_static_key_manager + FfiConverterString.lower(key), +) +return handleRustResult( + result, + FfiConverterTypeKeyManager.lift.bind(FfiConverterTypeKeyManager), + null, +) +} + + + + + + +// Export the FFIConverter object to make external types work. +export class FfiConverterOptionalString extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterString.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterString.read(dataStream) + default: + throw new UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterString.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterString.computeSize(value) + } +} +/** + * A login stored in the database + */ +export class Login { + constructor( + { + id, + timesUsed, + timeCreated, + timeLastUsed, + timePasswordChanged, + origin, + httpRealm, + formActionOrigin, + usernameField, + passwordField, + password, + username + } = { + id: undefined, + timesUsed: undefined, + timeCreated: undefined, + timeLastUsed: undefined, + timePasswordChanged: undefined, + origin: undefined, + httpRealm: undefined, + formActionOrigin: undefined, + usernameField: undefined, + passwordField: undefined, + password: undefined, + username: undefined + } + ) { + try { + FfiConverterString.checkType(id) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("id"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timesUsed) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timesUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timeCreated) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timeCreated"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timeLastUsed) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timeLastUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timePasswordChanged) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timePasswordChanged"); + } + throw e; + } + try { + FfiConverterString.checkType(origin) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("origin"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(httpRealm) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("httpRealm"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(formActionOrigin) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("formActionOrigin"); + } + throw e; + } + try { + FfiConverterString.checkType(usernameField) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("usernameField"); + } + throw e; + } + try { + FfiConverterString.checkType(passwordField) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("passwordField"); + } + throw e; + } + try { + FfiConverterString.checkType(password) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("password"); + } + throw e; + } + try { + FfiConverterString.checkType(username) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("username"); + } + throw e; + } + /** + * id + */ + this.id = id; + /** + * timesUsed + */ + this.timesUsed = timesUsed; + /** + * timeCreated + */ + this.timeCreated = timeCreated; + /** + * timeLastUsed + */ + this.timeLastUsed = timeLastUsed; + /** + * timePasswordChanged + */ + this.timePasswordChanged = timePasswordChanged; + /** + * origin + */ + this.origin = origin; + /** + * httpRealm + */ + this.httpRealm = httpRealm; + /** + * formActionOrigin + */ + this.formActionOrigin = formActionOrigin; + /** + * usernameField + */ + this.usernameField = usernameField; + /** + * passwordField + */ + this.passwordField = passwordField; + /** + * password + */ + this.password = password; + /** + * username + */ + this.username = username; + } + + equals(other) { + return ( + this.id == other.id + && this.timesUsed == other.timesUsed + && this.timeCreated == other.timeCreated + && this.timeLastUsed == other.timeLastUsed + && this.timePasswordChanged == other.timePasswordChanged + && this.origin == other.origin + && this.httpRealm == other.httpRealm + && this.formActionOrigin == other.formActionOrigin + && this.usernameField == other.usernameField + && this.passwordField == other.passwordField + && this.password == other.password + && this.username == other.username + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLogin extends FfiConverterArrayBuffer { + static read(dataStream) { + return new Login({ + id: FfiConverterString.read(dataStream), + timesUsed: FfiConverterInt64.read(dataStream), + timeCreated: FfiConverterInt64.read(dataStream), + timeLastUsed: FfiConverterInt64.read(dataStream), + timePasswordChanged: FfiConverterInt64.read(dataStream), + origin: FfiConverterString.read(dataStream), + httpRealm: FfiConverterOptionalString.read(dataStream), + formActionOrigin: FfiConverterOptionalString.read(dataStream), + usernameField: FfiConverterString.read(dataStream), + passwordField: FfiConverterString.read(dataStream), + password: FfiConverterString.read(dataStream), + username: FfiConverterString.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.id); + FfiConverterInt64.write(dataStream, value.timesUsed); + FfiConverterInt64.write(dataStream, value.timeCreated); + FfiConverterInt64.write(dataStream, value.timeLastUsed); + FfiConverterInt64.write(dataStream, value.timePasswordChanged); + FfiConverterString.write(dataStream, value.origin); + FfiConverterOptionalString.write(dataStream, value.httpRealm); + FfiConverterOptionalString.write(dataStream, value.formActionOrigin); + FfiConverterString.write(dataStream, value.usernameField); + FfiConverterString.write(dataStream, value.passwordField); + FfiConverterString.write(dataStream, value.password); + FfiConverterString.write(dataStream, value.username); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.id); + totalSize += FfiConverterInt64.computeSize(value.timesUsed); + totalSize += FfiConverterInt64.computeSize(value.timeCreated); + totalSize += FfiConverterInt64.computeSize(value.timeLastUsed); + totalSize += FfiConverterInt64.computeSize(value.timePasswordChanged); + totalSize += FfiConverterString.computeSize(value.origin); + totalSize += FfiConverterOptionalString.computeSize(value.httpRealm); + totalSize += FfiConverterOptionalString.computeSize(value.formActionOrigin); + totalSize += FfiConverterString.computeSize(value.usernameField); + totalSize += FfiConverterString.computeSize(value.passwordField); + totalSize += FfiConverterString.computeSize(value.password); + totalSize += FfiConverterString.computeSize(value.username); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof Login)) { + throw new UniFFITypeError(`Expected 'Login', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.id); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".id"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timesUsed); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timesUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timeCreated); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timeCreated"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timeLastUsed); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timeLastUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timePasswordChanged); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timePasswordChanged"); + } + throw e; + } + try { + FfiConverterString.checkType(value.origin); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".origin"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(value.httpRealm); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".httpRealm"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(value.formActionOrigin); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".formActionOrigin"); + } + throw e; + } + try { + FfiConverterString.checkType(value.usernameField); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".usernameField"); + } + throw e; + } + try { + FfiConverterString.checkType(value.passwordField); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".passwordField"); + } + throw e; + } + try { + FfiConverterString.checkType(value.password); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".password"); + } + throw e; + } + try { + FfiConverterString.checkType(value.username); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".username"); + } + throw e; + } + } +} +/** + * A login entry from the user, not linked to any database record. + * The add/update APIs input these. + */ +export class LoginEntry { + constructor( + { + origin, + httpRealm, + formActionOrigin, + usernameField, + passwordField, + password, + username + } = { + origin: undefined, + httpRealm: undefined, + formActionOrigin: undefined, + usernameField: undefined, + passwordField: undefined, + password: undefined, + username: undefined + } + ) { + try { + FfiConverterString.checkType(origin) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("origin"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(httpRealm) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("httpRealm"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(formActionOrigin) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("formActionOrigin"); + } + throw e; + } + try { + FfiConverterString.checkType(usernameField) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("usernameField"); + } + throw e; + } + try { + FfiConverterString.checkType(passwordField) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("passwordField"); + } + throw e; + } + try { + FfiConverterString.checkType(password) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("password"); + } + throw e; + } + try { + FfiConverterString.checkType(username) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("username"); + } + throw e; + } + /** + * origin + */ + this.origin = origin; + /** + * httpRealm + */ + this.httpRealm = httpRealm; + /** + * formActionOrigin + */ + this.formActionOrigin = formActionOrigin; + /** + * usernameField + */ + this.usernameField = usernameField; + /** + * passwordField + */ + this.passwordField = passwordField; + /** + * password + */ + this.password = password; + /** + * username + */ + this.username = username; + } + + equals(other) { + return ( + this.origin == other.origin + && this.httpRealm == other.httpRealm + && this.formActionOrigin == other.formActionOrigin + && this.usernameField == other.usernameField + && this.passwordField == other.passwordField + && this.password == other.password + && this.username == other.username + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginEntry extends FfiConverterArrayBuffer { + static read(dataStream) { + return new LoginEntry({ + origin: FfiConverterString.read(dataStream), + httpRealm: FfiConverterOptionalString.read(dataStream), + formActionOrigin: FfiConverterOptionalString.read(dataStream), + usernameField: FfiConverterString.read(dataStream), + passwordField: FfiConverterString.read(dataStream), + password: FfiConverterString.read(dataStream), + username: FfiConverterString.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.origin); + FfiConverterOptionalString.write(dataStream, value.httpRealm); + FfiConverterOptionalString.write(dataStream, value.formActionOrigin); + FfiConverterString.write(dataStream, value.usernameField); + FfiConverterString.write(dataStream, value.passwordField); + FfiConverterString.write(dataStream, value.password); + FfiConverterString.write(dataStream, value.username); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.origin); + totalSize += FfiConverterOptionalString.computeSize(value.httpRealm); + totalSize += FfiConverterOptionalString.computeSize(value.formActionOrigin); + totalSize += FfiConverterString.computeSize(value.usernameField); + totalSize += FfiConverterString.computeSize(value.passwordField); + totalSize += FfiConverterString.computeSize(value.password); + totalSize += FfiConverterString.computeSize(value.username); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof LoginEntry)) { + throw new UniFFITypeError(`Expected 'LoginEntry', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.origin); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".origin"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(value.httpRealm); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".httpRealm"); + } + throw e; + } + try { + FfiConverterOptionalString.checkType(value.formActionOrigin); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".formActionOrigin"); + } + throw e; + } + try { + FfiConverterString.checkType(value.usernameField); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".usernameField"); + } + throw e; + } + try { + FfiConverterString.checkType(value.passwordField); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".passwordField"); + } + throw e; + } + try { + FfiConverterString.checkType(value.password); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".password"); + } + throw e; + } + try { + FfiConverterString.checkType(value.username); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".username"); + } + throw e; + } + } +} +/** + * Login data specific to database records. + * The add_with_record API inputs this. + */ +export class LoginMeta { + constructor( + { + id, + timesUsed, + timeCreated, + timeLastUsed, + timePasswordChanged + } = { + id: undefined, + timesUsed: undefined, + timeCreated: undefined, + timeLastUsed: undefined, + timePasswordChanged: undefined + } + ) { + try { + FfiConverterString.checkType(id) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("id"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timesUsed) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timesUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timeCreated) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timeCreated"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timeLastUsed) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timeLastUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(timePasswordChanged) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timePasswordChanged"); + } + throw e; + } + /** + * id + */ + this.id = id; + /** + * timesUsed + */ + this.timesUsed = timesUsed; + /** + * timeCreated + */ + this.timeCreated = timeCreated; + /** + * timeLastUsed + */ + this.timeLastUsed = timeLastUsed; + /** + * timePasswordChanged + */ + this.timePasswordChanged = timePasswordChanged; + } + + equals(other) { + return ( + this.id == other.id + && this.timesUsed == other.timesUsed + && this.timeCreated == other.timeCreated + && this.timeLastUsed == other.timeLastUsed + && this.timePasswordChanged == other.timePasswordChanged + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginMeta extends FfiConverterArrayBuffer { + static read(dataStream) { + return new LoginMeta({ + id: FfiConverterString.read(dataStream), + timesUsed: FfiConverterInt64.read(dataStream), + timeCreated: FfiConverterInt64.read(dataStream), + timeLastUsed: FfiConverterInt64.read(dataStream), + timePasswordChanged: FfiConverterInt64.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.id); + FfiConverterInt64.write(dataStream, value.timesUsed); + FfiConverterInt64.write(dataStream, value.timeCreated); + FfiConverterInt64.write(dataStream, value.timeLastUsed); + FfiConverterInt64.write(dataStream, value.timePasswordChanged); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.id); + totalSize += FfiConverterInt64.computeSize(value.timesUsed); + totalSize += FfiConverterInt64.computeSize(value.timeCreated); + totalSize += FfiConverterInt64.computeSize(value.timeLastUsed); + totalSize += FfiConverterInt64.computeSize(value.timePasswordChanged); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof LoginMeta)) { + throw new UniFFITypeError(`Expected 'LoginMeta', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.id); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".id"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timesUsed); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timesUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timeCreated); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timeCreated"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timeLastUsed); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timeLastUsed"); + } + throw e; + } + try { + FfiConverterInt64.checkType(value.timePasswordChanged); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".timePasswordChanged"); + } + throw e; + } + } +} +/** + * A login together with record fields, handed over to the store API; ie a login persisted + * elsewhere, useful for migrations + */ +export class LoginEntryWithMeta { + constructor( + { + entry, + meta + } = { + entry: undefined, + meta: undefined + } + ) { + try { + FfiConverterTypeLoginEntry.checkType(entry) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("entry"); + } + throw e; + } + try { + FfiConverterTypeLoginMeta.checkType(meta) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("meta"); + } + throw e; + } + /** + * entry + */ + this.entry = entry; + /** + * meta + */ + this.meta = meta; + } + + equals(other) { + return ( + this.entry.equals(other.entry) + && this.meta.equals(other.meta) + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginEntryWithMeta extends FfiConverterArrayBuffer { + static read(dataStream) { + return new LoginEntryWithMeta({ + entry: FfiConverterTypeLoginEntry.read(dataStream), + meta: FfiConverterTypeLoginMeta.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterTypeLoginEntry.write(dataStream, value.entry); + FfiConverterTypeLoginMeta.write(dataStream, value.meta); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterTypeLoginEntry.computeSize(value.entry); + totalSize += FfiConverterTypeLoginMeta.computeSize(value.meta); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof LoginEntryWithMeta)) { + throw new UniFFITypeError(`Expected 'LoginEntryWithMeta', found '${typeof value}'`); + } + try { + FfiConverterTypeLoginEntry.checkType(value.entry); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".entry"); + } + throw e; + } + try { + FfiConverterTypeLoginMeta.checkType(value.meta); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".meta"); + } + throw e; + } + } +} + + +/** + * Metrics tracking deletion of logins that cannot be decrypted, see `delete_undecryptable_records_for_remote_replacement` + * for more details + */ +export class LoginsDeletionMetrics { + constructor( + { + localDeleted, + mirrorDeleted + } = { + localDeleted: undefined, + mirrorDeleted: undefined + } + ) { + try { + FfiConverterUInt64.checkType(localDeleted) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("localDeleted"); + } + throw e; + } + try { + FfiConverterUInt64.checkType(mirrorDeleted) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("mirrorDeleted"); + } + throw e; + } + /** + * localDeleted + */ + this.localDeleted = localDeleted; + /** + * mirrorDeleted + */ + this.mirrorDeleted = mirrorDeleted; + } + + equals(other) { + return ( + this.localDeleted == other.localDeleted + && this.mirrorDeleted == other.mirrorDeleted + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginsDeletionMetrics extends FfiConverterArrayBuffer { + static read(dataStream) { + return new LoginsDeletionMetrics({ + localDeleted: FfiConverterUInt64.read(dataStream), + mirrorDeleted: FfiConverterUInt64.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterUInt64.write(dataStream, value.localDeleted); + FfiConverterUInt64.write(dataStream, value.mirrorDeleted); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterUInt64.computeSize(value.localDeleted); + totalSize += FfiConverterUInt64.computeSize(value.mirrorDeleted); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof LoginsDeletionMetrics)) { + throw new UniFFITypeError(`Expected 'LoginsDeletionMetrics', found '${typeof value}'`); + } + try { + FfiConverterUInt64.checkType(value.localDeleted); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".localDeleted"); + } + throw e; + } + try { + FfiConverterUInt64.checkType(value.mirrorDeleted); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".mirrorDeleted"); + } + throw e; + } + } +} + +/** + * A bulk insert result entry, returned by `add_many` and `add_many_with_meta` + */ +export class BulkResultEntry {} +/** + * Success + */ +BulkResultEntry.Success = class extends BulkResultEntry{ + constructor({login = undefined } = {}) { + super(); + try { + FfiConverterTypeLogin.checkType(login); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("login"); + } + throw e; + } + this.login = login; + } +} +/** + * Error + */ +BulkResultEntry.Error = class extends BulkResultEntry{ + constructor({message = undefined } = {}) { + super(); + try { + FfiConverterString.checkType(message); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("message"); + } + throw e; + } + this.message = message; + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeBulkResultEntry extends FfiConverterArrayBuffer { + static read(dataStream) { + // Use sequential indices (1-based) for the wire format to match the Rust scaffolding + switch (dataStream.readInt32()) { + case 1: + return new BulkResultEntry.Success({ + login: FfiConverterTypeLogin.read(dataStream) + }); + case 2: + return new BulkResultEntry.Error({ + message: FfiConverterString.read(dataStream) + }); + default: + throw new UniFFITypeError("Unknown BulkResultEntry variant"); + } + } + + static write(dataStream, value) { + // Use sequential indices (1-based) for the wire format to match the Rust scaffolding + if (value instanceof BulkResultEntry.Success) { + dataStream.writeInt32(1); + FfiConverterTypeLogin.write(dataStream, value.login); + return; + } + if (value instanceof BulkResultEntry.Error) { + dataStream.writeInt32(2); + FfiConverterString.write(dataStream, value.message); + return; + } + throw new UniFFITypeError("Unknown BulkResultEntry variant"); + } + + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof BulkResultEntry.Success) { + totalSize += FfiConverterTypeLogin.computeSize(value.login); + return totalSize; + } + if (value instanceof BulkResultEntry.Error) { + totalSize += FfiConverterString.computeSize(value.message); + return totalSize; + } + throw new UniFFITypeError("Unknown BulkResultEntry variant"); + } + + static checkType(value) { + if (!(value instanceof BulkResultEntry)) { + throw new UniFFITypeError(`${value} is not a subclass instance of BulkResultEntry`); + } + } +} + +/** + * LoginOrErrorMessage + */ +export const LoginOrErrorMessage = { + /** + * LOGIN + */ + LOGIN: 0, + /** + * STRING + */ + STRING: 1, +}; +Object.freeze(LoginOrErrorMessage); + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginOrErrorMessage extends FfiConverterArrayBuffer { + static #validValues = Object.values(LoginOrErrorMessage) + + static read(dataStream) { + // Use sequential indices (1-based) for the wire format to match the Rust scaffolding + switch (dataStream.readInt32()) { + case 1: + return LoginOrErrorMessage.LOGIN + case 2: + return LoginOrErrorMessage.STRING + default: + throw new UniFFITypeError("Unknown LoginOrErrorMessage variant"); + } + } + + static write(dataStream, value) { + // Use sequential indices (1-based) for the wire format to match the Rust scaffolding + if (value === LoginOrErrorMessage.LOGIN) { + dataStream.writeInt32(1); + return; + } + if (value === LoginOrErrorMessage.STRING) { + dataStream.writeInt32(2); + return; + } + throw new UniFFITypeError("Unknown LoginOrErrorMessage variant"); + } + + static computeSize(value) { + return 4; + } + + static checkType(value) { + // Check that the value is a valid enum variant + if (!this.#validValues.includes(value)) { + throw new UniFFITypeError(`${value} is not a valid value for LoginOrErrorMessage`); + } + } +} + +/** + * These are the errors returned by our public API. + */ +export class LoginsApiError extends Error {} + + +/** + * NSS not initialized. + */ +export class NssUninitialized extends LoginsApiError { + + constructor( + ...params + ) { + super(...params); + } + toString() { + return `NssUninitialized: ${super.toString()}` + } +} + +/** + * NSS error during authentication + */ +export class NssAuthenticationError extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `NssAuthenticationError: ${super.toString()}` + } +} + +/** + * error during authentication (in PrimaryPasswordAuthenticator) + */ +export class AuthenticationError extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `AuthenticationError: ${super.toString()}` + } +} + +/** + * authentication has been cancelled. + */ +export class AuthenticationCanceled extends LoginsApiError { + + constructor( + ...params + ) { + super(...params); + } + toString() { + return `AuthenticationCanceled: ${super.toString()}` + } +} + +/** + * The login data supplied is invalid. The reason will indicate what's wrong with it. + */ +export class InvalidRecord extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `InvalidRecord: ${super.toString()}` + } +} + +/** + * Asking to do something with a guid which doesn't exist. + */ +export class NoSuchRecord extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `NoSuchRecord: ${super.toString()}` + } +} + +/** + * Encryption key is missing. + */ +export class MissingKey extends LoginsApiError { + + constructor( + ...params + ) { + super(...params); + } + toString() { + return `MissingKey: ${super.toString()}` + } +} + +/** + * Encryption key is not valid. + */ +export class InvalidKey extends LoginsApiError { + + constructor( + ...params + ) { + super(...params); + } + toString() { + return `InvalidKey: ${super.toString()}` + } +} + +/** + * encryption failed + */ +export class EncryptionFailed extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `EncryptionFailed: ${super.toString()}` + } +} + +/** + * decryption failed + */ +export class DecryptionFailed extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `DecryptionFailed: ${super.toString()}` + } +} + +/** + * An operation was interrupted at the request of the consuming app. + */ +export class Interrupted extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `Interrupted: ${super.toString()}` + } +} + +/** + * Sync reported that authentication failed and the user should re-enter their FxA password. + */ +export class SyncAuthInvalid extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `SyncAuthInvalid: ${super.toString()}` + } +} + +/** + * something internal went wrong which doesn't have a public error value + * because the consuming app can not reasonably take any action to resolve it. + * The underlying error will have been logged and reported. + * (ideally would just be `Unexpected`, but that would be a breaking change) + */ +export class UnexpectedLoginsApiError extends LoginsApiError { + + constructor( + reason, + ...params + ) { + const message = `reason: ${ reason }`; + super(message, ...params); + this.reason = reason; + } + toString() { + return `UnexpectedLoginsApiError: ${super.toString()}` + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginsApiError extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return new NssUninitialized( + ); + case 2: + return new NssAuthenticationError( + FfiConverterString.read(dataStream) + ); + case 3: + return new AuthenticationError( + FfiConverterString.read(dataStream) + ); + case 4: + return new AuthenticationCanceled( + ); + case 5: + return new InvalidRecord( + FfiConverterString.read(dataStream) + ); + case 6: + return new NoSuchRecord( + FfiConverterString.read(dataStream) + ); + case 7: + return new MissingKey( + ); + case 8: + return new InvalidKey( + ); + case 9: + return new EncryptionFailed( + FfiConverterString.read(dataStream) + ); + case 10: + return new DecryptionFailed( + FfiConverterString.read(dataStream) + ); + case 11: + return new Interrupted( + FfiConverterString.read(dataStream) + ); + case 12: + return new SyncAuthInvalid( + FfiConverterString.read(dataStream) + ); + case 13: + return new UnexpectedLoginsApiError( + FfiConverterString.read(dataStream) + ); + default: + throw new UniFFITypeError("Unknown LoginsApiError variant"); + } + } + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof NssUninitialized) { + return totalSize; + } + if (value instanceof NssAuthenticationError) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof AuthenticationError) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof AuthenticationCanceled) { + return totalSize; + } + if (value instanceof InvalidRecord) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof NoSuchRecord) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof MissingKey) { + return totalSize; + } + if (value instanceof InvalidKey) { + return totalSize; + } + if (value instanceof EncryptionFailed) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof DecryptionFailed) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof Interrupted) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof SyncAuthInvalid) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof UnexpectedLoginsApiError) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + throw new UniFFITypeError("Unknown LoginsApiError variant"); + } + static write(dataStream, value) { + if (value instanceof NssUninitialized) { + dataStream.writeInt32(1); + return; + } + if (value instanceof NssAuthenticationError) { + dataStream.writeInt32(2); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof AuthenticationError) { + dataStream.writeInt32(3); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof AuthenticationCanceled) { + dataStream.writeInt32(4); + return; + } + if (value instanceof InvalidRecord) { + dataStream.writeInt32(5); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof NoSuchRecord) { + dataStream.writeInt32(6); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof MissingKey) { + dataStream.writeInt32(7); + return; + } + if (value instanceof InvalidKey) { + dataStream.writeInt32(8); + return; + } + if (value instanceof EncryptionFailed) { + dataStream.writeInt32(9); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof DecryptionFailed) { + dataStream.writeInt32(10); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof Interrupted) { + dataStream.writeInt32(11); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof SyncAuthInvalid) { + dataStream.writeInt32(12); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof UnexpectedLoginsApiError) { + dataStream.writeInt32(13); + FfiConverterString.write(dataStream, value.reason); + return; + } + throw new UniFFITypeError("Unknown LoginsApiError variant"); + } + + static errorClass = LoginsApiError; +} + + + +/** + * EncryptorDecryptor + */ +export class EncryptorDecryptor { + /** + * decrypt + * @param {string} ciphertext + * @returns {string} + */ + decrypt( + ciphertext) { + throw Error("decrypt not implemented"); + } + /** + * encrypt + * @param {string} cleartext + * @returns {string} + */ + encrypt( + cleartext) { + throw Error("encrypt not implemented"); + } + +} + +/** + * EncryptorDecryptor + */ +export class EncryptorDecryptorImpl extends EncryptorDecryptor { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + + /** + * decrypt + * @param {string} ciphertext + * @returns {string} + */ + decrypt( + ciphertext) { + + FfiConverterBytes.checkType(ciphertext); + const result = UniFFIScaffolding.callSync( + 15, // uniffi_logins_fn_method_encryptordecryptor_decrypt + FfiConverterTypeEncryptorDecryptor.lowerReceiver(this), + FfiConverterBytes.lower(ciphertext), + ) + return handleRustResult( + result, + FfiConverterBytes.lift.bind(FfiConverterBytes), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * encrypt + * @param {string} cleartext + * @returns {string} + */ + encrypt( + cleartext) { + + FfiConverterBytes.checkType(cleartext); + const result = UniFFIScaffolding.callSync( + 16, // uniffi_logins_fn_method_encryptordecryptor_encrypt + FfiConverterTypeEncryptorDecryptor.lowerReceiver(this), + FfiConverterBytes.lower(cleartext), + ) + return handleRustResult( + result, + FfiConverterBytes.lift.bind(FfiConverterBytes), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + +} + +// FfiConverter for a trait interface. This is a hybrid of the FFIConverter regular interfaces and +// for callback interfaces. +// +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeEncryptorDecryptor extends FfiConverter { + // lift works like a regular interface + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new EncryptorDecryptorImpl(opts); + } + + // lower treats value like a callback interface + static lower(value) { + if (!(value instanceof EncryptorDecryptor)) { + throw new UniFFITypeError("expected 'EncryptorDecryptor' subclass"); + } + return uniffiCallbackHandlerLoginsEncryptorDecryptor.storeCallbackObj(value) + } + + // lowerReceiver is used when calling methods on an interface we got from Rust, + // it treats value like a regular interface. + static lowerReceiver(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'EncryptorDecryptorImpl' instance"); + } + return ptr; + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(3)); + } + + static write(dataStream, value) { + dataStream.writePointer(3, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + +const uniffiCallbackHandlerLoginsEncryptorDecryptor = new UniFFICallbackHandler( + "EncryptorDecryptor", + 2, + [ + new UniFFICallbackMethodHandler( + "decrypt", + [ + FfiConverterBytes, + ], + FfiConverterBytes.lower.bind(FfiConverterBytes), + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + new UniFFICallbackMethodHandler( + "encrypt", + [ + FfiConverterBytes, + ], + FfiConverterBytes.lower.bind(FfiConverterBytes), + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + ] +); + +// Allow the shutdown-related functionality to be tested in the unit tests +UnitTestObjs.uniffiCallbackHandlerLoginsEncryptorDecryptor = uniffiCallbackHandlerLoginsEncryptorDecryptor; + +/** + * KeyManager + */ +export class KeyManager { + /** + * getKey + * @returns {string} + */ + getKey() { + throw Error("getKey not implemented"); + } + +} + +/** + * KeyManager + */ +export class KeyManagerImpl extends KeyManager { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + + /** + * getKey + * @returns {string} + */ + getKey() { + + const result = UniFFIScaffolding.callSync( + 17, // uniffi_logins_fn_method_keymanager_get_key + FfiConverterTypeKeyManager.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterBytes.lift.bind(FfiConverterBytes), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + +} + +// FfiConverter for a trait interface. This is a hybrid of the FFIConverter regular interfaces and +// for callback interfaces. +// +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeKeyManager extends FfiConverter { + // lift works like a regular interface + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new KeyManagerImpl(opts); + } + + // lower treats value like a callback interface + static lower(value) { + if (!(value instanceof KeyManager)) { + throw new UniFFITypeError("expected 'KeyManager' subclass"); + } + return uniffiCallbackHandlerLoginsKeyManager.storeCallbackObj(value) + } + + // lowerReceiver is used when calling methods on an interface we got from Rust, + // it treats value like a regular interface. + static lowerReceiver(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'KeyManagerImpl' instance"); + } + return ptr; + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(4)); + } + + static write(dataStream, value) { + dataStream.writePointer(4, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + +const uniffiCallbackHandlerLoginsKeyManager = new UniFFICallbackHandler( + "KeyManager", + 3, + [ + new UniFFICallbackMethodHandler( + "getKey", + [ + ], + FfiConverterBytes.lower.bind(FfiConverterBytes), + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + ] +); + +// Allow the shutdown-related functionality to be tested in the unit tests +UnitTestObjs.uniffiCallbackHandlerLoginsKeyManager = uniffiCallbackHandlerLoginsKeyManager; +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeLoginEntry extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeLoginEntry.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeLoginEntry.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeLoginEntry.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeLoginEntry.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeBulkResultEntry extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeBulkResultEntry.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeBulkResultEntry.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeBulkResultEntry.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeBulkResultEntry.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeLoginEntryWithMeta extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeLoginEntryWithMeta.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeLoginEntryWithMeta.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeLoginEntryWithMeta.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeLoginEntryWithMeta.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + + +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceString extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterString.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterString.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterString.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterString.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceBoolean extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterBoolean.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterBoolean.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterBoolean.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterBoolean.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} +// Export the FFIConverter object to make external types work. +export class FfiConverterOptionalTypeLogin extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterTypeLogin.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterTypeLogin.read(dataStream) + default: + throw new UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterTypeLogin.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterTypeLogin.computeSize(value) + } +} +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeLogin extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeLogin.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeLogin.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeLogin.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeLogin.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + +/** + * LoginStoreInterface + */ +export class LoginStoreInterface { + /** + * add + * @param {LoginEntry} login + * @returns {Login} + */ + add( + login) { + throw Error("add not implemented"); + } + /** + * addMany + * @param {Array.<LoginEntry>} logins + * @returns {Array.<BulkResultEntry>} + */ + addMany( + logins) { + throw Error("addMany not implemented"); + } + /** + * addManyWithMeta + * @param {Array.<LoginEntryWithMeta>} entriesWithMeta + * @returns {Array.<BulkResultEntry>} + */ + addManyWithMeta( + entriesWithMeta) { + throw Error("addManyWithMeta not implemented"); + } + /** + * addOrUpdate + * @param {LoginEntry} login + * @returns {Login} + */ + addOrUpdate( + login) { + throw Error("addOrUpdate not implemented"); + } + /** + * addWithMeta + * @param {LoginEntryWithMeta} entryWithMeta + * @returns {Login} + */ + addWithMeta( + entryWithMeta) { + throw Error("addWithMeta not implemented"); + } + /** + * count + * @returns {number} + */ + count() { + throw Error("count not implemented"); + } + /** + * countByFormActionOrigin + * @param {string} formActionOrigin + * @returns {number} + */ + countByFormActionOrigin( + formActionOrigin) { + throw Error("countByFormActionOrigin not implemented"); + } + /** + * countByOrigin + * @param {string} origin + * @returns {number} + */ + countByOrigin( + origin) { + throw Error("countByOrigin not implemented"); + } + /** + * delete + * @param {string} id + * @returns {boolean} + */ + delete( + id) { + throw Error("delete not implemented"); + } + /** + * deleteMany + * @param {Array.<string>} ids + * @returns {Array.<boolean>} + */ + deleteMany( + ids) { + throw Error("deleteMany not implemented"); + } + /** + * The `delete_undecryptable_records_for_remote_replacement` function locally deletes stored logins + * that cannot be decrypted and sets the last sync time to 0 so any existing server records can be downloaded + * and overwrite the locally deleted records. + * + * NB: This function was created to unblock iOS logins users who are unable to sync logins and should not be used + * outside of this use case. + * @returns {LoginsDeletionMetrics} + */ + deleteUndecryptableRecordsForRemoteReplacement() { + throw Error("deleteUndecryptableRecordsForRemoteReplacement not implemented"); + } + /** + * findLoginToUpdate + * @param {LoginEntry} look + * @returns {?Login} + */ + findLoginToUpdate( + look) { + throw Error("findLoginToUpdate not implemented"); + } + /** + * get + * @param {string} id + * @returns {?Login} + */ + get( + id) { + throw Error("get not implemented"); + } + /** + * getByBaseDomain + * @param {string} baseDomain + * @returns {Array.<Login>} + */ + getByBaseDomain( + baseDomain) { + throw Error("getByBaseDomain not implemented"); + } + /** + * getCheckpoint + * @returns {?string} + */ + getCheckpoint() { + throw Error("getCheckpoint not implemented"); + } + /** + * hasLoginsByBaseDomain + * @param {string} baseDomain + * @returns {boolean} + */ + hasLoginsByBaseDomain( + baseDomain) { + throw Error("hasLoginsByBaseDomain not implemented"); + } + /** + * isEmpty + * @returns {boolean} + */ + isEmpty() { + throw Error("isEmpty not implemented"); + } + /** + * list + * @returns {Array.<Login>} + */ + list() { + throw Error("list not implemented"); + } + /** + * registerWithSyncManager + */ + registerWithSyncManager() { + throw Error("registerWithSyncManager not implemented"); + } + /** + * reset + */ + reset() { + throw Error("reset not implemented"); + } + /** + * Run maintenance on the DB + * + * This is intended to be run during idle time and will take steps / to clean up / shrink the + * database. + */ + async runMaintenance() { + throw Error("runMaintenance not implemented"); + } + /** + * setCheckpoint + * @param {string} checkpoint + */ + setCheckpoint( + checkpoint) { + throw Error("setCheckpoint not implemented"); + } + /** + * shutdown + */ + shutdown() { + throw Error("shutdown not implemented"); + } + /** + * touch + * @param {string} id + */ + touch( + id) { + throw Error("touch not implemented"); + } + /** + * update + * @param {string} id + * @param {LoginEntry} login + * @returns {Login} + */ + update( + id, + login) { + throw Error("update not implemented"); + } + /** + * Clear out locally stored logins data + * + * If sync is enabled, then we will try to recover the data on the next sync. + * + * The main reason to call this is when regenerating a new encryption key. + * In that case, there's no reason to keep around the local data since it can't be decrypted. + * Calling `wipe_local` is better than keeping around these un-decryptable logins, since we + * might be able to recover the data via sync. + * + * This is a no-op for freshly created databases, so it's safe to call this whenever a key is + * generated. + */ + wipeLocal() { + throw Error("wipeLocal not implemented"); + } + +} + +/** + * LoginStore + */ +export class LoginStore extends LoginStoreInterface { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + /** + * init + * @param {string} path + * @param {EncryptorDecryptor} encdec + * @returns {LoginStore} + */ + static init( + path, + encdec) { + + FfiConverterString.checkType(path); + FfiConverterTypeEncryptorDecryptor.checkType(encdec); + const result = UniFFIScaffolding.callSync( + 18, // uniffi_logins_fn_constructor_loginstore_new + FfiConverterString.lower(path), + FfiConverterTypeEncryptorDecryptor.lower(encdec), + ) + return handleRustResult( + result, + FfiConverterTypeLoginStore.lift.bind(FfiConverterTypeLoginStore), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * add + * @param {LoginEntry} login + * @returns {Login} + */ + add( + login) { + + FfiConverterTypeLoginEntry.checkType(login); + const result = UniFFIScaffolding.callSync( + 19, // uniffi_logins_fn_method_loginstore_add + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterTypeLoginEntry.lower(login), + ) + return handleRustResult( + result, + FfiConverterTypeLogin.lift.bind(FfiConverterTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * addMany + * @param {Array.<LoginEntry>} logins + * @returns {Array.<BulkResultEntry>} + */ + addMany( + logins) { + + FfiConverterSequenceTypeLoginEntry.checkType(logins); + const result = UniFFIScaffolding.callSync( + 20, // uniffi_logins_fn_method_loginstore_add_many + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterSequenceTypeLoginEntry.lower(logins), + ) + return handleRustResult( + result, + FfiConverterSequenceTypeBulkResultEntry.lift.bind(FfiConverterSequenceTypeBulkResultEntry), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * addManyWithMeta + * @param {Array.<LoginEntryWithMeta>} entriesWithMeta + * @returns {Array.<BulkResultEntry>} + */ + addManyWithMeta( + entriesWithMeta) { + + FfiConverterSequenceTypeLoginEntryWithMeta.checkType(entriesWithMeta); + const result = UniFFIScaffolding.callSync( + 21, // uniffi_logins_fn_method_loginstore_add_many_with_meta + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterSequenceTypeLoginEntryWithMeta.lower(entriesWithMeta), + ) + return handleRustResult( + result, + FfiConverterSequenceTypeBulkResultEntry.lift.bind(FfiConverterSequenceTypeBulkResultEntry), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * addOrUpdate + * @param {LoginEntry} login + * @returns {Login} + */ + addOrUpdate( + login) { + + FfiConverterTypeLoginEntry.checkType(login); + const result = UniFFIScaffolding.callSync( + 22, // uniffi_logins_fn_method_loginstore_add_or_update + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterTypeLoginEntry.lower(login), + ) + return handleRustResult( + result, + FfiConverterTypeLogin.lift.bind(FfiConverterTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * addWithMeta + * @param {LoginEntryWithMeta} entryWithMeta + * @returns {Login} + */ + addWithMeta( + entryWithMeta) { + + FfiConverterTypeLoginEntryWithMeta.checkType(entryWithMeta); + const result = UniFFIScaffolding.callSync( + 23, // uniffi_logins_fn_method_loginstore_add_with_meta + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterTypeLoginEntryWithMeta.lower(entryWithMeta), + ) + return handleRustResult( + result, + FfiConverterTypeLogin.lift.bind(FfiConverterTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * count + * @returns {number} + */ + count() { + + const result = UniFFIScaffolding.callSync( + 24, // uniffi_logins_fn_method_loginstore_count + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterInt64.lift.bind(FfiConverterInt64), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * countByFormActionOrigin + * @param {string} formActionOrigin + * @returns {number} + */ + countByFormActionOrigin( + formActionOrigin) { + + FfiConverterString.checkType(formActionOrigin); + const result = UniFFIScaffolding.callSync( + 25, // uniffi_logins_fn_method_loginstore_count_by_form_action_origin + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(formActionOrigin), + ) + return handleRustResult( + result, + FfiConverterInt64.lift.bind(FfiConverterInt64), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * countByOrigin + * @param {string} origin + * @returns {number} + */ + countByOrigin( + origin) { + + FfiConverterString.checkType(origin); + const result = UniFFIScaffolding.callSync( + 26, // uniffi_logins_fn_method_loginstore_count_by_origin + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(origin), + ) + return handleRustResult( + result, + FfiConverterInt64.lift.bind(FfiConverterInt64), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * delete + * @param {string} id + * @returns {boolean} + */ + delete( + id) { + + FfiConverterString.checkType(id); + const result = UniFFIScaffolding.callSync( + 27, // uniffi_logins_fn_method_loginstore_delete + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(id), + ) + return handleRustResult( + result, + FfiConverterBoolean.lift.bind(FfiConverterBoolean), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * deleteMany + * @param {Array.<string>} ids + * @returns {Array.<boolean>} + */ + deleteMany( + ids) { + + FfiConverterSequenceString.checkType(ids); + const result = UniFFIScaffolding.callSync( + 28, // uniffi_logins_fn_method_loginstore_delete_many + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterSequenceString.lower(ids), + ) + return handleRustResult( + result, + FfiConverterSequenceBoolean.lift.bind(FfiConverterSequenceBoolean), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * The `delete_undecryptable_records_for_remote_replacement` function locally deletes stored logins + * that cannot be decrypted and sets the last sync time to 0 so any existing server records can be downloaded + * and overwrite the locally deleted records. + * + * NB: This function was created to unblock iOS logins users who are unable to sync logins and should not be used + * outside of this use case. + * @returns {LoginsDeletionMetrics} + */ + deleteUndecryptableRecordsForRemoteReplacement() { + + const result = UniFFIScaffolding.callSync( + 29, // uniffi_logins_fn_method_loginstore_delete_undecryptable_records_for_remote_replacement + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterTypeLoginsDeletionMetrics.lift.bind(FfiConverterTypeLoginsDeletionMetrics), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * findLoginToUpdate + * @param {LoginEntry} look + * @returns {?Login} + */ + findLoginToUpdate( + look) { + + FfiConverterTypeLoginEntry.checkType(look); + const result = UniFFIScaffolding.callSync( + 30, // uniffi_logins_fn_method_loginstore_find_login_to_update + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterTypeLoginEntry.lower(look), + ) + return handleRustResult( + result, + FfiConverterOptionalTypeLogin.lift.bind(FfiConverterOptionalTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * get + * @param {string} id + * @returns {?Login} + */ + get( + id) { + + FfiConverterString.checkType(id); + const result = UniFFIScaffolding.callSync( + 31, // uniffi_logins_fn_method_loginstore_get + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(id), + ) + return handleRustResult( + result, + FfiConverterOptionalTypeLogin.lift.bind(FfiConverterOptionalTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * getByBaseDomain + * @param {string} baseDomain + * @returns {Array.<Login>} + */ + getByBaseDomain( + baseDomain) { + + FfiConverterString.checkType(baseDomain); + const result = UniFFIScaffolding.callSync( + 32, // uniffi_logins_fn_method_loginstore_get_by_base_domain + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(baseDomain), + ) + return handleRustResult( + result, + FfiConverterSequenceTypeLogin.lift.bind(FfiConverterSequenceTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * getCheckpoint + * @returns {?string} + */ + getCheckpoint() { + + const result = UniFFIScaffolding.callSync( + 33, // uniffi_logins_fn_method_loginstore_get_checkpoint + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterOptionalString.lift.bind(FfiConverterOptionalString), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * hasLoginsByBaseDomain + * @param {string} baseDomain + * @returns {boolean} + */ + hasLoginsByBaseDomain( + baseDomain) { + + FfiConverterString.checkType(baseDomain); + const result = UniFFIScaffolding.callSync( + 34, // uniffi_logins_fn_method_loginstore_has_logins_by_base_domain + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(baseDomain), + ) + return handleRustResult( + result, + FfiConverterBoolean.lift.bind(FfiConverterBoolean), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * isEmpty + * @returns {boolean} + */ + isEmpty() { + + const result = UniFFIScaffolding.callSync( + 35, // uniffi_logins_fn_method_loginstore_is_empty + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterBoolean.lift.bind(FfiConverterBoolean), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * list + * @returns {Array.<Login>} + */ + list() { + + const result = UniFFIScaffolding.callSync( + 36, // uniffi_logins_fn_method_loginstore_list + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterSequenceTypeLogin.lift.bind(FfiConverterSequenceTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * registerWithSyncManager + */ + registerWithSyncManager() { + + const result = UniFFIScaffolding.callSync( + 37, // uniffi_logins_fn_method_loginstore_register_with_sync_manager + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + null, + ) + } + + /** + * reset + */ + reset() { + + const result = UniFFIScaffolding.callSync( + 38, // uniffi_logins_fn_method_loginstore_reset + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * Run maintenance on the DB + * + * This is intended to be run during idle time and will take steps / to clean up / shrink the + * database. + */ + async runMaintenance() { + + const result = await UniFFIScaffolding.callAsyncWrapper( + 39, // uniffi_logins_fn_method_loginstore_run_maintenance + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * setCheckpoint + * @param {string} checkpoint + */ + setCheckpoint( + checkpoint) { + + FfiConverterString.checkType(checkpoint); + const result = UniFFIScaffolding.callSync( + 40, // uniffi_logins_fn_method_loginstore_set_checkpoint + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(checkpoint), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * shutdown + */ + shutdown() { + + const result = UniFFIScaffolding.callSync( + 41, // uniffi_logins_fn_method_loginstore_shutdown + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + null, + ) + } + + /** + * touch + * @param {string} id + */ + touch( + id) { + + FfiConverterString.checkType(id); + const result = UniFFIScaffolding.callSync( + 42, // uniffi_logins_fn_method_loginstore_touch + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(id), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * update + * @param {string} id + * @param {LoginEntry} login + * @returns {Login} + */ + update( + id, + login) { + + FfiConverterString.checkType(id); + FfiConverterTypeLoginEntry.checkType(login); + const result = UniFFIScaffolding.callSync( + 43, // uniffi_logins_fn_method_loginstore_update + FfiConverterTypeLoginStore.lowerReceiver(this), + FfiConverterString.lower(id), + FfiConverterTypeLoginEntry.lower(login), + ) + return handleRustResult( + result, + FfiConverterTypeLogin.lift.bind(FfiConverterTypeLogin), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * Clear out locally stored logins data + * + * If sync is enabled, then we will try to recover the data on the next sync. + * + * The main reason to call this is when regenerating a new encryption key. + * In that case, there's no reason to keep around the local data since it can't be decrypted. + * Calling `wipe_local` is better than keeping around these un-decryptable logins, since we + * might be able to recover the data via sync. + * + * This is a no-op for freshly created databases, so it's safe to call this whenever a key is + * generated. + */ + wipeLocal() { + + const result = UniFFIScaffolding.callSync( + 44, // uniffi_logins_fn_method_loginstore_wipe_local + FfiConverterTypeLoginStore.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeLoginStore extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new LoginStore(opts); + } + + static lower(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'LoginStore' instance"); + } + return ptr; + } + + static lowerReceiver(value) { + // This works exactly the same as lower for non-trait interfaces + return this.lower(value); + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(5)); + } + + static write(dataStream, value) { + dataStream.writePointer(5, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + + +/** + * ManagedEncryptorDecryptorInterface + */ +export class ManagedEncryptorDecryptorInterface { + +} + +/** + * ManagedEncryptorDecryptor + */ +export class ManagedEncryptorDecryptor extends ManagedEncryptorDecryptorInterface { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + /** + * init + * @param {KeyManager} keyManager + * @returns {ManagedEncryptorDecryptor} + */ + static init( + keyManager) { + + FfiConverterTypeKeyManager.checkType(keyManager); + const result = UniFFIScaffolding.callSync( + 45, // uniffi_logins_fn_constructor_managedencryptordecryptor_new + FfiConverterTypeKeyManager.lower(keyManager), + ) + return handleRustResult( + result, + FfiConverterTypeManagedEncryptorDecryptor.lift.bind(FfiConverterTypeManagedEncryptorDecryptor), + null, + ) + } + +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeManagedEncryptorDecryptor extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new ManagedEncryptorDecryptor(opts); + } + + static lower(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'ManagedEncryptorDecryptor' instance"); + } + return ptr; + } + + static lowerReceiver(value) { + // This works exactly the same as lower for non-trait interfaces + return this.lower(value); + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(6)); + } + + static write(dataStream, value) { + dataStream.writePointer(6, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + + +/** + * Use the `NSSKeyManager` to use NSS for key management. + * + * NSS stores keys in `key4.db` within the profile and wraps the key with a key derived from the + * primary password, if set. It defers to the provided `PrimaryPasswordAuthenticator` + * implementation to handle user authentication. Note that if no primary password is set, the + * wrapping key is deterministically derived from an empty string. + * + * Make sure to initialize NSS using `ensure_initialized_with_profile_dir` before creating a + * NSSKeyManager. + * + * # Examples + * ```no_run + * use async_trait::async_trait; + * use logins::encryption::KeyManager; + * use logins::{PrimaryPasswordAuthenticator, LoginsApiError, NSSKeyManager}; + * use std::sync::Arc; + * + * struct MyPrimaryPasswordAuthenticator {} + * + * #[async_trait] + * impl PrimaryPasswordAuthenticator for MyPrimaryPasswordAuthenticator { + * async fn get_primary_password(&self) -> Result<String, LoginsApiError> { + * // Most likely, you would want to prompt for a password. + * // let password = prompt_string("primary password").unwrap_or_default(); + * Ok("secret".to_string()) + * } + * + * async fn on_authentication_success(&self) -> Result<(), LoginsApiError> { + * println!("success"); + * Ok(()) + * } + * + * async fn on_authentication_failure(&self) -> Result<(), LoginsApiError> { + * println!("this did not work, please try again:"); + * Ok(()) + * } + * } + * let key_manager = NSSKeyManager::new(Arc::new(MyPrimaryPasswordAuthenticator {})); + * assert_eq!(key_manager.get_key().unwrap().len(), 63); + * ``` + */ +export class NssKeyManagerInterface { + /** + * intoDynKeyManager + * @returns {KeyManager} + */ + intoDynKeyManager() { + throw Error("intoDynKeyManager not implemented"); + } + +} + +/** + * Use the `NSSKeyManager` to use NSS for key management. + * + * NSS stores keys in `key4.db` within the profile and wraps the key with a key derived from the + * primary password, if set. It defers to the provided `PrimaryPasswordAuthenticator` + * implementation to handle user authentication. Note that if no primary password is set, the + * wrapping key is deterministically derived from an empty string. + * + * Make sure to initialize NSS using `ensure_initialized_with_profile_dir` before creating a + * NSSKeyManager. + * + * # Examples + * ```no_run + * use async_trait::async_trait; + * use logins::encryption::KeyManager; + * use logins::{PrimaryPasswordAuthenticator, LoginsApiError, NSSKeyManager}; + * use std::sync::Arc; + * + * struct MyPrimaryPasswordAuthenticator {} + * + * #[async_trait] + * impl PrimaryPasswordAuthenticator for MyPrimaryPasswordAuthenticator { + * async fn get_primary_password(&self) -> Result<String, LoginsApiError> { + * // Most likely, you would want to prompt for a password. + * // let password = prompt_string("primary password").unwrap_or_default(); + * Ok("secret".to_string()) + * } + * + * async fn on_authentication_success(&self) -> Result<(), LoginsApiError> { + * println!("success"); + * Ok(()) + * } + * + * async fn on_authentication_failure(&self) -> Result<(), LoginsApiError> { + * println!("this did not work, please try again:"); + * Ok(()) + * } + * } + * let key_manager = NSSKeyManager::new(Arc::new(MyPrimaryPasswordAuthenticator {})); + * assert_eq!(key_manager.get_key().unwrap().len(), 63); + * ``` + */ +export class NssKeyManager extends NssKeyManagerInterface { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + /** + * Initialize new `NSSKeyManager` with a given `PrimaryPasswordAuthenticator`. + * There must be a previous initializiation of NSS before initializing + * `NSSKeyManager`, otherwise this panics. + * @param {PrimaryPasswordAuthenticator} primaryPasswordAuthenticator + * @returns {NssKeyManager} + */ + static init( + primaryPasswordAuthenticator) { + + FfiConverterTypePrimaryPasswordAuthenticator.checkType(primaryPasswordAuthenticator); + const result = UniFFIScaffolding.callSync( + 46, // uniffi_logins_fn_constructor_nsskeymanager_new + FfiConverterTypePrimaryPasswordAuthenticator.lower(primaryPasswordAuthenticator), + ) + return handleRustResult( + result, + FfiConverterTypeNSSKeyManager.lift.bind(FfiConverterTypeNSSKeyManager), + null, + ) + } + + /** + * intoDynKeyManager + * @returns {KeyManager} + */ + intoDynKeyManager() { + + const result = UniFFIScaffolding.callSync( + 47, // uniffi_logins_fn_method_nsskeymanager_into_dyn_key_manager + FfiConverterTypeNSSKeyManager.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterTypeKeyManager.lift.bind(FfiConverterTypeKeyManager), + null, + ) + } + +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeNSSKeyManager extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new NssKeyManager(opts); + } + + static lower(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'NssKeyManager' instance"); + } + return ptr; + } + + static lowerReceiver(value) { + // This works exactly the same as lower for non-trait interfaces + return this.lower(value); + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(7)); + } + + static write(dataStream, value) { + dataStream.writePointer(7, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + + +/** + * `PrimaryPasswordAuthenticator` is used in conjunction with `NSSKeyManager` to provide the + * primary password and the success or failure actions of the authentication process. + */ +export class PrimaryPasswordAuthenticator { + /** + * Get a primary password for authentication, otherwise return the + * AuthenticationCancelled error to cancel the authentication process. + * @returns {Promise<string>}} + */ + async getPrimaryPassword() { + throw Error("getPrimaryPassword not implemented"); + } + /** + * onAuthenticationSuccess + */ + async onAuthenticationSuccess() { + throw Error("onAuthenticationSuccess not implemented"); + } + /** + * onAuthenticationFailure + */ + async onAuthenticationFailure() { + throw Error("onAuthenticationFailure not implemented"); + } + +} + +/** + * `PrimaryPasswordAuthenticator` is used in conjunction with `NSSKeyManager` to provide the + * primary password and the success or failure actions of the authentication process. + */ +export class PrimaryPasswordAuthenticatorImpl extends PrimaryPasswordAuthenticator { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + + /** + * Get a primary password for authentication, otherwise return the + * AuthenticationCancelled error to cancel the authentication process. + * @returns {Promise<string>}} + */ + async getPrimaryPassword() { + + const result = await UniFFIScaffolding.callAsync( + 48, // uniffi_logins_fn_method_primarypasswordauthenticator_get_primary_password + FfiConverterTypePrimaryPasswordAuthenticator.lowerReceiver(this), + ) + return handleRustResult( + result, + FfiConverterString.lift.bind(FfiConverterString), + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * onAuthenticationSuccess + */ + async onAuthenticationSuccess() { + + const result = await UniFFIScaffolding.callAsync( + 49, // uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_success + FfiConverterTypePrimaryPasswordAuthenticator.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + + /** + * onAuthenticationFailure + */ + async onAuthenticationFailure() { + + const result = await UniFFIScaffolding.callAsync( + 50, // uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_failure + FfiConverterTypePrimaryPasswordAuthenticator.lowerReceiver(this), + ) + return handleRustResult( + result, + (result) => undefined, + FfiConverterTypeLoginsApiError.lift.bind(FfiConverterTypeLoginsApiError), + ) + } + +} + +// FfiConverter for a trait interface. This is a hybrid of the FFIConverter regular interfaces and +// for callback interfaces. +// +// Export the FFIConverter object to make external types work. +export class FfiConverterTypePrimaryPasswordAuthenticator extends FfiConverter { + // lift works like a regular interface + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new PrimaryPasswordAuthenticatorImpl(opts); + } + + // lower treats value like a callback interface + static lower(value) { + if (!(value instanceof PrimaryPasswordAuthenticator)) { + throw new UniFFITypeError("expected 'PrimaryPasswordAuthenticator' subclass"); + } + return uniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator.storeCallbackObj(value) + } + + // lowerReceiver is used when calling methods on an interface we got from Rust, + // it treats value like a regular interface. + static lowerReceiver(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'PrimaryPasswordAuthenticatorImpl' instance"); + } + return ptr; + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(8)); + } + + static write(dataStream, value) { + dataStream.writePointer(8, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + +const uniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator = new UniFFICallbackHandler( + "PrimaryPasswordAuthenticator", + 4, + [ + new UniFFICallbackMethodHandler( + "getPrimaryPassword", + [ + ], + FfiConverterString.lower.bind(FfiConverterString), + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + new UniFFICallbackMethodHandler( + "onAuthenticationSuccess", + [ + ], + (result) => undefined, + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + new UniFFICallbackMethodHandler( + "onAuthenticationFailure", + [ + ], + (result) => undefined, + (e) => { + if (e instanceof LoginsApiError) { + return FfiConverterTypeLoginsApiError.lower(e); + } + throw e; + } + ), + ] +); + +// Allow the shutdown-related functionality to be tested in the unit tests +UnitTestObjs.uniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator = uniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator; + +/** + * StaticKeyManagerInterface + */ +export class StaticKeyManagerInterface { + +} + +/** + * StaticKeyManager + */ +export class StaticKeyManager extends StaticKeyManagerInterface { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + super(); + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + /** + * init + * @param {string} key + * @returns {StaticKeyManager} + */ + static init( + key) { + + FfiConverterString.checkType(key); + const result = UniFFIScaffolding.callSync( + 51, // uniffi_logins_fn_constructor_statickeymanager_new + FfiConverterString.lower(key), + ) + return handleRustResult( + result, + FfiConverterTypeStaticKeyManager.lift.bind(FfiConverterTypeStaticKeyManager), + null, + ) + } + +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeStaticKeyManager extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new StaticKeyManager(opts); + } + + static lower(value) { + const ptr = value[uniffiObjectPtr]; + if (!(ptr instanceof UniFFIPointer)) { + throw new UniFFITypeError("Object is not a 'StaticKeyManager' instance"); + } + return ptr; + } + + static lowerReceiver(value) { + // This works exactly the same as lower for non-trait interfaces + return this.lower(value); + } + + static read(dataStream) { + return this.lift(dataStream.readPointer(9)); + } + + static write(dataStream, value) { + dataStream.writePointer(9, this.lower(value)); + } + + static computeSize(value) { + return 8; + } +} + + + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs @@ -56,7 +56,7 @@ export function score( FfiConverterTypeInterestVector.checkType(interestVector); FfiConverterSequenceTypeInterest.checkType(contentCategories); const result = UniFFIScaffolding.callSync( - 7, // uniffi_relevancy_fn_func_score + 52, // uniffi_relevancy_fn_func_score FfiConverterTypeInterestVector.lower(interestVector), FfiConverterSequenceTypeInterest.lower(contentCategories), ) @@ -1414,7 +1414,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterString.checkType(dbPath); FfiConverterTypeRemoteSettingsService.checkType(remoteSettings); const result = UniFFIScaffolding.callSync( - 8, // uniffi_relevancy_fn_constructor_relevancystore_new + 53, // uniffi_relevancy_fn_constructor_relevancystore_new FfiConverterString.lower(dbPath), FfiConverterTypeRemoteSettingsService.lower(remoteSettings), ) @@ -1442,7 +1442,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterString.checkType(bandit); FfiConverterSequenceString.checkType(arms); const result = await UniFFIScaffolding.callAsyncWrapper( - 9, // uniffi_relevancy_fn_method_relevancystore_bandit_init + 54, // uniffi_relevancy_fn_method_relevancystore_bandit_init FfiConverterTypeRelevancyStore.lowerReceiver(this), FfiConverterString.lower(bandit), FfiConverterSequenceString.lower(arms), @@ -1473,7 +1473,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterString.checkType(bandit); FfiConverterSequenceString.checkType(arms); const result = await UniFFIScaffolding.callAsyncWrapper( - 10, // uniffi_relevancy_fn_method_relevancystore_bandit_select + 55, // uniffi_relevancy_fn_method_relevancystore_bandit_select FfiConverterTypeRelevancyStore.lowerReceiver(this), FfiConverterString.lower(bandit), FfiConverterSequenceString.lower(arms), @@ -1506,7 +1506,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterString.checkType(arm); FfiConverterBoolean.checkType(selected); const result = await UniFFIScaffolding.callAsyncWrapper( - 11, // uniffi_relevancy_fn_method_relevancystore_bandit_update + 56, // uniffi_relevancy_fn_method_relevancystore_bandit_update FfiConverterTypeRelevancyStore.lowerReceiver(this), FfiConverterString.lower(bandit), FfiConverterString.lower(arm), @@ -1527,7 +1527,7 @@ export class RelevancyStore extends RelevancyStoreInterface { close() { const result = UniFFIScaffolding.callSync( - 12, // uniffi_relevancy_fn_method_relevancystore_close + 57, // uniffi_relevancy_fn_method_relevancystore_close FfiConverterTypeRelevancyStore.lowerReceiver(this), ) return handleRustResult( @@ -1543,7 +1543,7 @@ export class RelevancyStore extends RelevancyStoreInterface { async ensureInterestDataPopulated() { const result = await UniFFIScaffolding.callAsyncWrapper( - 13, // uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated + 58, // uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated FfiConverterTypeRelevancyStore.lowerReceiver(this), ) return handleRustResult( @@ -1566,7 +1566,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterString.checkType(bandit); FfiConverterString.checkType(arm); const result = await UniFFIScaffolding.callAsyncWrapper( - 14, // uniffi_relevancy_fn_method_relevancystore_get_bandit_data + 59, // uniffi_relevancy_fn_method_relevancystore_get_bandit_data FfiConverterTypeRelevancyStore.lowerReceiver(this), FfiConverterString.lower(bandit), FfiConverterString.lower(arm), @@ -1598,7 +1598,7 @@ export class RelevancyStore extends RelevancyStoreInterface { FfiConverterSequenceString.checkType(topUrlsByFrecency); const result = await UniFFIScaffolding.callAsyncWrapper( - 15, // uniffi_relevancy_fn_method_relevancystore_ingest + 60, // uniffi_relevancy_fn_method_relevancystore_ingest FfiConverterTypeRelevancyStore.lowerReceiver(this), FfiConverterSequenceString.lower(topUrlsByFrecency), ) @@ -1615,7 +1615,7 @@ export class RelevancyStore extends RelevancyStoreInterface { interrupt() { const result = UniFFIScaffolding.callSync( - 16, // uniffi_relevancy_fn_method_relevancystore_interrupt + 61, // uniffi_relevancy_fn_method_relevancystore_interrupt FfiConverterTypeRelevancyStore.lowerReceiver(this), ) return handleRustResult( @@ -1635,7 +1635,7 @@ export class RelevancyStore extends RelevancyStoreInterface { async userInterestVector() { const result = await UniFFIScaffolding.callAsyncWrapper( - 17, // uniffi_relevancy_fn_method_relevancystore_user_interest_vector + 62, // uniffi_relevancy_fn_method_relevancystore_user_interest_vector FfiConverterTypeRelevancyStore.lowerReceiver(this), ) return handleRustResult( @@ -1669,11 +1669,11 @@ export class FfiConverterTypeRelevancyStore extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(3)); + return this.lift(dataStream.readPointer(10)); } static write(dataStream, value) { - dataStream.writePointer(3, this.lower(value)); + dataStream.writePointer(10, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs @@ -1623,7 +1623,7 @@ export class RemoteSettings extends RemoteSettingsInterface { FfiConverterTypeRemoteSettingsConfig.checkType(remoteSettingsConfig); const result = UniFFIScaffolding.callSync( - 18, // uniffi_remote_settings_fn_constructor_remotesettings_new + 63, // uniffi_remote_settings_fn_constructor_remotesettings_new FfiConverterTypeRemoteSettingsConfig.lower(remoteSettingsConfig), ) return handleRustResult( @@ -1645,7 +1645,7 @@ export class RemoteSettings extends RemoteSettingsInterface { FfiConverterString.checkType(attachmentId); FfiConverterString.checkType(path); const result = await UniFFIScaffolding.callAsyncWrapper( - 19, // uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path + 64, // uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path FfiConverterTypeRemoteSettings.lowerReceiver(this), FfiConverterString.lower(attachmentId), FfiConverterString.lower(path), @@ -1664,7 +1664,7 @@ export class RemoteSettings extends RemoteSettingsInterface { async getRecords() { const result = await UniFFIScaffolding.callAsyncWrapper( - 20, // uniffi_remote_settings_fn_method_remotesettings_get_records + 65, // uniffi_remote_settings_fn_method_remotesettings_get_records FfiConverterTypeRemoteSettings.lowerReceiver(this), ) return handleRustResult( @@ -1685,7 +1685,7 @@ export class RemoteSettings extends RemoteSettingsInterface { FfiConverterUInt64.checkType(timestamp); const result = await UniFFIScaffolding.callAsyncWrapper( - 21, // uniffi_remote_settings_fn_method_remotesettings_get_records_since + 66, // uniffi_remote_settings_fn_method_remotesettings_get_records_since FfiConverterTypeRemoteSettings.lowerReceiver(this), FfiConverterUInt64.lower(timestamp), ) @@ -1720,11 +1720,11 @@ export class FfiConverterTypeRemoteSettings extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(4)); + return this.lift(dataStream.readPointer(11)); } static write(dataStream, value) { - dataStream.writePointer(4, this.lower(value)); + dataStream.writePointer(11, this.lower(value)); } static computeSize(value) { @@ -1969,7 +1969,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { async collectionName() { const result = await UniFFIScaffolding.callAsyncWrapper( - 22, // uniffi_remote_settings_fn_method_remotesettingsclient_collection_name + 67, // uniffi_remote_settings_fn_method_remotesettingsclient_collection_name FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), ) return handleRustResult( @@ -1997,7 +1997,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { FfiConverterTypeRemoteSettingsRecord.checkType(record); const result = await UniFFIScaffolding.callAsyncWrapper( - 23, // uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment + 68, // uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), FfiConverterTypeRemoteSettingsRecord.lower(record), ) @@ -2033,7 +2033,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { FfiConverterBoolean.checkType(syncIfEmpty); const result = await UniFFIScaffolding.callAsyncWrapper( - 24, // uniffi_remote_settings_fn_method_remotesettingsclient_get_records + 69, // uniffi_remote_settings_fn_method_remotesettingsclient_get_records FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), FfiConverterBoolean.lower(syncIfEmpty), ) @@ -2057,7 +2057,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { FfiConverterBoolean.checkType(syncIfEmpty); const result = await UniFFIScaffolding.callAsyncWrapper( - 25, // uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map + 70, // uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), FfiConverterBoolean.lower(syncIfEmpty), ) @@ -2074,7 +2074,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { async shutdown() { const result = await UniFFIScaffolding.callAsyncWrapper( - 26, // uniffi_remote_settings_fn_method_remotesettingsclient_shutdown + 71, // uniffi_remote_settings_fn_method_remotesettingsclient_shutdown FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), ) return handleRustResult( @@ -2090,7 +2090,7 @@ export class RemoteSettingsClient extends RemoteSettingsClientInterface { async sync() { const result = await UniFFIScaffolding.callAsyncWrapper( - 27, // uniffi_remote_settings_fn_method_remotesettingsclient_sync + 72, // uniffi_remote_settings_fn_method_remotesettingsclient_sync FfiConverterTypeRemoteSettingsClient.lowerReceiver(this), ) return handleRustResult( @@ -2124,11 +2124,11 @@ export class FfiConverterTypeRemoteSettingsClient extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(5)); + return this.lift(dataStream.readPointer(12)); } static write(dataStream, value) { - dataStream.writePointer(5, this.lower(value)); + dataStream.writePointer(12, this.lower(value)); } static computeSize(value) { @@ -2264,7 +2264,7 @@ export class RemoteSettingsService extends RemoteSettingsServiceInterface { FfiConverterString.checkType(storageDir); FfiConverterTypeRemoteSettingsConfig2.checkType(config); const result = UniFFIScaffolding.callSync( - 28, // uniffi_remote_settings_fn_constructor_remotesettingsservice_new + 73, // uniffi_remote_settings_fn_constructor_remotesettingsservice_new FfiConverterString.lower(storageDir), FfiConverterTypeRemoteSettingsConfig2.lower(config), ) @@ -2287,7 +2287,7 @@ export class RemoteSettingsService extends RemoteSettingsServiceInterface { FfiConverterString.checkType(collectionName); const result = await UniFFIScaffolding.callAsyncWrapper( - 29, // uniffi_remote_settings_fn_method_remotesettingsservice_make_client + 74, // uniffi_remote_settings_fn_method_remotesettingsservice_make_client FfiConverterTypeRemoteSettingsService.lowerReceiver(this), FfiConverterString.lower(collectionName), ) @@ -2305,7 +2305,7 @@ export class RemoteSettingsService extends RemoteSettingsServiceInterface { async sync() { const result = await UniFFIScaffolding.callAsyncWrapper( - 30, // uniffi_remote_settings_fn_method_remotesettingsservice_sync + 75, // uniffi_remote_settings_fn_method_remotesettingsservice_sync FfiConverterTypeRemoteSettingsService.lowerReceiver(this), ) return handleRustResult( @@ -2330,7 +2330,7 @@ export class RemoteSettingsService extends RemoteSettingsServiceInterface { FfiConverterTypeRemoteSettingsConfig2.checkType(config); const result = UniFFIScaffolding.callSync( - 31, // uniffi_remote_settings_fn_method_remotesettingsservice_update_config + 76, // uniffi_remote_settings_fn_method_remotesettingsservice_update_config FfiConverterTypeRemoteSettingsService.lowerReceiver(this), FfiConverterTypeRemoteSettingsConfig2.lower(config), ) @@ -2365,11 +2365,11 @@ export class FfiConverterTypeRemoteSettingsService extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(6)); + return this.lift(dataStream.readPointer(13)); } static write(dataStream, value) { - dataStream.writePointer(6, this.lower(value)); + dataStream.writePointer(13, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs @@ -2782,7 +2782,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { static init() { const result = UniFFIScaffolding.callSync( - 32, // uniffi_search_fn_constructor_searchengineselector_new + 77, // uniffi_search_fn_constructor_searchengineselector_new ) return handleRustResult( result, @@ -2799,7 +2799,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { clearSearchConfig() { const result = UniFFIScaffolding.callSync( - 33, // uniffi_search_fn_method_searchengineselector_clear_search_config + 78, // uniffi_search_fn_method_searchengineselector_clear_search_config FfiConverterTypeSearchEngineSelector.lowerReceiver(this), ) return handleRustResult( @@ -2821,7 +2821,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { FfiConverterTypeSearchUserEnvironment.checkType(userEnvironment); const result = UniFFIScaffolding.callSync( - 34, // uniffi_search_fn_method_searchengineselector_filter_engine_configuration + 79, // uniffi_search_fn_method_searchengineselector_filter_engine_configuration FfiConverterTypeSearchEngineSelector.lowerReceiver(this), FfiConverterTypeSearchUserEnvironment.lower(userEnvironment), ) @@ -2841,7 +2841,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { FfiConverterString.checkType(overrides); const result = UniFFIScaffolding.callSync( - 35, // uniffi_search_fn_method_searchengineselector_set_config_overrides + 80, // uniffi_search_fn_method_searchengineselector_set_config_overrides FfiConverterTypeSearchEngineSelector.lowerReceiver(this), FfiConverterString.lower(overrides), ) @@ -2865,7 +2865,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { FfiConverterString.checkType(configuration); const result = UniFFIScaffolding.callSync( - 36, // uniffi_search_fn_method_searchengineselector_set_search_config + 81, // uniffi_search_fn_method_searchengineselector_set_search_config FfiConverterTypeSearchEngineSelector.lowerReceiver(this), FfiConverterString.lower(configuration), ) @@ -2896,7 +2896,7 @@ export class SearchEngineSelector extends SearchEngineSelectorInterface { FfiConverterTypeRemoteSettingsService.checkType(service); FfiConverterBoolean.checkType(applyEngineOverrides); const result = await UniFFIScaffolding.callAsyncWrapper( - 37, // uniffi_search_fn_method_searchengineselector_use_remote_settings_server + 82, // uniffi_search_fn_method_searchengineselector_use_remote_settings_server FfiConverterTypeSearchEngineSelector.lowerReceiver(this), FfiConverterTypeRemoteSettingsService.lower(service), FfiConverterBoolean.lower(applyEngineOverrides), @@ -2932,11 +2932,11 @@ export class FfiConverterTypeSearchEngineSelector extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(7)); + return this.lift(dataStream.readPointer(14)); } static write(dataStream, value) { - dataStream.writePointer(7, this.lower(value)); + dataStream.writePointer(14, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs @@ -47,7 +47,7 @@ export function rawSuggestionUrlMatches( FfiConverterString.checkType(rawUrl); FfiConverterString.checkType(cookedUrl); const result = UniFFIScaffolding.callSync( - 38, // uniffi_suggest_fn_func_raw_suggestion_url_matches + 83, // uniffi_suggest_fn_func_raw_suggestion_url_matches FfiConverterString.lower(rawUrl), FfiConverterString.lower(cookedUrl), ) @@ -4255,7 +4255,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterString.checkType(path); FfiConverterTypeRemoteSettingsService.checkType(remoteSettingsService); const result = UniFFIScaffolding.callSync( - 39, // uniffi_suggest_fn_constructor_suggeststore_new + 84, // uniffi_suggest_fn_constructor_suggeststore_new FfiConverterString.lower(path), FfiConverterTypeRemoteSettingsService.lower(remoteSettingsService), ) @@ -4273,7 +4273,7 @@ export class SuggestStore extends SuggestStoreInterface { async anyDismissedSuggestions() { const result = await UniFFIScaffolding.callAsyncWrapper( - 40, // uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions + 85, // uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions FfiConverterTypeSuggestStore.lowerReceiver(this), ) return handleRustResult( @@ -4289,7 +4289,7 @@ export class SuggestStore extends SuggestStoreInterface { async clear() { const result = await UniFFIScaffolding.callAsyncWrapper( - 41, // uniffi_suggest_fn_method_suggeststore_clear + 86, // uniffi_suggest_fn_method_suggeststore_clear FfiConverterTypeSuggestStore.lowerReceiver(this), ) return handleRustResult( @@ -4305,7 +4305,7 @@ export class SuggestStore extends SuggestStoreInterface { async clearDismissedSuggestions() { const result = await UniFFIScaffolding.callAsyncWrapper( - 42, // uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions + 87, // uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions FfiConverterTypeSuggestStore.lowerReceiver(this), ) return handleRustResult( @@ -4330,7 +4330,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterString.checkType(key); const result = await UniFFIScaffolding.callAsyncWrapper( - 43, // uniffi_suggest_fn_method_suggeststore_dismiss_by_key + 88, // uniffi_suggest_fn_method_suggeststore_dismiss_by_key FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterString.lower(key), ) @@ -4352,7 +4352,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestion.checkType(suggestion); const result = await UniFFIScaffolding.callAsyncWrapper( - 44, // uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion + 89, // uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestion.lower(suggestion), ) @@ -4377,7 +4377,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterString.checkType(suggestionUrl); const result = await UniFFIScaffolding.callAsyncWrapper( - 45, // uniffi_suggest_fn_method_suggeststore_dismiss_suggestion + 90, // uniffi_suggest_fn_method_suggeststore_dismiss_suggestion FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterString.lower(suggestionUrl), ) @@ -4400,7 +4400,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeGeoname.checkType(geoname); const result = await UniFFIScaffolding.callAsyncWrapper( - 46, // uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates + 91, // uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeGeoname.lower(geoname), ) @@ -4430,7 +4430,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterBoolean.checkType(matchNamePrefix); FfiConverterOptionalSequenceTypeGeoname.checkType(filter); const result = await UniFFIScaffolding.callAsyncWrapper( - 47, // uniffi_suggest_fn_method_suggeststore_fetch_geonames + 92, // uniffi_suggest_fn_method_suggeststore_fetch_geonames FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterString.lower(query), FfiConverterBoolean.lower(matchNamePrefix), @@ -4450,7 +4450,7 @@ export class SuggestStore extends SuggestStoreInterface { async fetchGlobalConfig() { const result = await UniFFIScaffolding.callAsyncWrapper( - 48, // uniffi_suggest_fn_method_suggeststore_fetch_global_config + 93, // uniffi_suggest_fn_method_suggeststore_fetch_global_config FfiConverterTypeSuggestStore.lowerReceiver(this), ) return handleRustResult( @@ -4470,7 +4470,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestionProvider.checkType(provider); const result = await UniFFIScaffolding.callAsyncWrapper( - 49, // uniffi_suggest_fn_method_suggeststore_fetch_provider_config + 94, // uniffi_suggest_fn_method_suggeststore_fetch_provider_config FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestionProvider.lower(provider), ) @@ -4491,7 +4491,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestIngestionConstraints.checkType(constraints); const result = await UniFFIScaffolding.callAsyncWrapper( - 50, // uniffi_suggest_fn_method_suggeststore_ingest + 95, // uniffi_suggest_fn_method_suggeststore_ingest FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestIngestionConstraints.lower(constraints), ) @@ -4515,7 +4515,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterOptionalTypeInterruptKind.checkType(kind); const result = UniFFIScaffolding.callSync( - 51, // uniffi_suggest_fn_method_suggeststore_interrupt + 96, // uniffi_suggest_fn_method_suggeststore_interrupt FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterOptionalTypeInterruptKind.lower(kind), ) @@ -4541,7 +4541,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterString.checkType(key); const result = await UniFFIScaffolding.callAsyncWrapper( - 52, // uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key + 97, // uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterString.lower(key), ) @@ -4566,7 +4566,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestion.checkType(suggestion); const result = await UniFFIScaffolding.callAsyncWrapper( - 53, // uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion + 98, // uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestion.lower(suggestion), ) @@ -4587,7 +4587,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestionQuery.checkType(query); const result = await UniFFIScaffolding.callAsyncWrapper( - 54, // uniffi_suggest_fn_method_suggeststore_query + 99, // uniffi_suggest_fn_method_suggeststore_query FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestionQuery.lower(query), ) @@ -4608,7 +4608,7 @@ export class SuggestStore extends SuggestStoreInterface { FfiConverterTypeSuggestionQuery.checkType(query); const result = await UniFFIScaffolding.callAsyncWrapper( - 55, // uniffi_suggest_fn_method_suggeststore_query_with_metrics + 100, // uniffi_suggest_fn_method_suggeststore_query_with_metrics FfiConverterTypeSuggestStore.lowerReceiver(this), FfiConverterTypeSuggestionQuery.lower(query), ) @@ -4643,11 +4643,11 @@ export class FfiConverterTypeSuggestStore extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(8)); + return this.lift(dataStream.readPointer(15)); } static write(dataStream, value) { - dataStream.writePointer(8, this.lower(value)); + dataStream.writePointer(15, this.lower(value)); } static computeSize(value) { @@ -4772,7 +4772,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { static init() { const result = UniFFIScaffolding.callSync( - 56, // uniffi_suggest_fn_constructor_suggeststorebuilder_new + 101, // uniffi_suggest_fn_constructor_suggeststorebuilder_new ) return handleRustResult( result, @@ -4788,7 +4788,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { build() { const result = UniFFIScaffolding.callSync( - 57, // uniffi_suggest_fn_method_suggeststorebuilder_build + 102, // uniffi_suggest_fn_method_suggeststorebuilder_build FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), ) return handleRustResult( @@ -4808,7 +4808,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterString.checkType(path); const result = await UniFFIScaffolding.callAsyncWrapper( - 58, // uniffi_suggest_fn_method_suggeststorebuilder_cache_path + 103, // uniffi_suggest_fn_method_suggeststorebuilder_cache_path FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterString.lower(path), ) @@ -4829,7 +4829,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterString.checkType(path); const result = UniFFIScaffolding.callSync( - 59, // uniffi_suggest_fn_method_suggeststorebuilder_data_path + 104, // uniffi_suggest_fn_method_suggeststorebuilder_data_path FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterString.lower(path), ) @@ -4857,7 +4857,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterString.checkType(library); FfiConverterOptionalString.checkType(entryPoint); const result = UniFFIScaffolding.callSync( - 60, // uniffi_suggest_fn_method_suggeststorebuilder_load_extension + 105, // uniffi_suggest_fn_method_suggeststorebuilder_load_extension FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterString.lower(library), FfiConverterOptionalString.lower(entryPoint), @@ -4879,7 +4879,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterString.checkType(bucketName); const result = UniFFIScaffolding.callSync( - 61, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name + 106, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterString.lower(bucketName), ) @@ -4900,7 +4900,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterTypeRemoteSettingsServer.checkType(server); const result = UniFFIScaffolding.callSync( - 62, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server + 107, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterTypeRemoteSettingsServer.lower(server), ) @@ -4921,7 +4921,7 @@ export class SuggestStoreBuilder extends SuggestStoreBuilderInterface { FfiConverterTypeRemoteSettingsService.checkType(rsService); const result = UniFFIScaffolding.callSync( - 63, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service + 108, // uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service FfiConverterTypeSuggestStoreBuilder.lowerReceiver(this), FfiConverterTypeRemoteSettingsService.lower(rsService), ) @@ -4956,11 +4956,11 @@ export class FfiConverterTypeSuggestStoreBuilder extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(9)); + return this.lift(dataStream.readPointer(16)); } static write(dataStream, value) { - dataStream.writePointer(9, this.lower(value)); + dataStream.writePointer(16, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs @@ -1053,7 +1053,7 @@ export class RemoteCommandStore extends RemoteCommandStoreInterface { FfiConverterString.checkType(deviceId); FfiConverterTypeRemoteCommand.checkType(command); const result = await UniFFIScaffolding.callAsyncWrapper( - 64, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command + 109, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command FfiConverterTypeRemoteCommandStore.lowerReceiver(this), FfiConverterString.lower(deviceId), FfiConverterTypeRemoteCommand.lower(command), @@ -1081,7 +1081,7 @@ export class RemoteCommandStore extends RemoteCommandStoreInterface { FfiConverterTypeRemoteCommand.checkType(command); FfiConverterTypeTimestamp.checkType(when); const result = await UniFFIScaffolding.callAsyncWrapper( - 65, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at + 110, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at FfiConverterTypeRemoteCommandStore.lowerReceiver(this), FfiConverterString.lower(deviceId), FfiConverterTypeRemoteCommand.lower(command), @@ -1101,7 +1101,7 @@ export class RemoteCommandStore extends RemoteCommandStoreInterface { async getUnsentCommands() { const result = await UniFFIScaffolding.callAsyncWrapper( - 66, // uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands + 111, // uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands FfiConverterTypeRemoteCommandStore.lowerReceiver(this), ) return handleRustResult( @@ -1125,7 +1125,7 @@ export class RemoteCommandStore extends RemoteCommandStoreInterface { FfiConverterString.checkType(deviceId); FfiConverterTypeRemoteCommand.checkType(command); const result = await UniFFIScaffolding.callAsyncWrapper( - 67, // uniffi_tabs_fn_method_remotecommandstore_remove_remote_command + 112, // uniffi_tabs_fn_method_remotecommandstore_remove_remote_command FfiConverterTypeRemoteCommandStore.lowerReceiver(this), FfiConverterString.lower(deviceId), FfiConverterTypeRemoteCommand.lower(command), @@ -1147,7 +1147,7 @@ export class RemoteCommandStore extends RemoteCommandStoreInterface { FfiConverterTypePendingCommand.checkType(command); const result = await UniFFIScaffolding.callAsyncWrapper( - 68, // uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent + 113, // uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent FfiConverterTypeRemoteCommandStore.lowerReceiver(this), FfiConverterTypePendingCommand.lower(command), ) @@ -1182,11 +1182,11 @@ export class FfiConverterTypeRemoteCommandStore extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(10)); + return this.lift(dataStream.readPointer(17)); } static write(dataStream, value) { - dataStream.writePointer(10, this.lower(value)); + dataStream.writePointer(17, this.lower(value)); } static computeSize(value) { @@ -1369,7 +1369,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async apply() { const result = await UniFFIScaffolding.callAsyncWrapper( - 69, // uniffi_tabs_fn_method_tabsbridgedengine_apply + 114, // uniffi_tabs_fn_method_tabsbridgedengine_apply FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1389,7 +1389,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { FfiConverterString.checkType(newSyncId); const result = await UniFFIScaffolding.callAsyncWrapper( - 70, // uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id + 115, // uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), FfiConverterString.lower(newSyncId), ) @@ -1407,7 +1407,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async lastSync() { const result = await UniFFIScaffolding.callAsyncWrapper( - 71, // uniffi_tabs_fn_method_tabsbridgedengine_last_sync + 116, // uniffi_tabs_fn_method_tabsbridgedengine_last_sync FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1426,7 +1426,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { FfiConverterString.checkType(clientData); const result = await UniFFIScaffolding.callAsyncWrapper( - 72, // uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync + 117, // uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), FfiConverterString.lower(clientData), ) @@ -1443,7 +1443,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async reset() { const result = await UniFFIScaffolding.callAsyncWrapper( - 73, // uniffi_tabs_fn_method_tabsbridgedengine_reset + 118, // uniffi_tabs_fn_method_tabsbridgedengine_reset FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1460,7 +1460,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async resetSyncId() { const result = await UniFFIScaffolding.callAsyncWrapper( - 74, // uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id + 119, // uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1479,7 +1479,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { FfiConverterInt64.checkType(lastSync); const result = await UniFFIScaffolding.callAsyncWrapper( - 75, // uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync + 120, // uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), FfiConverterInt64.lower(lastSync), ) @@ -1502,7 +1502,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { FfiConverterInt64.checkType(newTimestamp); FfiConverterSequenceTypeTabsGuid.checkType(uploadedIds); const result = await UniFFIScaffolding.callAsyncWrapper( - 76, // uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded + 121, // uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), FfiConverterInt64.lower(newTimestamp), FfiConverterSequenceTypeTabsGuid.lower(uploadedIds), @@ -1523,7 +1523,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { FfiConverterSequenceString.checkType(incomingEnvelopesAsJson); const result = await UniFFIScaffolding.callAsyncWrapper( - 77, // uniffi_tabs_fn_method_tabsbridgedengine_store_incoming + 122, // uniffi_tabs_fn_method_tabsbridgedengine_store_incoming FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), FfiConverterSequenceString.lower(incomingEnvelopesAsJson), ) @@ -1540,7 +1540,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async syncFinished() { const result = await UniFFIScaffolding.callAsyncWrapper( - 78, // uniffi_tabs_fn_method_tabsbridgedengine_sync_finished + 123, // uniffi_tabs_fn_method_tabsbridgedengine_sync_finished FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1557,7 +1557,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async syncId() { const result = await UniFFIScaffolding.callAsyncWrapper( - 79, // uniffi_tabs_fn_method_tabsbridgedengine_sync_id + 124, // uniffi_tabs_fn_method_tabsbridgedengine_sync_id FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1573,7 +1573,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async syncStarted() { const result = await UniFFIScaffolding.callAsyncWrapper( - 80, // uniffi_tabs_fn_method_tabsbridgedengine_sync_started + 125, // uniffi_tabs_fn_method_tabsbridgedengine_sync_started FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1589,7 +1589,7 @@ export class TabsBridgedEngine extends TabsBridgedEngineInterface { async wipe() { const result = await UniFFIScaffolding.callAsyncWrapper( - 81, // uniffi_tabs_fn_method_tabsbridgedengine_wipe + 126, // uniffi_tabs_fn_method_tabsbridgedengine_wipe FfiConverterTypeTabsBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1623,11 +1623,11 @@ export class FfiConverterTypeTabsBridgedEngine extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(11)); + return this.lift(dataStream.readPointer(18)); } static write(dataStream, value) { - dataStream.writePointer(11, this.lower(value)); + dataStream.writePointer(18, this.lower(value)); } static computeSize(value) { @@ -1754,7 +1754,7 @@ export class TabsStore extends TabsStoreInterface { FfiConverterString.checkType(path); const result = await UniFFIScaffolding.callAsyncWrapper( - 82, // uniffi_tabs_fn_constructor_tabsstore_new + 127, // uniffi_tabs_fn_constructor_tabsstore_new FfiConverterString.lower(path), ) return handleRustResult( @@ -1771,7 +1771,7 @@ export class TabsStore extends TabsStoreInterface { async bridgedEngine() { const result = await UniFFIScaffolding.callAsyncWrapper( - 83, // uniffi_tabs_fn_method_tabsstore_bridged_engine + 128, // uniffi_tabs_fn_method_tabsstore_bridged_engine FfiConverterTypeTabsStore.lowerReceiver(this), ) return handleRustResult( @@ -1787,7 +1787,7 @@ export class TabsStore extends TabsStoreInterface { async closeConnection() { const result = await UniFFIScaffolding.callAsyncWrapper( - 84, // uniffi_tabs_fn_method_tabsstore_close_connection + 129, // uniffi_tabs_fn_method_tabsstore_close_connection FfiConverterTypeTabsStore.lowerReceiver(this), ) return handleRustResult( @@ -1804,7 +1804,7 @@ export class TabsStore extends TabsStoreInterface { async getAll() { const result = await UniFFIScaffolding.callAsyncWrapper( - 85, // uniffi_tabs_fn_method_tabsstore_get_all + 130, // uniffi_tabs_fn_method_tabsstore_get_all FfiConverterTypeTabsStore.lowerReceiver(this), ) return handleRustResult( @@ -1821,7 +1821,7 @@ export class TabsStore extends TabsStoreInterface { async newRemoteCommandStore() { const result = await UniFFIScaffolding.callAsyncWrapper( - 86, // uniffi_tabs_fn_method_tabsstore_new_remote_command_store + 131, // uniffi_tabs_fn_method_tabsstore_new_remote_command_store FfiConverterTypeTabsStore.lowerReceiver(this), ) return handleRustResult( @@ -1837,7 +1837,7 @@ export class TabsStore extends TabsStoreInterface { async registerWithSyncManager() { const result = await UniFFIScaffolding.callAsyncWrapper( - 87, // uniffi_tabs_fn_method_tabsstore_register_with_sync_manager + 132, // uniffi_tabs_fn_method_tabsstore_register_with_sync_manager FfiConverterTypeTabsStore.lowerReceiver(this), ) return handleRustResult( @@ -1856,7 +1856,7 @@ export class TabsStore extends TabsStoreInterface { FfiConverterSequenceTypeRemoteTabRecord.checkType(remoteTabs); const result = await UniFFIScaffolding.callAsyncWrapper( - 88, // uniffi_tabs_fn_method_tabsstore_set_local_tabs + 133, // uniffi_tabs_fn_method_tabsstore_set_local_tabs FfiConverterTypeTabsStore.lowerReceiver(this), FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs), ) @@ -1891,11 +1891,11 @@ export class FfiConverterTypeTabsStore extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(12)); + return this.lift(dataStream.readPointer(19)); } static write(dataStream, value) { - dataStream.writePointer(12, this.lower(value)); + dataStream.writePointer(19, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTracing.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTracing.sys.mjs @@ -47,7 +47,7 @@ FfiConverterString.checkType(target); FfiConverterTypeTracingLevel.checkType(level); FfiConverterTypeEventSink.checkType(sink); const result = UniFFIScaffolding.callSync( - 89, // uniffi_tracing_support_fn_func_register_event_sink + 134, // uniffi_tracing_support_fn_func_register_event_sink FfiConverterString.lower(target), FfiConverterTypeTracingLevel.lower(level), FfiConverterTypeEventSink.lower(sink), @@ -71,7 +71,7 @@ export function registerMinLevelEventSink( FfiConverterTypeTracingLevel.checkType(level); FfiConverterTypeEventSink.checkType(sink); const result = UniFFIScaffolding.callSync( - 90, // uniffi_tracing_support_fn_func_register_min_level_event_sink + 135, // uniffi_tracing_support_fn_func_register_min_level_event_sink FfiConverterTypeTracingLevel.lower(level), FfiConverterTypeEventSink.lower(sink), ) @@ -91,7 +91,7 @@ export function unregisterEventSink( FfiConverterString.checkType(target); const result = UniFFIScaffolding.callSync( - 91, // uniffi_tracing_support_fn_func_unregister_event_sink + 136, // uniffi_tracing_support_fn_func_unregister_event_sink FfiConverterString.lower(target), ) return handleRustResult( @@ -107,7 +107,7 @@ return handleRustResult( export function unregisterMinLevelEventSink() { const result = UniFFIScaffolding.callSync( - 92, // uniffi_tracing_support_fn_func_unregister_min_level_event_sink + 137, // uniffi_tracing_support_fn_func_unregister_min_level_event_sink ) return handleRustResult( result, @@ -444,7 +444,7 @@ export class FfiConverterTypeEventSink extends FfiConverter { } const uniffiCallbackHandlerTracingEventSink = new UniFFICallbackHandler( "EventSink", - 2, + 5, [ new UniFFICallbackMethodHandler( "onEvent", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustViaduct.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustViaduct.sys.mjs @@ -38,7 +38,7 @@ export var UnitTestObjs = { export function allowAndroidEmulatorLoopback() { const result = UniFFIScaffolding.callSync( - 93, // uniffi_viaduct_fn_func_allow_android_emulator_loopback + 138, // uniffi_viaduct_fn_func_allow_android_emulator_loopback ) return handleRustResult( result, @@ -56,7 +56,7 @@ export function initBackend( FfiConverterTypeBackend.checkType(backend); const result = UniFFIScaffolding.callSync( - 94, // uniffi_viaduct_fn_func_init_backend + 139, // uniffi_viaduct_fn_func_init_backend FfiConverterTypeBackend.lower(backend), ) return handleRustResult( @@ -1050,7 +1050,7 @@ export class BackendImpl extends Backend { FfiConverterTypeRequest.checkType(request); FfiConverterTypeClientSettings.checkType(settings); const result = await UniFFIScaffolding.callAsync( - 95, // uniffi_viaduct_fn_method_backend_send_request + 140, // uniffi_viaduct_fn_method_backend_send_request FfiConverterTypeBackend.lowerReceiver(this), FfiConverterTypeRequest.lower(request), FfiConverterTypeClientSettings.lower(settings), @@ -1095,11 +1095,11 @@ export class FfiConverterTypeBackend extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(13)); + return this.lift(dataStream.readPointer(20)); } static write(dataStream, value) { - dataStream.writePointer(13, this.lower(value)); + dataStream.writePointer(20, this.lower(value)); } static computeSize(value) { @@ -1109,7 +1109,7 @@ export class FfiConverterTypeBackend extends FfiConverter { const uniffiCallbackHandlerViaductBackend = new UniFFICallbackHandler( "Backend", - 3, + 6, [ new UniFFICallbackMethodHandler( "sendRequest", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustWebextstorage.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustWebextstorage.sys.mjs @@ -877,7 +877,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async apply() { const result = await UniFFIScaffolding.callAsyncWrapper( - 96, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply + 141, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -897,7 +897,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf FfiConverterString.checkType(newSyncId); const result = await UniFFIScaffolding.callAsyncWrapper( - 97, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id + 142, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), FfiConverterString.lower(newSyncId), ) @@ -915,7 +915,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async lastSync() { const result = await UniFFIScaffolding.callAsyncWrapper( - 98, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync + 143, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -934,7 +934,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf FfiConverterString.checkType(clientData); const result = await UniFFIScaffolding.callAsyncWrapper( - 99, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync + 144, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), FfiConverterString.lower(clientData), ) @@ -951,7 +951,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async reset() { const result = await UniFFIScaffolding.callAsyncWrapper( - 100, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset + 145, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -968,7 +968,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async resetSyncId() { const result = await UniFFIScaffolding.callAsyncWrapper( - 101, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id + 146, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -987,7 +987,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf FfiConverterInt64.checkType(lastSync); const result = await UniFFIScaffolding.callAsyncWrapper( - 102, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync + 147, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), FfiConverterInt64.lower(lastSync), ) @@ -1010,7 +1010,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf FfiConverterInt64.checkType(serverModifiedMillis); FfiConverterSequenceTypeGuid.checkType(guids); const result = await UniFFIScaffolding.callAsyncWrapper( - 103, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded + 148, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), FfiConverterInt64.lower(serverModifiedMillis), FfiConverterSequenceTypeGuid.lower(guids), @@ -1031,7 +1031,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf FfiConverterSequenceString.checkType(incoming); const result = await UniFFIScaffolding.callAsyncWrapper( - 104, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming + 149, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), FfiConverterSequenceString.lower(incoming), ) @@ -1048,7 +1048,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async syncFinished() { const result = await UniFFIScaffolding.callAsyncWrapper( - 105, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished + 150, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1065,7 +1065,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async syncId() { const result = await UniFFIScaffolding.callAsyncWrapper( - 106, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id + 151, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1081,7 +1081,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async syncStarted() { const result = await UniFFIScaffolding.callAsyncWrapper( - 107, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started + 152, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1097,7 +1097,7 @@ export class WebExtStorageBridgedEngine extends WebExtStorageBridgedEngineInterf async wipe() { const result = await UniFFIScaffolding.callAsyncWrapper( - 108, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe + 153, // uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe FfiConverterTypeWebExtStorageBridgedEngine.lowerReceiver(this), ) return handleRustResult( @@ -1131,11 +1131,11 @@ export class FfiConverterTypeWebExtStorageBridgedEngine extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(14)); + return this.lift(dataStream.readPointer(21)); } static write(dataStream, value) { - dataStream.writePointer(14, this.lower(value)); + dataStream.writePointer(21, this.lower(value)); } static computeSize(value) { @@ -1305,7 +1305,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(path); const result = await UniFFIScaffolding.callAsyncWrapper( - 109, // uniffi_webext_storage_fn_constructor_webextstoragestore_new + 154, // uniffi_webext_storage_fn_constructor_webextstoragestore_new FfiConverterString.lower(path), ) return handleRustResult( @@ -1322,7 +1322,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { async bridgedEngine() { const result = await UniFFIScaffolding.callAsyncWrapper( - 110, // uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine + 155, // uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine FfiConverterTypeWebExtStorageStore.lowerReceiver(this), ) return handleRustResult( @@ -1342,7 +1342,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); const result = await UniFFIScaffolding.callAsyncWrapper( - 111, // uniffi_webext_storage_fn_method_webextstoragestore_clear + 156, // uniffi_webext_storage_fn_method_webextstoragestore_clear FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), ) @@ -1359,7 +1359,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { async close() { const result = await UniFFIScaffolding.callAsyncWrapper( - 112, // uniffi_webext_storage_fn_method_webextstoragestore_close + 157, // uniffi_webext_storage_fn_method_webextstoragestore_close FfiConverterTypeWebExtStorageStore.lowerReceiver(this), ) return handleRustResult( @@ -1382,7 +1382,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); FfiConverterTypeJsonValue.checkType(keys); const result = await UniFFIScaffolding.callAsyncWrapper( - 113, // uniffi_webext_storage_fn_method_webextstoragestore_get + 158, // uniffi_webext_storage_fn_method_webextstoragestore_get FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), FfiConverterTypeJsonValue.lower(keys), @@ -1407,7 +1407,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); FfiConverterTypeJsonValue.checkType(keys); const result = await UniFFIScaffolding.callAsyncWrapper( - 114, // uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use + 159, // uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), FfiConverterTypeJsonValue.lower(keys), @@ -1429,7 +1429,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); const result = await UniFFIScaffolding.callAsyncWrapper( - 115, // uniffi_webext_storage_fn_method_webextstoragestore_get_keys + 160, // uniffi_webext_storage_fn_method_webextstoragestore_get_keys FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), ) @@ -1447,7 +1447,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { async getSyncedChanges() { const result = await UniFFIScaffolding.callAsyncWrapper( - 116, // uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes + 161, // uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes FfiConverterTypeWebExtStorageStore.lowerReceiver(this), ) return handleRustResult( @@ -1470,7 +1470,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); FfiConverterTypeJsonValue.checkType(keys); const result = await UniFFIScaffolding.callAsyncWrapper( - 117, // uniffi_webext_storage_fn_method_webextstoragestore_remove + 162, // uniffi_webext_storage_fn_method_webextstoragestore_remove FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), FfiConverterTypeJsonValue.lower(keys), @@ -1495,7 +1495,7 @@ export class WebExtStorageStore extends WebExtStorageStoreInterface { FfiConverterString.checkType(extId); FfiConverterTypeJsonValue.checkType(val); const result = await UniFFIScaffolding.callAsyncWrapper( - 118, // uniffi_webext_storage_fn_method_webextstoragestore_set + 163, // uniffi_webext_storage_fn_method_webextstoragestore_set FfiConverterTypeWebExtStorageStore.lowerReceiver(this), FfiConverterString.lower(extId), FfiConverterTypeJsonValue.lower(val), @@ -1531,11 +1531,11 @@ export class FfiConverterTypeWebExtStorageStore extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(15)); + return this.lift(dataStream.readPointer(22)); } static write(dataStream, value) { - dataStream.writePointer(15, this.lower(value)); + dataStream.writePointer(22, this.lower(value)); } static computeSize(value) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTests.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTests.sys.mjs @@ -46,7 +46,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterFloat32.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 119, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f32 + 164, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f32 FfiConverterFloat32.lower(v), ) return handleRustResult( @@ -70,7 +70,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterFloat64.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 120, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f64 + 165, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f64 FfiConverterFloat64.lower(v), ) return handleRustResult( @@ -94,7 +94,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterInt16.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 121, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i16 + 166, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i16 FfiConverterInt16.lower(v), ) return handleRustResult( @@ -118,7 +118,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterInt32.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 122, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i32 + 167, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i32 FfiConverterInt32.lower(v), ) return handleRustResult( @@ -142,7 +142,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterInt64.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 123, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i64 + 168, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i64 FfiConverterInt64.lower(v), ) return handleRustResult( @@ -166,7 +166,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterInt8.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 124, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i8 + 169, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i8 FfiConverterInt8.lower(v), ) return handleRustResult( @@ -190,7 +190,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterMapStringString.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 125, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_map + 170, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_map FfiConverterMapStringString.lower(v), ) return handleRustResult( @@ -214,7 +214,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeAsyncInterface.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 126, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_obj + 171, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_obj FfiConverterTypeAsyncInterface.lower(v), ) return handleRustResult( @@ -238,7 +238,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterString.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 127, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_string + 172, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_string FfiConverterString.lower(v), ) return handleRustResult( @@ -262,7 +262,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt16.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 128, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u16 + 173, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u16 FfiConverterUInt16.lower(v), ) return handleRustResult( @@ -286,7 +286,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 129, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u32 + 174, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u32 FfiConverterUInt32.lower(v), ) return handleRustResult( @@ -310,7 +310,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt64.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 130, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u64 + 175, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u64 FfiConverterUInt64.lower(v), ) return handleRustResult( @@ -334,7 +334,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt8.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 131, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u8 + 176, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u8 FfiConverterUInt8.lower(v), ) return handleRustResult( @@ -358,7 +358,7 @@ if (v instanceof UniffiSkipJsTypeCheck) { FfiConverterSequenceUInt32.checkType(v); } const result = await UniFFIScaffolding.callAsync( - 132, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_vec + 177, // uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_vec FfiConverterSequenceUInt32.lower(v), ) return handleRustResult( @@ -374,7 +374,7 @@ return handleRustResult( export async function asyncThrowError() { const result = await UniFFIScaffolding.callAsync( - 133, // uniffi_uniffi_bindings_tests_fn_func_async_throw_error + 178, // uniffi_uniffi_bindings_tests_fn_func_async_throw_error ) return handleRustResult( result, @@ -397,7 +397,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestInterface.checkType(int); } const result = UniFFIScaffolding.callSync( - 134, // uniffi_uniffi_bindings_tests_fn_func_clone_interface + 179, // uniffi_uniffi_bindings_tests_fn_func_clone_interface FfiConverterTypeTestInterface.lower(int), ) return handleRustResult( @@ -421,7 +421,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = await UniFFIScaffolding.callAsyncWrapper( - 135, // uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface + 180, // uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface FfiConverterUInt32.lower(value), ) return handleRustResult( @@ -445,7 +445,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = UniFFIScaffolding.callSync( - 136, // uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface + 181, // uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface FfiConverterUInt32.lower(value), ) return handleRustResult( @@ -469,7 +469,7 @@ if (arg instanceof UniffiSkipJsTypeCheck) { FfiConverterString.checkType(arg); } const result = UniFFIScaffolding.callSync( - 137, // uniffi_uniffi_bindings_tests_fn_func_func_with_default + 182, // uniffi_uniffi_bindings_tests_fn_func_func_with_default FfiConverterString.lower(arg), ) return handleRustResult( @@ -492,7 +492,7 @@ if (input instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(input); } const result = UniFFIScaffolding.callSync( - 138, // uniffi_uniffi_bindings_tests_fn_func_func_with_error + 183, // uniffi_uniffi_bindings_tests_fn_func_func_with_error FfiConverterUInt32.lower(input), ) return handleRustResult( @@ -515,7 +515,7 @@ if (input instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(input); } const result = UniFFIScaffolding.callSync( - 139, // uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error + 184, // uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error FfiConverterUInt32.lower(input), ) return handleRustResult( @@ -540,7 +540,7 @@ if (theArgument instanceof UniffiSkipJsTypeCheck) { FfiConverterString.checkType(theArgument); } const result = UniFFIScaffolding.callSync( - 140, // uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg + 185, // uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg FfiConverterString.lower(theArgument), ) return handleRustResult( @@ -557,7 +557,7 @@ return handleRustResult( export async function getCustomTypesDemo() { const result = await UniFFIScaffolding.callAsyncWrapper( - 141, // uniffi_uniffi_bindings_tests_fn_func_get_custom_types_demo + 186, // uniffi_uniffi_bindings_tests_fn_func_get_custom_types_demo ) return handleRustResult( result, @@ -580,7 +580,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeAsyncTestTraitInterface.checkType(int); } const result = await UniFFIScaffolding.callAsync( - 142, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_get_value + 187, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_get_value FfiConverterTypeAsyncTestTraitInterface.lower(int), ) return handleRustResult( @@ -603,7 +603,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeAsyncTestTraitInterface.checkType(int); } const result = await UniFFIScaffolding.callAsync( - 143, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_noop + 188, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_noop FfiConverterTypeAsyncTestTraitInterface.lower(int), ) return handleRustResult( @@ -633,7 +633,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = await UniFFIScaffolding.callAsync( - 144, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_set_value + 189, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_set_value FfiConverterTypeAsyncTestTraitInterface.lower(int), FfiConverterUInt32.lower(value), ) @@ -665,7 +665,7 @@ if (numbers instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = await UniFFIScaffolding.callAsync( - 145, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_throw_if_equal + 190, // uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_throw_if_equal FfiConverterTypeAsyncTestTraitInterface.lower(int), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -690,7 +690,7 @@ if (cbi instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestAsyncCallbackInterface.checkType(cbi); } const result = await UniFFIScaffolding.callAsync( - 146, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_get_value + 191, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_get_value FfiConverterTypeTestAsyncCallbackInterface.lower(cbi), ) return handleRustResult( @@ -713,7 +713,7 @@ if (cbi instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestAsyncCallbackInterface.checkType(cbi); } const result = await UniFFIScaffolding.callAsync( - 147, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_noop + 192, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_noop FfiConverterTypeTestAsyncCallbackInterface.lower(cbi), ) return handleRustResult( @@ -743,7 +743,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = await UniFFIScaffolding.callAsync( - 148, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_set_value + 193, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_set_value FfiConverterTypeTestAsyncCallbackInterface.lower(cbi), FfiConverterUInt32.lower(value), ) @@ -775,7 +775,7 @@ if (numbers instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = await UniFFIScaffolding.callAsync( - 149, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_throw_if_equal + 194, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_throw_if_equal FfiConverterTypeTestAsyncCallbackInterface.lower(cbi), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -800,7 +800,7 @@ if (cbi instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestCallbackInterface.checkType(cbi); } const result = UniFFIScaffolding.callSync( - 150, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value + 195, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value FfiConverterTypeTestCallbackInterface.lower(cbi), ) return handleRustResult( @@ -823,7 +823,7 @@ if (cbi instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestCallbackInterface.checkType(cbi); } const result = UniFFIScaffolding.callSync( - 151, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop + 196, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop FfiConverterTypeTestCallbackInterface.lower(cbi), ) return handleRustResult( @@ -853,7 +853,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = UniFFIScaffolding.callSync( - 152, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value + 197, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value FfiConverterTypeTestCallbackInterface.lower(cbi), FfiConverterUInt32.lower(value), ) @@ -885,7 +885,7 @@ if (numbers instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = UniFFIScaffolding.callSync( - 153, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal + 198, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal FfiConverterTypeTestCallbackInterface.lower(cbi), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -910,7 +910,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestTraitInterface.checkType(int); } const result = UniFFIScaffolding.callSync( - 154, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value + 199, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value FfiConverterTypeTestTraitInterface.lower(int), ) return handleRustResult( @@ -933,7 +933,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestTraitInterface.checkType(int); } const result = UniFFIScaffolding.callSync( - 155, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop + 200, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop FfiConverterTypeTestTraitInterface.lower(int), ) return handleRustResult( @@ -963,7 +963,7 @@ if (value instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(value); } const result = UniFFIScaffolding.callSync( - 156, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value + 201, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value FfiConverterTypeTestTraitInterface.lower(int), FfiConverterUInt32.lower(value), ) @@ -995,7 +995,7 @@ if (numbers instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = UniFFIScaffolding.callSync( - 157, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal + 202, // uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal FfiConverterTypeTestTraitInterface.lower(int), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -1020,7 +1020,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterBoolean.checkType(a); } const result = UniFFIScaffolding.callSync( - 158, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool + 203, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool FfiConverterBoolean.lower(a), ) return handleRustResult( @@ -1044,7 +1044,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterOptionalSequenceMapStringUInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 159, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound + 204, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound FfiConverterOptionalSequenceMapStringUInt32.lower(a), ) return handleRustResult( @@ -1068,7 +1068,7 @@ if (en instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeComplexEnum.checkType(en); } const result = UniFFIScaffolding.callSync( - 160, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum + 205, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum FfiConverterTypeComplexEnum.lower(en), ) return handleRustResult( @@ -1092,7 +1092,7 @@ if (rec instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeComplexRec.checkType(rec); } const result = UniFFIScaffolding.callSync( - 161, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec + 206, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec FfiConverterTypeComplexRec.lower(rec), ) return handleRustResult( @@ -1116,7 +1116,7 @@ if (handle instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeHandle.checkType(handle); } const result = UniFFIScaffolding.callSync( - 162, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type + 207, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type FfiConverterTypeHandle.lower(handle), ) return handleRustResult( @@ -1140,7 +1140,7 @@ if (en instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeEnumNoData.checkType(en); } const result = UniFFIScaffolding.callSync( - 163, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data + 208, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data FfiConverterTypeEnumNoData.lower(en), ) return handleRustResult( @@ -1164,7 +1164,7 @@ if (en instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeEnumWithData.checkType(en); } const result = UniFFIScaffolding.callSync( - 164, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data + 209, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data FfiConverterTypeEnumWithData.lower(en), ) return handleRustResult( @@ -1188,7 +1188,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterFloat32.checkType(a); } const result = UniFFIScaffolding.callSync( - 165, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32 + 210, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32 FfiConverterFloat32.lower(a), ) return handleRustResult( @@ -1212,7 +1212,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterFloat64.checkType(a); } const result = UniFFIScaffolding.callSync( - 166, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64 + 211, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64 FfiConverterFloat64.lower(a), ) return handleRustResult( @@ -1236,7 +1236,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterMapStringUInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 167, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map + 212, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map FfiConverterMapStringUInt32.lower(a), ) return handleRustResult( @@ -1260,7 +1260,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterInt16.checkType(a); } const result = UniFFIScaffolding.callSync( - 168, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16 + 213, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16 FfiConverterInt16.lower(a), ) return handleRustResult( @@ -1284,7 +1284,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 169, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32 + 214, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32 FfiConverterInt32.lower(a), ) return handleRustResult( @@ -1308,7 +1308,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterInt64.checkType(a); } const result = UniFFIScaffolding.callSync( - 170, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64 + 215, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64 FfiConverterInt64.lower(a), ) return handleRustResult( @@ -1332,7 +1332,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterInt8.checkType(a); } const result = UniFFIScaffolding.callSync( - 171, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8 + 216, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8 FfiConverterInt8.lower(a), ) return handleRustResult( @@ -1356,7 +1356,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterOptionalUInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 172, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_option + 217, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_option FfiConverterOptionalUInt32.lower(a), ) return handleRustResult( @@ -1380,7 +1380,7 @@ if (rec instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeSimpleRec.checkType(rec); } const result = await UniFFIScaffolding.callAsyncWrapper( - 173, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec + 218, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec FfiConverterTypeSimpleRec.lower(rec), ) return handleRustResult( @@ -1404,7 +1404,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterString.checkType(a); } const result = UniFFIScaffolding.callSync( - 174, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_string + 219, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_string FfiConverterString.lower(a), ) return handleRustResult( @@ -1428,7 +1428,7 @@ if (time instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTimeIntervalMs.checkType(time); } const result = await UniFFIScaffolding.callAsyncWrapper( - 175, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms + 220, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms FfiConverterTypeTimeIntervalMs.lower(time), ) return handleRustResult( @@ -1452,7 +1452,7 @@ if (time instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTimeIntervalSecDbl.checkType(time); } const result = await UniFFIScaffolding.callAsyncWrapper( - 176, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl + 221, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl FfiConverterTypeTimeIntervalSecDbl.lower(time), ) return handleRustResult( @@ -1476,7 +1476,7 @@ if (time instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTimeIntervalSecFlt.checkType(time); } const result = await UniFFIScaffolding.callAsyncWrapper( - 177, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt + 222, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt FfiConverterTypeTimeIntervalSecFlt.lower(time), ) return handleRustResult( @@ -1500,7 +1500,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt16.checkType(a); } const result = UniFFIScaffolding.callSync( - 178, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16 + 223, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16 FfiConverterUInt16.lower(a), ) return handleRustResult( @@ -1524,7 +1524,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 179, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32 + 224, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32 FfiConverterUInt32.lower(a), ) return handleRustResult( @@ -1548,7 +1548,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt64.checkType(a); } const result = UniFFIScaffolding.callSync( - 180, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64 + 225, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64 FfiConverterUInt64.lower(a), ) return handleRustResult( @@ -1572,7 +1572,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterUInt8.checkType(a); } const result = UniFFIScaffolding.callSync( - 181, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8 + 226, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8 FfiConverterUInt8.lower(a), ) return handleRustResult( @@ -1596,7 +1596,7 @@ if (url instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeUrl.checkType(url); } const result = await UniFFIScaffolding.callAsyncWrapper( - 182, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_url + 227, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_url FfiConverterTypeUrl.lower(url), ) return handleRustResult( @@ -1620,7 +1620,7 @@ if (a instanceof UniffiSkipJsTypeCheck) { FfiConverterSequenceUInt32.checkType(a); } const result = UniFFIScaffolding.callSync( - 183, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec + 228, // uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec FfiConverterSequenceUInt32.lower(a), ) return handleRustResult( @@ -1714,7 +1714,7 @@ if (negate instanceof UniffiSkipJsTypeCheck) { FfiConverterBoolean.checkType(negate); } const result = UniFFIScaffolding.callSync( - 184, // uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types + 229, // uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types FfiConverterUInt8.lower(a), FfiConverterInt8.lower(b), FfiConverterUInt16.lower(c), @@ -1748,7 +1748,7 @@ if (interfaces instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTwoTestInterfaces.checkType(interfaces); } const result = UniFFIScaffolding.callSync( - 185, // uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces + 230, // uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces FfiConverterTypeTwoTestInterfaces.lower(interfaces), ) return handleRustResult( @@ -1764,7 +1764,7 @@ return handleRustResult( export function testFunc() { const result = UniFFIScaffolding.callSync( - 186, // uniffi_uniffi_bindings_tests_fn_func_test_func + 231, // uniffi_uniffi_bindings_tests_fn_func_test_func ) return handleRustResult( result, @@ -2748,7 +2748,7 @@ export class TestInterface extends TestInterfaceInterface { FfiConverterUInt32.checkType(value); } const result = UniFFIScaffolding.callSync( - 187, // uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new + 232, // uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new FfiConverterUInt32.lower(value), ) return handleRustResult( @@ -2765,7 +2765,7 @@ export class TestInterface extends TestInterfaceInterface { getValue() { const result = UniFFIScaffolding.callSync( - 188, // uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value + 233, // uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value FfiConverterTypeTestInterface.lowerReceiver(this), ) return handleRustResult( @@ -2784,7 +2784,7 @@ export class TestInterface extends TestInterfaceInterface { refCount() { const result = UniFFIScaffolding.callSync( - 189, // uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count + 234, // uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count FfiConverterTypeTestInterface.lowerReceiver(this), ) return handleRustResult( @@ -2818,11 +2818,11 @@ export class FfiConverterTypeTestInterface extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(16)); + return this.lift(dataStream.readPointer(23)); } static write(dataStream, value) { - dataStream.writePointer(16, this.lower(value)); + dataStream.writePointer(23, this.lower(value)); } static computeSize(value) { @@ -3563,7 +3563,7 @@ export class AsyncInterface extends AsyncInterfaceInterface { FfiConverterString.checkType(name); } const result = UniFFIScaffolding.callSync( - 190, // uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new + 235, // uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new FfiConverterString.lower(name), ) return handleRustResult( @@ -3580,7 +3580,7 @@ export class AsyncInterface extends AsyncInterfaceInterface { async name() { const result = await UniFFIScaffolding.callAsync( - 191, // uniffi_uniffi_bindings_tests_fn_method_asyncinterface_name + 236, // uniffi_uniffi_bindings_tests_fn_method_asyncinterface_name FfiConverterTypeAsyncInterface.lowerReceiver(this), ) return handleRustResult( @@ -3614,11 +3614,11 @@ export class FfiConverterTypeAsyncInterface extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(17)); + return this.lift(dataStream.readPointer(24)); } static write(dataStream, value) { - dataStream.writePointer(17, this.lower(value)); + dataStream.writePointer(24, this.lower(value)); } static computeSize(value) { @@ -3691,7 +3691,7 @@ export class AsyncTestTraitInterfaceImpl extends AsyncTestTraitInterface { async noop() { const result = await UniFFIScaffolding.callAsync( - 192, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_noop + 237, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_noop FfiConverterTypeAsyncTestTraitInterface.lowerReceiver(this), ) return handleRustResult( @@ -3708,7 +3708,7 @@ export class AsyncTestTraitInterfaceImpl extends AsyncTestTraitInterface { async getValue() { const result = await UniFFIScaffolding.callAsync( - 193, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_get_value + 238, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_get_value FfiConverterTypeAsyncTestTraitInterface.lowerReceiver(this), ) return handleRustResult( @@ -3731,7 +3731,7 @@ export class AsyncTestTraitInterfaceImpl extends AsyncTestTraitInterface { FfiConverterUInt32.checkType(value); } const result = await UniFFIScaffolding.callAsync( - 194, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_set_value + 239, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_set_value FfiConverterTypeAsyncTestTraitInterface.lowerReceiver(this), FfiConverterUInt32.lower(value), ) @@ -3759,7 +3759,7 @@ export class AsyncTestTraitInterfaceImpl extends AsyncTestTraitInterface { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = await UniFFIScaffolding.callAsync( - 195, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_throw_if_equal + 240, // uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_throw_if_equal FfiConverterTypeAsyncTestTraitInterface.lowerReceiver(this), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -3803,11 +3803,11 @@ export class FfiConverterTypeAsyncTestTraitInterface extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(18)); + return this.lift(dataStream.readPointer(25)); } static write(dataStream, value) { - dataStream.writePointer(18, this.lower(value)); + dataStream.writePointer(25, this.lower(value)); } static computeSize(value) { @@ -3817,7 +3817,7 @@ export class FfiConverterTypeAsyncTestTraitInterface extends FfiConverter { const uniffiCallbackHandlerUniffiBindingsTestsAsyncTestTraitInterface = new UniFFICallbackHandler( "AsyncTestTraitInterface", - 6, + 9, [ new UniFFICallbackMethodHandler( "noop", @@ -3915,7 +3915,7 @@ export class ComplexMethods extends ComplexMethodsInterface { static init() { const result = UniFFIScaffolding.callSync( - 196, // uniffi_uniffi_bindings_tests_fn_constructor_complexmethods_new + 241, // uniffi_uniffi_bindings_tests_fn_constructor_complexmethods_new ) return handleRustResult( result, @@ -3938,7 +3938,7 @@ export class ComplexMethods extends ComplexMethodsInterface { FfiConverterString.checkType(arg); } const result = UniFFIScaffolding.callSync( - 197, // uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default + 242, // uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default FfiConverterTypeComplexMethods.lowerReceiver(this), FfiConverterString.lower(arg), ) @@ -3963,7 +3963,7 @@ export class ComplexMethods extends ComplexMethodsInterface { FfiConverterString.checkType(theArgument); } const result = UniFFIScaffolding.callSync( - 198, // uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg + 243, // uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg FfiConverterTypeComplexMethods.lowerReceiver(this), FfiConverterString.lower(theArgument), ) @@ -3998,11 +3998,11 @@ export class FfiConverterTypeComplexMethods extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(19)); + return this.lift(dataStream.readPointer(26)); } static write(dataStream, value) { - dataStream.writePointer(19, this.lower(value)); + dataStream.writePointer(26, this.lower(value)); } static computeSize(value) { @@ -4075,7 +4075,7 @@ export class TestTraitInterfaceImpl extends TestTraitInterface { noop() { const result = UniFFIScaffolding.callSync( - 199, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop + 244, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop FfiConverterTypeTestTraitInterface.lowerReceiver(this), ) return handleRustResult( @@ -4092,7 +4092,7 @@ export class TestTraitInterfaceImpl extends TestTraitInterface { getValue() { const result = UniFFIScaffolding.callSync( - 200, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value + 245, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value FfiConverterTypeTestTraitInterface.lowerReceiver(this), ) return handleRustResult( @@ -4115,7 +4115,7 @@ export class TestTraitInterfaceImpl extends TestTraitInterface { FfiConverterUInt32.checkType(value); } const result = UniFFIScaffolding.callSync( - 201, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value + 246, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value FfiConverterTypeTestTraitInterface.lowerReceiver(this), FfiConverterUInt32.lower(value), ) @@ -4143,7 +4143,7 @@ export class TestTraitInterfaceImpl extends TestTraitInterface { FfiConverterTypeCallbackInterfaceNumbers.checkType(numbers); } const result = UniFFIScaffolding.callSync( - 202, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal + 247, // uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal FfiConverterTypeTestTraitInterface.lowerReceiver(this), FfiConverterTypeCallbackInterfaceNumbers.lower(numbers), ) @@ -4187,11 +4187,11 @@ export class FfiConverterTypeTestTraitInterface extends FfiConverter { } static read(dataStream) { - return this.lift(dataStream.readPointer(20)); + return this.lift(dataStream.readPointer(27)); } static write(dataStream, value) { - dataStream.writePointer(20, this.lower(value)); + dataStream.writePointer(27, this.lower(value)); } static computeSize(value) { @@ -4201,7 +4201,7 @@ export class FfiConverterTypeTestTraitInterface extends FfiConverter { const uniffiCallbackHandlerUniffiBindingsTestsTestTraitInterface = new UniFFICallbackHandler( "TestTraitInterface", - 7, + 10, [ new UniFFICallbackMethodHandler( "noop", @@ -4314,7 +4314,7 @@ export class FfiConverterTypeTestAsyncCallbackInterface extends FfiConverter { } const uniffiCallbackHandlerUniffiBindingsTestsTestAsyncCallbackInterface = new UniFFICallbackHandler( "TestAsyncCallbackInterface", - 4, + 7, [ new UniFFICallbackMethodHandler( "noop", @@ -4427,7 +4427,7 @@ export class FfiConverterTypeTestCallbackInterface extends FfiConverter { } const uniffiCallbackHandlerUniffiBindingsTestsTestCallbackInterface = new UniFFICallbackHandler( "TestCallbackInterface", - 5, + 8, [ new UniFFICallbackMethodHandler( "noop", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsCollision.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsCollision.sys.mjs @@ -46,7 +46,7 @@ if (cb instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestCallbackInterface.checkType(cb); } const result = UniFFIScaffolding.callSync( - 203, // uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback + 248, // uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback FfiConverterTypeTestCallbackInterface.lower(cb), ) return handleRustResult( @@ -101,7 +101,7 @@ export class FfiConverterTypeTestCallbackInterface extends FfiConverter { } const uniffiCallbackHandlerUniffiBindingsTestsCollisionTestCallbackInterface = new UniFFICallbackHandler( "TestCallbackInterface", - 8, + 11, [ new UniFFICallbackMethodHandler( "getValue", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsExternalTypes.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/tests/generated/RustUniffiBindingsTestsExternalTypes.sys.mjs @@ -46,7 +46,7 @@ if (custom instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeHandle.checkType(custom); } const result = UniFFIScaffolding.callSync( - 204, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type + 249, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type FfiConverterTypeHandle.lower(custom), ) return handleRustResult( @@ -70,7 +70,7 @@ if (en instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeEnumWithData.checkType(en); } const result = UniFFIScaffolding.callSync( - 205, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum + 250, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum FfiConverterTypeEnumWithData.lower(en), ) return handleRustResult( @@ -94,7 +94,7 @@ if (int instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeTestInterface.checkType(int); } const result = UniFFIScaffolding.callSync( - 206, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface + 251, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface FfiConverterTypeTestInterface.lower(int), ) return handleRustResult( @@ -118,7 +118,7 @@ if (rec instanceof UniffiSkipJsTypeCheck) { FfiConverterTypeSimpleRec.checkType(rec); } const result = UniFFIScaffolding.callSync( - 207, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record + 252, // uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record FfiConverterTypeSimpleRec.lower(rec), ) return handleRustResult( diff --git a/toolkit/components/uniffi-js/GeneratedScaffolding.cpp b/toolkit/components/uniffi-js/GeneratedScaffolding.cpp @@ -244,6 +244,260 @@ extern "C" { uint32_t ffi_filter_adult_uniffi_contract_version(); uint16_t uniffi_filter_adult_checksum_constructor_filteradultcomponent_new(); uint16_t uniffi_filter_adult_checksum_method_filteradultcomponent_contains(); + RustBuffer ffi_init_rust_components_rustbuffer_alloc(uint64_t, RustCallStatus*); + RustBuffer ffi_init_rust_components_rustbuffer_from_bytes(ForeignBytes, RustCallStatus*); + void ffi_init_rust_components_rustbuffer_free(RustBuffer, RustCallStatus*); + RustBuffer ffi_init_rust_components_rustbuffer_reserve(RustBuffer, uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_poll_u8(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_u8(uint64_t); + uint8_t ffi_init_rust_components_rust_future_complete_u8(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_u8(uint64_t); + void ffi_init_rust_components_rust_future_poll_i8(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_i8(uint64_t); + int8_t ffi_init_rust_components_rust_future_complete_i8(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_i8(uint64_t); + void ffi_init_rust_components_rust_future_poll_u16(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_u16(uint64_t); + uint16_t ffi_init_rust_components_rust_future_complete_u16(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_u16(uint64_t); + void ffi_init_rust_components_rust_future_poll_i16(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_i16(uint64_t); + int16_t ffi_init_rust_components_rust_future_complete_i16(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_i16(uint64_t); + void ffi_init_rust_components_rust_future_poll_u32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_u32(uint64_t); + uint32_t ffi_init_rust_components_rust_future_complete_u32(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_u32(uint64_t); + void ffi_init_rust_components_rust_future_poll_i32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_i32(uint64_t); + int32_t ffi_init_rust_components_rust_future_complete_i32(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_i32(uint64_t); + void ffi_init_rust_components_rust_future_poll_u64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_u64(uint64_t); + uint64_t ffi_init_rust_components_rust_future_complete_u64(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_u64(uint64_t); + void ffi_init_rust_components_rust_future_poll_i64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_i64(uint64_t); + int64_t ffi_init_rust_components_rust_future_complete_i64(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_i64(uint64_t); + void ffi_init_rust_components_rust_future_poll_f32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_f32(uint64_t); + float ffi_init_rust_components_rust_future_complete_f32(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_f32(uint64_t); + void ffi_init_rust_components_rust_future_poll_f64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_f64(uint64_t); + double ffi_init_rust_components_rust_future_complete_f64(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_f64(uint64_t); + void ffi_init_rust_components_rust_future_poll_pointer(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_pointer(uint64_t); + void* ffi_init_rust_components_rust_future_complete_pointer(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_pointer(uint64_t); + void ffi_init_rust_components_rust_future_poll_rust_buffer(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_rust_buffer(uint64_t); + RustBuffer ffi_init_rust_components_rust_future_complete_rust_buffer(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_rust_buffer(uint64_t); + void ffi_init_rust_components_rust_future_poll_void(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_init_rust_components_rust_future_cancel_void(uint64_t); + void ffi_init_rust_components_rust_future_complete_void(uint64_t, RustCallStatus*); + void ffi_init_rust_components_rust_future_free_void(uint64_t); + void uniffi_init_rust_components_fn_func_initialize(RustBuffer, RustCallStatus*); + uint32_t ffi_init_rust_components_uniffi_contract_version(); + uint16_t uniffi_init_rust_components_checksum_func_initialize(); + RustBuffer ffi_logins_rustbuffer_alloc(uint64_t, RustCallStatus*); + RustBuffer ffi_logins_rustbuffer_from_bytes(ForeignBytes, RustCallStatus*); + void ffi_logins_rustbuffer_free(RustBuffer, RustCallStatus*); + RustBuffer ffi_logins_rustbuffer_reserve(RustBuffer, uint64_t, RustCallStatus*); + void ffi_logins_rust_future_poll_u8(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_u8(uint64_t); + uint8_t ffi_logins_rust_future_complete_u8(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_u8(uint64_t); + void ffi_logins_rust_future_poll_i8(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_i8(uint64_t); + int8_t ffi_logins_rust_future_complete_i8(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_i8(uint64_t); + void ffi_logins_rust_future_poll_u16(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_u16(uint64_t); + uint16_t ffi_logins_rust_future_complete_u16(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_u16(uint64_t); + void ffi_logins_rust_future_poll_i16(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_i16(uint64_t); + int16_t ffi_logins_rust_future_complete_i16(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_i16(uint64_t); + void ffi_logins_rust_future_poll_u32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_u32(uint64_t); + uint32_t ffi_logins_rust_future_complete_u32(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_u32(uint64_t); + void ffi_logins_rust_future_poll_i32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_i32(uint64_t); + int32_t ffi_logins_rust_future_complete_i32(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_i32(uint64_t); + void ffi_logins_rust_future_poll_u64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_u64(uint64_t); + uint64_t ffi_logins_rust_future_complete_u64(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_u64(uint64_t); + void ffi_logins_rust_future_poll_i64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_i64(uint64_t); + int64_t ffi_logins_rust_future_complete_i64(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_i64(uint64_t); + void ffi_logins_rust_future_poll_f32(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_f32(uint64_t); + float ffi_logins_rust_future_complete_f32(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_f32(uint64_t); + void ffi_logins_rust_future_poll_f64(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_f64(uint64_t); + double ffi_logins_rust_future_complete_f64(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_f64(uint64_t); + void ffi_logins_rust_future_poll_pointer(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_pointer(uint64_t); + void* ffi_logins_rust_future_complete_pointer(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_pointer(uint64_t); + void ffi_logins_rust_future_poll_rust_buffer(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_rust_buffer(uint64_t); + RustBuffer ffi_logins_rust_future_complete_rust_buffer(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_rust_buffer(uint64_t); + void ffi_logins_rust_future_poll_void(uint64_t, RustFutureContinuationCallback, uint64_t); + void ffi_logins_rust_future_cancel_void(uint64_t); + void ffi_logins_rust_future_complete_void(uint64_t, RustCallStatus*); + void ffi_logins_rust_future_free_void(uint64_t); + void* uniffi_logins_fn_clone_encryptordecryptor(void*, RustCallStatus*); + void uniffi_logins_fn_free_encryptordecryptor(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_keymanager(void*, RustCallStatus*); + void uniffi_logins_fn_free_keymanager(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_loginstore(void*, RustCallStatus*); + void uniffi_logins_fn_free_loginstore(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_managedencryptordecryptor(void*, RustCallStatus*); + void uniffi_logins_fn_free_managedencryptordecryptor(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_nsskeymanager(void*, RustCallStatus*); + void uniffi_logins_fn_free_nsskeymanager(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_primarypasswordauthenticator(void*, RustCallStatus*); + void uniffi_logins_fn_free_primarypasswordauthenticator(void*, RustCallStatus*); + void* uniffi_logins_fn_clone_statickeymanager(void*, RustCallStatus*); + void uniffi_logins_fn_free_statickeymanager(void*, RustCallStatus*); + typedef void (*CallbackInterfaceLoginsEncryptorDecryptorMethod0)(uint64_t, RustBuffer, RustBuffer*, RustCallStatus*); + typedef void (*CallbackInterfaceLoginsEncryptorDecryptorMethod1)(uint64_t, RustBuffer, RustBuffer*, RustCallStatus*); + typedef void (*CallbackInterfaceFreeLogins_EncryptorDecryptor)(uint64_t); + struct VTableCallbackInterfaceLoginsEncryptorDecryptor { + CallbackInterfaceLoginsEncryptorDecryptorMethod0 decrypt; + CallbackInterfaceLoginsEncryptorDecryptorMethod1 encrypt; + CallbackInterfaceFreeLogins_EncryptorDecryptor uniffi_free; + }; + void uniffi_logins_fn_init_callback_vtable_encryptordecryptor(VTableCallbackInterfaceLoginsEncryptorDecryptor*); + typedef void (*CallbackInterfaceLoginsKeyManagerMethod0)(uint64_t, RustBuffer*, RustCallStatus*); + typedef void (*CallbackInterfaceFreeLogins_KeyManager)(uint64_t); + struct VTableCallbackInterfaceLoginsKeyManager { + CallbackInterfaceLoginsKeyManagerMethod0 get_key; + CallbackInterfaceFreeLogins_KeyManager uniffi_free; + }; + void uniffi_logins_fn_init_callback_vtable_keymanager(VTableCallbackInterfaceLoginsKeyManager*); + struct ForeignFutureResultRustBuffer { + RustBuffer return_value; + RustCallStatus call_status; + }; + typedef void (*ForeignFutureCompleterust_buffer)(uint64_t, ForeignFutureResultRustBuffer); + typedef void (*CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod0)(uint64_t, ForeignFutureCompleterust_buffer, uint64_t, ForeignFuture*); + struct ForeignFutureResultVoid { + RustCallStatus call_status; + }; + typedef void (*ForeignFutureCompletevoid)(uint64_t, ForeignFutureResultVoid); + typedef void (*CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod1)(uint64_t, ForeignFutureCompletevoid, uint64_t, ForeignFuture*); + typedef void (*CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod2)(uint64_t, ForeignFutureCompletevoid, uint64_t, ForeignFuture*); + typedef void (*CallbackInterfaceFreeLogins_PrimaryPasswordAuthenticator)(uint64_t); + struct VTableCallbackInterfaceLoginsPrimaryPasswordAuthenticator { + CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod0 get_primary_password; + CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod1 on_authentication_success; + CallbackInterfaceLoginsPrimaryPasswordAuthenticatorMethod2 on_authentication_failure; + CallbackInterfaceFreeLogins_PrimaryPasswordAuthenticator uniffi_free; + }; + void uniffi_logins_fn_init_callback_vtable_primarypasswordauthenticator(VTableCallbackInterfaceLoginsPrimaryPasswordAuthenticator*); + int8_t uniffi_logins_fn_func_check_canary(RustBuffer, RustBuffer, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_func_create_canary(RustBuffer, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_func_create_key(RustCallStatus*); + void* uniffi_logins_fn_func_create_login_store_with_nss_keymanager(RustBuffer, void*, RustCallStatus*); + void* uniffi_logins_fn_func_create_login_store_with_static_key_manager(RustBuffer, RustBuffer, RustCallStatus*); + void* uniffi_logins_fn_func_create_managed_encdec(void*, RustCallStatus*); + void* uniffi_logins_fn_func_create_static_key_manager(RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_encryptordecryptor_decrypt(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_encryptordecryptor_encrypt(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_keymanager_get_key(void*, RustCallStatus*); + void* uniffi_logins_fn_constructor_loginstore_new(RustBuffer, void*, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_add(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_add_many(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_add_many_with_meta(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_add_or_update(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_add_with_meta(void*, RustBuffer, RustCallStatus*); + int64_t uniffi_logins_fn_method_loginstore_count(void*, RustCallStatus*); + int64_t uniffi_logins_fn_method_loginstore_count_by_form_action_origin(void*, RustBuffer, RustCallStatus*); + int64_t uniffi_logins_fn_method_loginstore_count_by_origin(void*, RustBuffer, RustCallStatus*); + int8_t uniffi_logins_fn_method_loginstore_delete(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_delete_many(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_delete_undecryptable_records_for_remote_replacement(void*, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_find_login_to_update(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_get(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_get_by_base_domain(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_get_checkpoint(void*, RustCallStatus*); + int8_t uniffi_logins_fn_method_loginstore_has_logins_by_base_domain(void*, RustBuffer, RustCallStatus*); + int8_t uniffi_logins_fn_method_loginstore_is_empty(void*, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_list(void*, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_register_with_sync_manager(void*, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_reset(void*, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_run_maintenance(void*, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_set_checkpoint(void*, RustBuffer, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_shutdown(void*, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_touch(void*, RustBuffer, RustCallStatus*); + RustBuffer uniffi_logins_fn_method_loginstore_update(void*, RustBuffer, RustBuffer, RustCallStatus*); + void uniffi_logins_fn_method_loginstore_wipe_local(void*, RustCallStatus*); + void* uniffi_logins_fn_constructor_managedencryptordecryptor_new(void*, RustCallStatus*); + void* uniffi_logins_fn_constructor_nsskeymanager_new(void*, RustCallStatus*); + void* uniffi_logins_fn_method_nsskeymanager_into_dyn_key_manager(void*, RustCallStatus*); + uint64_t uniffi_logins_fn_method_primarypasswordauthenticator_get_primary_password(void*); + uint64_t uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_success(void*); + uint64_t uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_failure(void*); + void* uniffi_logins_fn_constructor_statickeymanager_new(RustBuffer, RustCallStatus*); + uint32_t ffi_logins_uniffi_contract_version(); + uint16_t uniffi_logins_checksum_func_check_canary(); + uint16_t uniffi_logins_checksum_func_create_canary(); + uint16_t uniffi_logins_checksum_func_create_key(); + uint16_t uniffi_logins_checksum_func_create_login_store_with_nss_keymanager(); + uint16_t uniffi_logins_checksum_func_create_login_store_with_static_key_manager(); + uint16_t uniffi_logins_checksum_func_create_managed_encdec(); + uint16_t uniffi_logins_checksum_func_create_static_key_manager(); + uint16_t uniffi_logins_checksum_method_encryptordecryptor_decrypt(); + uint16_t uniffi_logins_checksum_method_encryptordecryptor_encrypt(); + uint16_t uniffi_logins_checksum_method_keymanager_get_key(); + uint16_t uniffi_logins_checksum_constructor_loginstore_new(); + uint16_t uniffi_logins_checksum_method_loginstore_add(); + uint16_t uniffi_logins_checksum_method_loginstore_add_many(); + uint16_t uniffi_logins_checksum_method_loginstore_add_many_with_meta(); + uint16_t uniffi_logins_checksum_method_loginstore_add_or_update(); + uint16_t uniffi_logins_checksum_method_loginstore_add_with_meta(); + uint16_t uniffi_logins_checksum_method_loginstore_count(); + uint16_t uniffi_logins_checksum_method_loginstore_count_by_form_action_origin(); + uint16_t uniffi_logins_checksum_method_loginstore_count_by_origin(); + uint16_t uniffi_logins_checksum_method_loginstore_delete(); + uint16_t uniffi_logins_checksum_method_loginstore_delete_many(); + uint16_t uniffi_logins_checksum_method_loginstore_delete_undecryptable_records_for_remote_replacement(); + uint16_t uniffi_logins_checksum_method_loginstore_find_login_to_update(); + uint16_t uniffi_logins_checksum_method_loginstore_get(); + uint16_t uniffi_logins_checksum_method_loginstore_get_by_base_domain(); + uint16_t uniffi_logins_checksum_method_loginstore_get_checkpoint(); + uint16_t uniffi_logins_checksum_method_loginstore_has_logins_by_base_domain(); + uint16_t uniffi_logins_checksum_method_loginstore_is_empty(); + uint16_t uniffi_logins_checksum_method_loginstore_list(); + uint16_t uniffi_logins_checksum_method_loginstore_register_with_sync_manager(); + uint16_t uniffi_logins_checksum_method_loginstore_reset(); + uint16_t uniffi_logins_checksum_method_loginstore_run_maintenance(); + uint16_t uniffi_logins_checksum_method_loginstore_set_checkpoint(); + uint16_t uniffi_logins_checksum_method_loginstore_shutdown(); + uint16_t uniffi_logins_checksum_method_loginstore_touch(); + uint16_t uniffi_logins_checksum_method_loginstore_update(); + uint16_t uniffi_logins_checksum_method_loginstore_wipe_local(); + uint16_t uniffi_logins_checksum_constructor_managedencryptordecryptor_new(); + uint16_t uniffi_logins_checksum_constructor_nsskeymanager_new(); + uint16_t uniffi_logins_checksum_method_nsskeymanager_into_dyn_key_manager(); + uint16_t uniffi_logins_checksum_method_primarypasswordauthenticator_get_primary_password(); + uint16_t uniffi_logins_checksum_method_primarypasswordauthenticator_on_authentication_success(); + uint16_t uniffi_logins_checksum_method_primarypasswordauthenticator_on_authentication_failure(); + uint16_t uniffi_logins_checksum_constructor_statickeymanager_new(); RustBuffer ffi_relevancy_rustbuffer_alloc(uint64_t, RustCallStatus*); RustBuffer ffi_relevancy_rustbuffer_from_bytes(ForeignBytes, RustCallStatus*); void ffi_relevancy_rustbuffer_free(RustBuffer, RustCallStatus*); @@ -900,11 +1154,6 @@ extern "C" { void ffi_viaduct_rust_future_free_void(uint64_t); void* uniffi_viaduct_fn_clone_backend(void*, RustCallStatus*); void uniffi_viaduct_fn_free_backend(void*, RustCallStatus*); - struct ForeignFutureResultRustBuffer { - RustBuffer return_value; - RustCallStatus call_status; - }; - typedef void (*ForeignFutureCompleterust_buffer)(uint64_t, ForeignFutureResultRustBuffer); typedef void (*CallbackInterfaceViaductBackendMethod0)(uint64_t, RustBuffer, RustBuffer, ForeignFutureCompleterust_buffer, uint64_t, ForeignFuture*); typedef void (*CallbackInterfaceFreeViaduct_Backend)(uint64_t); struct VTableCallbackInterfaceViaductBackend { @@ -1094,10 +1343,6 @@ extern "C" { void uniffi_uniffi_bindings_tests_fn_free_testinterface(void*, RustCallStatus*); void* uniffi_uniffi_bindings_tests_fn_clone_testtraitinterface(void*, RustCallStatus*); void uniffi_uniffi_bindings_tests_fn_free_testtraitinterface(void*, RustCallStatus*); - struct ForeignFutureResultVoid { - RustCallStatus call_status; - }; - typedef void (*ForeignFutureCompletevoid)(uint64_t, ForeignFutureResultVoid); typedef void (*CallbackInterfaceUniffiBindingsTestsAsyncTestTraitInterfaceMethod0)(uint64_t, ForeignFutureCompletevoid, uint64_t, ForeignFuture*); struct ForeignFutureResultU32 { uint32_t return_value; @@ -1623,182 +1868,262 @@ class FfiValueObjectHandleFilterAdultFilterAdultComponent { FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kRelevancyRelevancyStorePointerType { - "relevancy::RelevancyStore"_ns, - uniffi_relevancy_fn_clone_relevancystore, - uniffi_relevancy_fn_free_relevancystore, +const static mozilla::uniffi::UniFFIPointerType kLoginsEncryptorDecryptorPointerType { + "logins::EncryptorDecryptor"_ns, + uniffi_logins_fn_clone_encryptordecryptor, + uniffi_logins_fn_free_encryptordecryptor, }; -class FfiValueObjectHandleRelevancyRelevancyStore { +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_logins_encryptor_decryptor(uint64_t uniffiHandle); + +// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback +// interface version +class FfiValueObjectHandleLoginsEncryptorDecryptor { private: + // Did we lower a callback interface, rather than lift an object interface? + // This is weird, but it's a needed work until something like + // https://github.com/mozilla/uniffi-rs/pull/1823 lands. + bool mLoweredCallbackInterface = false; + // The raw FFI value is a pointer. + // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface + // handles are incremented by one at a time, so even on a 32-bit system this + // shouldn't overflow. void* mValue = nullptr; public: - FfiValueObjectHandleRelevancyRelevancyStore() = default; - explicit FfiValueObjectHandleRelevancyRelevancyStore(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsEncryptorDecryptor() = default; + explicit FfiValueObjectHandleLoginsEncryptorDecryptor(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleRelevancyRelevancyStore(const FfiValueObjectHandleRelevancyRelevancyStore&) = delete; - FfiValueObjectHandleRelevancyRelevancyStore& operator=(const FfiValueObjectHandleRelevancyRelevancyStore&) = delete; + FfiValueObjectHandleLoginsEncryptorDecryptor(const FfiValueObjectHandleLoginsEncryptorDecryptor&) = delete; + FfiValueObjectHandleLoginsEncryptorDecryptor& operator=(const FfiValueObjectHandleLoginsEncryptorDecryptor&) = delete; - FfiValueObjectHandleRelevancyRelevancyStore& operator=(FfiValueObjectHandleRelevancyRelevancyStore&& aOther) { + FfiValueObjectHandleLoginsEncryptorDecryptor& operator=(FfiValueObjectHandleLoginsEncryptorDecryptor&& aOther) { FreeHandle(); mValue = aOther.mValue; + mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; aOther.mValue = nullptr; + aOther.mLoweredCallbackInterface = false; return *this; } + // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); + return; + } + double floatValue = aValue.GetAsDouble(); + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); + return; + } + FreeHandle(); + mValue = reinterpret_cast<void *>(intValue); + mLoweredCallbackInterface = true; + } + + // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { if (!aValue.IsUniFFIPointer()) { aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kRelevancyRelevancyStorePointerType)) { + if (!value.IsSamePtrType(&kLoginsEncryptorDecryptorPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } FreeHandle(); mValue = value.ClonePtr(); + mLoweredCallbackInterface = false; } - // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the - // same as `Lower` - void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { - Lower(aValue, aError); - } - + // Lift treats `aDest` as a regular interface void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kRelevancyRelevancyStorePointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsEncryptorDecryptorPointerType); mValue = nullptr; + mLoweredCallbackInterface = false; } void* IntoRust() { auto temp = mValue; mValue = nullptr; + mLoweredCallbackInterface = false; return temp; } - static FfiValueObjectHandleRelevancyRelevancyStore FromRust(void* aValue) { - return FfiValueObjectHandleRelevancyRelevancyStore(aValue); + static FfiValueObjectHandleLoginsEncryptorDecryptor FromRust(void* aValue) { + return FfiValueObjectHandleLoginsEncryptorDecryptor(aValue); } void FreeHandle() { - if (mValue) { + // This behavior depends on if we lowered a callback interface handle or lifted an interface + // pointer. + if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { + printf("FREEING CB %p\n", mValue); + callback_free_logins_encryptor_decryptor(reinterpret_cast<uintptr_t>(mValue)); + mValue = reinterpret_cast<void *>(0); + } else if (!mLoweredCallbackInterface && mValue != nullptr) { + printf("FREEING interface %p\n", mValue); RustCallStatus callStatus{}; - (uniffi_relevancy_fn_free_relevancystore)(mValue, &callStatus); + (uniffi_logins_fn_free_encryptordecryptor)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } + mValue = nullptr; + mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleRelevancyRelevancyStore() { + ~FfiValueObjectHandleLoginsEncryptorDecryptor() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsPointerType { - "remote_settings::RemoteSettings"_ns, - uniffi_remote_settings_fn_clone_remotesettings, - uniffi_remote_settings_fn_free_remotesettings, +const static mozilla::uniffi::UniFFIPointerType kLoginsKeyManagerPointerType { + "logins::KeyManager"_ns, + uniffi_logins_fn_clone_keymanager, + uniffi_logins_fn_free_keymanager, }; -class FfiValueObjectHandleRemoteSettingsRemoteSettings { +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_logins_key_manager(uint64_t uniffiHandle); + +// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback +// interface version +class FfiValueObjectHandleLoginsKeyManager { private: + // Did we lower a callback interface, rather than lift an object interface? + // This is weird, but it's a needed work until something like + // https://github.com/mozilla/uniffi-rs/pull/1823 lands. + bool mLoweredCallbackInterface = false; + // The raw FFI value is a pointer. + // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface + // handles are incremented by one at a time, so even on a 32-bit system this + // shouldn't overflow. void* mValue = nullptr; public: - FfiValueObjectHandleRemoteSettingsRemoteSettings() = default; - explicit FfiValueObjectHandleRemoteSettingsRemoteSettings(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsKeyManager() = default; + explicit FfiValueObjectHandleLoginsKeyManager(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleRemoteSettingsRemoteSettings(const FfiValueObjectHandleRemoteSettingsRemoteSettings&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettings& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettings&) = delete; + FfiValueObjectHandleLoginsKeyManager(const FfiValueObjectHandleLoginsKeyManager&) = delete; + FfiValueObjectHandleLoginsKeyManager& operator=(const FfiValueObjectHandleLoginsKeyManager&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettings& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettings&& aOther) { + FfiValueObjectHandleLoginsKeyManager& operator=(FfiValueObjectHandleLoginsKeyManager&& aOther) { FreeHandle(); mValue = aOther.mValue; + mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; aOther.mValue = nullptr; + aOther.mLoweredCallbackInterface = false; return *this; } + // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); + return; + } + double floatValue = aValue.GetAsDouble(); + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); + return; + } + FreeHandle(); + mValue = reinterpret_cast<void *>(intValue); + mLoweredCallbackInterface = true; + } + + // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { if (!aValue.IsUniFFIPointer()) { aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsPointerType)) { + if (!value.IsSamePtrType(&kLoginsKeyManagerPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } FreeHandle(); mValue = value.ClonePtr(); + mLoweredCallbackInterface = false; } - // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the - // same as `Lower` - void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { - Lower(aValue, aError); - } - + // Lift treats `aDest` as a regular interface void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsPointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsKeyManagerPointerType); mValue = nullptr; + mLoweredCallbackInterface = false; } void* IntoRust() { auto temp = mValue; mValue = nullptr; + mLoweredCallbackInterface = false; return temp; } - static FfiValueObjectHandleRemoteSettingsRemoteSettings FromRust(void* aValue) { - return FfiValueObjectHandleRemoteSettingsRemoteSettings(aValue); + static FfiValueObjectHandleLoginsKeyManager FromRust(void* aValue) { + return FfiValueObjectHandleLoginsKeyManager(aValue); } void FreeHandle() { - if (mValue) { + // This behavior depends on if we lowered a callback interface handle or lifted an interface + // pointer. + if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { + printf("FREEING CB %p\n", mValue); + callback_free_logins_key_manager(reinterpret_cast<uintptr_t>(mValue)); + mValue = reinterpret_cast<void *>(0); + } else if (!mLoweredCallbackInterface && mValue != nullptr) { + printf("FREEING interface %p\n", mValue); RustCallStatus callStatus{}; - (uniffi_remote_settings_fn_free_remotesettings)(mValue, &callStatus); + (uniffi_logins_fn_free_keymanager)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } + mValue = nullptr; + mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleRemoteSettingsRemoteSettings() { + ~FfiValueObjectHandleLoginsKeyManager() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsClientPointerType { - "remote_settings::RemoteSettingsClient"_ns, - uniffi_remote_settings_fn_clone_remotesettingsclient, - uniffi_remote_settings_fn_free_remotesettingsclient, +const static mozilla::uniffi::UniFFIPointerType kLoginsLoginStorePointerType { + "logins::LoginStore"_ns, + uniffi_logins_fn_clone_loginstore, + uniffi_logins_fn_free_loginstore, }; -class FfiValueObjectHandleRemoteSettingsRemoteSettingsClient { +class FfiValueObjectHandleLoginsLoginStore { private: void* mValue = nullptr; public: - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient() = default; - explicit FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsLoginStore() = default; + explicit FfiValueObjectHandleLoginsLoginStore(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(const FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&) = delete; + FfiValueObjectHandleLoginsLoginStore(const FfiValueObjectHandleLoginsLoginStore&) = delete; + FfiValueObjectHandleLoginsLoginStore& operator=(const FfiValueObjectHandleLoginsLoginStore&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&& aOther) { + FfiValueObjectHandleLoginsLoginStore& operator=(FfiValueObjectHandleLoginsLoginStore&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -1812,7 +2137,7 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsClient { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsClientPointerType)) { + if (!value.IsSamePtrType(&kLoginsLoginStorePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -1830,7 +2155,7 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsClient { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsClientPointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsLoginStorePointerType); mValue = nullptr; } @@ -1840,44 +2165,44 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsClient { return temp; } - static FfiValueObjectHandleRemoteSettingsRemoteSettingsClient FromRust(void* aValue) { - return FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(aValue); + static FfiValueObjectHandleLoginsLoginStore FromRust(void* aValue) { + return FfiValueObjectHandleLoginsLoginStore(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_remote_settings_fn_free_remotesettingsclient)(mValue, &callStatus); + (uniffi_logins_fn_free_loginstore)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleRemoteSettingsRemoteSettingsClient() { + ~FfiValueObjectHandleLoginsLoginStore() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsServicePointerType { - "remote_settings::RemoteSettingsService"_ns, - uniffi_remote_settings_fn_clone_remotesettingsservice, - uniffi_remote_settings_fn_free_remotesettingsservice, +const static mozilla::uniffi::UniFFIPointerType kLoginsManagedEncryptorDecryptorPointerType { + "logins::ManagedEncryptorDecryptor"_ns, + uniffi_logins_fn_clone_managedencryptordecryptor, + uniffi_logins_fn_free_managedencryptordecryptor, }; -class FfiValueObjectHandleRemoteSettingsRemoteSettingsService { +class FfiValueObjectHandleLoginsManagedEncryptorDecryptor { private: void* mValue = nullptr; public: - FfiValueObjectHandleRemoteSettingsRemoteSettingsService() = default; - explicit FfiValueObjectHandleRemoteSettingsRemoteSettingsService(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsManagedEncryptorDecryptor() = default; + explicit FfiValueObjectHandleLoginsManagedEncryptorDecryptor(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleRemoteSettingsRemoteSettingsService(const FfiValueObjectHandleRemoteSettingsRemoteSettingsService&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettingsService&) = delete; + FfiValueObjectHandleLoginsManagedEncryptorDecryptor(const FfiValueObjectHandleLoginsManagedEncryptorDecryptor&) = delete; + FfiValueObjectHandleLoginsManagedEncryptorDecryptor& operator=(const FfiValueObjectHandleLoginsManagedEncryptorDecryptor&) = delete; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettingsService&& aOther) { + FfiValueObjectHandleLoginsManagedEncryptorDecryptor& operator=(FfiValueObjectHandleLoginsManagedEncryptorDecryptor&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -1891,7 +2216,7 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsService { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsServicePointerType)) { + if (!value.IsSamePtrType(&kLoginsManagedEncryptorDecryptorPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -1909,7 +2234,7 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsService { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsServicePointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsManagedEncryptorDecryptorPointerType); mValue = nullptr; } @@ -1919,44 +2244,44 @@ class FfiValueObjectHandleRemoteSettingsRemoteSettingsService { return temp; } - static FfiValueObjectHandleRemoteSettingsRemoteSettingsService FromRust(void* aValue) { - return FfiValueObjectHandleRemoteSettingsRemoteSettingsService(aValue); + static FfiValueObjectHandleLoginsManagedEncryptorDecryptor FromRust(void* aValue) { + return FfiValueObjectHandleLoginsManagedEncryptorDecryptor(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_remote_settings_fn_free_remotesettingsservice)(mValue, &callStatus); + (uniffi_logins_fn_free_managedencryptordecryptor)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleRemoteSettingsRemoteSettingsService() { + ~FfiValueObjectHandleLoginsManagedEncryptorDecryptor() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kSearchSearchEngineSelectorPointerType { - "search::SearchEngineSelector"_ns, - uniffi_search_fn_clone_searchengineselector, - uniffi_search_fn_free_searchengineselector, +const static mozilla::uniffi::UniFFIPointerType kLoginsNssKeyManagerPointerType { + "logins::NSSKeyManager"_ns, + uniffi_logins_fn_clone_nsskeymanager, + uniffi_logins_fn_free_nsskeymanager, }; -class FfiValueObjectHandleSearchSearchEngineSelector { +class FfiValueObjectHandleLoginsNssKeyManager { private: void* mValue = nullptr; public: - FfiValueObjectHandleSearchSearchEngineSelector() = default; - explicit FfiValueObjectHandleSearchSearchEngineSelector(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsNssKeyManager() = default; + explicit FfiValueObjectHandleLoginsNssKeyManager(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleSearchSearchEngineSelector(const FfiValueObjectHandleSearchSearchEngineSelector&) = delete; - FfiValueObjectHandleSearchSearchEngineSelector& operator=(const FfiValueObjectHandleSearchSearchEngineSelector&) = delete; + FfiValueObjectHandleLoginsNssKeyManager(const FfiValueObjectHandleLoginsNssKeyManager&) = delete; + FfiValueObjectHandleLoginsNssKeyManager& operator=(const FfiValueObjectHandleLoginsNssKeyManager&) = delete; - FfiValueObjectHandleSearchSearchEngineSelector& operator=(FfiValueObjectHandleSearchSearchEngineSelector&& aOther) { + FfiValueObjectHandleLoginsNssKeyManager& operator=(FfiValueObjectHandleLoginsNssKeyManager&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -1970,7 +2295,7 @@ class FfiValueObjectHandleSearchSearchEngineSelector { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kSearchSearchEngineSelectorPointerType)) { + if (!value.IsSamePtrType(&kLoginsNssKeyManagerPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -1988,7 +2313,7 @@ class FfiValueObjectHandleSearchSearchEngineSelector { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kSearchSearchEngineSelectorPointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsNssKeyManagerPointerType); mValue = nullptr; } @@ -1998,123 +2323,163 @@ class FfiValueObjectHandleSearchSearchEngineSelector { return temp; } - static FfiValueObjectHandleSearchSearchEngineSelector FromRust(void* aValue) { - return FfiValueObjectHandleSearchSearchEngineSelector(aValue); + static FfiValueObjectHandleLoginsNssKeyManager FromRust(void* aValue) { + return FfiValueObjectHandleLoginsNssKeyManager(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_search_fn_free_searchengineselector)(mValue, &callStatus); + (uniffi_logins_fn_free_nsskeymanager)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleSearchSearchEngineSelector() { + ~FfiValueObjectHandleLoginsNssKeyManager() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStorePointerType { - "suggest::SuggestStore"_ns, - uniffi_suggest_fn_clone_suggeststore, - uniffi_suggest_fn_free_suggeststore, +const static mozilla::uniffi::UniFFIPointerType kLoginsPrimaryPasswordAuthenticatorPointerType { + "logins::PrimaryPasswordAuthenticator"_ns, + uniffi_logins_fn_clone_primarypasswordauthenticator, + uniffi_logins_fn_free_primarypasswordauthenticator, }; -class FfiValueObjectHandleSuggestSuggestStore { +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_logins_primary_password_authenticator(uint64_t uniffiHandle); + +// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback +// interface version +class FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator { private: + // Did we lower a callback interface, rather than lift an object interface? + // This is weird, but it's a needed work until something like + // https://github.com/mozilla/uniffi-rs/pull/1823 lands. + bool mLoweredCallbackInterface = false; + // The raw FFI value is a pointer. + // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface + // handles are incremented by one at a time, so even on a 32-bit system this + // shouldn't overflow. void* mValue = nullptr; public: - FfiValueObjectHandleSuggestSuggestStore() = default; - explicit FfiValueObjectHandleSuggestSuggestStore(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator() = default; + explicit FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleSuggestSuggestStore(const FfiValueObjectHandleSuggestSuggestStore&) = delete; - FfiValueObjectHandleSuggestSuggestStore& operator=(const FfiValueObjectHandleSuggestSuggestStore&) = delete; + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator(const FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator&) = delete; + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator& operator=(const FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator&) = delete; - FfiValueObjectHandleSuggestSuggestStore& operator=(FfiValueObjectHandleSuggestSuggestStore&& aOther) { + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator& operator=(FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator&& aOther) { FreeHandle(); mValue = aOther.mValue; + mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; aOther.mValue = nullptr; + aOther.mLoweredCallbackInterface = false; return *this; } + // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); + return; + } + double floatValue = aValue.GetAsDouble(); + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); + return; + } + FreeHandle(); + mValue = reinterpret_cast<void *>(intValue); + mLoweredCallbackInterface = true; + } + + // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { if (!aValue.IsUniFFIPointer()) { aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kSuggestSuggestStorePointerType)) { + if (!value.IsSamePtrType(&kLoginsPrimaryPasswordAuthenticatorPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } FreeHandle(); mValue = value.ClonePtr(); + mLoweredCallbackInterface = false; } - // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the - // same as `Lower` - void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { - Lower(aValue, aError); - } - + // Lift treats `aDest` as a regular interface void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kSuggestSuggestStorePointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsPrimaryPasswordAuthenticatorPointerType); mValue = nullptr; + mLoweredCallbackInterface = false; } void* IntoRust() { auto temp = mValue; mValue = nullptr; + mLoweredCallbackInterface = false; return temp; } - static FfiValueObjectHandleSuggestSuggestStore FromRust(void* aValue) { - return FfiValueObjectHandleSuggestSuggestStore(aValue); + static FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator FromRust(void* aValue) { + return FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator(aValue); } void FreeHandle() { - if (mValue) { + // This behavior depends on if we lowered a callback interface handle or lifted an interface + // pointer. + if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { + printf("FREEING CB %p\n", mValue); + callback_free_logins_primary_password_authenticator(reinterpret_cast<uintptr_t>(mValue)); + mValue = reinterpret_cast<void *>(0); + } else if (!mLoweredCallbackInterface && mValue != nullptr) { + printf("FREEING interface %p\n", mValue); RustCallStatus callStatus{}; - (uniffi_suggest_fn_free_suggeststore)(mValue, &callStatus); + (uniffi_logins_fn_free_primarypasswordauthenticator)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } + mValue = nullptr; + mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleSuggestSuggestStore() { + ~FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStoreBuilderPointerType { - "suggest::SuggestStoreBuilder"_ns, - uniffi_suggest_fn_clone_suggeststorebuilder, - uniffi_suggest_fn_free_suggeststorebuilder, +const static mozilla::uniffi::UniFFIPointerType kLoginsStaticKeyManagerPointerType { + "logins::StaticKeyManager"_ns, + uniffi_logins_fn_clone_statickeymanager, + uniffi_logins_fn_free_statickeymanager, }; -class FfiValueObjectHandleSuggestSuggestStoreBuilder { +class FfiValueObjectHandleLoginsStaticKeyManager { private: void* mValue = nullptr; public: - FfiValueObjectHandleSuggestSuggestStoreBuilder() = default; - explicit FfiValueObjectHandleSuggestSuggestStoreBuilder(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleLoginsStaticKeyManager() = default; + explicit FfiValueObjectHandleLoginsStaticKeyManager(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleSuggestSuggestStoreBuilder(const FfiValueObjectHandleSuggestSuggestStoreBuilder&) = delete; - FfiValueObjectHandleSuggestSuggestStoreBuilder& operator=(const FfiValueObjectHandleSuggestSuggestStoreBuilder&) = delete; + FfiValueObjectHandleLoginsStaticKeyManager(const FfiValueObjectHandleLoginsStaticKeyManager&) = delete; + FfiValueObjectHandleLoginsStaticKeyManager& operator=(const FfiValueObjectHandleLoginsStaticKeyManager&) = delete; - FfiValueObjectHandleSuggestSuggestStoreBuilder& operator=(FfiValueObjectHandleSuggestSuggestStoreBuilder&& aOther) { + FfiValueObjectHandleLoginsStaticKeyManager& operator=(FfiValueObjectHandleLoginsStaticKeyManager&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2128,7 +2493,7 @@ class FfiValueObjectHandleSuggestSuggestStoreBuilder { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kSuggestSuggestStoreBuilderPointerType)) { + if (!value.IsSamePtrType(&kLoginsStaticKeyManagerPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2146,7 +2511,7 @@ class FfiValueObjectHandleSuggestSuggestStoreBuilder { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kSuggestSuggestStoreBuilderPointerType); + dom::UniFFIPointer::Create(mValue, &kLoginsStaticKeyManagerPointerType); mValue = nullptr; } @@ -2156,44 +2521,44 @@ class FfiValueObjectHandleSuggestSuggestStoreBuilder { return temp; } - static FfiValueObjectHandleSuggestSuggestStoreBuilder FromRust(void* aValue) { - return FfiValueObjectHandleSuggestSuggestStoreBuilder(aValue); + static FfiValueObjectHandleLoginsStaticKeyManager FromRust(void* aValue) { + return FfiValueObjectHandleLoginsStaticKeyManager(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_suggest_fn_free_suggeststorebuilder)(mValue, &callStatus); + (uniffi_logins_fn_free_statickeymanager)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleSuggestSuggestStoreBuilder() { + ~FfiValueObjectHandleLoginsStaticKeyManager() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kTabsRemoteCommandStorePointerType { - "tabs::RemoteCommandStore"_ns, - uniffi_tabs_fn_clone_remotecommandstore, - uniffi_tabs_fn_free_remotecommandstore, +const static mozilla::uniffi::UniFFIPointerType kRelevancyRelevancyStorePointerType { + "relevancy::RelevancyStore"_ns, + uniffi_relevancy_fn_clone_relevancystore, + uniffi_relevancy_fn_free_relevancystore, }; -class FfiValueObjectHandleTabsRemoteCommandStore { +class FfiValueObjectHandleRelevancyRelevancyStore { private: void* mValue = nullptr; public: - FfiValueObjectHandleTabsRemoteCommandStore() = default; - explicit FfiValueObjectHandleTabsRemoteCommandStore(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleRelevancyRelevancyStore() = default; + explicit FfiValueObjectHandleRelevancyRelevancyStore(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleTabsRemoteCommandStore(const FfiValueObjectHandleTabsRemoteCommandStore&) = delete; - FfiValueObjectHandleTabsRemoteCommandStore& operator=(const FfiValueObjectHandleTabsRemoteCommandStore&) = delete; + FfiValueObjectHandleRelevancyRelevancyStore(const FfiValueObjectHandleRelevancyRelevancyStore&) = delete; + FfiValueObjectHandleRelevancyRelevancyStore& operator=(const FfiValueObjectHandleRelevancyRelevancyStore&) = delete; - FfiValueObjectHandleTabsRemoteCommandStore& operator=(FfiValueObjectHandleTabsRemoteCommandStore&& aOther) { + FfiValueObjectHandleRelevancyRelevancyStore& operator=(FfiValueObjectHandleRelevancyRelevancyStore&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2207,7 +2572,7 @@ class FfiValueObjectHandleTabsRemoteCommandStore { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kTabsRemoteCommandStorePointerType)) { + if (!value.IsSamePtrType(&kRelevancyRelevancyStorePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2225,7 +2590,7 @@ class FfiValueObjectHandleTabsRemoteCommandStore { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kTabsRemoteCommandStorePointerType); + dom::UniFFIPointer::Create(mValue, &kRelevancyRelevancyStorePointerType); mValue = nullptr; } @@ -2235,44 +2600,44 @@ class FfiValueObjectHandleTabsRemoteCommandStore { return temp; } - static FfiValueObjectHandleTabsRemoteCommandStore FromRust(void* aValue) { - return FfiValueObjectHandleTabsRemoteCommandStore(aValue); + static FfiValueObjectHandleRelevancyRelevancyStore FromRust(void* aValue) { + return FfiValueObjectHandleRelevancyRelevancyStore(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_tabs_fn_free_remotecommandstore)(mValue, &callStatus); + (uniffi_relevancy_fn_free_relevancystore)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleTabsRemoteCommandStore() { + ~FfiValueObjectHandleRelevancyRelevancyStore() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kTabsTabsBridgedEnginePointerType { - "tabs::TabsBridgedEngine"_ns, - uniffi_tabs_fn_clone_tabsbridgedengine, - uniffi_tabs_fn_free_tabsbridgedengine, +const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsPointerType { + "remote_settings::RemoteSettings"_ns, + uniffi_remote_settings_fn_clone_remotesettings, + uniffi_remote_settings_fn_free_remotesettings, }; -class FfiValueObjectHandleTabsTabsBridgedEngine { +class FfiValueObjectHandleRemoteSettingsRemoteSettings { private: void* mValue = nullptr; public: - FfiValueObjectHandleTabsTabsBridgedEngine() = default; - explicit FfiValueObjectHandleTabsTabsBridgedEngine(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleRemoteSettingsRemoteSettings() = default; + explicit FfiValueObjectHandleRemoteSettingsRemoteSettings(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleTabsTabsBridgedEngine(const FfiValueObjectHandleTabsTabsBridgedEngine&) = delete; - FfiValueObjectHandleTabsTabsBridgedEngine& operator=(const FfiValueObjectHandleTabsTabsBridgedEngine&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettings(const FfiValueObjectHandleRemoteSettingsRemoteSettings&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettings& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettings&) = delete; - FfiValueObjectHandleTabsTabsBridgedEngine& operator=(FfiValueObjectHandleTabsTabsBridgedEngine&& aOther) { + FfiValueObjectHandleRemoteSettingsRemoteSettings& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettings&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2286,7 +2651,7 @@ class FfiValueObjectHandleTabsTabsBridgedEngine { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kTabsTabsBridgedEnginePointerType)) { + if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2304,7 +2669,7 @@ class FfiValueObjectHandleTabsTabsBridgedEngine { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kTabsTabsBridgedEnginePointerType); + dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsPointerType); mValue = nullptr; } @@ -2314,44 +2679,44 @@ class FfiValueObjectHandleTabsTabsBridgedEngine { return temp; } - static FfiValueObjectHandleTabsTabsBridgedEngine FromRust(void* aValue) { - return FfiValueObjectHandleTabsTabsBridgedEngine(aValue); + static FfiValueObjectHandleRemoteSettingsRemoteSettings FromRust(void* aValue) { + return FfiValueObjectHandleRemoteSettingsRemoteSettings(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_tabs_fn_free_tabsbridgedengine)(mValue, &callStatus); + (uniffi_remote_settings_fn_free_remotesettings)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleTabsTabsBridgedEngine() { + ~FfiValueObjectHandleRemoteSettingsRemoteSettings() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kTabsTabsStorePointerType { - "tabs::TabsStore"_ns, - uniffi_tabs_fn_clone_tabsstore, - uniffi_tabs_fn_free_tabsstore, +const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsClientPointerType { + "remote_settings::RemoteSettingsClient"_ns, + uniffi_remote_settings_fn_clone_remotesettingsclient, + uniffi_remote_settings_fn_free_remotesettingsclient, }; -class FfiValueObjectHandleTabsTabsStore { +class FfiValueObjectHandleRemoteSettingsRemoteSettingsClient { private: void* mValue = nullptr; public: - FfiValueObjectHandleTabsTabsStore() = default; - explicit FfiValueObjectHandleTabsTabsStore(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient() = default; + explicit FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleTabsTabsStore(const FfiValueObjectHandleTabsTabsStore&) = delete; - FfiValueObjectHandleTabsTabsStore& operator=(const FfiValueObjectHandleTabsTabsStore&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(const FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&) = delete; - FfiValueObjectHandleTabsTabsStore& operator=(FfiValueObjectHandleTabsTabsStore&& aOther) { + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettingsClient&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2365,7 +2730,7 @@ class FfiValueObjectHandleTabsTabsStore { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kTabsTabsStorePointerType)) { + if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsClientPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2383,7 +2748,7 @@ class FfiValueObjectHandleTabsTabsStore { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kTabsTabsStorePointerType); + dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsClientPointerType); mValue = nullptr; } @@ -2393,163 +2758,123 @@ class FfiValueObjectHandleTabsTabsStore { return temp; } - static FfiValueObjectHandleTabsTabsStore FromRust(void* aValue) { - return FfiValueObjectHandleTabsTabsStore(aValue); + static FfiValueObjectHandleRemoteSettingsRemoteSettingsClient FromRust(void* aValue) { + return FfiValueObjectHandleRemoteSettingsRemoteSettingsClient(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_tabs_fn_free_tabsstore)(mValue, &callStatus); + (uniffi_remote_settings_fn_free_remotesettingsclient)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleTabsTabsStore() { + ~FfiValueObjectHandleRemoteSettingsRemoteSettingsClient() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kViaductBackendPointerType { - "viaduct::Backend"_ns, - uniffi_viaduct_fn_clone_backend, - uniffi_viaduct_fn_free_backend, +const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsServicePointerType { + "remote_settings::RemoteSettingsService"_ns, + uniffi_remote_settings_fn_clone_remotesettingsservice, + uniffi_remote_settings_fn_free_remotesettingsservice, }; -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_viaduct_backend(uint64_t uniffiHandle); - -// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback -// interface version -class FfiValueObjectHandleViaductBackend { +class FfiValueObjectHandleRemoteSettingsRemoteSettingsService { private: - // Did we lower a callback interface, rather than lift an object interface? - // This is weird, but it's a needed work until something like - // https://github.com/mozilla/uniffi-rs/pull/1823 lands. - bool mLoweredCallbackInterface = false; - // The raw FFI value is a pointer. - // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface - // handles are incremented by one at a time, so even on a 32-bit system this - // shouldn't overflow. void* mValue = nullptr; public: - FfiValueObjectHandleViaductBackend() = default; - explicit FfiValueObjectHandleViaductBackend(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleRemoteSettingsRemoteSettingsService() = default; + explicit FfiValueObjectHandleRemoteSettingsRemoteSettingsService(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleViaductBackend(const FfiValueObjectHandleViaductBackend&) = delete; - FfiValueObjectHandleViaductBackend& operator=(const FfiValueObjectHandleViaductBackend&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService(const FfiValueObjectHandleRemoteSettingsRemoteSettingsService&) = delete; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService& operator=(const FfiValueObjectHandleRemoteSettingsRemoteSettingsService&) = delete; - FfiValueObjectHandleViaductBackend& operator=(FfiValueObjectHandleViaductBackend&& aOther) { + FfiValueObjectHandleRemoteSettingsRemoteSettingsService& operator=(FfiValueObjectHandleRemoteSettingsRemoteSettingsService&& aOther) { FreeHandle(); mValue = aOther.mValue; - mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; aOther.mValue = nullptr; - aOther.mLoweredCallbackInterface = false; return *this; } - // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); - return; - } - double floatValue = aValue.GetAsDouble(); - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); - return; - } - FreeHandle(); - mValue = reinterpret_cast<void *>(intValue); - mLoweredCallbackInterface = true; - } - - // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. - void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { if (!aValue.IsUniFFIPointer()) { aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kViaductBackendPointerType)) { + if (!value.IsSamePtrType(&kRemoteSettingsRemoteSettingsServicePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } FreeHandle(); mValue = value.ClonePtr(); - mLoweredCallbackInterface = false; } - // Lift treats `aDest` as a regular interface + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); + } + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kViaductBackendPointerType); + dom::UniFFIPointer::Create(mValue, &kRemoteSettingsRemoteSettingsServicePointerType); mValue = nullptr; - mLoweredCallbackInterface = false; } void* IntoRust() { auto temp = mValue; mValue = nullptr; - mLoweredCallbackInterface = false; return temp; } - static FfiValueObjectHandleViaductBackend FromRust(void* aValue) { - return FfiValueObjectHandleViaductBackend(aValue); + static FfiValueObjectHandleRemoteSettingsRemoteSettingsService FromRust(void* aValue) { + return FfiValueObjectHandleRemoteSettingsRemoteSettingsService(aValue); } void FreeHandle() { - // This behavior depends on if we lowered a callback interface handle or lifted an interface - // pointer. - if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { - printf("FREEING CB %p\n", mValue); - callback_free_viaduct_backend(reinterpret_cast<uintptr_t>(mValue)); - mValue = reinterpret_cast<void *>(0); - } else if (!mLoweredCallbackInterface && mValue != nullptr) { - printf("FREEING interface %p\n", mValue); + if (mValue) { RustCallStatus callStatus{}; - (uniffi_viaduct_fn_free_backend)(mValue, &callStatus); + (uniffi_remote_settings_fn_free_remotesettingsservice)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } - mValue = nullptr; - mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleViaductBackend() { + ~FfiValueObjectHandleRemoteSettingsRemoteSettingsService() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kWebextstorageWebExtStorageBridgedEnginePointerType { - "webextstorage::WebExtStorageBridgedEngine"_ns, - uniffi_webext_storage_fn_clone_webextstoragebridgedengine, - uniffi_webext_storage_fn_free_webextstoragebridgedengine, +const static mozilla::uniffi::UniFFIPointerType kSearchSearchEngineSelectorPointerType { + "search::SearchEngineSelector"_ns, + uniffi_search_fn_clone_searchengineselector, + uniffi_search_fn_free_searchengineselector, }; -class FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine { +class FfiValueObjectHandleSearchSearchEngineSelector { private: void* mValue = nullptr; public: - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine() = default; - explicit FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleSearchSearchEngineSelector() = default; + explicit FfiValueObjectHandleSearchSearchEngineSelector(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(const FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&) = delete; - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine& operator=(const FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&) = delete; + FfiValueObjectHandleSearchSearchEngineSelector(const FfiValueObjectHandleSearchSearchEngineSelector&) = delete; + FfiValueObjectHandleSearchSearchEngineSelector& operator=(const FfiValueObjectHandleSearchSearchEngineSelector&) = delete; - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine& operator=(FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&& aOther) { + FfiValueObjectHandleSearchSearchEngineSelector& operator=(FfiValueObjectHandleSearchSearchEngineSelector&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2563,7 +2888,7 @@ class FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kWebextstorageWebExtStorageBridgedEnginePointerType)) { + if (!value.IsSamePtrType(&kSearchSearchEngineSelectorPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2581,7 +2906,7 @@ class FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kWebextstorageWebExtStorageBridgedEnginePointerType); + dom::UniFFIPointer::Create(mValue, &kSearchSearchEngineSelectorPointerType); mValue = nullptr; } @@ -2591,44 +2916,44 @@ class FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine { return temp; } - static FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine FromRust(void* aValue) { - return FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(aValue); + static FfiValueObjectHandleSearchSearchEngineSelector FromRust(void* aValue) { + return FfiValueObjectHandleSearchSearchEngineSelector(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_webext_storage_fn_free_webextstoragebridgedengine)(mValue, &callStatus); + (uniffi_search_fn_free_searchengineselector)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine() { + ~FfiValueObjectHandleSearchSearchEngineSelector() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kWebextstorageWebExtStorageStorePointerType { - "webextstorage::WebExtStorageStore"_ns, - uniffi_webext_storage_fn_clone_webextstoragestore, - uniffi_webext_storage_fn_free_webextstoragestore, +const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStorePointerType { + "suggest::SuggestStore"_ns, + uniffi_suggest_fn_clone_suggeststore, + uniffi_suggest_fn_free_suggeststore, }; -class FfiValueObjectHandleWebextstorageWebExtStorageStore { +class FfiValueObjectHandleSuggestSuggestStore { private: void* mValue = nullptr; public: - FfiValueObjectHandleWebextstorageWebExtStorageStore() = default; - explicit FfiValueObjectHandleWebextstorageWebExtStorageStore(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleSuggestSuggestStore() = default; + explicit FfiValueObjectHandleSuggestSuggestStore(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleWebextstorageWebExtStorageStore(const FfiValueObjectHandleWebextstorageWebExtStorageStore&) = delete; - FfiValueObjectHandleWebextstorageWebExtStorageStore& operator=(const FfiValueObjectHandleWebextstorageWebExtStorageStore&) = delete; + FfiValueObjectHandleSuggestSuggestStore(const FfiValueObjectHandleSuggestSuggestStore&) = delete; + FfiValueObjectHandleSuggestSuggestStore& operator=(const FfiValueObjectHandleSuggestSuggestStore&) = delete; - FfiValueObjectHandleWebextstorageWebExtStorageStore& operator=(FfiValueObjectHandleWebextstorageWebExtStorageStore&& aOther) { + FfiValueObjectHandleSuggestSuggestStore& operator=(FfiValueObjectHandleSuggestSuggestStore&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2642,7 +2967,7 @@ class FfiValueObjectHandleWebextstorageWebExtStorageStore { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kWebextstorageWebExtStorageStorePointerType)) { + if (!value.IsSamePtrType(&kSuggestSuggestStorePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2660,7 +2985,7 @@ class FfiValueObjectHandleWebextstorageWebExtStorageStore { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kWebextstorageWebExtStorageStorePointerType); + dom::UniFFIPointer::Create(mValue, &kSuggestSuggestStorePointerType); mValue = nullptr; } @@ -2670,46 +2995,44 @@ class FfiValueObjectHandleWebextstorageWebExtStorageStore { return temp; } - static FfiValueObjectHandleWebextstorageWebExtStorageStore FromRust(void* aValue) { - return FfiValueObjectHandleWebextstorageWebExtStorageStore(aValue); + static FfiValueObjectHandleSuggestSuggestStore FromRust(void* aValue) { + return FfiValueObjectHandleSuggestSuggestStore(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_webext_storage_fn_free_webextstoragestore)(mValue, &callStatus); + (uniffi_suggest_fn_free_suggeststore)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleWebextstorageWebExtStorageStore() { + ~FfiValueObjectHandleSuggestSuggestStore() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; - -#ifdef MOZ_UNIFFI_FIXTURES -const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsTestInterfacePointerType { - "uniffi_bindings_tests::TestInterface"_ns, - uniffi_uniffi_bindings_tests_fn_clone_testinterface, - uniffi_uniffi_bindings_tests_fn_free_testinterface, +const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStoreBuilderPointerType { + "suggest::SuggestStoreBuilder"_ns, + uniffi_suggest_fn_clone_suggeststorebuilder, + uniffi_suggest_fn_free_suggeststorebuilder, }; -class FfiValueObjectHandleUniffiBindingsTestsTestInterface { +class FfiValueObjectHandleSuggestSuggestStoreBuilder { private: void* mValue = nullptr; public: - FfiValueObjectHandleUniffiBindingsTestsTestInterface() = default; - explicit FfiValueObjectHandleUniffiBindingsTestsTestInterface(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleSuggestSuggestStoreBuilder() = default; + explicit FfiValueObjectHandleSuggestSuggestStoreBuilder(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleUniffiBindingsTestsTestInterface(const FfiValueObjectHandleUniffiBindingsTestsTestInterface&) = delete; - FfiValueObjectHandleUniffiBindingsTestsTestInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsTestInterface&) = delete; + FfiValueObjectHandleSuggestSuggestStoreBuilder(const FfiValueObjectHandleSuggestSuggestStoreBuilder&) = delete; + FfiValueObjectHandleSuggestSuggestStoreBuilder& operator=(const FfiValueObjectHandleSuggestSuggestStoreBuilder&) = delete; - FfiValueObjectHandleUniffiBindingsTestsTestInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsTestInterface&& aOther) { + FfiValueObjectHandleSuggestSuggestStoreBuilder& operator=(FfiValueObjectHandleSuggestSuggestStoreBuilder&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2723,7 +3046,7 @@ class FfiValueObjectHandleUniffiBindingsTestsTestInterface { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kUniffiBindingsTestsTestInterfacePointerType)) { + if (!value.IsSamePtrType(&kSuggestSuggestStoreBuilderPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2741,7 +3064,7 @@ class FfiValueObjectHandleUniffiBindingsTestsTestInterface { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsTestInterfacePointerType); + dom::UniFFIPointer::Create(mValue, &kSuggestSuggestStoreBuilderPointerType); mValue = nullptr; } @@ -2751,44 +3074,44 @@ class FfiValueObjectHandleUniffiBindingsTestsTestInterface { return temp; } - static FfiValueObjectHandleUniffiBindingsTestsTestInterface FromRust(void* aValue) { - return FfiValueObjectHandleUniffiBindingsTestsTestInterface(aValue); + static FfiValueObjectHandleSuggestSuggestStoreBuilder FromRust(void* aValue) { + return FfiValueObjectHandleSuggestSuggestStoreBuilder(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_uniffi_bindings_tests_fn_free_testinterface)(mValue, &callStatus); + (uniffi_suggest_fn_free_suggeststorebuilder)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleUniffiBindingsTestsTestInterface() { + ~FfiValueObjectHandleSuggestSuggestStoreBuilder() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsAsyncInterfacePointerType { - "uniffi_bindings_tests::AsyncInterface"_ns, - uniffi_uniffi_bindings_tests_fn_clone_asyncinterface, - uniffi_uniffi_bindings_tests_fn_free_asyncinterface, +const static mozilla::uniffi::UniFFIPointerType kTabsRemoteCommandStorePointerType { + "tabs::RemoteCommandStore"_ns, + uniffi_tabs_fn_clone_remotecommandstore, + uniffi_tabs_fn_free_remotecommandstore, }; -class FfiValueObjectHandleUniffiBindingsTestsAsyncInterface { +class FfiValueObjectHandleTabsRemoteCommandStore { private: void* mValue = nullptr; public: - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface() = default; - explicit FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleTabsRemoteCommandStore() = default; + explicit FfiValueObjectHandleTabsRemoteCommandStore(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(const FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&) = delete; - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&) = delete; + FfiValueObjectHandleTabsRemoteCommandStore(const FfiValueObjectHandleTabsRemoteCommandStore&) = delete; + FfiValueObjectHandleTabsRemoteCommandStore& operator=(const FfiValueObjectHandleTabsRemoteCommandStore&) = delete; - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&& aOther) { + FfiValueObjectHandleTabsRemoteCommandStore& operator=(FfiValueObjectHandleTabsRemoteCommandStore&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -2802,7 +3125,7 @@ class FfiValueObjectHandleUniffiBindingsTestsAsyncInterface { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kUniffiBindingsTestsAsyncInterfacePointerType)) { + if (!value.IsSamePtrType(&kTabsRemoteCommandStorePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -2820,7 +3143,7 @@ class FfiValueObjectHandleUniffiBindingsTestsAsyncInterface { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsAsyncInterfacePointerType); + dom::UniFFIPointer::Create(mValue, &kTabsRemoteCommandStorePointerType); mValue = nullptr; } @@ -2830,163 +3153,123 @@ class FfiValueObjectHandleUniffiBindingsTestsAsyncInterface { return temp; } - static FfiValueObjectHandleUniffiBindingsTestsAsyncInterface FromRust(void* aValue) { - return FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(aValue); + static FfiValueObjectHandleTabsRemoteCommandStore FromRust(void* aValue) { + return FfiValueObjectHandleTabsRemoteCommandStore(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_uniffi_bindings_tests_fn_free_asyncinterface)(mValue, &callStatus); + (uniffi_tabs_fn_free_remotecommandstore)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleUniffiBindingsTestsAsyncInterface() { + ~FfiValueObjectHandleTabsRemoteCommandStore() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsAsyncTestTraitInterfacePointerType { - "uniffi_bindings_tests::AsyncTestTraitInterface"_ns, - uniffi_uniffi_bindings_tests_fn_clone_asynctesttraitinterface, - uniffi_uniffi_bindings_tests_fn_free_asynctesttraitinterface, +const static mozilla::uniffi::UniFFIPointerType kTabsTabsBridgedEnginePointerType { + "tabs::TabsBridgedEngine"_ns, + uniffi_tabs_fn_clone_tabsbridgedengine, + uniffi_tabs_fn_free_tabsbridgedengine, }; -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_uniffi_bindings_tests_async_test_trait_interface(uint64_t uniffiHandle); - -// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback -// interface version -class FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface { +class FfiValueObjectHandleTabsTabsBridgedEngine { private: - // Did we lower a callback interface, rather than lift an object interface? - // This is weird, but it's a needed work until something like - // https://github.com/mozilla/uniffi-rs/pull/1823 lands. - bool mLoweredCallbackInterface = false; - // The raw FFI value is a pointer. - // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface - // handles are incremented by one at a time, so even on a 32-bit system this - // shouldn't overflow. void* mValue = nullptr; public: - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface() = default; - explicit FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleTabsTabsBridgedEngine() = default; + explicit FfiValueObjectHandleTabsTabsBridgedEngine(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(const FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&) = delete; - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&) = delete; + FfiValueObjectHandleTabsTabsBridgedEngine(const FfiValueObjectHandleTabsTabsBridgedEngine&) = delete; + FfiValueObjectHandleTabsTabsBridgedEngine& operator=(const FfiValueObjectHandleTabsTabsBridgedEngine&) = delete; - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&& aOther) { + FfiValueObjectHandleTabsTabsBridgedEngine& operator=(FfiValueObjectHandleTabsTabsBridgedEngine&& aOther) { FreeHandle(); mValue = aOther.mValue; - mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; aOther.mValue = nullptr; - aOther.mLoweredCallbackInterface = false; return *this; } - // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); - return; - } - double floatValue = aValue.GetAsDouble(); - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); - return; - } - FreeHandle(); - mValue = reinterpret_cast<void *>(intValue); - mLoweredCallbackInterface = true; - } - - // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. - void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { if (!aValue.IsUniFFIPointer()) { aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kUniffiBindingsTestsAsyncTestTraitInterfacePointerType)) { + if (!value.IsSamePtrType(&kTabsTabsBridgedEnginePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } FreeHandle(); mValue = value.ClonePtr(); - mLoweredCallbackInterface = false; } - // Lift treats `aDest` as a regular interface + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); + } + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType); + dom::UniFFIPointer::Create(mValue, &kTabsTabsBridgedEnginePointerType); mValue = nullptr; - mLoweredCallbackInterface = false; } void* IntoRust() { auto temp = mValue; mValue = nullptr; - mLoweredCallbackInterface = false; return temp; } - static FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface FromRust(void* aValue) { - return FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(aValue); + static FfiValueObjectHandleTabsTabsBridgedEngine FromRust(void* aValue) { + return FfiValueObjectHandleTabsTabsBridgedEngine(aValue); } void FreeHandle() { - // This behavior depends on if we lowered a callback interface handle or lifted an interface - // pointer. - if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { - printf("FREEING CB %p\n", mValue); - callback_free_uniffi_bindings_tests_async_test_trait_interface(reinterpret_cast<uintptr_t>(mValue)); - mValue = reinterpret_cast<void *>(0); - } else if (!mLoweredCallbackInterface && mValue != nullptr) { - printf("FREEING interface %p\n", mValue); + if (mValue) { RustCallStatus callStatus{}; - (uniffi_uniffi_bindings_tests_fn_free_asynctesttraitinterface)(mValue, &callStatus); + (uniffi_tabs_fn_free_tabsbridgedengine)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } - mValue = nullptr; - mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface() { + ~FfiValueObjectHandleTabsTabsBridgedEngine() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsComplexMethodsPointerType { - "uniffi_bindings_tests::ComplexMethods"_ns, - uniffi_uniffi_bindings_tests_fn_clone_complexmethods, - uniffi_uniffi_bindings_tests_fn_free_complexmethods, +const static mozilla::uniffi::UniFFIPointerType kTabsTabsStorePointerType { + "tabs::TabsStore"_ns, + uniffi_tabs_fn_clone_tabsstore, + uniffi_tabs_fn_free_tabsstore, }; -class FfiValueObjectHandleUniffiBindingsTestsComplexMethods { +class FfiValueObjectHandleTabsTabsStore { private: void* mValue = nullptr; public: - FfiValueObjectHandleUniffiBindingsTestsComplexMethods() = default; - explicit FfiValueObjectHandleUniffiBindingsTestsComplexMethods(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleTabsTabsStore() = default; + explicit FfiValueObjectHandleTabsTabsStore(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleUniffiBindingsTestsComplexMethods(const FfiValueObjectHandleUniffiBindingsTestsComplexMethods&) = delete; - FfiValueObjectHandleUniffiBindingsTestsComplexMethods& operator=(const FfiValueObjectHandleUniffiBindingsTestsComplexMethods&) = delete; + FfiValueObjectHandleTabsTabsStore(const FfiValueObjectHandleTabsTabsStore&) = delete; + FfiValueObjectHandleTabsTabsStore& operator=(const FfiValueObjectHandleTabsTabsStore&) = delete; - FfiValueObjectHandleUniffiBindingsTestsComplexMethods& operator=(FfiValueObjectHandleUniffiBindingsTestsComplexMethods&& aOther) { + FfiValueObjectHandleTabsTabsStore& operator=(FfiValueObjectHandleTabsTabsStore&& aOther) { FreeHandle(); mValue = aOther.mValue; aOther.mValue = nullptr; @@ -3000,7 +3283,7 @@ class FfiValueObjectHandleUniffiBindingsTestsComplexMethods { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kUniffiBindingsTestsComplexMethodsPointerType)) { + if (!value.IsSamePtrType(&kTabsTabsStorePointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -3018,7 +3301,7 @@ class FfiValueObjectHandleUniffiBindingsTestsComplexMethods { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsComplexMethodsPointerType); + dom::UniFFIPointer::Create(mValue, &kTabsTabsStorePointerType); mValue = nullptr; } @@ -3028,37 +3311,37 @@ class FfiValueObjectHandleUniffiBindingsTestsComplexMethods { return temp; } - static FfiValueObjectHandleUniffiBindingsTestsComplexMethods FromRust(void* aValue) { - return FfiValueObjectHandleUniffiBindingsTestsComplexMethods(aValue); + static FfiValueObjectHandleTabsTabsStore FromRust(void* aValue) { + return FfiValueObjectHandleTabsTabsStore(aValue); } void FreeHandle() { if (mValue) { RustCallStatus callStatus{}; - (uniffi_uniffi_bindings_tests_fn_free_complexmethods)(mValue, &callStatus); + (uniffi_tabs_fn_free_tabsstore)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } } - ~FfiValueObjectHandleUniffiBindingsTestsComplexMethods() { + ~FfiValueObjectHandleTabsTabsStore() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsTestTraitInterfacePointerType { - "uniffi_bindings_tests::TestTraitInterface"_ns, - uniffi_uniffi_bindings_tests_fn_clone_testtraitinterface, - uniffi_uniffi_bindings_tests_fn_free_testtraitinterface, +const static mozilla::uniffi::UniFFIPointerType kViaductBackendPointerType { + "viaduct::Backend"_ns, + uniffi_viaduct_fn_clone_backend, + uniffi_viaduct_fn_free_backend, }; // Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_uniffi_bindings_tests_test_trait_interface(uint64_t uniffiHandle); +extern "C" void callback_free_viaduct_backend(uint64_t uniffiHandle); // Trait interface FFI value class. This is a hybrid between the one for interfaces and callback // interface version -class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { +class FfiValueObjectHandleViaductBackend { private: // Did we lower a callback interface, rather than lift an object interface? // This is weird, but it's a needed work until something like @@ -3071,14 +3354,14 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { void* mValue = nullptr; public: - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface() = default; - explicit FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(void* aValue) : mValue(aValue) {} + FfiValueObjectHandleViaductBackend() = default; + explicit FfiValueObjectHandleViaductBackend(void* aValue) : mValue(aValue) {} // Delete copy constructor and assignment as this type is non-copyable. - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(const FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&) = delete; - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&) = delete; + FfiValueObjectHandleViaductBackend(const FfiValueObjectHandleViaductBackend&) = delete; + FfiValueObjectHandleViaductBackend& operator=(const FfiValueObjectHandleViaductBackend&) = delete; - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&& aOther) { + FfiValueObjectHandleViaductBackend& operator=(FfiValueObjectHandleViaductBackend&& aOther) { FreeHandle(); mValue = aOther.mValue; mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; @@ -3113,7 +3396,7 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { return; } dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); - if (!value.IsSamePtrType(&kUniffiBindingsTestsTestTraitInterfacePointerType)) { + if (!value.IsSamePtrType(&kViaductBackendPointerType)) { aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } @@ -3126,7 +3409,7 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { aDest->SetAsUniFFIPointer() = - dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsTestTraitInterfacePointerType); + dom::UniFFIPointer::Create(mValue, &kViaductBackendPointerType); mValue = nullptr; mLoweredCallbackInterface = false; } @@ -3138,8 +3421,8 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { return temp; } - static FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface FromRust(void* aValue) { - return FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(aValue); + static FfiValueObjectHandleViaductBackend FromRust(void* aValue) { + return FfiValueObjectHandleViaductBackend(aValue); } void FreeHandle() { @@ -3147,12 +3430,12 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { // pointer. if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { printf("FREEING CB %p\n", mValue); - callback_free_uniffi_bindings_tests_test_trait_interface(reinterpret_cast<uintptr_t>(mValue)); + callback_free_viaduct_backend(reinterpret_cast<uintptr_t>(mValue)); mValue = reinterpret_cast<void *>(0); } else if (!mLoweredCallbackInterface && mValue != nullptr) { printf("FREEING interface %p\n", mValue); RustCallStatus callStatus{}; - (uniffi_uniffi_bindings_tests_fn_free_testtraitinterface)(mValue, &callStatus); + (uniffi_viaduct_fn_free_backend)(mValue, &callStatus); // No need to check `RustCallStatus`, it's only part of the API to match // other FFI calls. The free function can never fail. } @@ -3160,489 +3443,371 @@ class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { mLoweredCallbackInterface = false; } - ~FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface() { + ~FfiValueObjectHandleViaductBackend() { // If the pointer is non-null, this means Lift/IntoRust was never called // because there was some failure along the way. Free the pointer to avoid a // leak FreeHandle(); } }; -#endif /* MOZ_UNIFFI_FIXTURES */ - -Maybe<already_AddRefed<UniFFIPointer>> ReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { - const UniFFIPointerType* type; - switch (aId) { - - case 1: { - type = &kContextIdContextIdComponentPointerType; - break; - } - case 2: { - type = &kFilterAdultFilterAdultComponentPointerType; - break; - } - case 3: { - type = &kRelevancyRelevancyStorePointerType; - break; - } - case 4: { - type = &kRemoteSettingsRemoteSettingsPointerType; - break; - } - case 5: { - type = &kRemoteSettingsRemoteSettingsClientPointerType; - break; - } - case 6: { - type = &kRemoteSettingsRemoteSettingsServicePointerType; - break; - } - case 7: { - type = &kSearchSearchEngineSelectorPointerType; - break; - } - case 8: { - type = &kSuggestSuggestStorePointerType; - break; - } - case 9: { - type = &kSuggestSuggestStoreBuilderPointerType; - break; - } - case 10: { - type = &kTabsRemoteCommandStorePointerType; - break; - } - case 11: { - type = &kTabsTabsBridgedEnginePointerType; - break; - } - case 12: { - type = &kTabsTabsStorePointerType; - break; - } - case 13: { - type = &kViaductBackendPointerType; - break; - } - case 14: { - type = &kWebextstorageWebExtStorageBridgedEnginePointerType; - break; - } - case 15: { - type = &kWebextstorageWebExtStorageStorePointerType; - break; - } - -#ifdef MOZ_UNIFFI_FIXTURES - case 16: { - type = &kUniffiBindingsTestsTestInterfacePointerType; - break; - } - case 17: { - type = &kUniffiBindingsTestsAsyncInterfacePointerType; - break; - } - case 18: { - type = &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType; - break; - } - case 19: { - type = &kUniffiBindingsTestsComplexMethodsPointerType; - break; - } - case 20: { - type = &kUniffiBindingsTestsTestTraitInterfacePointerType; - break; - } -#endif /* MOZ_UNIFFI_FIXTURES */ - default: - return Nothing(); - } - return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError)); -} +const static mozilla::uniffi::UniFFIPointerType kWebextstorageWebExtStorageBridgedEnginePointerType { + "webextstorage::WebExtStorageBridgedEngine"_ns, + uniffi_webext_storage_fn_clone_webextstoragebridgedengine, + uniffi_webext_storage_fn_free_webextstoragebridgedengine, +}; +class FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine { + private: + void* mValue = nullptr; -bool WritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { - const UniFFIPointerType* type; - switch (aId) { + public: + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine() = default; + explicit FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(void* aValue) : mValue(aValue) {} - case 1: { - type = &kContextIdContextIdComponentPointerType; - break; - } - case 2: { - type = &kFilterAdultFilterAdultComponentPointerType; - break; - } - case 3: { - type = &kRelevancyRelevancyStorePointerType; - break; - } - case 4: { - type = &kRemoteSettingsRemoteSettingsPointerType; - break; - } - case 5: { - type = &kRemoteSettingsRemoteSettingsClientPointerType; - break; - } - case 6: { - type = &kRemoteSettingsRemoteSettingsServicePointerType; - break; - } - case 7: { - type = &kSearchSearchEngineSelectorPointerType; - break; - } - case 8: { - type = &kSuggestSuggestStorePointerType; - break; - } - case 9: { - type = &kSuggestSuggestStoreBuilderPointerType; - break; - } - case 10: { - type = &kTabsRemoteCommandStorePointerType; - break; - } - case 11: { - type = &kTabsTabsBridgedEnginePointerType; - break; - } - case 12: { - type = &kTabsTabsStorePointerType; - break; - } - case 13: { - type = &kViaductBackendPointerType; - break; - } - case 14: { - type = &kWebextstorageWebExtStorageBridgedEnginePointerType; - break; - } - case 15: { - type = &kWebextstorageWebExtStorageStorePointerType; - break; - } + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(const FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&) = delete; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine& operator=(const FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&) = delete; -#ifdef MOZ_UNIFFI_FIXTURES - case 16: { - type = &kUniffiBindingsTestsTestInterfacePointerType; - break; - } - case 17: { - type = &kUniffiBindingsTestsAsyncInterfacePointerType; - break; - } - case 18: { - type = &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType; - break; - } - case 19: { - type = &kUniffiBindingsTestsComplexMethodsPointerType; - break; - } - case 20: { - type = &kUniffiBindingsTestsTestTraitInterfacePointerType; - break; - } -#endif /* MOZ_UNIFFI_FIXTURES */ - default: - return false; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine& operator=(FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + aOther.mValue = nullptr; + return *this; } - aPtr.Write(aArrayBuff, aPosition, type, aError); - return true; -} -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - - -// Callback interface FfiValueClasses -// -// These need to come first so they're defined for the scaffolding call code - - -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_context_id_context_id_callback(uint64_t uniffiHandle); - -// FfiValue class for these callback interface handles. This works like the -// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. -class FfiValueCallbackInterfacecontext_id_ContextIdCallback { - private: - // Was this value lowered? If so, that means we own the handle and are responsible for cleaning - // it up if we don't pass it to Rust because other values failed to lower - bool mLowered = false; - uint64_t mValue = 0; - - public: - FfiValueCallbackInterfacecontext_id_ContextIdCallback() = default; - explicit FfiValueCallbackInterfacecontext_id_ContextIdCallback(uint64_t aValue) : mValue(aValue) {} void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - double floatValue = aValue.GetAsDouble(); - - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kWebextstorageWebExtStorageBridgedEnginePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } - ReleaseHandleIfSet(); - mValue = intValue; - mLowered = true; + FreeHandle(); + mValue = value.ClonePtr(); + } + + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); } void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { - aDest->SetAsDouble() = mValue; - mValue = 0; - mLowered = false; + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kWebextstorageWebExtStorageBridgedEnginePointerType); + mValue = nullptr; } - uint64_t IntoRust() { - auto handle = mValue; - mValue = 0; - mLowered = false; - return handle; + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + return temp; } - static FfiValueCallbackInterfacecontext_id_ContextIdCallback FromRust(uint64_t aValue) { return FfiValueCallbackInterfacecontext_id_ContextIdCallback(aValue); }; + static FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine FromRust(void* aValue) { + return FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine(aValue); + } - void ReleaseHandleIfSet() { - // A non-zero value indicates that we own a callback handle that was never passed to Rust or - // lifted to JS and needs to be freed. - if (mValue != 0 && mLowered) { - callback_free_context_id_context_id_callback(mValue); - mValue = 0; - mLowered = false; + void FreeHandle() { + if (mValue) { + RustCallStatus callStatus{}; + (uniffi_webext_storage_fn_free_webextstoragebridgedengine)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. } } - ~FfiValueCallbackInterfacecontext_id_ContextIdCallback() { - ReleaseHandleIfSet(); + ~FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; - -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_tracing_event_sink(uint64_t uniffiHandle); - -// FfiValue class for these callback interface handles. This works like the -// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. -class FfiValueCallbackInterfacetracing_EventSink { +const static mozilla::uniffi::UniFFIPointerType kWebextstorageWebExtStorageStorePointerType { + "webextstorage::WebExtStorageStore"_ns, + uniffi_webext_storage_fn_clone_webextstoragestore, + uniffi_webext_storage_fn_free_webextstoragestore, +}; +class FfiValueObjectHandleWebextstorageWebExtStorageStore { private: - // Was this value lowered? If so, that means we own the handle and are responsible for cleaning - // it up if we don't pass it to Rust because other values failed to lower - bool mLowered = false; - uint64_t mValue = 0; + void* mValue = nullptr; public: - FfiValueCallbackInterfacetracing_EventSink() = default; - explicit FfiValueCallbackInterfacetracing_EventSink(uint64_t aValue) : mValue(aValue) {} + FfiValueObjectHandleWebextstorageWebExtStorageStore() = default; + explicit FfiValueObjectHandleWebextstorageWebExtStorageStore(void* aValue) : mValue(aValue) {} + + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleWebextstorageWebExtStorageStore(const FfiValueObjectHandleWebextstorageWebExtStorageStore&) = delete; + FfiValueObjectHandleWebextstorageWebExtStorageStore& operator=(const FfiValueObjectHandleWebextstorageWebExtStorageStore&) = delete; + + FfiValueObjectHandleWebextstorageWebExtStorageStore& operator=(FfiValueObjectHandleWebextstorageWebExtStorageStore&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + aOther.mValue = nullptr; + return *this; + } void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - double floatValue = aValue.GetAsDouble(); - - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kWebextstorageWebExtStorageStorePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } - ReleaseHandleIfSet(); - mValue = intValue; - mLowered = true; + FreeHandle(); + mValue = value.ClonePtr(); + } + + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); } void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { - aDest->SetAsDouble() = mValue; - mValue = 0; - mLowered = false; + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kWebextstorageWebExtStorageStorePointerType); + mValue = nullptr; } - uint64_t IntoRust() { - auto handle = mValue; - mValue = 0; - mLowered = false; - return handle; + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + return temp; } - static FfiValueCallbackInterfacetracing_EventSink FromRust(uint64_t aValue) { return FfiValueCallbackInterfacetracing_EventSink(aValue); }; + static FfiValueObjectHandleWebextstorageWebExtStorageStore FromRust(void* aValue) { + return FfiValueObjectHandleWebextstorageWebExtStorageStore(aValue); + } - void ReleaseHandleIfSet() { - // A non-zero value indicates that we own a callback handle that was never passed to Rust or - // lifted to JS and needs to be freed. - if (mValue != 0 && mLowered) { - callback_free_tracing_event_sink(mValue); - mValue = 0; - mLowered = false; + void FreeHandle() { + if (mValue) { + RustCallStatus callStatus{}; + (uniffi_webext_storage_fn_free_webextstoragestore)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. } } - ~FfiValueCallbackInterfacetracing_EventSink() { - ReleaseHandleIfSet(); + ~FfiValueObjectHandleWebextstorageWebExtStorageStore() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; #ifdef MOZ_UNIFFI_FIXTURES - -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_uniffi_bindings_tests_test_async_callback_interface(uint64_t uniffiHandle); - -// FfiValue class for these callback interface handles. This works like the -// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. -class FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface { +const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsTestInterfacePointerType { + "uniffi_bindings_tests::TestInterface"_ns, + uniffi_uniffi_bindings_tests_fn_clone_testinterface, + uniffi_uniffi_bindings_tests_fn_free_testinterface, +}; +class FfiValueObjectHandleUniffiBindingsTestsTestInterface { private: - // Was this value lowered? If so, that means we own the handle and are responsible for cleaning - // it up if we don't pass it to Rust because other values failed to lower - bool mLowered = false; - uint64_t mValue = 0; + void* mValue = nullptr; public: - FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface() = default; - explicit FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface(uint64_t aValue) : mValue(aValue) {} + FfiValueObjectHandleUniffiBindingsTestsTestInterface() = default; + explicit FfiValueObjectHandleUniffiBindingsTestsTestInterface(void* aValue) : mValue(aValue) {} + + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleUniffiBindingsTestsTestInterface(const FfiValueObjectHandleUniffiBindingsTestsTestInterface&) = delete; + FfiValueObjectHandleUniffiBindingsTestsTestInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsTestInterface&) = delete; + + FfiValueObjectHandleUniffiBindingsTestsTestInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsTestInterface&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + aOther.mValue = nullptr; + return *this; + } void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - double floatValue = aValue.GetAsDouble(); - - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kUniffiBindingsTestsTestInterfacePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } - ReleaseHandleIfSet(); - mValue = intValue; - mLowered = true; + FreeHandle(); + mValue = value.ClonePtr(); + } + + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); } void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { - aDest->SetAsDouble() = mValue; - mValue = 0; - mLowered = false; + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsTestInterfacePointerType); + mValue = nullptr; } - uint64_t IntoRust() { - auto handle = mValue; - mValue = 0; - mLowered = false; - return handle; + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + return temp; } - static FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface(aValue); }; + static FfiValueObjectHandleUniffiBindingsTestsTestInterface FromRust(void* aValue) { + return FfiValueObjectHandleUniffiBindingsTestsTestInterface(aValue); + } - void ReleaseHandleIfSet() { - // A non-zero value indicates that we own a callback handle that was never passed to Rust or - // lifted to JS and needs to be freed. - if (mValue != 0 && mLowered) { - callback_free_uniffi_bindings_tests_test_async_callback_interface(mValue); - mValue = 0; - mLowered = false; + void FreeHandle() { + if (mValue) { + RustCallStatus callStatus{}; + (uniffi_uniffi_bindings_tests_fn_free_testinterface)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. } } - ~FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface() { - ReleaseHandleIfSet(); + ~FfiValueObjectHandleUniffiBindingsTestsTestInterface() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; - -// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_uniffi_bindings_tests_test_callback_interface(uint64_t uniffiHandle); - -// FfiValue class for these callback interface handles. This works like the -// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. -class FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface { +const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsAsyncInterfacePointerType { + "uniffi_bindings_tests::AsyncInterface"_ns, + uniffi_uniffi_bindings_tests_fn_clone_asyncinterface, + uniffi_uniffi_bindings_tests_fn_free_asyncinterface, +}; +class FfiValueObjectHandleUniffiBindingsTestsAsyncInterface { private: - // Was this value lowered? If so, that means we own the handle and are responsible for cleaning - // it up if we don't pass it to Rust because other values failed to lower - bool mLowered = false; - uint64_t mValue = 0; + void* mValue = nullptr; public: - FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface() = default; - explicit FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface(uint64_t aValue) : mValue(aValue) {} + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface() = default; + explicit FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(void* aValue) : mValue(aValue) {} - void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, - ErrorResult& aError) { - if (!aValue.IsDouble()) { - aError.ThrowTypeError("Bad argument type"_ns); - return; - } - double floatValue = aValue.GetAsDouble(); + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(const FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&) = delete; + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&) = delete; - uint64_t intValue = static_cast<uint64_t>(floatValue); - if (intValue != floatValue) { - aError.ThrowTypeError("Not an integer"_ns); + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsAsyncInterface&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + aOther.mValue = nullptr; + return *this; + } + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - ReleaseHandleIfSet(); - mValue = intValue; - mLowered = true; + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kUniffiBindingsTestsAsyncInterfacePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); + return; + } + FreeHandle(); + mValue = value.ClonePtr(); + } + + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); } void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { - aDest->SetAsDouble() = mValue; - mValue = 0; - mLowered = false; + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsAsyncInterfacePointerType); + mValue = nullptr; } - uint64_t IntoRust() { - auto handle = mValue; - mValue = 0; - mLowered = false; - return handle; + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + return temp; } - static FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface(aValue); }; + static FfiValueObjectHandleUniffiBindingsTestsAsyncInterface FromRust(void* aValue) { + return FfiValueObjectHandleUniffiBindingsTestsAsyncInterface(aValue); + } - void ReleaseHandleIfSet() { - // A non-zero value indicates that we own a callback handle that was never passed to Rust or - // lifted to JS and needs to be freed. - if (mValue != 0 && mLowered) { - callback_free_uniffi_bindings_tests_test_callback_interface(mValue); - mValue = 0; - mLowered = false; + void FreeHandle() { + if (mValue) { + RustCallStatus callStatus{}; + (uniffi_uniffi_bindings_tests_fn_free_asyncinterface)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. } } - ~FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface() { - ReleaseHandleIfSet(); + ~FfiValueObjectHandleUniffiBindingsTestsAsyncInterface() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; - +const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsAsyncTestTraitInterfacePointerType { + "uniffi_bindings_tests::AsyncTestTraitInterface"_ns, + uniffi_uniffi_bindings_tests_fn_clone_asynctesttraitinterface, + uniffi_uniffi_bindings_tests_fn_free_asynctesttraitinterface, +}; // Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` -extern "C" void callback_free_uniffi_bindings_tests_collision_test_callback_interface(uint64_t uniffiHandle); +extern "C" void callback_free_uniffi_bindings_tests_async_test_trait_interface(uint64_t uniffiHandle); -// FfiValue class for these callback interface handles. This works like the -// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. -class FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface { +// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback +// interface version +class FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface { private: - // Was this value lowered? If so, that means we own the handle and are responsible for cleaning - // it up if we don't pass it to Rust because other values failed to lower - bool mLowered = false; - uint64_t mValue = 0; + // Did we lower a callback interface, rather than lift an object interface? + // This is weird, but it's a needed work until something like + // https://github.com/mozilla/uniffi-rs/pull/1823 lands. + bool mLoweredCallbackInterface = false; + // The raw FFI value is a pointer. + // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface + // handles are incremented by one at a time, so even on a 32-bit system this + // shouldn't overflow. + void* mValue = nullptr; public: - FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface() = default; - explicit FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface(uint64_t aValue) : mValue(aValue) {} + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface() = default; + explicit FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(void* aValue) : mValue(aValue) {} + + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(const FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&) = delete; + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&) = delete; + + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; + aOther.mValue = nullptr; + aOther.mLoweredCallbackInterface = false; + return *this; + } + // Lower treats `aValue` as a callback interface void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, ErrorResult& aError) { if (!aValue.IsDouble()) { @@ -3650,866 +3815,907 @@ class FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInter return; } double floatValue = aValue.GetAsDouble(); - uint64_t intValue = static_cast<uint64_t>(floatValue); if (intValue != floatValue) { aError.ThrowTypeError("Not an integer"_ns); return; } - ReleaseHandleIfSet(); - mValue = intValue; - mLowered = true; + FreeHandle(); + mValue = reinterpret_cast<void *>(intValue); + mLoweredCallbackInterface = true; + } + + // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); + return; + } + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kUniffiBindingsTestsAsyncTestTraitInterfacePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); + return; + } + FreeHandle(); + mValue = value.ClonePtr(); + mLoweredCallbackInterface = false; } + // Lift treats `aDest` as a regular interface void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, ErrorResult& aError) { - aDest->SetAsDouble() = mValue; - mValue = 0; - mLowered = false; + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType); + mValue = nullptr; + mLoweredCallbackInterface = false; } - uint64_t IntoRust() { - auto handle = mValue; - mValue = 0; - mLowered = false; - return handle; + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + mLoweredCallbackInterface = false; + return temp; } - static FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface(aValue); }; + static FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface FromRust(void* aValue) { + return FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface(aValue); + } - void ReleaseHandleIfSet() { - // A non-zero value indicates that we own a callback handle that was never passed to Rust or - // lifted to JS and needs to be freed. - if (mValue != 0 && mLowered) { - callback_free_uniffi_bindings_tests_collision_test_callback_interface(mValue); - mValue = 0; - mLowered = false; + void FreeHandle() { + // This behavior depends on if we lowered a callback interface handle or lifted an interface + // pointer. + if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { + printf("FREEING CB %p\n", mValue); + callback_free_uniffi_bindings_tests_async_test_trait_interface(reinterpret_cast<uintptr_t>(mValue)); + mValue = reinterpret_cast<void *>(0); + } else if (!mLoweredCallbackInterface && mValue != nullptr) { + printf("FREEING interface %p\n", mValue); + RustCallStatus callStatus{}; + (uniffi_uniffi_bindings_tests_fn_free_asynctesttraitinterface)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. } + mValue = nullptr; + mLoweredCallbackInterface = false; } - ~FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface() { - ReleaseHandleIfSet(); + ~FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; -#endif /* MOZ_UNIFFI_FIXTURES */ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsComplexMethodsPointerType { + "uniffi_bindings_tests::ComplexMethods"_ns, + uniffi_uniffi_bindings_tests_fn_clone_complexmethods, + uniffi_uniffi_bindings_tests_fn_free_complexmethods, +}; +class FfiValueObjectHandleUniffiBindingsTestsComplexMethods { + private: + void* mValue = nullptr; -// Define scaffolding call classes for each combination of return/argument types + public: + FfiValueObjectHandleUniffiBindingsTestsComplexMethods() = default; + explicit FfiValueObjectHandleUniffiBindingsTestsComplexMethods(void* aValue) : mValue(aValue) {} -class ScaffoldingCallHandlerUniffiContextIdFnConstructorContextidcomponentNew : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mInitContextId{}; - FfiValueInt<int64_t> mCreationTimestampS{}; - FfiValueInt<int8_t> mRunningInTestAutomation{}; - FfiValueCallbackInterfacecontext_id_ContextIdCallback mCallback{}; + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleUniffiBindingsTestsComplexMethods(const FfiValueObjectHandleUniffiBindingsTestsComplexMethods&) = delete; + FfiValueObjectHandleUniffiBindingsTestsComplexMethods& operator=(const FfiValueObjectHandleUniffiBindingsTestsComplexMethods&) = delete; - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleContextIdContextIdComponent mUniffiReturnValue{}; + FfiValueObjectHandleUniffiBindingsTestsComplexMethods& operator=(FfiValueObjectHandleUniffiBindingsTestsComplexMethods&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + aOther.mValue = nullptr; + return *this; + } -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 4) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_constructor_contextidcomponent_new (expected: 4, actual: %zu)", aArgs.Length())); - return; - } - mInitContextId.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mCreationTimestampS.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mRunningInTestAutomation.Lower(aArgs[2], aError); - if (aError.Failed()) { + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - mCallback.Lower(aArgs[3], aError); - if (aError.Failed()) { + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kUniffiBindingsTestsComplexMethodsPointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } + FreeHandle(); + mValue = value.ClonePtr(); } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleContextIdContextIdComponent::FromRust( - uniffi_context_id_fn_constructor_contextidcomponent_new( - mInitContextId.IntoRust(), - mCreationTimestampS.IntoRust(), - mRunningInTestAutomation.IntoRust(), - mCallback.IntoRust(), - aOutStatus - ) - ); + // LowerReceiver is used for method receivers. For non-trait interfaces, it works exactly the + // same as `Lower` + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + Lower(aValue, aError); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsComplexMethodsPointerType); + mValue = nullptr; } -}; -class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentForceRotation : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; - // MakeRustCall stores the result of the call in these fields + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + return temp; + } -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_force_rotation (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } + static FfiValueObjectHandleUniffiBindingsTestsComplexMethods FromRust(void* aValue) { + return FfiValueObjectHandleUniffiBindingsTestsComplexMethods(aValue); } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_context_id_fn_method_contextidcomponent_force_rotation( - mUniffiPtr.IntoRust(), - aOutStatus - ); + void FreeHandle() { + if (mValue) { + RustCallStatus callStatus{}; + (uniffi_uniffi_bindings_tests_fn_free_complexmethods)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. + } } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + ~FfiValueObjectHandleUniffiBindingsTestsComplexMethods() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; -class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentRequest : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; - FfiValueInt<uint8_t> mRotationDaysInS{}; +const static mozilla::uniffi::UniFFIPointerType kUniffiBindingsTestsTestTraitInterfacePointerType { + "uniffi_bindings_tests::TestTraitInterface"_ns, + uniffi_uniffi_bindings_tests_fn_clone_testtraitinterface, + uniffi_uniffi_bindings_tests_fn_free_testtraitinterface, +}; +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_uniffi_bindings_tests_test_trait_interface(uint64_t uniffiHandle); - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +// Trait interface FFI value class. This is a hybrid between the one for interfaces and callback +// interface version +class FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface { + private: + // Did we lower a callback interface, rather than lift an object interface? + // This is weird, but it's a needed work until something like + // https://github.com/mozilla/uniffi-rs/pull/1823 lands. + bool mLoweredCallbackInterface = false; + // The raw FFI value is a pointer. + // For callback interfaces, the uint64_t handle gets casted to a pointer. Callback interface + // handles are incremented by one at a time, so even on a 32-bit system this + // shouldn't overflow. + void* mValue = nullptr; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_request (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + public: + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface() = default; + explicit FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(void* aValue) : mValue(aValue) {} + + // Delete copy constructor and assignment as this type is non-copyable. + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(const FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&) = delete; + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface& operator=(const FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&) = delete; + + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface& operator=(FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface&& aOther) { + FreeHandle(); + mValue = aOther.mValue; + mLoweredCallbackInterface = aOther.mLoweredCallbackInterface; + aOther.mValue = nullptr; + aOther.mLoweredCallbackInterface = false; + return *this; + } + + // Lower treats `aValue` as a callback interface + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mRotationDaysInS.Lower(aArgs[1], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + FreeHandle(); + mValue = reinterpret_cast<void *>(intValue); + mLoweredCallbackInterface = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_context_id_fn_method_contextidcomponent_request( - mUniffiPtr.IntoRust(), - mRotationDaysInS.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); - } -}; -class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentUnsetCallback : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; - - // MakeRustCall stores the result of the call in these fields - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_unset_callback (expected: 1, actual: %zu)", aArgs.Length())); + // LowerReceiver is used for method receivers. It treats `aValue` as an object pointer. + void LowerReciever(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsUniFFIPointer()) { + aError.ThrowTypeError("Expected UniFFI pointer argument"_ns); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(&kUniffiBindingsTestsTestTraitInterfacePointerType)) { + aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns); return; } + FreeHandle(); + mValue = value.ClonePtr(); + mLoweredCallbackInterface = false; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_context_id_fn_method_contextidcomponent_unset_callback( - mUniffiPtr.IntoRust(), - aOutStatus - ); + // Lift treats `aDest` as a regular interface + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsUniFFIPointer() = + dom::UniFFIPointer::Create(mValue, &kUniffiBindingsTestsTestTraitInterfacePointerType); + mValue = nullptr; + mLoweredCallbackInterface = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void* IntoRust() { + auto temp = mValue; + mValue = nullptr; + mLoweredCallbackInterface = false; + return temp; } -}; -class ScaffoldingCallHandlerUniffiFilterAdultFnConstructorFilteradultcomponentNew : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleFilterAdultFilterAdultComponent mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + static FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface FromRust(void* aValue) { + return FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface(aValue); } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleFilterAdultFilterAdultComponent::FromRust( - uniffi_filter_adult_fn_constructor_filteradultcomponent_new( - aOutStatus - ) - ); + void FreeHandle() { + // This behavior depends on if we lowered a callback interface handle or lifted an interface + // pointer. + if (mLoweredCallbackInterface && reinterpret_cast<uintptr_t>(mValue) != 0) { + printf("FREEING CB %p\n", mValue); + callback_free_uniffi_bindings_tests_test_trait_interface(reinterpret_cast<uintptr_t>(mValue)); + mValue = reinterpret_cast<void *>(0); + } else if (!mLoweredCallbackInterface && mValue != nullptr) { + printf("FREEING interface %p\n", mValue); + RustCallStatus callStatus{}; + (uniffi_uniffi_bindings_tests_fn_free_testtraitinterface)(mValue, &callStatus); + // No need to check `RustCallStatus`, it's only part of the API to match + // other FFI calls. The free function can never fail. + } + mValue = nullptr; + mLoweredCallbackInterface = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + ~FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface() { + // If the pointer is non-null, this means Lift/IntoRust was never called + // because there was some failure along the way. Free the pointer to avoid a + // leak + FreeHandle(); } }; -class ScaffoldingCallHandlerUniffiFilterAdultFnMethodFilteradultcomponentContains : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleFilterAdultFilterAdultComponent mUniffiPtr{}; - FfiValueRustBuffer mBaseDomainToCheck{}; +#endif /* MOZ_UNIFFI_FIXTURES */ - // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; +Maybe<already_AddRefed<UniFFIPointer>> ReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_filter_adult_fn_method_filteradultcomponent_contains (expected: 2, actual: %zu)", aArgs.Length())); - return; + case 1: { + type = &kContextIdContextIdComponentPointerType; + break; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + case 2: { + type = &kFilterAdultFilterAdultComponentPointerType; + break; } - mBaseDomainToCheck.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 3: { + type = &kLoginsEncryptorDecryptorPointerType; + break; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_filter_adult_fn_method_filteradultcomponent_contains( - mUniffiPtr.IntoRust(), - mBaseDomainToCheck.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnFuncScore : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mInterestVector{}; - FfiValueRustBuffer mContentCategories{}; - - // MakeRustCall stores the result of the call in these fields - FfiValueFloat<double> mUniffiReturnValue{}; - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_func_score (expected: 2, actual: %zu)", aArgs.Length())); - return; + case 4: { + type = &kLoginsKeyManagerPointerType; + break; } - mInterestVector.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; + case 5: { + type = &kLoginsLoginStorePointerType; + break; } - mContentCategories.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 6: { + type = &kLoginsManagedEncryptorDecryptorPointerType; + break; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<double>::FromRust( - uniffi_relevancy_fn_func_score( - mInterestVector.IntoRust(), - mContentCategories.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnConstructorRelevancystoreNew : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mDbPath{}; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRemoteSettings{}; - - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiReturnValue{}; - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_constructor_relevancystore_new (expected: 2, actual: %zu)", aArgs.Length())); - return; + case 7: { + type = &kLoginsNssKeyManagerPointerType; + break; } - mDbPath.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; + case 8: { + type = &kLoginsPrimaryPasswordAuthenticatorPointerType; + break; } - mRemoteSettings.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 9: { + type = &kLoginsStaticKeyManagerPointerType; + break; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleRelevancyRelevancyStore::FromRust( - uniffi_relevancy_fn_constructor_relevancystore_new( - mDbPath.IntoRust(), - mRemoteSettings.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditInit : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - FfiValueRustBuffer mBandit{}; - FfiValueRustBuffer mArms{}; - - // MakeRustCall stores the result of the call in these fields - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_init (expected: 3, actual: %zu)", aArgs.Length())); - return; + case 10: { + type = &kRelevancyRelevancyStorePointerType; + break; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + case 11: { + type = &kRemoteSettingsRemoteSettingsPointerType; + break; } - mBandit.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 12: { + type = &kRemoteSettingsRemoteSettingsClientPointerType; + break; } - mArms.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; + case 13: { + type = &kRemoteSettingsRemoteSettingsServicePointerType; + break; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_relevancy_fn_method_relevancystore_bandit_init( - mUniffiPtr.IntoRust(), - mBandit.IntoRust(), - mArms.IntoRust(), - aOutStatus - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditSelect : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - FfiValueRustBuffer mBandit{}; - FfiValueRustBuffer mArms{}; - - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_select (expected: 3, actual: %zu)", aArgs.Length())); - return; + case 14: { + type = &kSearchSearchEngineSelectorPointerType; + break; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + case 15: { + type = &kSuggestSuggestStorePointerType; + break; } - mBandit.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 16: { + type = &kSuggestSuggestStoreBuilderPointerType; + break; } - mArms.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; + case 17: { + type = &kTabsRemoteCommandStorePointerType; + break; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_relevancy_fn_method_relevancystore_bandit_select( - mUniffiPtr.IntoRust(), - mBandit.IntoRust(), - mArms.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditUpdate : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - FfiValueRustBuffer mBandit{}; - FfiValueRustBuffer mArm{}; - FfiValueInt<int8_t> mSelected{}; - - // MakeRustCall stores the result of the call in these fields - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 4) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_update (expected: 4, actual: %zu)", aArgs.Length())); - return; + case 18: { + type = &kTabsTabsBridgedEnginePointerType; + break; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + case 19: { + type = &kTabsTabsStorePointerType; + break; } - mBandit.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; + case 20: { + type = &kViaductBackendPointerType; + break; } - mArm.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; + case 21: { + type = &kWebextstorageWebExtStorageBridgedEnginePointerType; + break; } - mSelected.Lower(aArgs[3], aError); - if (aError.Failed()) { - return; + case 22: { + type = &kWebextstorageWebExtStorageStorePointerType; + break; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_relevancy_fn_method_relevancystore_bandit_update( - mUniffiPtr.IntoRust(), - mBandit.IntoRust(), - mArm.IntoRust(), - mSelected.IntoRust(), - aOutStatus - ); +#ifdef MOZ_UNIFFI_FIXTURES + case 23: { + type = &kUniffiBindingsTestsTestInterfacePointerType; + break; + } + case 24: { + type = &kUniffiBindingsTestsAsyncInterfacePointerType; + break; + } + case 25: { + type = &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType; + break; + } + case 26: { + type = &kUniffiBindingsTestsComplexMethodsPointerType; + break; + } + case 27: { + type = &kUniffiBindingsTestsTestTraitInterfacePointerType; + break; + } +#endif /* MOZ_UNIFFI_FIXTURES */ + default: + return Nothing(); } + return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError)); +} - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreClose : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; +bool WritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { - // MakeRustCall stores the result of the call in these fields + case 1: { + type = &kContextIdContextIdComponentPointerType; + break; + } + case 2: { + type = &kFilterAdultFilterAdultComponentPointerType; + break; + } + case 3: { + type = &kLoginsEncryptorDecryptorPointerType; + break; + } + case 4: { + type = &kLoginsKeyManagerPointerType; + break; + } + case 5: { + type = &kLoginsLoginStorePointerType; + break; + } + case 6: { + type = &kLoginsManagedEncryptorDecryptorPointerType; + break; + } + case 7: { + type = &kLoginsNssKeyManagerPointerType; + break; + } + case 8: { + type = &kLoginsPrimaryPasswordAuthenticatorPointerType; + break; + } + case 9: { + type = &kLoginsStaticKeyManagerPointerType; + break; + } + case 10: { + type = &kRelevancyRelevancyStorePointerType; + break; + } + case 11: { + type = &kRemoteSettingsRemoteSettingsPointerType; + break; + } + case 12: { + type = &kRemoteSettingsRemoteSettingsClientPointerType; + break; + } + case 13: { + type = &kRemoteSettingsRemoteSettingsServicePointerType; + break; + } + case 14: { + type = &kSearchSearchEngineSelectorPointerType; + break; + } + case 15: { + type = &kSuggestSuggestStorePointerType; + break; + } + case 16: { + type = &kSuggestSuggestStoreBuilderPointerType; + break; + } + case 17: { + type = &kTabsRemoteCommandStorePointerType; + break; + } + case 18: { + type = &kTabsTabsBridgedEnginePointerType; + break; + } + case 19: { + type = &kTabsTabsStorePointerType; + break; + } + case 20: { + type = &kViaductBackendPointerType; + break; + } + case 21: { + type = &kWebextstorageWebExtStorageBridgedEnginePointerType; + break; + } + case 22: { + type = &kWebextstorageWebExtStorageStorePointerType; + break; + } -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_close (expected: 1, actual: %zu)", aArgs.Length())); - return; +#ifdef MOZ_UNIFFI_FIXTURES + case 23: { + type = &kUniffiBindingsTestsTestInterfacePointerType; + break; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + case 24: { + type = &kUniffiBindingsTestsAsyncInterfacePointerType; + break; + } + case 25: { + type = &kUniffiBindingsTestsAsyncTestTraitInterfacePointerType; + break; + } + case 26: { + type = &kUniffiBindingsTestsComplexMethodsPointerType; + break; + } + case 27: { + type = &kUniffiBindingsTestsTestTraitInterfacePointerType; + break; } +#endif /* MOZ_UNIFFI_FIXTURES */ + default: + return false; } + aPtr.Write(aArrayBuff, aPosition, type, aError); + return true; +} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_relevancy_fn_method_relevancystore_close( - mUniffiPtr.IntoRust(), - aOutStatus - ); - } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreEnsureInterestDataPopulated : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; +// Callback interface FfiValueClasses +// +// These need to come first so they're defined for the scaffolding call code - // MakeRustCall stores the result of the call in these fields -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated (expected: 1, actual: %zu)", aArgs.Length())); +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_context_id_context_id_callback(uint64_t uniffiHandle); + +// FfiValue class for these callback interface handles. This works like the +// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. +class FfiValueCallbackInterfacecontext_id_ContextIdCallback { + private: + // Was this value lowered? If so, that means we own the handle and are responsible for cleaning + // it up if we don't pass it to Rust because other values failed to lower + bool mLowered = false; + uint64_t mValue = 0; + + public: + FfiValueCallbackInterfacecontext_id_ContextIdCallback() = default; + explicit FfiValueCallbackInterfacecontext_id_ContextIdCallback(uint64_t aValue) : mValue(aValue) {} + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + ReleaseHandleIfSet(); + mValue = intValue; + mLowered = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated( - mUniffiPtr.IntoRust(), - aOutStatus - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsDouble() = mValue; + mValue = 0; + mLowered = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + uint64_t IntoRust() { + auto handle = mValue; + mValue = 0; + mLowered = false; + return handle; } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreGetBanditData : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - FfiValueRustBuffer mBandit{}; - FfiValueRustBuffer mArm{}; - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + static FfiValueCallbackInterfacecontext_id_ContextIdCallback FromRust(uint64_t aValue) { return FfiValueCallbackInterfacecontext_id_ContextIdCallback(aValue); }; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_get_bandit_data (expected: 3, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mBandit.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mArm.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; + void ReleaseHandleIfSet() { + // A non-zero value indicates that we own a callback handle that was never passed to Rust or + // lifted to JS and needs to be freed. + if (mValue != 0 && mLowered) { + callback_free_context_id_context_id_callback(mValue); + mValue = 0; + mLowered = false; } } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_relevancy_fn_method_relevancystore_get_bandit_data( - mUniffiPtr.IntoRust(), - mBandit.IntoRust(), - mArm.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + ~FfiValueCallbackInterfacecontext_id_ContextIdCallback() { + ReleaseHandleIfSet(); } }; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreIngest : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - FfiValueRustBuffer mTopUrlsByFrecency{}; - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_tracing_event_sink(uint64_t uniffiHandle); -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_ingest (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { +// FfiValue class for these callback interface handles. This works like the +// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. +class FfiValueCallbackInterfacetracing_EventSink { + private: + // Was this value lowered? If so, that means we own the handle and are responsible for cleaning + // it up if we don't pass it to Rust because other values failed to lower + bool mLowered = false; + uint64_t mValue = 0; + + public: + FfiValueCallbackInterfacetracing_EventSink() = default; + explicit FfiValueCallbackInterfacetracing_EventSink(uint64_t aValue) : mValue(aValue) {} + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mTopUrlsByFrecency.Lower(aArgs[1], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + ReleaseHandleIfSet(); + mValue = intValue; + mLowered = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_relevancy_fn_method_relevancystore_ingest( - mUniffiPtr.IntoRust(), - mTopUrlsByFrecency.IntoRust(), - aOutStatus - ) - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsDouble() = mValue; + mValue = 0; + mLowered = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + uint64_t IntoRust() { + auto handle = mValue; + mValue = 0; + mLowered = false; + return handle; } -}; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreInterrupt : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - // MakeRustCall stores the result of the call in these fields + static FfiValueCallbackInterfacetracing_EventSink FromRust(uint64_t aValue) { return FfiValueCallbackInterfacetracing_EventSink(aValue); }; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_interrupt (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; + void ReleaseHandleIfSet() { + // A non-zero value indicates that we own a callback handle that was never passed to Rust or + // lifted to JS and needs to be freed. + if (mValue != 0 && mLowered) { + callback_free_tracing_event_sink(mValue); + mValue = 0; + mLowered = false; } } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_relevancy_fn_method_relevancystore_interrupt( - mUniffiPtr.IntoRust(), - aOutStatus - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + ~FfiValueCallbackInterfacetracing_EventSink() { + ReleaseHandleIfSet(); } }; -class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreUserInterestVector : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +#ifdef MOZ_UNIFFI_FIXTURES -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_user_interest_vector (expected: 1, actual: %zu)", aArgs.Length())); +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_uniffi_bindings_tests_test_async_callback_interface(uint64_t uniffiHandle); + +// FfiValue class for these callback interface handles. This works like the +// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. +class FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface { + private: + // Was this value lowered? If so, that means we own the handle and are responsible for cleaning + // it up if we don't pass it to Rust because other values failed to lower + bool mLowered = false; + uint64_t mValue = 0; + + public: + FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface() = default; + explicit FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface(uint64_t aValue) : mValue(aValue) {} + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + ReleaseHandleIfSet(); + mValue = intValue; + mLowered = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_relevancy_fn_method_relevancystore_user_interest_vector( - mUniffiPtr.IntoRust(), - aOutStatus - ) - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsDouble() = mValue; + mValue = 0; + mLowered = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + uint64_t IntoRust() { + auto handle = mValue; + mValue = 0; + mLowered = false; + return handle; } -}; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsNew : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mRemoteSettingsConfig{}; - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiReturnValue{}; + static FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface(aValue); }; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_constructor_remotesettings_new (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mRemoteSettingsConfig.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; + void ReleaseHandleIfSet() { + // A non-zero value indicates that we own a callback handle that was never passed to Rust or + // lifted to JS and needs to be freed. + if (mValue != 0 && mLowered) { + callback_free_uniffi_bindings_tests_test_async_callback_interface(mValue); + mValue = 0; + mLowered = false; } } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettings::FromRust( - uniffi_remote_settings_fn_constructor_remotesettings_new( - mRemoteSettingsConfig.IntoRust(), - aOutStatus - ) - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + ~FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface() { + ReleaseHandleIfSet(); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsDownloadAttachmentToPath : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; - FfiValueRustBuffer mAttachmentId{}; - FfiValueRustBuffer mPath{}; - // MakeRustCall stores the result of the call in these fields +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_uniffi_bindings_tests_test_callback_interface(uint64_t uniffiHandle); -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path (expected: 3, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mAttachmentId.Lower(aArgs[1], aError); - if (aError.Failed()) { +// FfiValue class for these callback interface handles. This works like the +// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. +class FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface { + private: + // Was this value lowered? If so, that means we own the handle and are responsible for cleaning + // it up if we don't pass it to Rust because other values failed to lower + bool mLowered = false; + uint64_t mValue = 0; + + public: + FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface() = default; + explicit FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface(uint64_t aValue) : mValue(aValue) {} + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mPath.Lower(aArgs[2], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + ReleaseHandleIfSet(); + mValue = intValue; + mLowered = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path( - mUniffiPtr.IntoRust(), - mAttachmentId.IntoRust(), - mPath.IntoRust(), - aOutStatus - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsDouble() = mValue; + mValue = 0; + mLowered = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + uint64_t IntoRust() { + auto handle = mValue; + mValue = 0; + mLowered = false; + return handle; + } + + static FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface(aValue); }; + + void ReleaseHandleIfSet() { + // A non-zero value indicates that we own a callback handle that was never passed to Rust or + // lifted to JS and needs to be freed. + if (mValue != 0 && mLowered) { + callback_free_uniffi_bindings_tests_test_callback_interface(mValue); + mValue = 0; + mLowered = false; + } + } + + ~FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface() { + ReleaseHandleIfSet(); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecords : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +// Forward declare the free function, which is defined later on in `CallbackInterfaces.cpp` +extern "C" void callback_free_uniffi_bindings_tests_collision_test_callback_interface(uint64_t uniffiHandle); -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_get_records (expected: 1, actual: %zu)", aArgs.Length())); +// FfiValue class for these callback interface handles. This works like the +// `FfiValueInt<uint64_t>`, except it has extra code to cleanup the callback handles. +class FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface { + private: + // Was this value lowered? If so, that means we own the handle and are responsible for cleaning + // it up if we don't pass it to Rust because other values failed to lower + bool mLowered = false; + uint64_t mValue = 0; + + public: + FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface() = default; + explicit FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface(uint64_t aValue) : mValue(aValue) {} + + void Lower(const dom::OwningUniFFIScaffoldingValue& aValue, + ErrorResult& aError) { + if (!aValue.IsDouble()) { + aError.ThrowTypeError("Bad argument type"_ns); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + double floatValue = aValue.GetAsDouble(); + + uint64_t intValue = static_cast<uint64_t>(floatValue); + if (intValue != floatValue) { + aError.ThrowTypeError("Not an integer"_ns); return; } + ReleaseHandleIfSet(); + mValue = intValue; + mLowered = true; } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettings_get_records( - mUniffiPtr.IntoRust(), - aOutStatus - ) - ); + void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest, + ErrorResult& aError) { + aDest->SetAsDouble() = mValue; + mValue = 0; + mLowered = false; } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + uint64_t IntoRust() { + auto handle = mValue; + mValue = 0; + mLowered = false; + return handle; + } + + static FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface FromRust(uint64_t aValue) { return FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface(aValue); }; + + void ReleaseHandleIfSet() { + // A non-zero value indicates that we own a callback handle that was never passed to Rust or + // lifted to JS and needs to be freed. + if (mValue != 0 && mLowered) { + callback_free_uniffi_bindings_tests_collision_test_callback_interface(mValue); + mValue = 0; + mLowered = false; + } + } + + ~FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface() { + ReleaseHandleIfSet(); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecordsSince : public UniffiSyncCallHandler { +#endif /* MOZ_UNIFFI_FIXTURES */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// Define scaffolding call classes for each combination of return/argument types + +class ScaffoldingCallHandlerUniffiContextIdFnConstructorContextidcomponentNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; - FfiValueInt<uint64_t> mTimestamp{}; + FfiValueRustBuffer mInitContextId{}; + FfiValueInt<int64_t> mCreationTimestampS{}; + FfiValueInt<int8_t> mRunningInTestAutomation{}; + FfiValueCallbackInterfacecontext_id_ContextIdCallback mCallback{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleContextIdContextIdComponent mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_get_records_since (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 4) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_constructor_contextidcomponent_new (expected: 4, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mInitContextId.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mTimestamp.Lower(aArgs[1], aError); + mCreationTimestampS.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mRunningInTestAutomation.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } + mCallback.Lower(aArgs[3], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettings_get_records_since( - mUniffiPtr.IntoRust(), - mTimestamp.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleContextIdContextIdComponent::FromRust( + uniffi_context_id_fn_constructor_contextidcomponent_new( + mInitContextId.IntoRust(), + mCreationTimestampS.IntoRust(), + mRunningInTestAutomation.IntoRust(), + mCallback.IntoRust(), aOutStatus ) ); @@ -4523,18 +4729,17 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientCollectionName : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentForceRotation : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_collection_name (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_force_rotation (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -4544,27 +4749,20 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettingsclient_collection_name( - mUniffiPtr.IntoRust(), - aOutStatus - ) + uniffi_context_id_fn_method_contextidcomponent_force_rotation( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetAttachment : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentRequest : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; - FfiValueRustBuffer mRecord{}; + FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; + FfiValueInt<uint8_t> mRotationDaysInS{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -4572,14 +4770,14 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_request (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mRecord.Lower(aArgs[1], aError); + mRotationDaysInS.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -4587,9 +4785,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment( + uniffi_context_id_fn_method_contextidcomponent_request( mUniffiPtr.IntoRust(), - mRecord.IntoRust(), + mRotationDaysInS.IntoRust(), aOutStatus ) ); @@ -4603,79 +4801,92 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecords : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentUnsetCallback : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; - FfiValueInt<int8_t> mSyncIfEmpty{}; + FfiValueObjectHandleContextIdContextIdComponent mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_records (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_context_id_fn_method_contextidcomponent_unset_callback (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSyncIfEmpty.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettingsclient_get_records( - mUniffiPtr.IntoRust(), - mSyncIfEmpty.IntoRust(), - aOutStatus - ) + uniffi_context_id_fn_method_contextidcomponent_unset_callback( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecordsMap : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiFilterAdultFnConstructorFilteradultcomponentNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; - FfiValueInt<int8_t> mSyncIfEmpty{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleFilterAdultFilterAdultComponent mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleFilterAdultFilterAdultComponent::FromRust( + uniffi_filter_adult_fn_constructor_filteradultcomponent_new( + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiFilterAdultFnMethodFilteradultcomponentContains : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleFilterAdultFilterAdultComponent mUniffiPtr{}; + FfiValueRustBuffer mBaseDomainToCheck{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_filter_adult_fn_method_filteradultcomponent_contains (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSyncIfEmpty.Lower(aArgs[1], aError); + mBaseDomainToCheck.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_filter_adult_fn_method_filteradultcomponent_contains( mUniffiPtr.IntoRust(), - mSyncIfEmpty.IntoRust(), + mBaseDomainToCheck.IntoRust(), aOutStatus ) ); @@ -4689,28 +4900,24 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientShutdown : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiInitRustComponentsFnFuncInitialize : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueRustBuffer mProfilePath{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_shutdown (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mProfilePath.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_remote_settings_fn_method_remotesettingsclient_shutdown( - mUniffiPtr.IntoRust(), + uniffi_init_rust_components_fn_func_initialize( + mProfilePath.IntoRust(), aOutStatus ); } @@ -4718,65 +4925,77 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCheckCanary : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueRustBuffer mCanary{}; + FfiValueRustBuffer mText{}; + FfiValueRustBuffer mEncryptionKey{}; // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_sync (expected: 1, actual: %zu)", aArgs.Length())); + mCanary.Lower(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mText.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mEncryptionKey.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_remote_settings_fn_method_remotesettingsclient_sync( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_logins_fn_func_check_canary( + mCanary.IntoRust(), + mText.IntoRust(), + mEncryptionKey.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsserviceNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateCanary : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mStorageDir{}; - FfiValueRustBuffer mConfig{}; + FfiValueRustBuffer mText{}; + FfiValueRustBuffer mEncryptionKey{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_constructor_remotesettingsservice_new (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mStorageDir.Lower(aArgs[0], aError); + mText.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mConfig.Lower(aArgs[1], aError); + mEncryptionKey.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettingsService::FromRust( - uniffi_remote_settings_fn_constructor_remotesettingsservice_new( - mStorageDir.IntoRust(), - mConfig.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_func_create_canary( + mText.IntoRust(), + mEncryptionKey.IntoRust(), aOutStatus ) ); @@ -4790,36 +5009,20 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceMakeClient : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateKey : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; - FfiValueRustBuffer mCollectionName{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_make_client (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mCollectionName.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettingsClient::FromRust( - uniffi_remote_settings_fn_method_remotesettingsservice_make_client( - mUniffiPtr.IntoRust(), - mCollectionName.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_func_create_key( aOutStatus ) ); @@ -4833,30 +5036,32 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateLoginStoreWithNssKeymanager : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; + FfiValueRustBuffer mPath{}; + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator mPrimaryPasswordAuthenticator{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleLoginsLoginStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_sync (expected: 1, actual: %zu)", aArgs.Length())); + mPath.Lower(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mPrimaryPasswordAuthenticator.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_remote_settings_fn_method_remotesettingsservice_sync( - mUniffiPtr.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleLoginsLoginStore::FromRust( + uniffi_logins_fn_func_create_login_store_with_nss_keymanager( + mPath.IntoRust(), + mPrimaryPasswordAuthenticator.IntoRust(), aOutStatus ) ); @@ -4870,55 +5075,65 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceUpdateConfig : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateLoginStoreWithStaticKeyManager : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; - FfiValueRustBuffer mConfig{}; + FfiValueRustBuffer mPath{}; + FfiValueRustBuffer mKey{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleLoginsLoginStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_update_config (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mPath.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mConfig.Lower(aArgs[1], aError); + mKey.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_remote_settings_fn_method_remotesettingsservice_update_config( - mUniffiPtr.IntoRust(), - mConfig.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleLoginsLoginStore::FromRust( + uniffi_logins_fn_func_create_login_store_with_static_key_manager( + mPath.IntoRust(), + mKey.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSearchFnConstructorSearchengineselectorNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateManagedEncdec : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleLoginsKeyManager mKeyManager{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiReturnValue{}; + FfiValueObjectHandleLoginsEncryptorDecryptor mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + mKeyManager.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSearchSearchEngineSelector::FromRust( - uniffi_search_fn_constructor_searchengineselector_new( + mUniffiReturnValue = FfiValueObjectHandleLoginsEncryptorDecryptor::FromRust( + uniffi_logins_fn_func_create_managed_encdec( + mKeyManager.IntoRust(), aOutStatus ) ); @@ -4932,55 +5147,55 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorClearSearchConfig : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnFuncCreateStaticKeyManager : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; + FfiValueRustBuffer mKey{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleLoginsKeyManager mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_clear_search_config (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mKey.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_search_fn_method_searchengineselector_clear_search_config( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleLoginsKeyManager::FromRust( + uniffi_logins_fn_func_create_static_key_manager( + mKey.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorFilterEngineConfiguration : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodEncryptordecryptorDecrypt : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; - FfiValueRustBuffer mUserEnvironment{}; + FfiValueObjectHandleLoginsEncryptorDecryptor mUniffiPtr{}; + FfiValueRustBuffer mCiphertext{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_filter_engine_configuration (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mUserEnvironment.Lower(aArgs[1], aError); + mCiphertext.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -4988,9 +5203,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_search_fn_method_searchengineselector_filter_engine_configuration( + uniffi_logins_fn_method_encryptordecryptor_decrypt( mUniffiPtr.IntoRust(), - mUserEnvironment.IntoRust(), + mCiphertext.IntoRust(), aOutStatus ) ); @@ -5004,147 +5219,143 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetConfigOverrides : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodEncryptordecryptorEncrypt : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; - FfiValueRustBuffer mOverrides{}; + FfiValueObjectHandleLoginsEncryptorDecryptor mUniffiPtr{}; + FfiValueRustBuffer mCleartext{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_set_config_overrides (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mOverrides.Lower(aArgs[1], aError); + mCleartext.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_search_fn_method_searchengineselector_set_config_overrides( - mUniffiPtr.IntoRust(), - mOverrides.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_encryptordecryptor_encrypt( + mUniffiPtr.IntoRust(), + mCleartext.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetSearchConfig : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodKeymanagerGetKey : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; - FfiValueRustBuffer mConfiguration{}; + FfiValueObjectHandleLoginsKeyManager mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_set_search_config (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mConfiguration.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_search_fn_method_searchengineselector_set_search_config( - mUniffiPtr.IntoRust(), - mConfiguration.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_keymanager_get_key( + mUniffiPtr.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorUseRemoteSettingsServer : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnConstructorLoginstoreNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mService{}; - FfiValueInt<int8_t> mApplyEngineOverrides{}; + FfiValueRustBuffer mPath{}; + FfiValueObjectHandleLoginsEncryptorDecryptor mEncdec{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleLoginsLoginStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_use_remote_settings_server (expected: 3, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mService.Lower(aArgs[1], aError); + mPath.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mApplyEngineOverrides.Lower(aArgs[2], aError); + mEncdec.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_search_fn_method_searchengineselector_use_remote_settings_server( - mUniffiPtr.IntoRust(), - mService.IntoRust(), - mApplyEngineOverrides.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleLoginsLoginStore::FromRust( + uniffi_logins_fn_constructor_loginstore_new( + mPath.IntoRust(), + mEncdec.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnFuncRawSuggestionUrlMatches : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAdd : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mRawUrl{}; - FfiValueRustBuffer mCookedUrl{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mLogin{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_func_raw_suggestion_url_matches (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mRawUrl.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mCookedUrl.Lower(aArgs[1], aError); + mLogin.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_suggest_fn_func_raw_suggestion_url_matches( - mRawUrl.IntoRust(), - mCookedUrl.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_add( + mUniffiPtr.IntoRust(), + mLogin.IntoRust(), aOutStatus ) ); @@ -5158,36 +5369,32 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststoreNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddMany : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mPath{}; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRemoteSettingsService{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mLogins{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_constructor_suggeststore_new (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mPath.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mRemoteSettingsService.Lower(aArgs[1], aError); + mLogins.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStore::FromRust( - uniffi_suggest_fn_constructor_suggeststore_new( - mPath.IntoRust(), - mRemoteSettingsService.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_add_many( + mUniffiPtr.IntoRust(), + mLogins.IntoRust(), aOutStatus ) ); @@ -5201,30 +5408,32 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreAnyDismissedSuggestions : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddManyWithMeta : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mEntriesWithMeta{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions (expected: 1, actual: %zu)", aArgs.Length())); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mEntriesWithMeta.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_add_many_with_meta( mUniffiPtr.IntoRust(), + mEntriesWithMeta.IntoRust(), aOutStatus ) ); @@ -5238,199 +5447,221 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClear : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddOrUpdate : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mLogin{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_clear (expected: 1, actual: %zu)", aArgs.Length())); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mLogin.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_clear( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_add_or_update( + mUniffiPtr.IntoRust(), + mLogin.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClearDismissedSuggestions : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddWithMeta : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mEntryWithMeta{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions (expected: 1, actual: %zu)", aArgs.Length())); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mEntryWithMeta.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_add_with_meta( + mUniffiPtr.IntoRust(), + mEntryWithMeta.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissByKey : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCount : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mKey{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_by_key (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mKey.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_dismiss_by_key( - mUniffiPtr.IntoRust(), - mKey.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_logins_fn_method_loginstore_count( + mUniffiPtr.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissBySuggestion : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCountByFormActionOrigin : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mSuggestion{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mFormActionOrigin{}; // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSuggestion.Lower(aArgs[1], aError); + mFormActionOrigin.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion( - mUniffiPtr.IntoRust(), - mSuggestion.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_logins_fn_method_loginstore_count_by_form_action_origin( + mUniffiPtr.IntoRust(), + mFormActionOrigin.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissSuggestion : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCountByOrigin : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mSuggestionUrl{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mOrigin{}; // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_suggestion (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSuggestionUrl.Lower(aArgs[1], aError); + mOrigin.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_dismiss_suggestion( - mUniffiPtr.IntoRust(), - mSuggestionUrl.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_logins_fn_method_loginstore_count_by_origin( + mUniffiPtr.IntoRust(), + mOrigin.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonameAlternates : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDelete : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mGeoname{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mId{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mGeoname.Lower(aArgs[1], aError); + mId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_logins_fn_method_loginstore_delete( mUniffiPtr.IntoRust(), - mGeoname.IntoRust(), + mId.IntoRust(), aOutStatus ) ); @@ -5444,36 +5675,22 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonames : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDeleteMany : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mQuery{}; - FfiValueInt<int8_t> mMatchNamePrefix{}; - FfiValueRustBuffer mFilter{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mIds{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 4) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_geonames (expected: 4, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mQuery.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mMatchNamePrefix.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } - mFilter.Lower(aArgs[3], aError); + mIds.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -5481,11 +5698,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_fetch_geonames( + uniffi_logins_fn_method_loginstore_delete_many( mUniffiPtr.IntoRust(), - mQuery.IntoRust(), - mMatchNamePrefix.IntoRust(), - mFilter.IntoRust(), + mIds.IntoRust(), aOutStatus ) ); @@ -5499,20 +5714,16 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGlobalConfig : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDeleteUndecryptableRecordsForRemoteReplacement : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_global_config (expected: 1, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; @@ -5521,7 +5732,7 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_fetch_global_config( + uniffi_logins_fn_method_loginstore_delete_undecryptable_records_for_remote_replacement( mUniffiPtr.IntoRust(), aOutStatus ) @@ -5536,26 +5747,22 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchProviderConfig : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreFindLoginToUpdate : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mProvider{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mLook{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_provider_config (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mProvider.Lower(aArgs[1], aError); + mLook.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -5563,9 +5770,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_fetch_provider_config( + uniffi_logins_fn_method_loginstore_find_login_to_update( mUniffiPtr.IntoRust(), - mProvider.IntoRust(), + mLook.IntoRust(), aOutStatus ) ); @@ -5579,26 +5786,22 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIngest : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGet : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mConstraints{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mId{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_ingest (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mConstraints.Lower(aArgs[1], aError); + mId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -5606,9 +5809,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_ingest( + uniffi_logins_fn_method_loginstore_get( mUniffiPtr.IntoRust(), - mConstraints.IntoRust(), + mId.IntoRust(), aOutStatus ) ); @@ -5622,71 +5825,65 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreInterrupt : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGetByBaseDomain : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mKind{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mBaseDomain{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_interrupt (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mKind.Lower(aArgs[1], aError); + mBaseDomain.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_suggest_fn_method_suggeststore_interrupt( - mUniffiPtr.IntoRust(), - mKind.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_get_by_base_domain( + mUniffiPtr.IntoRust(), + mBaseDomain.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedByKey : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGetCheckpoint : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mKey{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mKey.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_get_checkpoint( mUniffiPtr.IntoRust(), - mKey.IntoRust(), aOutStatus ) ); @@ -5700,26 +5897,22 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedBySuggestion : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreHasLoginsByBaseDomain : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mSuggestion{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mBaseDomain{}; // MakeRustCall stores the result of the call in these fields FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSuggestion.Lower(aArgs[1], aError); + mBaseDomain.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -5727,9 +5920,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion( + uniffi_logins_fn_method_loginstore_has_logins_by_base_domain( mUniffiPtr.IntoRust(), - mSuggestion.IntoRust(), + mBaseDomain.IntoRust(), aOutStatus ) ); @@ -5743,36 +5936,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQuery : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreIsEmpty : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mQuery{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_query (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mQuery.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_query( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_logins_fn_method_loginstore_is_empty( mUniffiPtr.IntoRust(), - mQuery.IntoRust(), aOutStatus ) ); @@ -5786,36 +5969,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQueryWithMetrics : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreList : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; - FfiValueRustBuffer mQuery{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_query_with_metrics (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mQuery.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_suggest_fn_method_suggeststore_query_with_metrics( + uniffi_logins_fn_method_loginstore_list( mUniffiPtr.IntoRust(), - mQuery.IntoRust(), aOutStatus ) ); @@ -5829,47 +6002,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststorebuilderNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreRegisterWithSyncManager : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_constructor_suggeststorebuilder_new( - aOutStatus - ) + uniffi_logins_fn_method_loginstore_register_with_sync_manager( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderBuild : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreReset : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_build (expected: 1, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; @@ -5877,230 +6043,159 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStore::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_build( - mUniffiPtr.IntoRust(), - aOutStatus - ) + uniffi_logins_fn_method_loginstore_reset( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderCachePath : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreRunMaintenance : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueRustBuffer mPath{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_cache_path (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mPath.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_cache_path( - mUniffiPtr.IntoRust(), - mPath.IntoRust(), - aOutStatus - ) + uniffi_logins_fn_method_loginstore_run_maintenance( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderDataPath : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreSetCheckpoint : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueRustBuffer mPath{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mCheckpoint{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_data_path (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mPath.Lower(aArgs[1], aError); + mCheckpoint.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_data_path( - mUniffiPtr.IntoRust(), - mPath.IntoRust(), - aOutStatus - ) + uniffi_logins_fn_method_loginstore_set_checkpoint( + mUniffiPtr.IntoRust(), + mCheckpoint.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderLoadExtension : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreShutdown : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueRustBuffer mLibrary{}; - FfiValueRustBuffer mEntryPoint{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_load_extension (expected: 3, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mLibrary.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mEntryPoint.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_load_extension( - mUniffiPtr.IntoRust(), - mLibrary.IntoRust(), - mEntryPoint.IntoRust(), - aOutStatus - ) + uniffi_logins_fn_method_loginstore_shutdown( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsBucketName : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreTouch : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueRustBuffer mBucketName{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mId{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mBucketName.Lower(aArgs[1], aError); + mId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name( - mUniffiPtr.IntoRust(), - mBucketName.IntoRust(), - aOutStatus - ) + uniffi_logins_fn_method_loginstore_touch( + mUniffiPtr.IntoRust(), + mId.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsServer : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreUpdate : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueRustBuffer mServer{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; + FfiValueRustBuffer mId{}; + FfiValueRustBuffer mLogin{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server (expected: 2, actual: %zu)", aArgs.Length())); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - mServer.Lower(aArgs[1], aError); + mLogin.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_logins_fn_method_loginstore_update( mUniffiPtr.IntoRust(), - mServer.IntoRust(), + mId.IntoRust(), + mLogin.IntoRust(), aOutStatus ) ); @@ -6114,36 +6209,51 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsService : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreWipeLocal : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; - FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRsService{}; + FfiValueObjectHandleLoginsLoginStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service (expected: 2, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mRsService.Lower(aArgs[1], aError); + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_logins_fn_method_loginstore_wipe_local( + mUniffiPtr.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiLoginsFnConstructorManagedencryptordecryptorNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleLoginsKeyManager mKeyManager{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleLoginsManagedEncryptorDecryptor mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + mKeyManager.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( - uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service( - mUniffiPtr.IntoRust(), - mRsService.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleLoginsManagedEncryptorDecryptor::FromRust( + uniffi_logins_fn_constructor_managedencryptordecryptor_new( + mKeyManager.IntoRust(), aOutStatus ) ); @@ -6157,42 +6267,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommand : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnConstructorNsskeymanagerNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; - FfiValueRustBuffer mDeviceId{}; - FfiValueRustBuffer mCommand{}; + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator mPrimaryPasswordAuthenticator{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueObjectHandleLoginsNssKeyManager mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_add_remote_command (expected: 3, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mDeviceId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mCommand.Lower(aArgs[2], aError); + mPrimaryPasswordAuthenticator.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_tabs_fn_method_remotecommandstore_add_remote_command( - mUniffiPtr.IntoRust(), - mDeviceId.IntoRust(), - mCommand.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleLoginsNssKeyManager::FromRust( + uniffi_logins_fn_constructor_nsskeymanager_new( + mPrimaryPasswordAuthenticator.IntoRust(), aOutStatus ) ); @@ -6206,48 +6300,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommandAt : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiLoginsFnMethodNsskeymanagerIntoDynKeyManager : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; - FfiValueRustBuffer mDeviceId{}; - FfiValueRustBuffer mCommand{}; - FfiValueInt<int64_t> mWhen{}; + FfiValueObjectHandleLoginsNssKeyManager mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueObjectHandleLoginsKeyManager mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 4) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at (expected: 4, actual: %zu)", aArgs.Length())); - return; - } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mDeviceId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mCommand.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } - mWhen.Lower(aArgs[3], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at( + mUniffiReturnValue = FfiValueObjectHandleLoginsKeyManager::FromRust( + uniffi_logins_fn_method_nsskeymanager_into_dyn_key_manager( mUniffiPtr.IntoRust(), - mDeviceId.IntoRust(), - mCommand.IntoRust(), - mWhen.IntoRust(), aOutStatus ) ); @@ -6261,36 +6333,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreGetUnsentCommands : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; +class ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorGetPrimaryPassword : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorGetPrimaryPassword() : UniffiAsyncCallHandler( + ffi_logins_rust_future_poll_rust_buffer, + ffi_logins_rust_future_free_rust_buffer + ) { } - // MakeRustCall stores the result of the call in these fields +private: + // Complete stores the result of the call in mUniffiReturnValue FfiValueRustBuffer mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands (expected: 1, actual: %zu)", aArgs.Length())); - return; - } +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator mUniffiPtr{}; mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + + mFutureHandle = uniffi_logins_fn_method_primarypasswordauthenticator_get_primary_password( + mUniffiPtr.IntoRust() + ); } - void MakeRustCall(RustCallStatus* aOutStatus) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands( - mUniffiPtr.IntoRust(), - aOutStatus - ) - ); + ffi_logins_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -6298,42 +6374,94 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreRemoveRemoteCommand : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; - FfiValueRustBuffer mDeviceId{}; - FfiValueRustBuffer mCommand{}; +class ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationSuccess : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationSuccess() : UniffiAsyncCallHandler( + ffi_logins_rust_future_poll_void, + ffi_logins_rust_future_free_void + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_remove_remote_command (expected: 3, actual: %zu)", aArgs.Length())); - return; - } +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator mUniffiPtr{}; mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mDeviceId.Lower(aArgs[1], aError); + + mFutureHandle = uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_success( + mUniffiPtr.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_logins_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationFailure : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationFailure() : UniffiAsyncCallHandler( + ffi_logins_rust_future_poll_void, + ffi_logins_rust_future_free_void + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleLoginsPrimaryPasswordAuthenticator mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mCommand.Lower(aArgs[2], aError); + + mFutureHandle = uniffi_logins_fn_method_primarypasswordauthenticator_on_authentication_failure( + mUniffiPtr.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_logins_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiLoginsFnConstructorStatickeymanagerNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mKey{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleLoginsStaticKeyManager mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + mKey.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_tabs_fn_method_remotecommandstore_remove_remote_command( - mUniffiPtr.IntoRust(), - mDeviceId.IntoRust(), - mCommand.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleLoginsStaticKeyManager::FromRust( + uniffi_logins_fn_constructor_statickeymanager_new( + mKey.IntoRust(), aOutStatus ) ); @@ -6347,36 +6475,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreSetPendingCommandSent : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnFuncScore : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; - FfiValueRustBuffer mCommand{}; + FfiValueRustBuffer mInterestVector{}; + FfiValueRustBuffer mContentCategories{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueFloat<double> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_func_score (expected: 2, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mInterestVector.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mCommand.Lower(aArgs[1], aError); + mContentCategories.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent( - mUniffiPtr.IntoRust(), - mCommand.IntoRust(), + mUniffiReturnValue = FfiValueFloat<double>::FromRust( + uniffi_relevancy_fn_func_score( + mInterestVector.IntoRust(), + mContentCategories.IntoRust(), aOutStatus ) ); @@ -6390,30 +6518,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineApply : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnConstructorRelevancystoreNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mDbPath{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRemoteSettings{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_apply (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_constructor_relevancystore_new (expected: 2, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mDbPath.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mRemoteSettings.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_tabsbridgedengine_apply( - mUniffiPtr.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleRelevancyRelevancyStore::FromRust( + uniffi_relevancy_fn_constructor_relevancystore_new( + mDbPath.IntoRust(), + mRemoteSettings.IntoRust(), aOutStatus ) ); @@ -6427,73 +6561,83 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineEnsureCurrentSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditInit : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mNewSyncId{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; + FfiValueRustBuffer mBandit{}; + FfiValueRustBuffer mArms{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_init (expected: 3, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mNewSyncId.Lower(aArgs[1], aError); + mBandit.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mArms.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id( - mUniffiPtr.IntoRust(), - mNewSyncId.IntoRust(), - aOutStatus - ) + uniffi_relevancy_fn_method_relevancystore_bandit_init( + mUniffiPtr.IntoRust(), + mBandit.IntoRust(), + mArms.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineLastSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditSelect : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; + FfiValueRustBuffer mBandit{}; + FfiValueRustBuffer mArms{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int64_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_last_sync (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_select (expected: 3, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mBandit.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mArms.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( - uniffi_tabs_fn_method_tabsbridgedengine_last_sync( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_relevancy_fn_method_relevancystore_bandit_select( mUniffiPtr.IntoRust(), + mBandit.IntoRust(), + mArms.IntoRust(), aOutStatus ) ); @@ -6507,63 +6651,46 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedenginePrepareForSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditUpdate : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mClientData{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; + FfiValueRustBuffer mBandit{}; + FfiValueRustBuffer mArm{}; + FfiValueInt<int8_t> mSelected{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 4) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_bandit_update (expected: 4, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mClientData.Lower(aArgs[1], aError); + mBandit.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync( - mUniffiPtr.IntoRust(), - mClientData.IntoRust(), - aOutStatus - ); - } - - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineReset : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - - // MakeRustCall stores the result of the call in these fields - -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_reset (expected: 1, actual: %zu)", aArgs.Length())); + mArm.Lower(aArgs[2], aError); + if (aError.Failed()) { return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mSelected.Lower(aArgs[3], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_reset( + uniffi_relevancy_fn_method_relevancystore_bandit_update( mUniffiPtr.IntoRust(), + mBandit.IntoRust(), + mArm.IntoRust(), + mSelected.IntoRust(), aOutStatus ); } @@ -6571,18 +6698,17 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineResetSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreClose : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_close (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -6592,50 +6718,37 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id( - mUniffiPtr.IntoRust(), - aOutStatus - ) + uniffi_relevancy_fn_method_relevancystore_close( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetLastSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreEnsureInterestDataPopulated : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - FfiValueInt<int64_t> mLastSync{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mLastSync.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync( + uniffi_relevancy_fn_method_relevancystore_ensure_interest_data_populated( mUniffiPtr.IntoRust(), - mLastSync.IntoRust(), aOutStatus ); } @@ -6643,93 +6756,109 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetUploaded : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreGetBanditData : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - FfiValueInt<int64_t> mNewTimestamp{}; - FfiValueRustBuffer mUploadedIds{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; + FfiValueRustBuffer mBandit{}; + FfiValueRustBuffer mArm{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded (expected: 3, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_get_bandit_data (expected: 3, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mNewTimestamp.Lower(aArgs[1], aError); + mBandit.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - mUploadedIds.Lower(aArgs[2], aError); + mArm.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded( - mUniffiPtr.IntoRust(), - mNewTimestamp.IntoRust(), - mUploadedIds.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_relevancy_fn_method_relevancystore_get_bandit_data( + mUniffiPtr.IntoRust(), + mBandit.IntoRust(), + mArm.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineStoreIncoming : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreIngest : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mIncomingEnvelopesAsJson{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; + FfiValueRustBuffer mTopUrlsByFrecency{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_store_incoming (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_ingest (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mIncomingEnvelopesAsJson.Lower(aArgs[1], aError); + mTopUrlsByFrecency.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_store_incoming( - mUniffiPtr.IntoRust(), - mIncomingEnvelopesAsJson.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_relevancy_fn_method_relevancystore_ingest( + mUniffiPtr.IntoRust(), + mTopUrlsByFrecency.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncFinished : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreInterrupt : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_finished (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_interrupt (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -6739,7 +6868,7 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_sync_finished( + uniffi_relevancy_fn_method_relevancystore_interrupt( mUniffiPtr.IntoRust(), aOutStatus ); @@ -6748,10 +6877,10 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreUserInterestVector : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleRelevancyRelevancyStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -6759,7 +6888,7 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_id (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_relevancy_fn_method_relevancystore_user_interest_vector (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -6770,7 +6899,7 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_tabsbridgedengine_sync_id( + uniffi_relevancy_fn_method_relevancystore_user_interest_vector( mUniffiPtr.IntoRust(), aOutStatus ) @@ -6785,57 +6914,77 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncStarted : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mRemoteSettingsConfig{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_started (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_constructor_remotesettings_new (expected: 1, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mRemoteSettingsConfig.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_sync_started( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettings::FromRust( + uniffi_remote_settings_fn_constructor_remotesettings_new( + mRemoteSettingsConfig.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineWipe : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsDownloadAttachmentToPath : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; + FfiValueRustBuffer mAttachmentId{}; + FfiValueRustBuffer mPath{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_wipe (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path (expected: 3, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mAttachmentId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mPath.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsbridgedengine_wipe( + uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path( mUniffiPtr.IntoRust(), + mAttachmentId.IntoRust(), + mPath.IntoRust(), aOutStatus ); } @@ -6843,30 +6992,30 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiTabsFnConstructorTabsstoreNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecords : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mPath{}; + FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleTabsTabsStore mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_constructor_tabsstore_new (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_get_records (expected: 1, actual: %zu)", aArgs.Length())); return; } - mPath.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleTabsTabsStore::FromRust( - uniffi_tabs_fn_constructor_tabsstore_new( - mPath.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettings_get_records( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -6880,30 +7029,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreBridgedEngine : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecordsSince : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettings mUniffiPtr{}; + FfiValueInt<uint64_t> mTimestamp{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleTabsTabsBridgedEngine mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_bridged_engine (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettings_get_records_since (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mTimestamp.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleTabsTabsBridgedEngine::FromRust( - uniffi_tabs_fn_method_tabsstore_bridged_engine( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettings_get_records_since( mUniffiPtr.IntoRust(), + mTimestamp.IntoRust(), aOutStatus ) ); @@ -6917,17 +7072,18 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreCloseConnection : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientCollectionName : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_close_connection (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_collection_name (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -6937,39 +7093,52 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsstore_close_connection( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettingsclient_collection_name( + mUniffiPtr.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreGetAll : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetAttachment : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueRustBuffer mRecord{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_get_all (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mRecord.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_tabs_fn_method_tabsstore_get_all( + uniffi_remote_settings_fn_method_remotesettingsclient_get_attachment( mUniffiPtr.IntoRust(), + mRecord.IntoRust(), aOutStatus ) ); @@ -6983,30 +7152,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreNewRemoteCommandStore : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecords : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueInt<int8_t> mSyncIfEmpty{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleTabsRemoteCommandStore mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_new_remote_command_store (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_records (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mSyncIfEmpty.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleTabsRemoteCommandStore::FromRust( - uniffi_tabs_fn_method_tabsstore_new_remote_command_store( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettingsclient_get_records( mUniffiPtr.IntoRust(), + mSyncIfEmpty.IntoRust(), aOutStatus ) ); @@ -7020,63 +7195,71 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreRegisterWithSyncManager : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecordsMap : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; + FfiValueInt<int8_t> mSyncIfEmpty{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_register_with_sync_manager (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mSyncIfEmpty.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsstore_register_with_sync_manager( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettingsclient_get_records_map( + mUniffiPtr.IntoRust(), + mSyncIfEmpty.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreSetLocalTabs : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientShutdown : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; - FfiValueRustBuffer mRemoteTabs{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_set_local_tabs (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_shutdown (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mRemoteTabs.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tabs_fn_method_tabsstore_set_local_tabs( + uniffi_remote_settings_fn_method_remotesettingsclient_shutdown( mUniffiPtr.IntoRust(), - mRemoteTabs.IntoRust(), aOutStatus ); } @@ -7084,123 +7267,186 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterEventSink : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mTarget{}; - FfiValueRustBuffer mLevel{}; - FfiValueCallbackInterfacetracing_EventSink mSink{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_register_event_sink (expected: 3, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsclient_sync (expected: 1, actual: %zu)", aArgs.Length())); return; } - mTarget.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mLevel.Lower(aArgs[1], aError); + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_remote_settings_fn_method_remotesettingsclient_sync( + mUniffiPtr.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsserviceNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mStorageDir{}; + FfiValueRustBuffer mConfig{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_constructor_remotesettingsservice_new (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mStorageDir.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mSink.Lower(aArgs[2], aError); + mConfig.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tracing_support_fn_func_register_event_sink( - mTarget.IntoRust(), - mLevel.IntoRust(), - mSink.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettingsService::FromRust( + uniffi_remote_settings_fn_constructor_remotesettingsservice_new( + mStorageDir.IntoRust(), + mConfig.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterMinLevelEventSink : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceMakeClient : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mLevel{}; - FfiValueCallbackInterfacetracing_EventSink mSink{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; + FfiValueRustBuffer mCollectionName{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleRemoteSettingsRemoteSettingsClient mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_register_min_level_event_sink (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_make_client (expected: 2, actual: %zu)", aArgs.Length())); return; } - mLevel.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mSink.Lower(aArgs[1], aError); + mCollectionName.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tracing_support_fn_func_register_min_level_event_sink( - mLevel.IntoRust(), - mSink.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleRemoteSettingsRemoteSettingsClient::FromRust( + uniffi_remote_settings_fn_method_remotesettingsservice_make_client( + mUniffiPtr.IntoRust(), + mCollectionName.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterEventSink : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mTarget{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_unregister_event_sink (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_sync (expected: 1, actual: %zu)", aArgs.Length())); return; } - mTarget.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tracing_support_fn_func_unregister_event_sink( - mTarget.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_remote_settings_fn_method_remotesettingsservice_sync( + mUniffiPtr.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterMinLevelEventSink : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceUpdateConfig : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mUniffiPtr{}; + FfiValueRustBuffer mConfig{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_remote_settings_fn_method_remotesettingsservice_update_config (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mConfig.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_tracing_support_fn_func_unregister_min_level_event_sink( + uniffi_remote_settings_fn_method_remotesettingsservice_update_config( + mUniffiPtr.IntoRust(), + mConfig.IntoRust(), aOutStatus ); } @@ -7208,47 +7454,55 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiViaductFnFuncAllowAndroidEmulatorLoopback : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSearchFnConstructorSearchengineselectorNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSearchSearchEngineSelector mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_viaduct_fn_func_allow_android_emulator_loopback( - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleSearchSearchEngineSelector::FromRust( + uniffi_search_fn_constructor_searchengineselector_new( + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiViaductFnFuncInitBackend : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorClearSearchConfig : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleViaductBackend mBackend{}; + FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_viaduct_fn_func_init_backend (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_clear_search_config (expected: 1, actual: %zu)", aArgs.Length())); return; } - mBackend.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_viaduct_fn_func_init_backend( - mBackend.IntoRust(), + uniffi_search_fn_method_searchengineselector_clear_search_config( + mUniffiPtr.IntoRust(), aOutStatus ); } @@ -7256,52 +7510,42 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest() : UniffiAsyncCallHandler( - ffi_viaduct_rust_future_poll_rust_buffer, - ffi_viaduct_rust_future_free_rust_buffer - ) { } - +class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorFilterEngineConfiguration : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; + FfiValueRustBuffer mUserEnvironment{}; + + // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleViaductBackend mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_filter_engine_configuration (expected: 2, actual: %zu)", aArgs.Length())); return; } - FfiValueRustBuffer mRequest{}; - mRequest.Lower(aArgs[1], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - FfiValueRustBuffer mSettings{}; - mSettings.Lower(aArgs[2], aError); + mUserEnvironment.Lower(aArgs[1], aError); if (aError.Failed()) { return; } + } - mFutureHandle = uniffi_viaduct_fn_method_backend_send_request( - mUniffiPtr.IntoRust(), - mRequest.IntoRust(), - mSettings.IntoRust() - ); - } - - void CallCompleteFn(RustCallStatus* aOutStatus) override { + void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_viaduct_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + uniffi_search_fn_method_searchengineselector_filter_engine_configuration( + mUniffiPtr.IntoRust(), + mUserEnvironment.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -7309,199 +7553,215 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineApply : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetConfigOverrides : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; + FfiValueRustBuffer mOverrides{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_set_config_overrides (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mOverrides.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply( - mUniffiPtr.IntoRust(), - aOutStatus - ) + uniffi_search_fn_method_searchengineselector_set_config_overrides( + mUniffiPtr.IntoRust(), + mOverrides.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineEnsureCurrentSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetSearchConfig : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mNewSyncId{}; + FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; + FfiValueRustBuffer mConfiguration{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_set_search_config (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mNewSyncId.Lower(aArgs[1], aError); + mConfiguration.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id( - mUniffiPtr.IntoRust(), - mNewSyncId.IntoRust(), - aOutStatus - ) + uniffi_search_fn_method_searchengineselector_set_search_config( + mUniffiPtr.IntoRust(), + mConfiguration.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineLastSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorUseRemoteSettingsServer : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSearchSearchEngineSelector mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mService{}; + FfiValueInt<int8_t> mApplyEngineOverrides{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_search_fn_method_searchengineselector_use_remote_settings_server (expected: 3, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mService.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mApplyEngineOverrides.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( - uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync( - mUniffiPtr.IntoRust(), - aOutStatus - ) + uniffi_search_fn_method_searchengineselector_use_remote_settings_server( + mUniffiPtr.IntoRust(), + mService.IntoRust(), + mApplyEngineOverrides.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedenginePrepareForSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnFuncRawSuggestionUrlMatches : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mClientData{}; + FfiValueRustBuffer mRawUrl{}; + FfiValueRustBuffer mCookedUrl{}; // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_func_raw_suggestion_url_matches (expected: 2, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mRawUrl.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mClientData.Lower(aArgs[1], aError); + mCookedUrl.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync( - mUniffiPtr.IntoRust(), - mClientData.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_suggest_fn_func_raw_suggestion_url_matches( + mRawUrl.IntoRust(), + mCookedUrl.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineReset : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststoreNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mPath{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRemoteSettingsService{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_constructor_suggeststore_new (expected: 2, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mPath.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mRemoteSettingsService.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStore::FromRust( + uniffi_suggest_fn_constructor_suggeststore_new( + mPath.IntoRust(), + mRemoteSettingsService.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineResetSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreAnyDismissedSuggestions : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); @@ -7511,8 +7771,8 @@ public: } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_suggest_fn_method_suggeststore_any_dismissed_suggestions( mUniffiPtr.IntoRust(), aOutStatus ) @@ -7527,34 +7787,28 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetLastSync : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClear : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; - FfiValueInt<int64_t> mLastSync{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync (expected: 2, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_clear (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mLastSync.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync( + uniffi_suggest_fn_method_suggeststore_clear( mUniffiPtr.IntoRust(), - mLastSync.IntoRust(), aOutStatus ); } @@ -7562,40 +7816,28 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetUploaded : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClearDismissedSuggestions : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; - FfiValueInt<int64_t> mServerModifiedMillis{}; - FfiValueRustBuffer mGuids{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded (expected: 3, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mServerModifiedMillis.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mGuids.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded( + uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions( mUniffiPtr.IntoRust(), - mServerModifiedMillis.IntoRust(), - mGuids.IntoRust(), aOutStatus ); } @@ -7603,34 +7845,34 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineStoreIncoming : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissByKey : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; - FfiValueRustBuffer mIncoming{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mKey{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_by_key (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mIncoming.Lower(aArgs[1], aError); + mKey.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming( + uniffi_suggest_fn_method_suggeststore_dismiss_by_key( mUniffiPtr.IntoRust(), - mIncoming.IntoRust(), + mKey.IntoRust(), aOutStatus ); } @@ -7638,28 +7880,34 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncFinished : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissBySuggestion : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mSuggestion{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mSuggestion.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished( + uniffi_suggest_fn_method_suggeststore_dismiss_by_suggestion( mUniffiPtr.IntoRust(), + mSuggestion.IntoRust(), aOutStatus ); } @@ -7667,125 +7915,163 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncId : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissSuggestion : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mSuggestionUrl{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_dismiss_suggestion (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id( - mUniffiPtr.IntoRust(), - aOutStatus - ) + mSuggestionUrl.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_suggest_fn_method_suggeststore_dismiss_suggestion( + mUniffiPtr.IntoRust(), + mSuggestionUrl.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncStarted : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonameAlternates : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mGeoname{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mGeoname.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_suggest_fn_method_suggeststore_fetch_geoname_alternates( + mUniffiPtr.IntoRust(), + mGeoname.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineWipe : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonames : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mQuery{}; + FfiValueInt<int8_t> mMatchNamePrefix{}; + FfiValueRustBuffer mFilter{}; // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 4) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_geonames (expected: 4, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mQuery.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mMatchNamePrefix.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } + mFilter.Lower(aArgs[3], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_suggest_fn_method_suggeststore_fetch_geonames( + mUniffiPtr.IntoRust(), + mQuery.IntoRust(), + mMatchNamePrefix.IntoRust(), + mFilter.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnConstructorWebextstoragestoreNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGlobalConfig : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mPath{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_constructor_webextstoragestore_new (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_global_config (expected: 1, actual: %zu)", aArgs.Length())); return; } - mPath.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleWebextstorageWebExtStorageStore::FromRust( - uniffi_webext_storage_fn_constructor_webextstoragestore_new( - mPath.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_suggest_fn_method_suggeststore_fetch_global_config( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -7799,30 +8085,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreBridgedEngine : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchProviderConfig : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mProvider{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_fetch_provider_config (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mProvider.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine( + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_suggest_fn_method_suggeststore_fetch_provider_config( mUniffiPtr.IntoRust(), + mProvider.IntoRust(), aOutStatus ) ); @@ -7836,11 +8128,11 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClear : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIngest : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mConstraints{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -7848,14 +8140,14 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_clear (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_ingest (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mExtId.Lower(aArgs[1], aError); + mConstraints.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -7863,9 +8155,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_clear( + uniffi_suggest_fn_method_suggeststore_ingest( mUniffiPtr.IntoRust(), - mExtId.IntoRust(), + mConstraints.IntoRust(), aOutStatus ) ); @@ -7879,28 +8171,34 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClose : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreInterrupt : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mKind{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_close (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_interrupt (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mKind.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_webext_storage_fn_method_webextstoragestore_close( + uniffi_suggest_fn_method_suggeststore_interrupt( mUniffiPtr.IntoRust(), + mKind.IntoRust(), aOutStatus ); } @@ -7908,42 +8206,36 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGet : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedByKey : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; - FfiValueRustBuffer mKeys{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mKey{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get (expected: 3, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mExtId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mKeys.Lower(aArgs[2], aError); + mKey.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_get( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_suggest_fn_method_suggeststore_is_dismissed_by_key( mUniffiPtr.IntoRust(), - mExtId.IntoRust(), - mKeys.IntoRust(), + mKey.IntoRust(), aOutStatus ) ); @@ -7957,42 +8249,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetBytesInUse : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedBySuggestion : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; - FfiValueRustBuffer mKeys{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mSuggestion{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint64_t> mUniffiReturnValue{}; + FfiValueInt<int8_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use (expected: 3, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mExtId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mKeys.Lower(aArgs[2], aError); + mSuggestion.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use( + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_suggest_fn_method_suggeststore_is_dismissed_by_suggestion( mUniffiPtr.IntoRust(), - mExtId.IntoRust(), - mKeys.IntoRust(), + mSuggestion.IntoRust(), aOutStatus ) ); @@ -8006,11 +8292,11 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetKeys : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQuery : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mQuery{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -8018,14 +8304,14 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_keys (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_query (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mExtId.Lower(aArgs[1], aError); + mQuery.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -8033,9 +8319,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_get_keys( + uniffi_suggest_fn_method_suggeststore_query( mUniffiPtr.IntoRust(), - mExtId.IntoRust(), + mQuery.IntoRust(), aOutStatus ) ); @@ -8049,30 +8335,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetSyncedChanges : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQueryWithMetrics : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiPtr{}; + FfiValueRustBuffer mQuery{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststore_query_with_metrics (expected: 2, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + mQuery.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes( + uniffi_suggest_fn_method_suggeststore_query_with_metrics( mUniffiPtr.IntoRust(), + mQuery.IntoRust(), aOutStatus ) ); @@ -8086,42 +8378,20 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreRemove : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststorebuilderNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; - FfiValueRustBuffer mKeys{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_remove (expected: 3, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mExtId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mKeys.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_remove( - mUniffiPtr.IntoRust(), - mExtId.IntoRust(), - mKeys.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_constructor_suggeststorebuilder_new( aOutStatus ) ); @@ -8135,42 +8405,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreSet : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderBuild : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; - FfiValueRustBuffer mExtId{}; - FfiValueRustBuffer mVal{}; + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleSuggestSuggestStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 3) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_set (expected: 3, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_build (expected: 1, actual: %zu)", aArgs.Length())); return; } mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - mExtId.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mVal.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_webext_storage_fn_method_webextstoragestore_set( + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStore::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_build( mUniffiPtr.IntoRust(), - mExtId.IntoRust(), - mVal.IntoRust(), aOutStatus ) ); @@ -8184,42 +8442,42 @@ public: ); } }; - -#ifdef MOZ_UNIFFI_FIXTURES -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_f32, - ffi_uniffi_bindings_tests_rust_future_free_f32 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderCachePath : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueFloat<float> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueRustBuffer mPath{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueFloat<float> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_cache_path (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mPath.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f32( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<float>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_f32(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_cache_path( + mUniffiPtr.IntoRust(), + mPath.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8227,40 +8485,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_f64, - ffi_uniffi_bindings_tests_rust_future_free_f64 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderDataPath : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueFloat<double> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueRustBuffer mPath{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueFloat<double> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_data_path (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mPath.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f64( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<double>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_f64(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_data_path( + mUniffiPtr.IntoRust(), + mPath.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8268,40 +8528,48 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_i16, - ffi_uniffi_bindings_tests_rust_future_free_i16 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderLoadExtension : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<int16_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueRustBuffer mLibrary{}; + FfiValueRustBuffer mEntryPoint{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<int16_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_load_extension (expected: 3, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mLibrary.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mEntryPoint.Lower(aArgs[2], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i16( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int16_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_i16(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_load_extension( + mUniffiPtr.IntoRust(), + mLibrary.IntoRust(), + mEntryPoint.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8309,40 +8577,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_i32, - ffi_uniffi_bindings_tests_rust_future_free_i32 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsBucketName : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<int32_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueRustBuffer mBucketName{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<int32_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mBucketName.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i32( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int32_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_i32(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_bucket_name( + mUniffiPtr.IntoRust(), + mBucketName.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8350,40 +8620,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_i64, - ffi_uniffi_bindings_tests_rust_future_free_i64 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsServer : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<int64_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueRustBuffer mServer{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<int64_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mServer.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i64( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_i64(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_server( + mUniffiPtr.IntoRust(), + mServer.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8391,40 +8663,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_i8, - ffi_uniffi_bindings_tests_rust_future_free_i8 - ) { } - +class ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsService : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<int8_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiPtr{}; + FfiValueObjectHandleRemoteSettingsRemoteSettingsService mRsService{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<int8_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleSuggestSuggestStoreBuilder mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mRsService.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i8( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_i8(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleSuggestSuggestStoreBuilder::FromRust( + uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_service( + mUniffiPtr.IntoRust(), + mRsService.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8432,40 +8706,48 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommand : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueRustBuffer mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; + FfiValueRustBuffer mDeviceId{}; + FfiValueRustBuffer mCommand{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueRustBuffer mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_add_remote_command (expected: 3, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mDeviceId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mCommand.Lower(aArgs[2], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_map( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_tabs_fn_method_remotecommandstore_add_remote_command( + mUniffiPtr.IntoRust(), + mDeviceId.IntoRust(), + mCommand.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8473,40 +8755,54 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_pointer, - ffi_uniffi_bindings_tests_rust_future_free_pointer - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommandAt : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; + FfiValueRustBuffer mDeviceId{}; + FfiValueRustBuffer mCommand{}; + FfiValueInt<int64_t> mWhen{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 4) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at (expected: 4, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mDeviceId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mCommand.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } + mWhen.Lower(aArgs[3], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_obj( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncInterface::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_pointer(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at( + mUniffiPtr.IntoRust(), + mDeviceId.IntoRust(), + mCommand.IntoRust(), + mWhen.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8514,40 +8810,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreGetUnsentCommands : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueRustBuffer mV{}; - mV.Lower(aArgs[0], aError); +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_string( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { + void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8555,40 +8847,48 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u16, - ffi_uniffi_bindings_tests_rust_future_free_u16 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreRemoveRemoteCommand : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint16_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; + FfiValueRustBuffer mDeviceId{}; + FfiValueRustBuffer mCommand{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<uint16_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_remove_remote_command (expected: 3, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mDeviceId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mCommand.Lower(aArgs[2], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u16( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint16_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u16(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_tabs_fn_method_remotecommandstore_remove_remote_command( + mUniffiPtr.IntoRust(), + mDeviceId.IntoRust(), + mCommand.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8596,40 +8896,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u32, - ffi_uniffi_bindings_tests_rust_future_free_u32 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreSetPendingCommandSent : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint32_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiPtr{}; + FfiValueRustBuffer mCommand{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<uint32_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mCommand.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u32( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent( + mUniffiPtr.IntoRust(), + mCommand.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8637,40 +8939,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u64, - ffi_uniffi_bindings_tests_rust_future_free_u64 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineApply : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint64_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<uint64_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_apply (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u64( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u64(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_tabs_fn_method_tabsbridgedengine_apply( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8678,40 +8976,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8 : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u8, - ffi_uniffi_bindings_tests_rust_future_free_u8 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineEnsureCurrentSyncId : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint8_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mNewSyncId{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueInt<uint8_t> mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNewSyncId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u8( - mV.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint8_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u8(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id( + mUniffiPtr.IntoRust(), + mNewSyncId.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8719,40 +9019,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineLastSync : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueRustBuffer mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueRustBuffer mV{}; - mV.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_last_sync (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } + } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_vec( - mV.IntoRust() + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_tabs_fn_method_tabsbridgedengine_last_sync( + mUniffiPtr.IntoRust(), + aOutStatus + ) ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); - } - -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -8760,95 +9056,94 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedenginePrepareForSync : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mClientData{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + // MakeRustCall stores the result of the call in these fields - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_throw_error( - ); +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mClientData.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync( + mUniffiPtr.IntoRust(), + mClientData.IntoRust(), + aOutStatus + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCloneInterface : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineReset : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mInt{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_clone_interface (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_reset (expected: 1, actual: %zu)", aArgs.Length())); return; } - mInt.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( - uniffi_uniffi_bindings_tests_fn_func_clone_interface( - mInt.IntoRust(), - aOutStatus - ) + uniffi_tabs_fn_method_tabsbridgedengine_reset( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateAsyncTestTraitInterface : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineResetSyncId : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mValue{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id (expected: 1, actual: %zu)", aArgs.Length())); return; } - mValue.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface::FromRust( - uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface( - mValue.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -8862,102 +9157,110 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateTestTraitInterface : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetLastSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mValue{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueInt<int64_t> mLastSync{}; // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync (expected: 2, actual: %zu)", aArgs.Length())); return; } - mValue.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mLastSync.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface::FromRust( - uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface( - mValue.IntoRust(), - aOutStatus - ) + uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync( + mUniffiPtr.IntoRust(), + mLastSync.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithDefault : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetUploaded : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mArg{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueInt<int64_t> mNewTimestamp{}; + FfiValueRustBuffer mUploadedIds{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_default (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded (expected: 3, actual: %zu)", aArgs.Length())); return; } - mArg.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNewTimestamp.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mUploadedIds.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_func_with_default( - mArg.IntoRust(), - aOutStatus - ) + uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded( + mUniffiPtr.IntoRust(), + mNewTimestamp.IntoRust(), + mUploadedIds.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithError : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineStoreIncoming : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mInput{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mIncomingEnvelopesAsJson{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_error (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_store_incoming (expected: 2, actual: %zu)", aArgs.Length())); return; } - mInput.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mIncomingEnvelopesAsJson.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_func_with_error( - mInput.IntoRust(), + uniffi_tabs_fn_method_tabsbridgedengine_store_incoming( + mUniffiPtr.IntoRust(), + mIncomingEnvelopesAsJson.IntoRust(), aOutStatus ); } @@ -8965,28 +9268,28 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithFlatError : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncFinished : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mInput{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_finished (expected: 1, actual: %zu)", aArgs.Length())); return; } - mInput.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error( - mInput.IntoRust(), + uniffi_tabs_fn_method_tabsbridgedengine_sync_finished( + mUniffiPtr.IntoRust(), aOutStatus ); } @@ -8994,10 +9297,10 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithMultiWordArg : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncId : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mTheArgument{}; + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -9005,10 +9308,10 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_id (expected: 1, actual: %zu)", aArgs.Length())); return; } - mTheArgument.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } @@ -9016,8 +9319,8 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg( - mTheArgument.IntoRust(), + uniffi_tabs_fn_method_tabsbridgedengine_sync_id( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -9031,67 +9334,94 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncGetCustomTypesDemo : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncStarted : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_sync_started (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_get_custom_types_demo( - aOutStatus - ) + uniffi_tabs_fn_method_tabsbridgedengine_sync_started( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u32, - ffi_uniffi_bindings_tests_rust_future_free_u32 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineWipe : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint32_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; - mInt.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsbridgedengine_wipe (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_get_value( - mInt.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_tabs_fn_method_tabsbridgedengine_wipe( + mUniffiPtr.IntoRust(), + aOutStatus + ); } + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiTabsFnConstructorTabsstoreNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mPath{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleTabsTabsStore mUniffiReturnValue{}; + public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_constructor_tabsstore_new (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mPath.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleTabsTabsStore::FromRust( + uniffi_tabs_fn_constructor_tabsstore_new( + mPath.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -9099,120 +9429,102 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreBridgedEngine : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; - mInt.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleTabsTabsBridgedEngine mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_bridged_engine (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_noop( - mInt.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleTabsTabsBridgedEngine::FromRust( + uniffi_tabs_fn_method_tabsstore_bridged_engine( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreCloseConnection : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; - mInt.Lower(aArgs[0], aError); - if (aError.Failed()) { + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_close_connection (expected: 1, actual: %zu)", aArgs.Length())); return; } - FfiValueInt<uint32_t> mValue{}; - mValue.Lower(aArgs[1], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_set_value( - mInt.IntoRust(), - mValue.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_tabs_fn_method_tabsstore_close_connection( + mUniffiPtr.IntoRust(), + aOutStatus + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreGetAll : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; - mInt.Lower(aArgs[0], aError); - if (aError.Failed()) { +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_get_all (expected: 1, actual: %zu)", aArgs.Length())); return; } - FfiValueRustBuffer mNumbers{}; - mNumbers.Lower(aArgs[1], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_throw_if_equal( - mInt.IntoRust(), - mNumbers.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { + void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + uniffi_tabs_fn_method_tabsstore_get_all( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -9220,40 +9532,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u32, - ffi_uniffi_bindings_tests_rust_future_free_u32 - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreNewRemoteCommandStore : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint32_t> mUniffiReturnValue{}; + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; - mCbi.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleTabsRemoteCommandStore mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_new_remote_command_store (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_get_value( - mCbi.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleTabsRemoteCommandStore::FromRust( + uniffi_tabs_fn_method_tabsstore_new_remote_command_store( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); } -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -9261,186 +9569,104 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void - ) { } - +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreRegisterWithSyncManager : public UniffiSyncCallHandler { private: - // Complete stores the result of the call in mUniffiReturnValue + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; - mCbi.Lower(aArgs[0], aError); + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_register_with_sync_manager (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_noop( - mCbi.IntoRust() - ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); - } - -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void - ) { } - -private: - // Complete stores the result of the call in mUniffiReturnValue - -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; - mCbi.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } - FfiValueInt<uint32_t> mValue{}; - mValue.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_set_value( - mCbi.IntoRust(), - mValue.IntoRust() - ); - } - - void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); - } - -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual : public UniffiAsyncCallHandler { -public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer - ) { } - -private: - // Complete stores the result of the call in mUniffiReturnValue - FfiValueRustBuffer mUniffiReturnValue{}; - -protected: - // Convert a sequence of JS arguments and call the scaffolding function. - // Always called on the main thread since async Rust calls don't block, they - // return a future. - void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; - mCbi.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } - FfiValueRustBuffer mNumbers{}; - mNumbers.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - - mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_throw_if_equal( - mCbi.IntoRust(), - mNumbers.IntoRust() + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_tabs_fn_method_tabsstore_register_with_sync_manager( + mUniffiPtr.IntoRust(), + aOutStatus ); } - void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); - } - -public: - void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceGetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreSetLocalTabs : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + FfiValueObjectHandleTabsTabsStore mUniffiPtr{}; + FfiValueRustBuffer mRemoteTabs{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tabs_fn_method_tabsstore_set_local_tabs (expected: 2, actual: %zu)", aArgs.Length())); return; } - mCbi.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mRemoteTabs.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value( - mCbi.IntoRust(), - aOutStatus - ) + uniffi_tabs_fn_method_tabsstore_set_local_tabs( + mUniffiPtr.IntoRust(), + mRemoteTabs.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceNoop : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterEventSink : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + FfiValueRustBuffer mTarget{}; + FfiValueRustBuffer mLevel{}; + FfiValueCallbackInterfacetracing_EventSink mSink{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_register_event_sink (expected: 3, actual: %zu)", aArgs.Length())); return; } - mCbi.Lower(aArgs[0], aError); + mTarget.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mLevel.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mSink.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop( - mCbi.IntoRust(), + uniffi_tracing_support_fn_func_register_event_sink( + mTarget.IntoRust(), + mLevel.IntoRust(), + mSink.IntoRust(), aOutStatus ); } @@ -9448,34 +9674,34 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceSetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterMinLevelEventSink : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; - FfiValueInt<uint32_t> mValue{}; + FfiValueRustBuffer mLevel{}; + FfiValueCallbackInterfacetracing_EventSink mSink{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value (expected: 2, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_register_min_level_event_sink (expected: 2, actual: %zu)", aArgs.Length())); return; } - mCbi.Lower(aArgs[0], aError); + mLevel.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mValue.Lower(aArgs[1], aError); + mSink.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value( - mCbi.IntoRust(), - mValue.IntoRust(), + uniffi_tracing_support_fn_func_register_min_level_event_sink( + mLevel.IntoRust(), + mSink.IntoRust(), aOutStatus ); } @@ -9483,108 +9709,66 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceThrowIfEqual : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterEventSink : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; - FfiValueRustBuffer mNumbers{}; + FfiValueRustBuffer mTarget{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mCbi.Lower(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_tracing_support_fn_func_unregister_event_sink (expected: 1, actual: %zu)", aArgs.Length())); return; } - mNumbers.Lower(aArgs[1], aError); + mTarget.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal( - mCbi.IntoRust(), - mNumbers.IntoRust(), - aOutStatus - ) + uniffi_tracing_support_fn_func_unregister_event_sink( + mTarget.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceGetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterMinLevelEventSink : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mInt.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value( - mInt.IntoRust(), - aOutStatus - ) + uniffi_tracing_support_fn_func_unregister_min_level_event_sink( + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceNoop : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiViaductFnFuncAllowAndroidEmulatorLoopback : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mInt.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop( - mInt.IntoRust(), + uniffi_viaduct_fn_func_allow_android_emulator_loopback( aOutStatus ); } @@ -9592,34 +9776,28 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceSetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiViaductFnFuncInitBackend : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; - FfiValueInt<uint32_t> mValue{}; + FfiValueObjectHandleViaductBackend mBackend{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mInt.Lower(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_viaduct_fn_func_init_backend (expected: 1, actual: %zu)", aArgs.Length())); return; } - mValue.Lower(aArgs[1], aError); + mBackend.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value( - mInt.IntoRust(), - mValue.IntoRust(), + uniffi_viaduct_fn_func_init_backend( + mBackend.IntoRust(), aOutStatus ); } @@ -9627,42 +9805,52 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceThrowIfEqual : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; - FfiValueRustBuffer mNumbers{}; +class ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest() : UniffiAsyncCallHandler( + ffi_viaduct_rust_future_poll_rust_buffer, + ffi_viaduct_rust_future_free_rust_buffer + ) { } - // MakeRustCall stores the result of the call in these fields +private: + // Complete stores the result of the call in mUniffiReturnValue FfiValueRustBuffer mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleViaductBackend mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { return; } - mInt.Lower(aArgs[0], aError); + FfiValueRustBuffer mRequest{}; + mRequest.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - mNumbers.Lower(aArgs[1], aError); + FfiValueRustBuffer mSettings{}; + mSettings.Lower(aArgs[2], aError); if (aError.Failed()) { return; } + + mFutureHandle = uniffi_viaduct_fn_method_backend_send_request( + mUniffiPtr.IntoRust(), + mRequest.IntoRust(), + mSettings.IntoRust() + ); } - void MakeRustCall(RustCallStatus* aOutStatus) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal( - mInt.IntoRust(), - mNumbers.IntoRust(), - aOutStatus - ) - ); + ffi_viaduct_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -9670,30 +9858,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripBool : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineApply : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int8_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool( - mA.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -9707,21 +9895,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexCompound : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineEnsureCurrentSyncId : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mNewSyncId{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id (expected: 2, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNewSyncId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -9729,8 +9922,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound( - mA.IntoRust(), + uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id( + mUniffiPtr.IntoRust(), + mNewSyncId.IntoRust(), aOutStatus ) ); @@ -9744,30 +9938,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexEnum : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineLastSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mEn{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync (expected: 1, actual: %zu)", aArgs.Length())); return; } - mEn.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum( - mEn.IntoRust(), + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -9781,84 +9975,74 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexRec : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedenginePrepareForSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mRec{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mClientData{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync (expected: 2, actual: %zu)", aArgs.Length())); return; } - mRec.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mClientData.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec( - mRec.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync( + mUniffiPtr.IntoRust(), + mClientData.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripCustomType : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineReset : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint64_t> mHandle{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset (expected: 1, actual: %zu)", aArgs.Length())); return; } - mHandle.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type( - mHandle.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumNoData : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineResetSyncId : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mEn{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -9866,10 +10050,10 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id (expected: 1, actual: %zu)", aArgs.Length())); return; } - mEn.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } @@ -9877,8 +10061,8 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data( - mEn.IntoRust(), + uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -9892,178 +10076,170 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumWithData : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetLastSync : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mEn{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueInt<int64_t> mLastSync{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync (expected: 2, actual: %zu)", aArgs.Length())); return; } - mEn.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mLastSync.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data( - mEn.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync( + mUniffiPtr.IntoRust(), + mLastSync.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF32 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetUploaded : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueFloat<float> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueInt<int64_t> mServerModifiedMillis{}; + FfiValueRustBuffer mGuids{}; // MakeRustCall stores the result of the call in these fields - FfiValueFloat<float> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32 (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded (expected: 3, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mServerModifiedMillis.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mGuids.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<float>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded( + mUniffiPtr.IntoRust(), + mServerModifiedMillis.IntoRust(), + mGuids.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF64 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineStoreIncoming : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueFloat<double> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; + FfiValueRustBuffer mIncoming{}; // MakeRustCall stores the result of the call in these fields - FfiValueFloat<double> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64 (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming (expected: 2, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mIncoming.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<double>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming( + mUniffiPtr.IntoRust(), + mIncoming.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripHashMap : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncFinished : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI16 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncId : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int16_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int16_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16 (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int16_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16( - mA.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -10077,104 +10253,88 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI32 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncStarted : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int32_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int32_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32 (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI64 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineWipe : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int64_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64 (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI8 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnConstructorWebextstoragestoreNew : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int8_t> mA{}; + FfiValueRustBuffer mPath{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int8_t> mUniffiReturnValue{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8 (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_constructor_webextstoragestore_new (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mPath.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8( - mA.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleWebextstorageWebExtStorageStore::FromRust( + uniffi_webext_storage_fn_constructor_webextstoragestore_new( + mPath.IntoRust(), aOutStatus ) ); @@ -10188,30 +10348,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripOption : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreBridgedEngine : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_option (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_option( - mA.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleWebextstorageWebExtStorageBridgedEngine::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -10225,21 +10385,26 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripSimpleRec : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClear : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mRec{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_clear (expected: 2, actual: %zu)", aArgs.Length())); return; } - mRec.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } @@ -10247,8 +10412,9 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec( - mRec.IntoRust(), + uniffi_webext_storage_fn_method_webextstoragestore_clear( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), aOutStatus ) ); @@ -10262,67 +10428,71 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripString : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClose : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_string (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_close (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_string( - mA.IntoRust(), - aOutStatus - ) + uniffi_webext_storage_fn_method_webextstoragestore_close( + mUniffiPtr.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalMs : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGet : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<int64_t> mTime{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; + FfiValueRustBuffer mKeys{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<int64_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get (expected: 3, actual: %zu)", aArgs.Length())); return; } - mTime.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mKeys.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms( - mTime.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_get( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), + mKeys.IntoRust(), aOutStatus ) ); @@ -10336,30 +10506,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecDbl : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetBytesInUse : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueFloat<double> mTime{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; + FfiValueRustBuffer mKeys{}; // MakeRustCall stores the result of the call in these fields - FfiValueFloat<double> mUniffiReturnValue{}; + FfiValueInt<uint64_t> mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use (expected: 3, actual: %zu)", aArgs.Length())); return; } - mTime.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mKeys.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<double>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl( - mTime.IntoRust(), + mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), + mKeys.IntoRust(), aOutStatus ) ); @@ -10373,30 +10555,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecFlt : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetKeys : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueFloat<float> mTime{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; // MakeRustCall stores the result of the call in these fields - FfiValueFloat<float> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_keys (expected: 2, actual: %zu)", aArgs.Length())); return; } - mTime.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<float>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt( - mTime.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_get_keys( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), aOutStatus ) ); @@ -10410,30 +10598,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU16 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetSyncedChanges : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint16_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint16_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16 (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes (expected: 1, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint16_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16( - mA.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes( + mUniffiPtr.IntoRust(), aOutStatus ) ); @@ -10447,30 +10635,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU32 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreRemove : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; + FfiValueRustBuffer mKeys{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32 (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_remove (expected: 3, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mKeys.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32( - mA.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_remove( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), + mKeys.IntoRust(), aOutStatus ) ); @@ -10484,30 +10684,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU64 : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreSet : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint64_t> mA{}; + FfiValueObjectHandleWebextstorageWebExtStorageStore mUniffiPtr{}; + FfiValueRustBuffer mExtId{}; + FfiValueRustBuffer mVal{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint64_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64 (expected: 1, actual: %zu)", aArgs.Length())); + if (aArgs.Length() < 3) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_webext_storage_fn_method_webextstoragestore_set (expected: 3, actual: %zu)", aArgs.Length())); return; } - mA.Lower(aArgs[0], aError); + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mExtId.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mVal.Lower(aArgs[2], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64( - mA.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_webext_storage_fn_method_webextstoragestore_set( + mUniffiPtr.IntoRust(), + mExtId.IntoRust(), + mVal.IntoRust(), aOutStatus ) ); @@ -10521,36 +10733,42 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU8 : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint8_t> mA{}; - - // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint8_t> mUniffiReturnValue{}; +#ifdef MOZ_UNIFFI_FIXTURES +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32 : public UniffiAsyncCallHandler { public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8 (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mA.Lower(aArgs[0], aError); + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_f32, + ffi_uniffi_bindings_tests_rust_future_free_f32 + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueFloat<float> mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueFloat<float> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint8_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8( - mA.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f32( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<float>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_f32(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10558,36 +10776,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripUrl : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mUrl{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64 : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_f64, + ffi_uniffi_bindings_tests_rust_future_free_f64 + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueFloat<double> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_url (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUrl.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueFloat<double> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_url( - mUrl.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_f64( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<double>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_f64(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10595,36 +10817,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripVec : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mA{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16 : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_i16, + ffi_uniffi_bindings_tests_rust_future_free_i16 + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<int16_t> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mA.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueInt<int16_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec( - mA.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i16( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int16_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_i16(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10632,96 +10858,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSumWithManyTypes : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint8_t> mA{}; - FfiValueInt<int8_t> mB{}; - FfiValueInt<uint16_t> mC{}; - FfiValueInt<int16_t> mD{}; - FfiValueInt<uint32_t> mE{}; - FfiValueInt<int32_t> mF{}; - FfiValueInt<uint64_t> mG{}; - FfiValueInt<int64_t> mH{}; - FfiValueFloat<float> mI{}; - FfiValueFloat<double> mJ{}; - FfiValueInt<int8_t> mNegate{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32 : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_i32, + ffi_uniffi_bindings_tests_rust_future_free_i32 + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueFloat<double> mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<int32_t> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 11) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types (expected: 11, actual: %zu)", aArgs.Length())); - return; - } - mA.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } - mB.Lower(aArgs[1], aError); - if (aError.Failed()) { - return; - } - mC.Lower(aArgs[2], aError); - if (aError.Failed()) { - return; - } - mD.Lower(aArgs[3], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueInt<int32_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mE.Lower(aArgs[4], aError); - if (aError.Failed()) { - return; - } - mF.Lower(aArgs[5], aError); - if (aError.Failed()) { - return; - } - mG.Lower(aArgs[6], aError); - if (aError.Failed()) { - return; - } - mH.Lower(aArgs[7], aError); - if (aError.Failed()) { - return; - } - mI.Lower(aArgs[8], aError); - if (aError.Failed()) { - return; - } - mJ.Lower(aArgs[9], aError); - if (aError.Failed()) { - return; - } - mNegate.Lower(aArgs[10], aError); - if (aError.Failed()) { - return; - } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueFloat<double>::FromRust( - uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types( - mA.IntoRust(), - mB.IntoRust(), - mC.IntoRust(), - mD.IntoRust(), - mE.IntoRust(), - mF.IntoRust(), - mG.IntoRust(), - mH.IntoRust(), - mI.IntoRust(), - mJ.IntoRust(), - mNegate.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i32( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int32_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_i32(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10729,36 +10899,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSwapTestInterfaces : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mInterfaces{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64 : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_i64, + ffi_uniffi_bindings_tests_rust_future_free_i64 + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<int64_t> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mInterfaces.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueInt<int64_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces( - mInterfaces.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i64( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_i64(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10766,55 +10940,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncTestFunc : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - - // MakeRustCall stores the result of the call in these fields - +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8 : public UniffiAsyncCallHandler { public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - } - - void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_func_test_func( - aOutStatus - ); - } + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_i8, + ffi_uniffi_bindings_tests_rust_future_free_i8 + ) { } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - } -}; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorTestinterfaceNew : public UniffiSyncCallHandler { private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint32_t> mValue{}; - - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<int8_t> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mValue.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueInt<int8_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( - uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new( - mValue.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_i8( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_i8(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10822,36 +10981,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceGetValue : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiPtr{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueRustBuffer mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value( - mUniffiPtr.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_map( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10859,36 +11022,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceRefCount : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiPtr{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_pointer, + ffi_uniffi_bindings_tests_rust_future_free_pointer + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count( - mUniffiPtr.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_obj( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncInterface::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_pointer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10896,36 +11063,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorAsyncinterfaceNew : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mName{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mName.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueRustBuffer mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncInterface::FromRust( - uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new( - mName.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_string( + mV.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -10933,36 +11104,36 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName : public UniffiAsyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16 : public UniffiAsyncCallHandler { public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, - ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u16, + ffi_uniffi_bindings_tests_rust_future_free_u16 ) { } private: // Complete stores the result of the call in mUniffiReturnValue - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueInt<uint16_t> mUniffiReturnValue{}; protected: // Convert a sequence of JS arguments and call the scaffolding function. // Always called on the main thread since async Rust calls don't block, they // return a future. void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); + FfiValueInt<uint16_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asyncinterface_name( - mUniffiPtr.IntoRust() + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u16( + mV.IntoRust() ); } void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + mUniffiReturnValue = FfiValueInt<uint16_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u16(mFutureHandle, aOutStatus)); } public: @@ -10974,70 +11145,77 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop : public UniffiAsyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32 : public UniffiAsyncCallHandler { public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u32, + ffi_uniffi_bindings_tests_rust_future_free_u32 ) { } private: // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<uint32_t> mUniffiReturnValue{}; protected: // Convert a sequence of JS arguments and call the scaffolding function. // Always called on the main thread since async Rust calls don't block, they // return a future. void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); + FfiValueInt<uint32_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_noop( - mUniffiPtr.IntoRust() + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u32( + mV.IntoRust() ); } void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); } public: void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue : public UniffiAsyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64 : public UniffiAsyncCallHandler { public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_u32, - ffi_uniffi_bindings_tests_rust_future_free_u32 + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u64, + ffi_uniffi_bindings_tests_rust_future_free_u64 ) { } private: // Complete stores the result of the call in mUniffiReturnValue - FfiValueInt<uint32_t> mUniffiReturnValue{}; + FfiValueInt<uint64_t> mUniffiReturnValue{}; protected: // Convert a sequence of JS arguments and call the scaffolding function. // Always called on the main thread since async Rust calls don't block, they // return a future. void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); + FfiValueInt<uint64_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_get_value( - mUniffiPtr.IntoRust() + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u64( + mV.IntoRust() ); } void CallCompleteFn(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u64(mFutureHandle, aOutStatus)); } public: @@ -11049,49 +11227,50 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue : public UniffiAsyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8 : public UniffiAsyncCallHandler { public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue() : UniffiAsyncCallHandler( - ffi_uniffi_bindings_tests_rust_future_poll_void, - ffi_uniffi_bindings_tests_rust_future_free_void + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u8, + ffi_uniffi_bindings_tests_rust_future_free_u8 ) { } private: // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<uint8_t> mUniffiReturnValue{}; protected: // Convert a sequence of JS arguments and call the scaffolding function. // Always called on the main thread since async Rust calls don't block, they // return a future. void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - FfiValueInt<uint32_t> mValue{}; - mValue.Lower(aArgs[1], aError); + FfiValueInt<uint8_t> mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_set_value( - mUniffiPtr.IntoRust(), - mValue.IntoRust() + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_u8( + mV.IntoRust() ); } void CallCompleteFn(RustCallStatus* aOutStatus) override { - ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + mUniffiReturnValue = FfiValueInt<uint8_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u8(mFutureHandle, aOutStatus)); } public: void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual : public UniffiAsyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec : public UniffiAsyncCallHandler { public: - ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual() : UniffiAsyncCallHandler( + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec() : UniffiAsyncCallHandler( ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, ffi_uniffi_bindings_tests_rust_future_free_rust_buffer ) { } @@ -11105,20 +11284,14 @@ protected: // Always called on the main thread since async Rust calls don't block, they // return a future. void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { - return; - } - FfiValueRustBuffer mNumbers{}; - mNumbers.Lower(aArgs[1], aError); + FfiValueRustBuffer mV{}; + mV.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_throw_if_equal( - mUniffiPtr.IntoRust(), - mNumbers.IntoRust() + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_roundtrip_vec( + mV.IntoRust() ); } @@ -11136,63 +11309,58 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorComplexmethodsNew : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } + private: - // LowerRustArgs stores the resulting arguments in these fields + // Complete stores the result of the call in mUniffiReturnValue - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiReturnValue{}; +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_async_throw_error( + ); } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsComplexMethods::FromRust( - uniffi_uniffi_bindings_tests_fn_constructor_complexmethods_new( - aOutStatus - ) - ); + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithDefault : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCloneInterface : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiPtr{}; - FfiValueRustBuffer mArg{}; + FfiValueObjectHandleUniffiBindingsTestsTestInterface mInt{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_clone_interface (expected: 1, actual: %zu)", aArgs.Length())); return; } - mArg.Lower(aArgs[1], aError); + mInt.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default( - mUniffiPtr.IntoRust(), - mArg.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( + uniffi_uniffi_bindings_tests_fn_func_clone_interface( + mInt.IntoRust(), aOutStatus ) ); @@ -11206,36 +11374,30 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithMultiWordArg : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateAsyncTestTraitInterface : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiPtr{}; - FfiValueRustBuffer mTheArgument{}; + FfiValueInt<uint32_t> mValue{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface (expected: 1, actual: %zu)", aArgs.Length())); return; } - mTheArgument.Lower(aArgs[1], aError); + mValue.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg( - mUniffiPtr.IntoRust(), - mTheArgument.IntoRust(), + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface::FromRust( + uniffi_uniffi_bindings_tests_fn_func_create_async_test_trait_interface( + mValue.IntoRust(), aOutStatus ) ); @@ -11249,59 +11411,67 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceNoop : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateTestTraitInterface : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + FfiValueInt<uint32_t> mValue{}; // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface (expected: 1, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mValue.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop( - mUniffiPtr.IntoRust(), - aOutStatus + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface::FromRust( + uniffi_uniffi_bindings_tests_fn_func_create_test_trait_interface( + mValue.IntoRust(), + aOutStatus + ) ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceGetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithDefault : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + FfiValueRustBuffer mArg{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint32_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_default (expected: 1, actual: %zu)", aArgs.Length())); return; } - mUniffiPtr.LowerReciever(aArgs[0], aError); + mArg.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( - uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value( - mUniffiPtr.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_func_with_default( + mArg.IntoRust(), aOutStatus ) ); @@ -11315,34 +11485,28 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceSetValue : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithError : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; - FfiValueInt<uint32_t> mValue{}; + FfiValueInt<uint32_t> mInput{}; // MakeRustCall stores the result of the call in these fields public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_error (expected: 1, actual: %zu)", aArgs.Length())); return; } - mValue.Lower(aArgs[1], aError); + mInput.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value( - mUniffiPtr.IntoRust(), - mValue.IntoRust(), + uniffi_uniffi_bindings_tests_fn_func_func_with_error( + mInput.IntoRust(), aOutStatus ); } @@ -11350,53 +11514,39 @@ public: virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceThrowIfEqual : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithFlatError : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; - FfiValueRustBuffer mNumbers{}; + FfiValueInt<uint32_t> mInput{}; // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 2) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); - return; - } - mUniffiPtr.LowerReciever(aArgs[0], aError); - if (aError.Failed()) { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error (expected: 1, actual: %zu)", aArgs.Length())); return; } - mNumbers.Lower(aArgs[1], aError); + mInput.Lower(aArgs[0], aError); if (aError.Failed()) { return; } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal( - mUniffiPtr.IntoRust(), - mNumbers.IntoRust(), - aOutStatus - ) + uniffi_uniffi_bindings_tests_fn_func_func_with_flat_error( + mInput.IntoRust(), + aOutStatus ); } virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsCollisionFnFuncInvokeCollisionCallback : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithMultiWordArg : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface mCb{}; + FfiValueRustBuffer mTheArgument{}; // MakeRustCall stores the result of the call in these fields FfiValueRustBuffer mUniffiReturnValue{}; @@ -11404,10 +11554,10 @@ private: public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback (expected: 1, actual: %zu)", aArgs.Length())); + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg (expected: 1, actual: %zu)", aArgs.Length())); return; } - mCb.Lower(aArgs[0], aError); + mTheArgument.Lower(aArgs[0], aError); if (aError.Failed()) { return; } @@ -11415,8 +11565,8 @@ public: void MakeRustCall(RustCallStatus* aOutStatus) override { mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback( - mCb.IntoRust(), + uniffi_uniffi_bindings_tests_fn_func_func_with_multi_word_arg( + mTheArgument.IntoRust(), aOutStatus ) ); @@ -11430,30 +11580,20 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtCustomType : public UniffiSyncCallHandler { +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncGetCustomTypesDemo : public UniffiSyncCallHandler { private: // LowerRustArgs stores the resulting arguments in these fields - FfiValueInt<uint64_t> mCustom{}; // MakeRustCall stores the result of the call in these fields - FfiValueInt<uint64_t> mUniffiReturnValue{}; + FfiValueRustBuffer mUniffiReturnValue{}; public: void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mCustom.Lower(aArgs[0], aError); - if (aError.Failed()) { - return; - } } void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( - uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type( - mCustom.IntoRust(), + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_get_custom_types_demo( aOutStatus ) ); @@ -11467,36 +11607,40 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtEnum : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mEn{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u32, + ffi_uniffi_bindings_tests_rust_future_free_u32 + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<uint32_t> mUniffiReturnValue{}; -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum (expected: 1, actual: %zu)", aArgs.Length())); - return; - } - mEn.Lower(aArgs[0], aError); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; + mInt.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum( - mEn.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_get_value( + mInt.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { mUniffiReturnValue.Lift( aCx, &aDest.Construct(), @@ -11504,87 +11648,2492 @@ public: ); } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtInterface : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mInt{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface (expected: 1, actual: %zu)", aArgs.Length())); - return; - } +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; mInt.Lower(aArgs[0], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( - uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface( - mInt.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_noop( + mInt.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { } }; -class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtRecord : public UniffiSyncCallHandler { -private: - // LowerRustArgs stores the resulting arguments in these fields - FfiValueRustBuffer mRec{}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } - // MakeRustCall stores the result of the call in these fields - FfiValueRustBuffer mUniffiReturnValue{}; +private: + // Complete stores the result of the call in mUniffiReturnValue -public: - void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { - if (aArgs.Length() < 1) { - aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record (expected: 1, actual: %zu)", aArgs.Length())); +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { return; } - mRec.Lower(aArgs[0], aError); + FfiValueInt<uint32_t> mValue{}; + mValue.Lower(aArgs[1], aError); if (aError.Failed()) { return; } - } - void MakeRustCall(RustCallStatus* aOutStatus) override { - mUniffiReturnValue = FfiValueRustBuffer::FromRust( - uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record( - mRec.IntoRust(), - aOutStatus - ) + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_set_value( + mInt.IntoRust(), + mValue.IntoRust() ); } - virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { - mUniffiReturnValue.Lift( - aCx, - &aDest.Construct(), - aError - ); + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); } -}; -#endif /* MOZ_UNIFFI_FIXTURES */ - -UniquePtr<UniffiSyncCallHandler> GetSyncCallHandler(uint64_t aId) { - switch (aId) { - case 1: { - return MakeUnique<ScaffoldingCallHandlerUniffiContextIdFnConstructorContextidcomponentNew>(); +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mInt{}; + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + FfiValueRustBuffer mNumbers{}; + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_async_test_trait_interface_throw_if_equal( + mInt.IntoRust(), + mNumbers.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u32, + ffi_uniffi_bindings_tests_rust_future_free_u32 + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_get_value( + mCbi.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_noop( + mCbi.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + FfiValueInt<uint32_t> mValue{}; + mValue.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_set_value( + mCbi.IntoRust(), + mValue.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueCallbackInterfaceuniffi_bindings_tests_TestAsyncCallbackInterface mCbi{}; + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + FfiValueRustBuffer mNumbers{}; + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_func_invoke_test_async_callback_interface_throw_if_equal( + mCbi.IntoRust(), + mNumbers.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceGetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_get_value( + mCbi.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceNoop : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_noop( + mCbi.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceSetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + FfiValueInt<uint32_t> mValue{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mValue.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_set_value( + mCbi.IntoRust(), + mValue.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceThrowIfEqual : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueCallbackInterfaceuniffi_bindings_tests_TestCallbackInterface mCbi{}; + FfiValueRustBuffer mNumbers{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mCbi.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_invoke_test_callback_interface_throw_if_equal( + mCbi.IntoRust(), + mNumbers.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceGetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_get_value( + mInt.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceNoop : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_noop( + mInt.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceSetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; + FfiValueInt<uint32_t> mValue{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mValue.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_set_value( + mInt.IntoRust(), + mValue.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceThrowIfEqual : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mInt{}; + FfiValueRustBuffer mNumbers{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_invoke_test_trait_interface_throw_if_equal( + mInt.IntoRust(), + mNumbers.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripBool : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int8_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_bool( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexCompound : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_compound( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexEnum : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mEn{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mEn.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_enum( + mEn.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexRec : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mRec{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mRec.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_complex_rec( + mRec.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripCustomType : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint64_t> mHandle{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mHandle.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_custom_type( + mHandle.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumNoData : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mEn{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mEn.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_no_data( + mEn.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumWithData : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mEn{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mEn.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_enum_with_data( + mEn.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF32 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueFloat<float> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueFloat<float> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<float>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_f32( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF64 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueFloat<double> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueFloat<double> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<double>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_f64( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripHashMap : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_hash_map( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI16 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int16_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int16_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int16_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_i16( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI32 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int32_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_i32( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI64 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int64_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_i64( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI8 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int8_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int8_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_i8( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripOption : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_option (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_option( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripSimpleRec : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mRec{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mRec.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_simple_rec( + mRec.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripString : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_string (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_string( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalMs : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<int64_t> mTime{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<int64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mTime.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<int64_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_ms( + mTime.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecDbl : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueFloat<double> mTime{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueFloat<double> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mTime.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<double>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_dbl( + mTime.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecFlt : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueFloat<float> mTime{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueFloat<float> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mTime.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<float>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_time_interval_sec_flt( + mTime.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU16 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint16_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint16_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint16_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_u16( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU32 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint32_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_u32( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU64 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint64_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_u64( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU8 : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint8_t> mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint8_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8 (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint8_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_u8( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripUrl : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mUrl{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_url (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUrl.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_url( + mUrl.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripVec : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mA{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_roundtrip_vec( + mA.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSumWithManyTypes : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint8_t> mA{}; + FfiValueInt<int8_t> mB{}; + FfiValueInt<uint16_t> mC{}; + FfiValueInt<int16_t> mD{}; + FfiValueInt<uint32_t> mE{}; + FfiValueInt<int32_t> mF{}; + FfiValueInt<uint64_t> mG{}; + FfiValueInt<int64_t> mH{}; + FfiValueFloat<float> mI{}; + FfiValueFloat<double> mJ{}; + FfiValueInt<int8_t> mNegate{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueFloat<double> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 11) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types (expected: 11, actual: %zu)", aArgs.Length())); + return; + } + mA.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mB.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + mC.Lower(aArgs[2], aError); + if (aError.Failed()) { + return; + } + mD.Lower(aArgs[3], aError); + if (aError.Failed()) { + return; + } + mE.Lower(aArgs[4], aError); + if (aError.Failed()) { + return; + } + mF.Lower(aArgs[5], aError); + if (aError.Failed()) { + return; + } + mG.Lower(aArgs[6], aError); + if (aError.Failed()) { + return; + } + mH.Lower(aArgs[7], aError); + if (aError.Failed()) { + return; + } + mI.Lower(aArgs[8], aError); + if (aError.Failed()) { + return; + } + mJ.Lower(aArgs[9], aError); + if (aError.Failed()) { + return; + } + mNegate.Lower(aArgs[10], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueFloat<double>::FromRust( + uniffi_uniffi_bindings_tests_fn_func_sum_with_many_types( + mA.IntoRust(), + mB.IntoRust(), + mC.IntoRust(), + mD.IntoRust(), + mE.IntoRust(), + mF.IntoRust(), + mG.IntoRust(), + mH.IntoRust(), + mI.IntoRust(), + mJ.IntoRust(), + mNegate.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSwapTestInterfaces : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mInterfaces{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mInterfaces.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_func_swap_test_interfaces( + mInterfaces.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncTestFunc : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_func_test_func( + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorTestinterfaceNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint32_t> mValue{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mValue.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( + uniffi_uniffi_bindings_tests_fn_constructor_testinterface_new( + mValue.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceGetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_method_testinterface_get_value( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceRefCount : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_method_testinterface_ref_count( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorAsyncinterfaceNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mName{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mName.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsAsyncInterface::FromRust( + uniffi_uniffi_bindings_tests_fn_constructor_asyncinterface_new( + mName.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncInterface mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asyncinterface_name( + mUniffiPtr.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_noop( + mUniffiPtr.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_u32, + ffi_uniffi_bindings_tests_rust_future_free_u32 + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_get_value( + mUniffiPtr.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_u32(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_void, + ffi_uniffi_bindings_tests_rust_future_free_void + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + FfiValueInt<uint32_t> mValue{}; + mValue.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_set_value( + mUniffiPtr.IntoRust(), + mValue.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + ffi_uniffi_bindings_tests_rust_future_complete_void(mFutureHandle, aOutStatus); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual : public UniffiAsyncCallHandler { +public: + ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual() : UniffiAsyncCallHandler( + ffi_uniffi_bindings_tests_rust_future_poll_rust_buffer, + ffi_uniffi_bindings_tests_rust_future_free_rust_buffer + ) { } + +private: + // Complete stores the result of the call in mUniffiReturnValue + FfiValueRustBuffer mUniffiReturnValue{}; + +protected: + // Convert a sequence of JS arguments and call the scaffolding function. + // Always called on the main thread since async Rust calls don't block, they + // return a future. + void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + FfiValueObjectHandleUniffiBindingsTestsAsyncTestTraitInterface mUniffiPtr{}; + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + FfiValueRustBuffer mNumbers{}; + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + + mFutureHandle = uniffi_uniffi_bindings_tests_fn_method_asynctesttraitinterface_throw_if_equal( + mUniffiPtr.IntoRust(), + mNumbers.IntoRust() + ); + } + + void CallCompleteFn(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + ffi_uniffi_bindings_tests_rust_future_complete_rust_buffer(mFutureHandle, aOutStatus)); + } + +public: + void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorComplexmethodsNew : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsComplexMethods::FromRust( + uniffi_uniffi_bindings_tests_fn_constructor_complexmethods_new( + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithDefault : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiPtr{}; + FfiValueRustBuffer mArg{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mArg.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_default( + mUniffiPtr.IntoRust(), + mArg.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithMultiWordArg : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsComplexMethods mUniffiPtr{}; + FfiValueRustBuffer mTheArgument{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mTheArgument.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_method_complexmethods_method_with_multi_word_arg( + mUniffiPtr.IntoRust(), + mTheArgument.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceNoop : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_noop( + mUniffiPtr.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceGetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint32_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint32_t>::FromRust( + uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_get_value( + mUniffiPtr.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceSetValue : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + FfiValueInt<uint32_t> mValue{}; + + // MakeRustCall stores the result of the call in these fields + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mValue.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_set_value( + mUniffiPtr.IntoRust(), + mValue.IntoRust(), + aOutStatus + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceThrowIfEqual : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestTraitInterface mUniffiPtr{}; + FfiValueRustBuffer mNumbers{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 2) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal (expected: 2, actual: %zu)", aArgs.Length())); + return; + } + mUniffiPtr.LowerReciever(aArgs[0], aError); + if (aError.Failed()) { + return; + } + mNumbers.Lower(aArgs[1], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_fn_method_testtraitinterface_throw_if_equal( + mUniffiPtr.IntoRust(), + mNumbers.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsCollisionFnFuncInvokeCollisionCallback : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueCallbackInterfaceuniffi_bindings_tests_collision_TestCallbackInterface mCb{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mCb.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_collision_fn_func_invoke_collision_callback( + mCb.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtCustomType : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueInt<uint64_t> mCustom{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueInt<uint64_t> mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mCustom.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueInt<uint64_t>::FromRust( + uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_custom_type( + mCustom.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtEnum : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mEn{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mEn.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_enum( + mEn.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtInterface : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueObjectHandleUniffiBindingsTestsTestInterface mInt{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueObjectHandleUniffiBindingsTestsTestInterface mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mInt.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueObjectHandleUniffiBindingsTestsTestInterface::FromRust( + uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_interface( + mInt.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +class ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtRecord : public UniffiSyncCallHandler { +private: + // LowerRustArgs stores the resulting arguments in these fields + FfiValueRustBuffer mRec{}; + + // MakeRustCall stores the result of the call in these fields + FfiValueRustBuffer mUniffiReturnValue{}; + +public: + void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override { + if (aArgs.Length() < 1) { + aError.ThrowUnknownError(nsPrintfCString("LowerRustArgs: Incorrect argument length for uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record (expected: 1, actual: %zu)", aArgs.Length())); + return; + } + mRec.Lower(aArgs[0], aError); + if (aError.Failed()) { + return; + } + } + + void MakeRustCall(RustCallStatus* aOutStatus) override { + mUniffiReturnValue = FfiValueRustBuffer::FromRust( + uniffi_uniffi_bindings_tests_external_types_fn_func_roundtrip_ext_record( + mRec.IntoRust(), + aOutStatus + ) + ); + } + + virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override { + mUniffiReturnValue.Lift( + aCx, + &aDest.Construct(), + aError + ); + } +}; +#endif /* MOZ_UNIFFI_FIXTURES */ + +UniquePtr<UniffiSyncCallHandler> GetSyncCallHandler(uint64_t aId) { + switch (aId) { + + case 1: { + return MakeUnique<ScaffoldingCallHandlerUniffiContextIdFnConstructorContextidcomponentNew>(); } case 2: { return MakeUnique<ScaffoldingCallHandlerUniffiContextIdFnMethodContextidcomponentForceRotation>(); @@ -11602,944 +14151,1499 @@ UniquePtr<UniffiSyncCallHandler> GetSyncCallHandler(uint64_t aId) { return MakeUnique<ScaffoldingCallHandlerUniffiFilterAdultFnMethodFilteradultcomponentContains>(); } case 7: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnFuncScore>(); + return MakeUnique<ScaffoldingCallHandlerUniffiInitRustComponentsFnFuncInitialize>(); } case 8: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnConstructorRelevancystoreNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCheckCanary>(); } case 9: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditInit>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateCanary>(); } case 10: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditSelect>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateKey>(); } case 11: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditUpdate>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateLoginStoreWithNssKeymanager>(); } case 12: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreClose>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateLoginStoreWithStaticKeyManager>(); } case 13: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreEnsureInterestDataPopulated>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateManagedEncdec>(); } case 14: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreGetBanditData>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnFuncCreateStaticKeyManager>(); } case 15: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreIngest>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodEncryptordecryptorDecrypt>(); } case 16: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreInterrupt>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodEncryptordecryptorEncrypt>(); } case 17: { - return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreUserInterestVector>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodKeymanagerGetKey>(); } case 18: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnConstructorLoginstoreNew>(); } case 19: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsDownloadAttachmentToPath>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAdd>(); } case 20: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecords>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddMany>(); } case 21: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecordsSince>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddManyWithMeta>(); } case 22: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientCollectionName>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddOrUpdate>(); } case 23: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetAttachment>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreAddWithMeta>(); } case 24: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecords>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCount>(); } case 25: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecordsMap>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCountByFormActionOrigin>(); } case 26: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientShutdown>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreCountByOrigin>(); } case 27: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientSync>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDelete>(); } case 28: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsserviceNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDeleteMany>(); } case 29: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceMakeClient>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreDeleteUndecryptableRecordsForRemoteReplacement>(); } case 30: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceSync>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreFindLoginToUpdate>(); } case 31: { - return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceUpdateConfig>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGet>(); } case 32: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnConstructorSearchengineselectorNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGetByBaseDomain>(); } case 33: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorClearSearchConfig>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreGetCheckpoint>(); } case 34: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorFilterEngineConfiguration>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreHasLoginsByBaseDomain>(); } case 35: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetConfigOverrides>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreIsEmpty>(); } case 36: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetSearchConfig>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreList>(); } case 37: { - return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorUseRemoteSettingsServer>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreRegisterWithSyncManager>(); } case 38: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnFuncRawSuggestionUrlMatches>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreReset>(); } case 39: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststoreNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreRunMaintenance>(); } case 40: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreAnyDismissedSuggestions>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreSetCheckpoint>(); } case 41: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClear>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreShutdown>(); } case 42: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClearDismissedSuggestions>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreTouch>(); } case 43: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissByKey>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreUpdate>(); } case 44: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissBySuggestion>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodLoginstoreWipeLocal>(); } case 45: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissSuggestion>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnConstructorManagedencryptordecryptorNew>(); } case 46: { - return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonameAlternates>(); + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnConstructorNsskeymanagerNew>(); } case 47: { + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodNsskeymanagerIntoDynKeyManager>(); + } + case 51: { + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnConstructorStatickeymanagerNew>(); + } + case 52: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnFuncScore>(); + } + case 53: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnConstructorRelevancystoreNew>(); + } + case 54: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditInit>(); + } + case 55: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditSelect>(); + } + case 56: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreBanditUpdate>(); + } + case 57: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreClose>(); + } + case 58: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreEnsureInterestDataPopulated>(); + } + case 59: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreGetBanditData>(); + } + case 60: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreIngest>(); + } + case 61: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreInterrupt>(); + } + case 62: { + return MakeUnique<ScaffoldingCallHandlerUniffiRelevancyFnMethodRelevancystoreUserInterestVector>(); + } + case 63: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsNew>(); + } + case 64: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsDownloadAttachmentToPath>(); + } + case 65: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecords>(); + } + case 66: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsGetRecordsSince>(); + } + case 67: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientCollectionName>(); + } + case 68: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetAttachment>(); + } + case 69: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecords>(); + } + case 70: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientGetRecordsMap>(); + } + case 71: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientShutdown>(); + } + case 72: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsclientSync>(); + } + case 73: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnConstructorRemotesettingsserviceNew>(); + } + case 74: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceMakeClient>(); + } + case 75: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceSync>(); + } + case 76: { + return MakeUnique<ScaffoldingCallHandlerUniffiRemoteSettingsFnMethodRemotesettingsserviceUpdateConfig>(); + } + case 77: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnConstructorSearchengineselectorNew>(); + } + case 78: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorClearSearchConfig>(); + } + case 79: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorFilterEngineConfiguration>(); + } + case 80: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetConfigOverrides>(); + } + case 81: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorSetSearchConfig>(); + } + case 82: { + return MakeUnique<ScaffoldingCallHandlerUniffiSearchFnMethodSearchengineselectorUseRemoteSettingsServer>(); + } + case 83: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnFuncRawSuggestionUrlMatches>(); + } + case 84: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststoreNew>(); + } + case 85: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreAnyDismissedSuggestions>(); + } + case 86: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClear>(); + } + case 87: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreClearDismissedSuggestions>(); + } + case 88: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissByKey>(); + } + case 89: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissBySuggestion>(); + } + case 90: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreDismissSuggestion>(); + } + case 91: { + return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonameAlternates>(); + } + case 92: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGeonames>(); } - case 48: { + case 93: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchGlobalConfig>(); } - case 49: { + case 94: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreFetchProviderConfig>(); } - case 50: { + case 95: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIngest>(); } - case 51: { + case 96: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreInterrupt>(); } - case 52: { + case 97: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedByKey>(); } - case 53: { + case 98: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreIsDismissedBySuggestion>(); } - case 54: { + case 99: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQuery>(); } - case 55: { + case 100: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststoreQueryWithMetrics>(); } - case 56: { + case 101: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnConstructorSuggeststorebuilderNew>(); } - case 57: { + case 102: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderBuild>(); } - case 58: { + case 103: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderCachePath>(); } - case 59: { + case 104: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderDataPath>(); } - case 60: { + case 105: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderLoadExtension>(); } - case 61: { + case 106: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsBucketName>(); } - case 62: { + case 107: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsServer>(); } - case 63: { + case 108: { return MakeUnique<ScaffoldingCallHandlerUniffiSuggestFnMethodSuggeststorebuilderRemoteSettingsService>(); } - case 64: { + case 109: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommand>(); } - case 65: { + case 110: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreAddRemoteCommandAt>(); } - case 66: { + case 111: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreGetUnsentCommands>(); } - case 67: { + case 112: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreRemoveRemoteCommand>(); } - case 68: { + case 113: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodRemotecommandstoreSetPendingCommandSent>(); } - case 69: { + case 114: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineApply>(); } - case 70: { + case 115: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineEnsureCurrentSyncId>(); } - case 71: { + case 116: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineLastSync>(); } - case 72: { + case 117: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedenginePrepareForSync>(); } - case 73: { + case 118: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineReset>(); } - case 74: { + case 119: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineResetSyncId>(); } - case 75: { + case 120: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetLastSync>(); } - case 76: { + case 121: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSetUploaded>(); } - case 77: { + case 122: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineStoreIncoming>(); } - case 78: { + case 123: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncFinished>(); } - case 79: { + case 124: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncId>(); } - case 80: { + case 125: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineSyncStarted>(); } - case 81: { + case 126: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsbridgedengineWipe>(); } - case 82: { + case 127: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnConstructorTabsstoreNew>(); } - case 83: { + case 128: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreBridgedEngine>(); } - case 84: { + case 129: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreCloseConnection>(); } - case 85: { + case 130: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreGetAll>(); } - case 86: { + case 131: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreNewRemoteCommandStore>(); } - case 87: { + case 132: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreRegisterWithSyncManager>(); } - case 88: { + case 133: { return MakeUnique<ScaffoldingCallHandlerUniffiTabsFnMethodTabsstoreSetLocalTabs>(); } - case 89: { + case 134: { return MakeUnique<ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterEventSink>(); } - case 90: { + case 135: { return MakeUnique<ScaffoldingCallHandlerUniffiTracingSupportFnFuncRegisterMinLevelEventSink>(); } - case 91: { + case 136: { return MakeUnique<ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterEventSink>(); } - case 92: { + case 137: { return MakeUnique<ScaffoldingCallHandlerUniffiTracingSupportFnFuncUnregisterMinLevelEventSink>(); } - case 93: { + case 138: { return MakeUnique<ScaffoldingCallHandlerUniffiViaductFnFuncAllowAndroidEmulatorLoopback>(); } - case 94: { + case 139: { return MakeUnique<ScaffoldingCallHandlerUniffiViaductFnFuncInitBackend>(); } - case 96: { + case 141: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineApply>(); } - case 97: { + case 142: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineEnsureCurrentSyncId>(); } - case 98: { + case 143: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineLastSync>(); } - case 99: { + case 144: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedenginePrepareForSync>(); } - case 100: { + case 145: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineReset>(); } - case 101: { + case 146: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineResetSyncId>(); } - case 102: { + case 147: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetLastSync>(); } - case 103: { + case 148: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSetUploaded>(); } - case 104: { + case 149: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineStoreIncoming>(); } - case 105: { + case 150: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncFinished>(); } - case 106: { + case 151: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncId>(); } - case 107: { + case 152: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineSyncStarted>(); } - case 108: { + case 153: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragebridgedengineWipe>(); } - case 109: { + case 154: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnConstructorWebextstoragestoreNew>(); } - case 110: { + case 155: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreBridgedEngine>(); } - case 111: { + case 156: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClear>(); } - case 112: { + case 157: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreClose>(); } - case 113: { + case 158: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGet>(); } - case 114: { + case 159: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetBytesInUse>(); } - case 115: { + case 160: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetKeys>(); } - case 116: { + case 161: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreGetSyncedChanges>(); } - case 117: { + case 162: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreRemove>(); } - case 118: { + case 163: { return MakeUnique<ScaffoldingCallHandlerUniffiWebextStorageFnMethodWebextstoragestoreSet>(); } #ifdef MOZ_UNIFFI_FIXTURES - case 134: { + case 179: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCloneInterface>(); } - case 135: { + case 180: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateAsyncTestTraitInterface>(); } - case 136: { + case 181: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncCreateTestTraitInterface>(); } - case 137: { + case 182: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithDefault>(); } - case 138: { + case 183: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithError>(); } - case 139: { + case 184: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithFlatError>(); } - case 140: { + case 185: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncFuncWithMultiWordArg>(); } - case 141: { + case 186: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncGetCustomTypesDemo>(); } - case 150: { + case 195: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceGetValue>(); } - case 151: { + case 196: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceNoop>(); } - case 152: { + case 197: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceSetValue>(); } - case 153: { + case 198: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestCallbackInterfaceThrowIfEqual>(); } - case 154: { + case 199: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceGetValue>(); } - case 155: { + case 200: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceNoop>(); } - case 156: { + case 201: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceSetValue>(); } - case 157: { + case 202: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestTraitInterfaceThrowIfEqual>(); } - case 158: { + case 203: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripBool>(); } - case 159: { + case 204: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexCompound>(); } - case 160: { + case 205: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexEnum>(); } - case 161: { + case 206: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripComplexRec>(); } - case 162: { + case 207: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripCustomType>(); } - case 163: { + case 208: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumNoData>(); } - case 164: { + case 209: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripEnumWithData>(); } - case 165: { + case 210: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF32>(); } - case 166: { + case 211: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripF64>(); } - case 167: { + case 212: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripHashMap>(); } - case 168: { + case 213: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI16>(); } - case 169: { + case 214: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI32>(); } - case 170: { + case 215: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI64>(); } - case 171: { + case 216: { return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripI8>(); } + case 217: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripOption>(); + } + case 218: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripSimpleRec>(); + } + case 219: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripString>(); + } + case 220: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalMs>(); + } + case 221: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecDbl>(); + } + case 222: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecFlt>(); + } + case 223: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU16>(); + } + case 224: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU32>(); + } + case 225: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU64>(); + } + case 226: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU8>(); + } + case 227: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripUrl>(); + } + case 228: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripVec>(); + } + case 229: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSumWithManyTypes>(); + } + case 230: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSwapTestInterfaces>(); + } + case 231: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncTestFunc>(); + } + case 232: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorTestinterfaceNew>(); + } + case 233: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceGetValue>(); + } + case 234: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceRefCount>(); + } + case 235: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorAsyncinterfaceNew>(); + } + case 241: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorComplexmethodsNew>(); + } + case 242: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithDefault>(); + } + case 243: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithMultiWordArg>(); + } + case 244: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceNoop>(); + } + case 245: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceGetValue>(); + } + case 246: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceSetValue>(); + } + case 247: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceThrowIfEqual>(); + } + case 248: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsCollisionFnFuncInvokeCollisionCallback>(); + } + case 249: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtCustomType>(); + } + case 250: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtEnum>(); + } + case 251: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtInterface>(); + } + case 252: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtRecord>(); + } +#endif /* MOZ_UNIFFI_FIXTURES */ + + default: + return nullptr; + } +} + +UniquePtr<UniffiAsyncCallHandler> GetAsyncCallHandler(uint64_t aId) { + switch (aId) { + + case 48: { + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorGetPrimaryPassword>(); + } + case 49: { + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationSuccess>(); + } + case 50: { + return MakeUnique<ScaffoldingCallHandlerUniffiLoginsFnMethodPrimarypasswordauthenticatorOnAuthenticationFailure>(); + } + case 140: { + return MakeUnique<ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest>(); + } + +#ifdef MOZ_UNIFFI_FIXTURES + case 164: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32>(); + } + case 165: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64>(); + } + case 166: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16>(); + } + case 167: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32>(); + } + case 168: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64>(); + } + case 169: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8>(); + } + case 170: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap>(); + } + case 171: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj>(); + } case 172: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripOption>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString>(); } case 173: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripSimpleRec>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16>(); } case 174: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripString>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32>(); } case 175: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalMs>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64>(); } case 176: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecDbl>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8>(); } case 177: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripTimeIntervalSecFlt>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec>(); } case 178: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU16>(); - } - case 179: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU32>(); - } - case 180: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU64>(); - } - case 181: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripU8>(); - } - case 182: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripUrl>(); - } - case 183: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncRoundtripVec>(); - } - case 184: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSumWithManyTypes>(); - } - case 185: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncSwapTestInterfaces>(); - } - case 186: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncTestFunc>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError>(); } case 187: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorTestinterfaceNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue>(); } case 188: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceGetValue>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop>(); } case 189: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTestinterfaceRefCount>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue>(); } case 190: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorAsyncinterfaceNew>(); + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual>(); } - case 196: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnConstructorComplexmethodsNew>(); + case 191: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue>(); } - case 197: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithDefault>(); + case 192: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop>(); } - case 198: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodComplexmethodsMethodWithMultiWordArg>(); + case 193: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue>(); } - case 199: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceNoop>(); + case 194: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual>(); } - case 200: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceGetValue>(); + case 236: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName>(); } - case 201: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceSetValue>(); + case 237: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop>(); } - case 202: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodTesttraitinterfaceThrowIfEqual>(); + case 238: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue>(); } - case 203: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsCollisionFnFuncInvokeCollisionCallback>(); + case 239: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue>(); } - case 204: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtCustomType>(); + case 240: { + return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual>(); } - case 205: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtEnum>(); +#endif /* MOZ_UNIFFI_FIXTURES */ + + default: + return nullptr; + } +} +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + + +/** + * Handle callback interface return values for a single return type + */ +class CallbackLowerReturnVoid { +public: + /** + * Lower return values + * + * This inputs a UniFFIScaffoldingCallResult from JS and converts it to + * something that can be passed to Rust. + * + * - On success, it returns the FFI return value + * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. + */ + static void + Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + RustCallStatus* aOutCallStatus, + ErrorResult& aRv) { + aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; + switch (aCallResult.mCode) { + case UniFFIScaffoldingCallCode::Success: { + aOutCallStatus->code = RUST_CALL_SUCCESS; + break; + } + + case UniFFIScaffoldingCallCode::Error: { + if (!aCallResult.mData.WasPassed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] No data passed")); + break; + } + FfiValueRustBuffer errorBuf; + errorBuf.Lower(aCallResult.mData.Value(), aRv); + if (aRv.Failed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] Failed to lower error buffer")); + break; + } + + aOutCallStatus->error_buf = errorBuf.IntoRust(); + aOutCallStatus->code = RUST_CALL_ERROR; + break; + } + + default: { + break; + } } - case 206: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtInterface>(); + + } +}; + +/** + * Handle callback interface return values for a single return type + */ +class CallbackLowerReturnRustBuffer { +public: + /** + * Lower return values + * + * This inputs a UniFFIScaffoldingCallResult from JS and converts it to + * something that can be passed to Rust. + * + * - On success, it returns the FFI return value + * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. + */ + static RustBuffer + Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + RustCallStatus* aOutCallStatus, + ErrorResult& aRv) { + aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; + FfiValueRustBuffer returnValue; + switch (aCallResult.mCode) { + case UniFFIScaffoldingCallCode::Success: { + if (!aCallResult.mData.WasPassed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] No data passed")); + break; + } + returnValue.Lower(aCallResult.mData.Value(), aRv); + if (aRv.Failed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] Failed to lower return value")); + break; + } + aOutCallStatus->code = RUST_CALL_SUCCESS; + break; + } + + case UniFFIScaffoldingCallCode::Error: { + if (!aCallResult.mData.WasPassed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] No data passed")); + break; + } + FfiValueRustBuffer errorBuf; + errorBuf.Lower(aCallResult.mData.Value(), aRv); + if (aRv.Failed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] Failed to lower error buffer")); + break; + } + + aOutCallStatus->error_buf = errorBuf.IntoRust(); + aOutCallStatus->code = RUST_CALL_ERROR; + break; + } + + default: { + break; + } + } + + return returnValue.IntoRust(); + } +}; + +#ifdef MOZ_UNIFFI_FIXTURES + +/** + * Handle callback interface return values for a single return type + */ +class CallbackLowerReturnUInt32 { +public: + /** + * Lower return values + * + * This inputs a UniFFIScaffoldingCallResult from JS and converts it to + * something that can be passed to Rust. + * + * - On success, it returns the FFI return value + * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. + */ + static uint32_t + Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + RustCallStatus* aOutCallStatus, + ErrorResult& aRv) { + aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; + FfiValueInt<uint32_t> returnValue; + switch (aCallResult.mCode) { + case UniFFIScaffoldingCallCode::Success: { + if (!aCallResult.mData.WasPassed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] No data passed")); + break; + } + returnValue.Lower(aCallResult.mData.Value(), aRv); + if (aRv.Failed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] Failed to lower return value")); + break; + } + aOutCallStatus->code = RUST_CALL_SUCCESS; + break; + } + + case UniFFIScaffoldingCallCode::Error: { + if (!aCallResult.mData.WasPassed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] No data passed")); + break; + } + FfiValueRustBuffer errorBuf; + errorBuf.Lower(aCallResult.mData.Value(), aRv); + if (aRv.Failed()) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] Failed to lower error buffer")); + break; + } + + aOutCallStatus->error_buf = errorBuf.IntoRust(); + aOutCallStatus->code = RUST_CALL_ERROR; + break; + } + + default: { + break; + } } - case 207: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsExternalTypesFnFuncRoundtripExtRecord>(); + + return returnValue.IntoRust(); } +}; #endif /* MOZ_UNIFFI_FIXTURES */ - default: - return nullptr; - } -} +// Callback interface method handlers, vtables, etc. -UniquePtr<UniffiAsyncCallHandler> GetAsyncCallHandler(uint64_t aId) { - switch (aId) { +static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerContextIdContextIdCallback; +/** + * Callback method handler subclass for callback_interface_context_id_context_id_callback_persist + * + * This is like the handler for an async function except: + * + * - It doesn't input the complete callback function/data + * - It doesn't override HandleReturn and returns `nullptr` from MakeCall. + * This means ScheduleAsyncCall will schedule `MakeCall` and not do anything + * with the result, which is what we want. + */ +class CallbackInterfaceMethodContextIdContextIdCallbackPersist final : public AsyncCallbackMethodHandlerBase { +private: + // Rust arguments + FfiValueRustBuffer mContextId{}; + FfiValueInt<int64_t> mCreationDate{}; - case 95: { - return MakeUnique<ScaffoldingCallHandlerUniffiViaductFnMethodBackendSendRequest>(); - } +public: + CallbackInterfaceMethodContextIdContextIdCallbackPersist( + uint64_t aUniffiHandle, + RustBuffer aContextId, + int64_t aCreationDate + ) : AsyncCallbackMethodHandlerBase ("ContextIdCallback.callback_interface_context_id_context_id_callback_persist", aUniffiHandle), + mContextId(FfiValueRustBuffer::FromRust(aContextId)), + mCreationDate(FfiValueInt<int64_t>::FromRust(aCreationDate)){ } -#ifdef MOZ_UNIFFI_FIXTURES - case 119: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF32>(); - } - case 120: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripF64>(); - } - case 121: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI16>(); - } - case 122: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI32>(); - } - case 123: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI64>(); - } - case 124: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripI8>(); - } - case 125: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripMap>(); - } - case 126: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripObj>(); - } - case 127: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripString>(); - } - case 128: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU16>(); - } - case 129: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU32>(); - } - case 130: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU64>(); - } - case 131: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripU8>(); - } - case 132: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncRoundtripVec>(); - } - case 133: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncAsyncThrowError>(); - } - case 142: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceGetValue>(); - } - case 143: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceNoop>(); - } - case 144: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceSetValue>(); - } - case 145: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeAsyncTestTraitInterfaceThrowIfEqual>(); - } - case 146: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceGetValue>(); - } - case 147: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceNoop>(); - } - case 148: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceSetValue>(); - } - case 149: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnFuncInvokeTestAsyncCallbackInterfaceThrowIfEqual>(); - } - case 191: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsyncinterfaceName>(); + MOZ_CAN_RUN_SCRIPT + already_AddRefed<dom::Promise> + MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler, ErrorResult& aError) override { + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(2, mozilla::fallible)) { + aError.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; } - case 192: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceNoop>(); + mContextId.Lift(aCx, &uniffiArgs[0], aError); + if (aError.Failed()) { + return nullptr; } - case 193: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceGetValue>(); + mCreationDate.Lift(aCx, &uniffiArgs[1], aError); + if (aError.Failed()) { + return nullptr; } - case 194: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceSetValue>(); + + RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 0, uniffiArgs, aError); + return nullptr; + } +}; + +/** + * callback_interface_context_id_context_id_callback_persist -- C function to handle the callback method + * + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_context_id_context_id_callback_persist( + uint64_t aUniffiHandle, + RustBuffer aContextId, + int64_t aCreationDate, + void* aUniffiOutReturn, + RustCallStatus* uniffiOutStatus +) { + UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodContextIdContextIdCallbackPersist>(aUniffiHandle, aContextId, aCreationDate); + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerContextIdContextIdCallback); +} +/** + * Callback method handler subclass for callback_interface_context_id_context_id_callback_rotated + * + * This is like the handler for an async function except: + * + * - It doesn't input the complete callback function/data + * - It doesn't override HandleReturn and returns `nullptr` from MakeCall. + * This means ScheduleAsyncCall will schedule `MakeCall` and not do anything + * with the result, which is what we want. + */ +class CallbackInterfaceMethodContextIdContextIdCallbackRotated final : public AsyncCallbackMethodHandlerBase { +private: + // Rust arguments + FfiValueRustBuffer mOldContextId{}; + +public: + CallbackInterfaceMethodContextIdContextIdCallbackRotated( + uint64_t aUniffiHandle, + RustBuffer aOldContextId + ) : AsyncCallbackMethodHandlerBase ("ContextIdCallback.callback_interface_context_id_context_id_callback_rotated", aUniffiHandle), + mOldContextId(FfiValueRustBuffer::FromRust(aOldContextId)){ } + + MOZ_CAN_RUN_SCRIPT + already_AddRefed<dom::Promise> + MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler, ErrorResult& aError) override { + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(1, mozilla::fallible)) { + aError.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; } - case 195: { - return MakeUnique<ScaffoldingCallHandlerUniffiUniffiBindingsTestsFnMethodAsynctesttraitinterfaceThrowIfEqual>(); + mOldContextId.Lift(aCx, &uniffiArgs[0], aError); + if (aError.Failed()) { + return nullptr; } -#endif /* MOZ_UNIFFI_FIXTURES */ - default: - return nullptr; + RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 1, uniffiArgs, aError); + return nullptr; + } +}; + +/** + * callback_interface_context_id_context_id_callback_rotated -- C function to handle the callback method + * + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_context_id_context_id_callback_rotated( + uint64_t aUniffiHandle, + RustBuffer aOldContextId, + void* aUniffiOutReturn, + RustCallStatus* uniffiOutStatus +) { + UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodContextIdContextIdCallbackRotated>(aUniffiHandle, aOldContextId); + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerContextIdContextIdCallback); +} + +extern "C" void callback_free_context_id_context_id_callback(uint64_t uniffiHandle) { + // Callback object handles are keys in a map stored in the JS handler. To + // handle the free call, schedule a fire-and-forget JS call to remove the key. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall( + MakeUnique<CallbackFreeHandler>("ContextIdCallback.uniffi_free", uniffiHandle), + &gUniffiCallbackHandlerContextIdContextIdCallback); +} + +static VTableCallbackInterfaceContextIdContextIdCallback kUniffiVtableContextIdContextIdCallback { + callback_interface_context_id_context_id_callback_persist, + callback_interface_context_id_context_id_callback_rotated, + callback_free_context_id_context_id_callback +}; +static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerLoginsEncryptorDecryptor; +/** + * callback_interface_logins_encryptor_decryptor_decrypt -- C function to handle the callback method + * + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_logins_encryptor_decryptor_decrypt( + uint64_t aUniffiHandle, + RustBuffer aCiphertext, + RustBuffer* aUniffiOutReturn, + RustCallStatus* aUniffiOutStatus +) { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + // Take our own reference to the callback handler to ensure that it + // stays alive for the duration of this call + RefPtr<dom::UniFFICallbackHandler> jsHandler = gUniffiCallbackHandlerLoginsEncryptorDecryptor; + // Create a JS context for the call + JSObject* global = jsHandler->CallbackGlobalOrNull(); + if (!global) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_encryptor_decryptor_decrypt] JS handler has null global")); + return; + } + dom::AutoEntryScript aes(global, "callback_interface_logins_encryptor_decryptor_decrypt"); + + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(1, mozilla::fallible)) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_encryptor_decryptor_decrypt] Failed to allocate arguments")); + return; + } + IgnoredErrorResult error; + FfiValueRustBuffer ciphertext = FfiValueRustBuffer::FromRust(aCiphertext); + ciphertext.Lift(aes.cx(), &uniffiArgs[0], error); + if (error.Failed()) { + MOZ_LOG( + gUniffiLogger, LogLevel::Error, + ("[callback_interface_logins_encryptor_decryptor_decrypt] Failed to lift aCiphertext")); + return; } -} -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - + RootedDictionary<UniFFIScaffoldingCallResult> callResult(aes.cx()); + jsHandler->CallSync(aUniffiHandle, 0, uniffiArgs, callResult, error); + if (error.Failed()) { + MOZ_LOG( + gUniffiLogger, LogLevel::Error, + ("[callback_interface_logins_encryptor_decryptor_decrypt] Error invoking JS handler")); + return; + } + *aUniffiOutReturn = CallbackLowerReturnRustBuffer::Lower(callResult, aUniffiOutStatus, error); + } /** - * Handle callback interface return values for a single return type - */ -class CallbackLowerReturnVoid { -public: - /** - * Lower return values - * - * This inputs a UniFFIScaffoldingCallResult from JS and converts it to - * something that can be passed to Rust. - * - * - On success, it returns the FFI return value - * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. - */ - static void - Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, - RustCallStatus* aOutCallStatus, - ErrorResult& aRv) { - aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; - switch (aCallResult.mCode) { - case UniFFIScaffoldingCallCode::Success: { - aOutCallStatus->code = RUST_CALL_SUCCESS; - break; - } + * callback_interface_logins_encryptor_decryptor_encrypt -- C function to handle the callback method + * + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_logins_encryptor_decryptor_encrypt( + uint64_t aUniffiHandle, + RustBuffer aCleartext, + RustBuffer* aUniffiOutReturn, + RustCallStatus* aUniffiOutStatus +) { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + // Take our own reference to the callback handler to ensure that it + // stays alive for the duration of this call + RefPtr<dom::UniFFICallbackHandler> jsHandler = gUniffiCallbackHandlerLoginsEncryptorDecryptor; + // Create a JS context for the call + JSObject* global = jsHandler->CallbackGlobalOrNull(); + if (!global) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_encryptor_decryptor_encrypt] JS handler has null global")); + return; + } + dom::AutoEntryScript aes(global, "callback_interface_logins_encryptor_decryptor_encrypt"); - case UniFFIScaffoldingCallCode::Error: { - if (!aCallResult.mData.WasPassed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] No data passed")); - break; - } - FfiValueRustBuffer errorBuf; - errorBuf.Lower(aCallResult.mData.Value(), aRv); - if (aRv.Failed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] Failed to lower error buffer")); - break; - } + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(1, mozilla::fallible)) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_encryptor_decryptor_encrypt] Failed to allocate arguments")); + return; + } + IgnoredErrorResult error; + FfiValueRustBuffer cleartext = FfiValueRustBuffer::FromRust(aCleartext); + cleartext.Lift(aes.cx(), &uniffiArgs[0], error); + if (error.Failed()) { + MOZ_LOG( + gUniffiLogger, LogLevel::Error, + ("[callback_interface_logins_encryptor_decryptor_encrypt] Failed to lift aCleartext")); + return; + } - aOutCallStatus->error_buf = errorBuf.IntoRust(); - aOutCallStatus->code = RUST_CALL_ERROR; - break; - } + RootedDictionary<UniFFIScaffoldingCallResult> callResult(aes.cx()); + jsHandler->CallSync(aUniffiHandle, 1, uniffiArgs, callResult, error); + if (error.Failed()) { + MOZ_LOG( + gUniffiLogger, LogLevel::Error, + ("[callback_interface_logins_encryptor_decryptor_encrypt] Error invoking JS handler")); + return; + } + *aUniffiOutReturn = CallbackLowerReturnRustBuffer::Lower(callResult, aUniffiOutStatus, error); + } - default: { - break; - } - } +extern "C" void callback_free_logins_encryptor_decryptor(uint64_t uniffiHandle) { + // Callback object handles are keys in a map stored in the JS handler. To + // handle the free call, schedule a fire-and-forget JS call to remove the key. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall( + MakeUnique<CallbackFreeHandler>("EncryptorDecryptor.uniffi_free", uniffiHandle), + &gUniffiCallbackHandlerLoginsEncryptorDecryptor); +} - } +static VTableCallbackInterfaceLoginsEncryptorDecryptor kUniffiVtableLoginsEncryptorDecryptor { + callback_interface_logins_encryptor_decryptor_decrypt, + callback_interface_logins_encryptor_decryptor_encrypt, + callback_free_logins_encryptor_decryptor }; - +static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerLoginsKeyManager; /** - * Handle callback interface return values for a single return type - */ -class CallbackLowerReturnRustBuffer { -public: - /** - * Lower return values - * - * This inputs a UniFFIScaffoldingCallResult from JS and converts it to - * something that can be passed to Rust. - * - * - On success, it returns the FFI return value - * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. - */ - static RustBuffer - Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, - RustCallStatus* aOutCallStatus, - ErrorResult& aRv) { - aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; - FfiValueRustBuffer returnValue; - switch (aCallResult.mCode) { - case UniFFIScaffoldingCallCode::Success: { - if (!aCallResult.mData.WasPassed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] No data passed")); - break; - } - returnValue.Lower(aCallResult.mData.Value(), aRv); - if (aRv.Failed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] Failed to lower return value")); - break; - } - aOutCallStatus->code = RUST_CALL_SUCCESS; - break; - } + * callback_interface_logins_key_manager_get_key -- C function to handle the callback method + * + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_logins_key_manager_get_key( + uint64_t aUniffiHandle, + RustBuffer* aUniffiOutReturn, + RustCallStatus* aUniffiOutStatus +) { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + // Take our own reference to the callback handler to ensure that it + // stays alive for the duration of this call + RefPtr<dom::UniFFICallbackHandler> jsHandler = gUniffiCallbackHandlerLoginsKeyManager; + // Create a JS context for the call + JSObject* global = jsHandler->CallbackGlobalOrNull(); + if (!global) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_key_manager_get_key] JS handler has null global")); + return; + } + dom::AutoEntryScript aes(global, "callback_interface_logins_key_manager_get_key"); - case UniFFIScaffoldingCallCode::Error: { - if (!aCallResult.mData.WasPassed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] No data passed")); - break; - } - FfiValueRustBuffer errorBuf; - errorBuf.Lower(aCallResult.mData.Value(), aRv); - if (aRv.Failed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] Failed to lower error buffer")); - break; - } + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(0, mozilla::fallible)) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[callback_interface_logins_key_manager_get_key] Failed to allocate arguments")); + return; + } + IgnoredErrorResult error; - aOutCallStatus->error_buf = errorBuf.IntoRust(); - aOutCallStatus->code = RUST_CALL_ERROR; - break; - } + RootedDictionary<UniFFIScaffoldingCallResult> callResult(aes.cx()); + jsHandler->CallSync(aUniffiHandle, 0, uniffiArgs, callResult, error); + if (error.Failed()) { + MOZ_LOG( + gUniffiLogger, LogLevel::Error, + ("[callback_interface_logins_key_manager_get_key] Error invoking JS handler")); + return; + } + *aUniffiOutReturn = CallbackLowerReturnRustBuffer::Lower(callResult, aUniffiOutStatus, error); + } - default: { - break; - } - } +extern "C" void callback_free_logins_key_manager(uint64_t uniffiHandle) { + // Callback object handles are keys in a map stored in the JS handler. To + // handle the free call, schedule a fire-and-forget JS call to remove the key. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall( + MakeUnique<CallbackFreeHandler>("KeyManager.uniffi_free", uniffiHandle), + &gUniffiCallbackHandlerLoginsKeyManager); +} - return returnValue.IntoRust(); - } +static VTableCallbackInterfaceLoginsKeyManager kUniffiVtableLoginsKeyManager { + callback_interface_logins_key_manager_get_key, + callback_free_logins_key_manager }; - -#ifdef MOZ_UNIFFI_FIXTURES - +static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator; /** - * Handle callback interface return values for a single return type - */ -class CallbackLowerReturnUInt32 { + * Callback method handler subclass for callback_interface_logins_primary_password_authenticator_get_primary_password + * + * This handles the specifics of the async call. + * AsyncCallbackMethodHandlerBase::ScheduleAsyncCall handles the general parts. + */ +class CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorGetPrimaryPassword final : public AsyncCallbackMethodHandlerBase { +private: + // Rust arguments + ForeignFutureCompleterust_buffer mUniffiCompleteCallback; + uint64_t mUniffiCallbackData; + public: - /** - * Lower return values - * - * This inputs a UniFFIScaffoldingCallResult from JS and converts it to - * something that can be passed to Rust. - * - * - On success, it returns the FFI return value - * - On error, it updates the `RustCallStatus` struct and returns a default FFI value. - */ - static uint32_t - Lower(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, - RustCallStatus* aOutCallStatus, - ErrorResult& aRv) { - aOutCallStatus->code = RUST_CALL_INTERNAL_ERROR; - FfiValueInt<uint32_t> returnValue; - switch (aCallResult.mCode) { - case UniFFIScaffoldingCallCode::Success: { - if (!aCallResult.mData.WasPassed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] No data passed")); - break; - } - returnValue.Lower(aCallResult.mData.Value(), aRv); - if (aRv.Failed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] Failed to lower return value")); - break; - } - aOutCallStatus->code = RUST_CALL_SUCCESS; - break; - } + CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorGetPrimaryPassword( + uint64_t aUniffiHandle, + ForeignFutureCompleterust_buffer aUniffiCompleteCallback, + uint64_t aUniffiCallbackData + ) : AsyncCallbackMethodHandlerBase ("PrimaryPasswordAuthenticator.callback_interface_logins_primary_password_authenticator_get_primary_password", aUniffiHandle), + mUniffiCompleteCallback(aUniffiCompleteCallback), + mUniffiCallbackData(aUniffiCallbackData) { } - case UniFFIScaffoldingCallCode::Error: { - if (!aCallResult.mData.WasPassed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] No data passed")); - break; - } - FfiValueRustBuffer errorBuf; - errorBuf.Lower(aCallResult.mData.Value(), aRv); - if (aRv.Failed()) { - MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnUInt32] Failed to lower error buffer")); - break; - } + MOZ_CAN_RUN_SCRIPT + already_AddRefed<dom::Promise> + MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler, ErrorResult& aError) override { + // Convert arguments + nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; + if (!uniffiArgs.AppendElements(0, mozilla::fallible)) { + aError.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } - aOutCallStatus->error_buf = errorBuf.IntoRust(); - aOutCallStatus->code = RUST_CALL_ERROR; - break; - } + RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 0, uniffiArgs, aError); + return result.forget(); + } - default: { - break; - } + void HandleReturn(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + ErrorResult& aRv) override { + if (!mUniffiCompleteCallback) { + MOZ_ASSERT_UNREACHABLE("HandleReturn called multiple times"); + return; } - return returnValue.IntoRust(); + ForeignFutureResultRustBuffer result{}; + result.return_value = CallbackLowerReturnRustBuffer::Lower(aCallResult, &result.call_status, aRv); + mUniffiCompleteCallback(mUniffiCallbackData, result); + mUniffiCompleteCallback = nullptr; + } + + ~CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorGetPrimaryPassword() { + if (mUniffiCompleteCallback) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnRustBuffer] promise never completed")); + ForeignFutureResultRustBuffer result{}; + result.call_status.code = RUST_CALL_INTERNAL_ERROR; + mUniffiCompleteCallback(mUniffiCallbackData, result); } + } }; -#endif /* MOZ_UNIFFI_FIXTURES */ - -// Callback interface method handlers, vtables, etc. -static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerContextIdContextIdCallback; /** - * Callback method handler subclass for callback_interface_context_id_context_id_callback_persist + * callback_interface_logins_primary_password_authenticator_get_primary_password -- C function to handle the callback method * - * This is like the handler for an async function except: + * This is what Rust calls when it invokes a callback method. + */ +extern "C" void callback_interface_logins_primary_password_authenticator_get_primary_password( + uint64_t aUniffiHandle, + ForeignFutureCompleterust_buffer aUniffiForeignFutureCallback, + uint64_t aUniffiForeignFutureCallbackData, + // This can be used to detected when the future is dropped from the Rust side and cancel the + // async task on the foreign side. However, there's no way to do that in JS, so we just ignore + // it. + ForeignFuture *aUniffiOutForeignFuture +) { + UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorGetPrimaryPassword>( + aUniffiHandle, + aUniffiForeignFutureCallback, + aUniffiForeignFutureCallbackData); + // Now that everything is set up, schedule the call in the JS main thread. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator); +} +/** + * Callback method handler subclass for callback_interface_logins_primary_password_authenticator_on_authentication_success * - * - It doesn't input the complete callback function/data - * - It doesn't override HandleReturn and returns `nullptr` from MakeCall. - * This means ScheduleAsyncCall will schedule `MakeCall` and not do anything - * with the result, which is what we want. + * This handles the specifics of the async call. + * AsyncCallbackMethodHandlerBase::ScheduleAsyncCall handles the general parts. */ -class CallbackInterfaceMethodContextIdContextIdCallbackPersist final : public AsyncCallbackMethodHandlerBase { +class CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationSuccess final : public AsyncCallbackMethodHandlerBase { private: // Rust arguments - FfiValueRustBuffer mContextId{}; - FfiValueInt<int64_t> mCreationDate{}; + ForeignFutureCompletevoid mUniffiCompleteCallback; + uint64_t mUniffiCallbackData; public: - CallbackInterfaceMethodContextIdContextIdCallbackPersist( + CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationSuccess( uint64_t aUniffiHandle, - RustBuffer aContextId, - int64_t aCreationDate - ) : AsyncCallbackMethodHandlerBase ("ContextIdCallback.callback_interface_context_id_context_id_callback_persist", aUniffiHandle), - mContextId(FfiValueRustBuffer::FromRust(aContextId)), - mCreationDate(FfiValueInt<int64_t>::FromRust(aCreationDate)){ } + ForeignFutureCompletevoid aUniffiCompleteCallback, + uint64_t aUniffiCallbackData + ) : AsyncCallbackMethodHandlerBase ("PrimaryPasswordAuthenticator.callback_interface_logins_primary_password_authenticator_on_authentication_success", aUniffiHandle), + mUniffiCompleteCallback(aUniffiCompleteCallback), + mUniffiCallbackData(aUniffiCallbackData) { } MOZ_CAN_RUN_SCRIPT already_AddRefed<dom::Promise> MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler, ErrorResult& aError) override { // Convert arguments nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; - if (!uniffiArgs.AppendElements(2, mozilla::fallible)) { + if (!uniffiArgs.AppendElements(0, mozilla::fallible)) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } - mContextId.Lift(aCx, &uniffiArgs[0], aError); - if (aError.Failed()) { - return nullptr; - } - mCreationDate.Lift(aCx, &uniffiArgs[1], aError); - if (aError.Failed()) { - return nullptr; + + RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 1, uniffiArgs, aError); + return result.forget(); + } + + void HandleReturn(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + ErrorResult& aRv) override { + if (!mUniffiCompleteCallback) { + MOZ_ASSERT_UNREACHABLE("HandleReturn called multiple times"); + return; } - RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 0, uniffiArgs, aError); - return nullptr; + ForeignFutureResultVoid result{}; + CallbackLowerReturnVoid::Lower(aCallResult, &result.call_status, aRv); + mUniffiCompleteCallback(mUniffiCallbackData, result); + mUniffiCompleteCallback = nullptr; + } + + ~CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationSuccess() { + if (mUniffiCompleteCallback) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] promise never completed")); + ForeignFutureResultVoid result{}; + result.call_status.code = RUST_CALL_INTERNAL_ERROR; + mUniffiCompleteCallback(mUniffiCallbackData, result); + } } }; /** - * callback_interface_context_id_context_id_callback_persist -- C function to handle the callback method + * callback_interface_logins_primary_password_authenticator_on_authentication_success -- C function to handle the callback method * * This is what Rust calls when it invokes a callback method. */ -extern "C" void callback_interface_context_id_context_id_callback_persist( +extern "C" void callback_interface_logins_primary_password_authenticator_on_authentication_success( uint64_t aUniffiHandle, - RustBuffer aContextId, - int64_t aCreationDate, - void* aUniffiOutReturn, - RustCallStatus* uniffiOutStatus + ForeignFutureCompletevoid aUniffiForeignFutureCallback, + uint64_t aUniffiForeignFutureCallbackData, + // This can be used to detected when the future is dropped from the Rust side and cancel the + // async task on the foreign side. However, there's no way to do that in JS, so we just ignore + // it. + ForeignFuture *aUniffiOutForeignFuture ) { - UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodContextIdContextIdCallbackPersist>(aUniffiHandle, aContextId, aCreationDate); - AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerContextIdContextIdCallback); + UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationSuccess>( + aUniffiHandle, + aUniffiForeignFutureCallback, + aUniffiForeignFutureCallbackData); + // Now that everything is set up, schedule the call in the JS main thread. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator); } /** - * Callback method handler subclass for callback_interface_context_id_context_id_callback_rotated - * - * This is like the handler for an async function except: + * Callback method handler subclass for callback_interface_logins_primary_password_authenticator_on_authentication_failure * - * - It doesn't input the complete callback function/data - * - It doesn't override HandleReturn and returns `nullptr` from MakeCall. - * This means ScheduleAsyncCall will schedule `MakeCall` and not do anything - * with the result, which is what we want. + * This handles the specifics of the async call. + * AsyncCallbackMethodHandlerBase::ScheduleAsyncCall handles the general parts. */ -class CallbackInterfaceMethodContextIdContextIdCallbackRotated final : public AsyncCallbackMethodHandlerBase { +class CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationFailure final : public AsyncCallbackMethodHandlerBase { private: // Rust arguments - FfiValueRustBuffer mOldContextId{}; + ForeignFutureCompletevoid mUniffiCompleteCallback; + uint64_t mUniffiCallbackData; public: - CallbackInterfaceMethodContextIdContextIdCallbackRotated( + CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationFailure( uint64_t aUniffiHandle, - RustBuffer aOldContextId - ) : AsyncCallbackMethodHandlerBase ("ContextIdCallback.callback_interface_context_id_context_id_callback_rotated", aUniffiHandle), - mOldContextId(FfiValueRustBuffer::FromRust(aOldContextId)){ } + ForeignFutureCompletevoid aUniffiCompleteCallback, + uint64_t aUniffiCallbackData + ) : AsyncCallbackMethodHandlerBase ("PrimaryPasswordAuthenticator.callback_interface_logins_primary_password_authenticator_on_authentication_failure", aUniffiHandle), + mUniffiCompleteCallback(aUniffiCompleteCallback), + mUniffiCallbackData(aUniffiCallbackData) { } MOZ_CAN_RUN_SCRIPT already_AddRefed<dom::Promise> MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler, ErrorResult& aError) override { // Convert arguments nsTArray<dom::OwningUniFFIScaffoldingValue> uniffiArgs; - if (!uniffiArgs.AppendElements(1, mozilla::fallible)) { + if (!uniffiArgs.AppendElements(0, mozilla::fallible)) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } - mOldContextId.Lift(aCx, &uniffiArgs[0], aError); - if (aError.Failed()) { - return nullptr; + + RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 2, uniffiArgs, aError); + return result.forget(); + } + + void HandleReturn(const RootedDictionary<UniFFIScaffoldingCallResult>& aCallResult, + ErrorResult& aRv) override { + if (!mUniffiCompleteCallback) { + MOZ_ASSERT_UNREACHABLE("HandleReturn called multiple times"); + return; } - RefPtr<dom::Promise> result = aJsHandler->CallAsync(mUniffiHandle.IntoRust(), 1, uniffiArgs, aError); - return nullptr; + ForeignFutureResultVoid result{}; + CallbackLowerReturnVoid::Lower(aCallResult, &result.call_status, aRv); + mUniffiCompleteCallback(mUniffiCallbackData, result); + mUniffiCompleteCallback = nullptr; + } + + ~CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationFailure() { + if (mUniffiCompleteCallback) { + MOZ_LOG(gUniffiLogger, LogLevel::Error, ("[CallbackLowerReturnVoid] promise never completed")); + ForeignFutureResultVoid result{}; + result.call_status.code = RUST_CALL_INTERNAL_ERROR; + mUniffiCompleteCallback(mUniffiCallbackData, result); + } } }; /** - * callback_interface_context_id_context_id_callback_rotated -- C function to handle the callback method + * callback_interface_logins_primary_password_authenticator_on_authentication_failure -- C function to handle the callback method * * This is what Rust calls when it invokes a callback method. */ -extern "C" void callback_interface_context_id_context_id_callback_rotated( +extern "C" void callback_interface_logins_primary_password_authenticator_on_authentication_failure( uint64_t aUniffiHandle, - RustBuffer aOldContextId, - void* aUniffiOutReturn, - RustCallStatus* uniffiOutStatus + ForeignFutureCompletevoid aUniffiForeignFutureCallback, + uint64_t aUniffiForeignFutureCallbackData, + // This can be used to detected when the future is dropped from the Rust side and cancel the + // async task on the foreign side. However, there's no way to do that in JS, so we just ignore + // it. + ForeignFuture *aUniffiOutForeignFuture ) { - UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodContextIdContextIdCallbackRotated>(aUniffiHandle, aOldContextId); - AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerContextIdContextIdCallback); + UniquePtr<AsyncCallbackMethodHandlerBase> handler = MakeUnique<CallbackInterfaceMethodLoginsPrimaryPasswordAuthenticatorOnAuthenticationFailure>( + aUniffiHandle, + aUniffiForeignFutureCallback, + aUniffiForeignFutureCallbackData); + // Now that everything is set up, schedule the call in the JS main thread. + AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(std::move(handler), &gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator); } -extern "C" void callback_free_context_id_context_id_callback(uint64_t uniffiHandle) { +extern "C" void callback_free_logins_primary_password_authenticator(uint64_t uniffiHandle) { // Callback object handles are keys in a map stored in the JS handler. To // handle the free call, schedule a fire-and-forget JS call to remove the key. AsyncCallbackMethodHandlerBase::ScheduleAsyncCall( - MakeUnique<CallbackFreeHandler>("ContextIdCallback.uniffi_free", uniffiHandle), - &gUniffiCallbackHandlerContextIdContextIdCallback); + MakeUnique<CallbackFreeHandler>("PrimaryPasswordAuthenticator.uniffi_free", uniffiHandle), + &gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator); } -static VTableCallbackInterfaceContextIdContextIdCallback kUniffiVtableContextIdContextIdCallback { - callback_interface_context_id_context_id_callback_persist, - callback_interface_context_id_context_id_callback_rotated, - callback_free_context_id_context_id_callback +static VTableCallbackInterfaceLoginsPrimaryPasswordAuthenticator kUniffiVtableLoginsPrimaryPasswordAuthenticator { + callback_interface_logins_primary_password_authenticator_get_primary_password, + callback_interface_logins_primary_password_authenticator_on_authentication_success, + callback_interface_logins_primary_password_authenticator_on_authentication_failure, + callback_free_logins_primary_password_authenticator }; static StaticRefPtr<dom::UniFFICallbackHandler> gUniffiCallbackHandlerTracingEventSink; /** @@ -13892,6 +16996,36 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall break; } case 2: { + if (gUniffiCallbackHandlerLoginsEncryptorDecryptor) { + aError.ThrowUnknownError("[UniFFI] Callback handler already registered for EncryptorDecryptor"_ns); + return; + } + + gUniffiCallbackHandlerLoginsEncryptorDecryptor = &aCallbackHandler; + uniffi_logins_fn_init_callback_vtable_encryptordecryptor(&kUniffiVtableLoginsEncryptorDecryptor); + break; + } + case 3: { + if (gUniffiCallbackHandlerLoginsKeyManager) { + aError.ThrowUnknownError("[UniFFI] Callback handler already registered for KeyManager"_ns); + return; + } + + gUniffiCallbackHandlerLoginsKeyManager = &aCallbackHandler; + uniffi_logins_fn_init_callback_vtable_keymanager(&kUniffiVtableLoginsKeyManager); + break; + } + case 4: { + if (gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator) { + aError.ThrowUnknownError("[UniFFI] Callback handler already registered for PrimaryPasswordAuthenticator"_ns); + return; + } + + gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator = &aCallbackHandler; + uniffi_logins_fn_init_callback_vtable_primarypasswordauthenticator(&kUniffiVtableLoginsPrimaryPasswordAuthenticator); + break; + } + case 5: { if (gUniffiCallbackHandlerTracingEventSink) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for EventSink"_ns); return; @@ -13901,7 +17035,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall uniffi_tracing_support_fn_init_callback_vtable_eventsink(&kUniffiVtableTracingEventSink); break; } - case 3: { + case 6: { if (gUniffiCallbackHandlerViaductBackend) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for Backend"_ns); return; @@ -13913,7 +17047,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall } #ifdef MOZ_UNIFFI_FIXTURES - case 4: { + case 7: { if (gUniffiCallbackHandlerUniffiBindingsTestsTestAsyncCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for TestAsyncCallbackInterface"_ns); return; @@ -13923,7 +17057,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall uniffi_uniffi_bindings_tests_fn_init_callback_vtable_testasynccallbackinterface(&kUniffiVtableUniffiBindingsTestsTestAsyncCallbackInterface); break; } - case 5: { + case 8: { if (gUniffiCallbackHandlerUniffiBindingsTestsTestCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for TestCallbackInterface"_ns); return; @@ -13933,7 +17067,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall uniffi_uniffi_bindings_tests_fn_init_callback_vtable_testcallbackinterface(&kUniffiVtableUniffiBindingsTestsTestCallbackInterface); break; } - case 6: { + case 9: { if (gUniffiCallbackHandlerUniffiBindingsTestsAsyncTestTraitInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for AsyncTestTraitInterface"_ns); return; @@ -13943,7 +17077,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall uniffi_uniffi_bindings_tests_fn_init_callback_vtable_asynctesttraitinterface(&kUniffiVtableUniffiBindingsTestsAsyncTestTraitInterface); break; } - case 7: { + case 10: { if (gUniffiCallbackHandlerUniffiBindingsTestsTestTraitInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for TestTraitInterface"_ns); return; @@ -13953,7 +17087,7 @@ void RegisterCallbackHandler(uint64_t aInterfaceId, UniFFICallbackHandler& aCall uniffi_uniffi_bindings_tests_fn_init_callback_vtable_testtraitinterface(&kUniffiVtableUniffiBindingsTestsTestTraitInterface); break; } - case 8: { + case 11: { if (gUniffiCallbackHandlerUniffiBindingsTestsCollisionTestCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler already registered for TestCallbackInterface"_ns); return; @@ -13984,6 +17118,33 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { break; } case 2: { + if (!gUniffiCallbackHandlerLoginsEncryptorDecryptor) { + aError.ThrowUnknownError("[UniFFI] Callback handler not registered for EncryptorDecryptor"_ns); + return; + } + + gUniffiCallbackHandlerLoginsEncryptorDecryptor = nullptr; + break; + } + case 3: { + if (!gUniffiCallbackHandlerLoginsKeyManager) { + aError.ThrowUnknownError("[UniFFI] Callback handler not registered for KeyManager"_ns); + return; + } + + gUniffiCallbackHandlerLoginsKeyManager = nullptr; + break; + } + case 4: { + if (!gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator) { + aError.ThrowUnknownError("[UniFFI] Callback handler not registered for PrimaryPasswordAuthenticator"_ns); + return; + } + + gUniffiCallbackHandlerLoginsPrimaryPasswordAuthenticator = nullptr; + break; + } + case 5: { if (!gUniffiCallbackHandlerTracingEventSink) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for EventSink"_ns); return; @@ -13992,7 +17153,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { gUniffiCallbackHandlerTracingEventSink = nullptr; break; } - case 3: { + case 6: { if (!gUniffiCallbackHandlerViaductBackend) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for Backend"_ns); return; @@ -14003,7 +17164,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { } #ifdef MOZ_UNIFFI_FIXTURES - case 4: { + case 7: { if (!gUniffiCallbackHandlerUniffiBindingsTestsTestAsyncCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for TestAsyncCallbackInterface"_ns); return; @@ -14012,7 +17173,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { gUniffiCallbackHandlerUniffiBindingsTestsTestAsyncCallbackInterface = nullptr; break; } - case 5: { + case 8: { if (!gUniffiCallbackHandlerUniffiBindingsTestsTestCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for TestCallbackInterface"_ns); return; @@ -14021,7 +17182,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { gUniffiCallbackHandlerUniffiBindingsTestsTestCallbackInterface = nullptr; break; } - case 6: { + case 9: { if (!gUniffiCallbackHandlerUniffiBindingsTestsAsyncTestTraitInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for AsyncTestTraitInterface"_ns); return; @@ -14030,7 +17191,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { gUniffiCallbackHandlerUniffiBindingsTestsAsyncTestTraitInterface = nullptr; break; } - case 7: { + case 10: { if (!gUniffiCallbackHandlerUniffiBindingsTestsTestTraitInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for TestTraitInterface"_ns); return; @@ -14039,7 +17200,7 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) { gUniffiCallbackHandlerUniffiBindingsTestsTestTraitInterface = nullptr; break; } - case 8: { + case 11: { if (!gUniffiCallbackHandlerUniffiBindingsTestsCollisionTestCallbackInterface) { aError.ThrowUnknownError("[UniFFI] Callback handler not registered for TestCallbackInterface"_ns); return;