From 51118199353d09b8feadeb874546e000d3c0ca4e Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 10 Oct 2025 15:27:54 +1100 Subject: [PATCH 01/30] feat: add encrypt query functionality and update dependencies --- Cargo.lock | 447 ++++++++++++++++++++++++++++++---- crates/protect-ffi/Cargo.toml | 3 +- crates/protect-ffi/src/lib.rs | 47 +++- src/index.cts | 11 + 4 files changed, 453 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 580e710..6c44896 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -89,6 +101,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -175,15 +193,40 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" +dependencies = [ + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libloading", +] + [[package]] name = "axum" -version = "0.7.9" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ - "async-trait", "axum-core", "bytes", + "form_urlencoded", "futures-util", "http", "http-body", @@ -196,8 +239,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -211,25 +253,60 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ - "async-trait", "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-extra" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +dependencies = [ + "axum", + "axum-core", + "axum-macros", + "bytes", + "form_urlencoded", "futures-util", "http", "http-body", "http-body-util", "mime", + "percent-encoding", "pin-project-lite", "rustversion", - "sync_wrapper", + "serde_core", + "serde_html_form", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -281,6 +358,26 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.104", +] + [[package]] name = "bit-vec" version = "0.8.0" @@ -439,6 +536,42 @@ name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "cached" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae" +dependencies = [ + "ahash 0.8.12", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown 0.14.5", + "once_cell", + "thiserror 1.0.69", + "web-time", +] + +[[package]] +name = "cached_proc_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" @@ -446,9 +579,20 @@ version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -496,9 +640,7 @@ dependencies = [ [[package]] name = "cipherstash-client" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c46537ccace9b25a3f1e79a03e5dd19256cbd80152c4fd155049a38884da5d" +version = "0.28.0" dependencies = [ "aes-gcm-siv", "anyhow", @@ -514,7 +656,7 @@ dependencies = [ "cipherstash-core", "cllw-ore", "cts-common", - "derive_more", + "derive_more 1.0.0", "dirs", "futures", "hex", @@ -555,9 +697,7 @@ dependencies = [ [[package]] name = "cipherstash-config" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30104045751da6e528e83804f4b22d0cddcb27aacce0e1c79604872ddb076bbf" +version = "0.2.4" dependencies = [ "serde", "thiserror 1.0.69", @@ -566,8 +706,6 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd56dfac0a35146968ef6696fb822b22f70a664a8739874385876d5452844b7a" dependencies = [ "hmac", "lazy_static", @@ -578,11 +716,20 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "cllw-ore" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1b01c26e11101044f85802e31d842483ef983a890c03472d9489f6969cf865a" dependencies = [ "bit-vec", "bitvec", @@ -607,6 +754,15 @@ dependencies = [ "digest", ] +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "const-hex" version = "1.14.1" @@ -672,23 +828,28 @@ dependencies = [ [[package]] name = "cts-common" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058540fce9a147af37cab4f55a5f9d8ae7f35f66efeec58c08cce6beb173d9c3" +version = "0.3.1" dependencies = [ "arrayvec", "axum", + "axum-extra", "base32", + "cached", + "chrono", + "derive_more 2.0.1", "diesel", + "either", "fake 3.1.0", "http", "miette", - "nom", + "nom 8.0.0", "rand 0.8.5", "regex", "serde", "thiserror 1.0.69", "url", + "utoipa", + "uuid", "vitaminc", ] @@ -742,7 +903,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", ] [[package]] @@ -757,6 +927,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "unicode-xid", +] + [[package]] name = "deunicode" version = "1.6.2" @@ -876,11 +1058,20 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] [[package]] name = "env_logger" @@ -968,6 +1159,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -1106,6 +1303,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "half" version = "1.8.3" @@ -1118,7 +1321,17 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.12", + "allocator-api2", ] [[package]] @@ -1409,6 +1622,7 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.4", + "serde", ] [[package]] @@ -1469,6 +1683,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1567,9 +1791,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" @@ -1623,6 +1847,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1674,6 +1904,16 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nom" version = "8.0.0" @@ -1964,6 +2204,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn 2.0.104", +] + [[package]] name = "proc-macro-crate" version = "3.3.0" @@ -2004,7 +2254,6 @@ version = "0.1.0" dependencies = [ "chrono", "cipherstash-client", - "cts-common", "hex", "neon", "once_cell", @@ -2017,6 +2266,16 @@ dependencies = [ "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc)", ] +[[package]] +name = "protected-derive" +version = "0.1.0-pre2" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "protected-derive" version = "0.1.0-pre2" @@ -2216,8 +2475,6 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72aa0940c8f5b753bfd3ed212d60896760579324c59194b7e51fcec35e5c1b0f" dependencies = [ "aes", "async-trait", @@ -2400,7 +2657,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -2538,7 +2795,7 @@ checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -2579,10 +2836,11 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -2605,17 +2863,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn 2.0.104", ] +[[package]] +name = "serde_html_form" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" +dependencies = [ + "form_urlencoded", + "indexmap", + "itoa", + "ryu", + "serde_core", +] + [[package]] name = "serde_json" version = "1.0.140" @@ -3175,6 +3455,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -3199,6 +3485,31 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "url", + "uuid", +] + [[package]] name = "uuid" version = "1.17.0" @@ -3223,22 +3534,47 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vitaminc" version = "0.1.0-pre2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4c7e4e19bd3795b3bc4b99aa31d43d1b06a9c6fd9297ce8237467869d268c" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" +dependencies = [ + "vitaminc-encrypt", + "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", + "vitaminc-random", + "vitaminc-traits", +] + +[[package]] +name = "vitaminc-aead" +version = "0.1.0-pre2" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" +dependencies = [ + "bytes", + "serde", + "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", + "vitaminc-random", + "zeroize", +] + +[[package]] +name = "vitaminc-encrypt" +version = "0.1.0-pre2" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" dependencies = [ - "vitaminc-protected 0.1.0-pre2 (registry+https://github.com/rust-lang/crates.io-index)", + "aws-lc-rs", + "vitaminc-aead", + "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", "vitaminc-random", + "zeroize", ] [[package]] name = "vitaminc-protected" version = "0.1.0-pre2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f032763fc27651980ec2c811917d9cccc566ec126250be75d82d3f8d1e37cc26" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" dependencies = [ "bitvec", "digest", "opaque-debug", + "protected-derive 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", "serde", "serde_bytes", "subtle", @@ -3253,7 +3589,7 @@ dependencies = [ "bitvec", "digest", "opaque-debug", - "protected-derive", + "protected-derive 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc)", "serde", "serde_bytes", "subtle", @@ -3263,13 +3599,27 @@ dependencies = [ [[package]] name = "vitaminc-random" version = "0.1.0-pre2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a544c02ef2c1724db33d7bcb8df2c1f8c2ddab27965e57cc5373c55b8da567b6" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "thiserror 1.0.69", - "vitaminc-protected 0.1.0-pre2 (registry+https://github.com/rust-lang/crates.io-index)", + "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", + "zeroize", +] + +[[package]] +name = "vitaminc-traits" +version = "0.1.0-pre2" +source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd32e990dff79c765adeecf1cd9ac9d2945a71" +dependencies = [ + "anyhow", + "bytes", + "rmp-serde", + "serde", + "thiserror 1.0.69", + "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq)", + "vitaminc-random", "zeroize", ] @@ -3840,14 +4190,13 @@ dependencies = [ [[package]] name = "zerokms-protocol" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f49316e3bee7e2244f5ea9f1463479615a7f8c36a86c34ea59a314830e64c0" +version = "0.7.0" dependencies = [ "async-trait", "base64", "cipherstash-config", "const-hex", + "cts-common", "fake 2.10.0", "opaque-debug", "rand 0.8.5", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 0c51c07..ad0236e 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,8 +11,7 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cipherstash-client = "0.24.0" -cts-common = { version = "0.3.0", default-features = false } +cipherstash-client = { version = "0.28.0", path = "../../../cipherstash-suite/packages/cipherstash-client" } hex = "0.4.3" neon = {version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index adc9128..e3791c5 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -2,6 +2,7 @@ mod encrypt_config; mod js_plaintext; use cipherstash_client::{ + Crn, config::{ console_config::ConsoleConfig, cts_config::CtsConfig, errors::ConfigError, zero_kms_config::ZeroKMSConfig, CipherStashConfigFile, CipherStashSecretConfigFile, @@ -9,14 +10,12 @@ use cipherstash_client::{ }, credentials::{ServiceCredentials, ServiceToken}, encryption::{ - self, EncryptionError, IndexTerm, Plaintext, PlaintextTarget, ReferencedPendingPipeline, - ScopedCipher, SteVec, TypeParseError, + self, EncryptionError, IndexTerm, Plaintext, PlaintextTarget, Queryable, QueryOp, ReferencedPendingPipeline, ScopedCipher, SteVec, TypeParseError }, - schema::ColumnConfig, + schema::{operator::Operator, ColumnConfig}, zerokms::{self, EncryptedRecord, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, UnverifiedContext, }; -use cts_common::Crn; use encrypt_config::{EncryptConfig, Identifier}; use js_plaintext::JsPlaintext; use neon::{ @@ -133,6 +132,24 @@ struct EncryptOptions { unverified_context: Option, } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct QueryOptions { + plaintext: JsPlaintext, + column: String, + table: String, + #[serde(deserialize_with = "deserialize_operator")] + operator: Operator, +} + +fn deserialize_operator<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s: String = Deserialize::deserialize(deserializer)?; + s.parse().map_err(serde::de::Error::custom) +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct EncryptBulkOptions { @@ -332,6 +349,26 @@ async fn encrypt_bulk( Ok(Json(results)) } +#[neon::export] +async fn encrypt_query( + Boxed(client): Boxed, + Json(opts): Json, +) -> Result, neon::types::extract::Error> { + let ident = Identifier::new(opts.table, opts.column); + + let column_config = client + .encrypt_config + .get(&ident) + .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; + + let plaintext: Plaintext = opts.plaintext.try_into()?; + let index = column_config.index_for_operator(&opts.operator).unwrap(); // TODO: Handle no index found + let term = (index, plaintext).build_queryable(client.cipher, QueryOp::Default)?; + + Ok(Json(term)) +} + + #[neon::export] async fn decrypt( Boxed(client): Boxed, @@ -344,6 +381,7 @@ async fn decrypt( .zerokms .decrypt_single( encrypted_record, + None, opts.service_token, opts.unverified_context, ) @@ -381,6 +419,7 @@ async fn decrypt_bulk( .zerokms .decrypt( encrypted_records, + None, opts.service_token, opts.unverified_context, ) diff --git a/src/index.cts b/src/index.cts index 036ad85..0a39836 100644 --- a/src/index.cts +++ b/src/index.cts @@ -22,6 +22,7 @@ declare module './load.cjs' { function encrypt(client: Client, opts: EncryptOptions): Promise function decrypt(client: Client, opts: DecryptOptions): Promise function isEncrypted(encrypted: Encrypted): boolean + function encryptQuery(client: Client, opts: QueryOptions): Promise function encryptBulk( client: Client, opts: EncryptBulkOptions, @@ -196,3 +197,13 @@ export type DecryptBulkOptions = { serviceToken?: CtsToken unverifiedContext?: Record } + +export type QueryOptions = { + plaintext: JsPlaintext + column: string + table: string + operator: QueryOperator +} + +export type QueryOperator = '<' | '<=' | '=' | '>=' | '>' | '~~' | '~~*' | '@>' | '<@'; + From e95452ce850563b06ed500882888ffad5779b8fa Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Sun, 19 Oct 2025 18:39:23 +1100 Subject: [PATCH 02/30] feat: update cipherstash-client and add query term types --- Cargo.lock | 141 +++++++++++++++++-- crates/protect-ffi/Cargo.toml | 2 +- crates/protect-ffi/src/lib.rs | 12 +- integration-tests/tests/lock-context.test.ts | 4 +- integration-tests/tests/scalar-bulk.test.ts | 4 +- src/index.cts | 32 ++++- 6 files changed, 173 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c44896..6aecc85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,8 +503,20 @@ version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ - "bytecheck_derive", - "ptr_meta", + "bytecheck_derive 0.6.12", + "ptr_meta 0.1.4", + "simdutf8", +] + +[[package]] +name = "bytecheck" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b" +dependencies = [ + "bytecheck_derive 0.8.2", + "ptr_meta 0.3.1", + "rancor", "simdutf8", ] @@ -519,6 +531,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bytecheck_derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "bytemuck" version = "1.23.1" @@ -641,6 +664,7 @@ dependencies = [ [[package]] name = "cipherstash-client" version = "0.28.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "aes-gcm-siv", "anyhow", @@ -698,6 +722,7 @@ dependencies = [ [[package]] name = "cipherstash-config" version = "0.2.4" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "serde", "thiserror 1.0.69", @@ -706,6 +731,7 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "hmac", "lazy_static", @@ -730,6 +756,7 @@ dependencies = [ [[package]] name = "cllw-ore" version = "0.1.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "bit-vec", "bitvec", @@ -829,6 +856,7 @@ dependencies = [ [[package]] name = "cts-common" version = "0.3.1" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "arrayvec", "axum", @@ -1873,6 +1901,26 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "neon" version = "1.1.1" @@ -2292,7 +2340,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ - "ptr_meta_derive", + "ptr_meta_derive 0.1.4", +] + +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive 0.3.1", ] [[package]] @@ -2306,6 +2363,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "quickcheck" version = "1.0.3" @@ -2404,6 +2472,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta 0.3.1", +] + [[package]] name = "rand" version = "0.8.5" @@ -2475,6 +2552,7 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "aes", "async-trait", @@ -2555,7 +2633,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ - "bytecheck", + "bytecheck 0.6.12", +] + +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +dependencies = [ + "bytecheck 0.8.2", ] [[package]] @@ -2668,17 +2755,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", - "bytecheck", + "bytecheck 0.6.12", "bytes", "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", + "ptr_meta 0.1.4", + "rend 0.4.2", + "rkyv_derive 0.7.45", "seahash", "tinyvec", "uuid", ] +[[package]] +name = "rkyv" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" +dependencies = [ + "bytecheck 0.8.2", + "bytes", + "hashbrown 0.15.4", + "indexmap", + "munge", + "ptr_meta 0.3.1", + "rancor", + "rend 0.5.3", + "rkyv_derive 0.8.12", + "tinyvec", + "uuid", +] + [[package]] name = "rkyv_derive" version = "0.7.45" @@ -2690,6 +2796,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rkyv_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "rmp" version = "0.8.14" @@ -2733,7 +2850,7 @@ dependencies = [ "bytes", "num-traits", "rand 0.8.5", - "rkyv", + "rkyv 0.7.45", "serde", "serde_json", ] @@ -3512,9 +3629,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "atomic", "getrandom 0.3.3", @@ -4191,6 +4308,7 @@ dependencies = [ [[package]] name = "zerokms-protocol" version = "0.7.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "async-trait", "base64", @@ -4200,6 +4318,7 @@ dependencies = [ "fake 2.10.0", "opaque-debug", "rand 0.8.5", + "rkyv 0.8.12", "serde", "static_assertions", "thiserror 1.0.69", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index ad0236e..49a636d 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cipherstash-client = { version = "0.28.0", path = "../../../cipherstash-suite/packages/cipherstash-client" } +cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", branch = "refactor/minor-cs-client-api" } hex = "0.4.3" neon = {version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index e3791c5..898ebd9 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -2,7 +2,6 @@ mod encrypt_config; mod js_plaintext; use cipherstash_client::{ - Crn, config::{ console_config::ConsoleConfig, cts_config::CtsConfig, errors::ConfigError, zero_kms_config::ZeroKMSConfig, CipherStashConfigFile, CipherStashSecretConfigFile, @@ -10,11 +9,12 @@ use cipherstash_client::{ }, credentials::{ServiceCredentials, ServiceToken}, encryption::{ - self, EncryptionError, IndexTerm, Plaintext, PlaintextTarget, Queryable, QueryOp, ReferencedPendingPipeline, ScopedCipher, SteVec, TypeParseError + self, EncryptionError, IndexTerm, Plaintext, PlaintextTarget, QueryOp, Queryable, + ReferencedPendingPipeline, ScopedCipher, SteVec, TypeParseError, }, schema::{operator::Operator, ColumnConfig}, zerokms::{self, EncryptedRecord, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, - UnverifiedContext, + Crn, IdentifiedBy, UnverifiedContext, }; use encrypt_config::{EncryptConfig, Identifier}; use js_plaintext::JsPlaintext; @@ -105,6 +105,7 @@ struct ClientOpts { access_key: Option, client_id: Option, client_key: Option, + keyset: Option, } #[derive(Deserialize)] @@ -246,7 +247,7 @@ pub async fn new_client( let zerokms = Arc::new(zerokms_config.create_client()); - let cipher = ScopedZeroKMSNoRefresh::init(zerokms.clone(), None).await?; + let cipher = ScopedZeroKMSNoRefresh::init(zerokms.clone(), client_opts.keyset).await?; let client = Client { cipher: Arc::new(cipher), @@ -361,14 +362,13 @@ async fn encrypt_query( .get(&ident) .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; - let plaintext: Plaintext = opts.plaintext.try_into()?; + let plaintext: Plaintext = opts.plaintext.into(); let index = column_config.index_for_operator(&opts.operator).unwrap(); // TODO: Handle no index found let term = (index, plaintext).build_queryable(client.cipher, QueryOp::Default)?; Ok(Json(term)) } - #[neon::export] async fn decrypt( Boxed(client): Boxed, diff --git a/integration-tests/tests/lock-context.test.ts b/integration-tests/tests/lock-context.test.ts index 393050e..c91fe77 100644 --- a/integration-tests/tests/lock-context.test.ts +++ b/integration-tests/tests/lock-context.test.ts @@ -48,7 +48,9 @@ describe('lock context', () => { identityClaim: ['sub'], }, }) - }).rejects.toThrowError(/Failed to send request/) + // NOTE: New ZeroKMS changes will report this as an authentication error + // See https://github.com/cipherstash/cipherstash-suite/pull/1516 + }).rejects.toThrowError(/Unexpected error/) }, 10000) test('decrypt throws an error when identityClaim is used without a service token', async () => { diff --git a/integration-tests/tests/scalar-bulk.test.ts b/integration-tests/tests/scalar-bulk.test.ts index 9d82a12..3bbc497 100644 --- a/integration-tests/tests/scalar-bulk.test.ts +++ b/integration-tests/tests/scalar-bulk.test.ts @@ -128,7 +128,9 @@ describe('encryptBulk and decryptBulk', async () => { }, })), }) - }).rejects.toThrowError(/Failed to send request/) + // NOTE: New ZeroKMS changes will report this as an authentication error + // See https://github.com/cipherstash/cipherstash-suite/pull/1516 + }).rejects.toThrowError(/Unexpected error/) }, 10000) test('decryptBulk throws an error when identityClaim is used without a service token', async () => { diff --git a/src/index.cts b/src/index.cts index 0a39836..83f4545 100644 --- a/src/index.cts +++ b/src/index.cts @@ -162,8 +162,12 @@ export type ClientOpts = { accessKey?: string clientId?: string clientKey?: string + keyset?: IdentifiedBy } +// This is a UUID or name +export type IdentifiedBy = string + export type JsPlaintext = | string | number @@ -205,5 +209,29 @@ export type QueryOptions = { operator: QueryOperator } -export type QueryOperator = '<' | '<=' | '=' | '>=' | '>' | '~~' | '~~*' | '@>' | '<@'; - +export type QueryOperator = + | '<' + | '<=' + | '=' + | '>=' + | '>' + | '~~' + | '~~*' + | '@>' + | '<@' + +export type IndexTerm = + | { type: 'Binary'; value: Uint8Array } + | { type: 'BinaryVec'; value: Uint8Array[] } + | { type: 'BitMap'; value: number[] } // u16 fits safely in JS number + | { type: 'OreFull'; value: Uint8Array } + | { type: 'OreArray'; value: Uint8Array[] } + | { type: 'OreLeft'; value: Uint8Array } + | { type: 'SteVecSelector'; value: TokenizedSelector } + | { type: 'SteVecTerm'; value: EncryptedSteVecTerm } + | { type: 'SteQueryVec'; value: SteQueryVec } + | { type: 'Null' } + +export type TokenizedSelector = string +export type EncryptedSteVecTerm = string[] +export type SteQueryVec = string[] From 91d872987809bbc4496b46c755b877bcf313dce9 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Sun, 19 Oct 2025 19:07:14 +1100 Subject: [PATCH 03/30] chore: set git-fetch-with-cli to true --- crates/protect-ffi/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 49a636d..116ab11 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -25,3 +25,6 @@ vitaminc-protected = { version = "0.1.0-pre2", git = "https://github.com/ciphers chrono = "0.4.42" quickcheck = "1.0.3" quickcheck_macros = "1.0.3" + +[package.metadata.cargo] +net.git-fetch-with-cli = true From 1c3d24a3aed76c64ad399a60449d2138ac0a60aa Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Sun, 19 Oct 2025 18:57:41 +1100 Subject: [PATCH 04/30] feat: Update dependencies and refactor encryption handling - Updated `cipherstash-client` to version 0.28.0 and `cts-common` to 0.3.1 in `Cargo.toml`. - Added new module `eql.rs` to handle encrypted data structures and conversions. - Refactored encryption handling in `lib.rs` to utilize the new `Encrypted` enum from `eql.rs`. - Introduced new `query.rs` module to define query structures and serialization for `SteQueryVec` and `TokenizedSelector`. - Added tests for query serialization in the new `query.rs` module. - Updated various dependencies in `Cargo.lock` to their latest versions, including `serde`, `ahash`, and others. --- Cargo.lock | 978 ++++++++++++++++---------------- crates/protect-ffi/Cargo.toml | 2 +- crates/protect-ffi/src/eql.rs | 120 ++++ crates/protect-ffi/src/lib.rs | 115 +--- crates/protect-ffi/src/query.rs | 57 ++ 5 files changed, 671 insertions(+), 601 deletions(-) create mode 100644 crates/protect-ffi/src/eql.rs create mode 100644 crates/protect-ffi/src/query.rs diff --git a/Cargo.lock b/Cargo.lock index 6aecc85..bc626e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "array-init" @@ -146,14 +146,13 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.27" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" dependencies = [ - "brotli", - "flate2", + "compression-codecs", + "compression-core", "futures-core", - "memchr", "pin-project-lite", "tokio", ] @@ -169,13 +168,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -187,6 +186,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -206,16 +211,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.32.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" +checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", - "libloading", ] [[package]] @@ -304,14 +308,14 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -319,7 +323,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -364,10 +368,10 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -375,7 +379,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -392,9 +396,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitvec" @@ -467,14 +471,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "brotli" -version = "8.0.1" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -503,20 +507,8 @@ version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ - "bytecheck_derive 0.6.12", - "ptr_meta 0.1.4", - "simdutf8", -] - -[[package]] -name = "bytecheck" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b" -dependencies = [ - "bytecheck_derive 0.8.2", - "ptr_meta 0.3.1", - "rancor", + "bytecheck_derive", + "ptr_meta", "simdutf8", ] @@ -531,22 +523,11 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bytecheck_derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -584,10 +565,10 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -598,10 +579,11 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -618,9 +600,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -639,7 +621,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -664,7 +646,6 @@ dependencies = [ [[package]] name = "cipherstash-client" version = "0.28.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "aes-gcm-siv", "anyhow", @@ -685,7 +666,7 @@ dependencies = [ "futures", "hex", "hmac", - "itertools", + "itertools 0.12.1", "lazy_static", "log", "miette", @@ -722,7 +703,6 @@ dependencies = [ [[package]] name = "cipherstash-config" version = "0.2.4" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "serde", "thiserror 1.0.69", @@ -731,7 +711,6 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "hmac", "lazy_static", @@ -756,7 +735,6 @@ dependencies = [ [[package]] name = "cllw-ore" version = "0.1.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "bit-vec", "bitvec", @@ -790,17 +768,34 @@ dependencies = [ "cc", ] +[[package]] +name = "compression-codecs" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + [[package]] name = "const-hex" -version = "1.14.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e22e0ed40b96a48d3db274f72fd365bd78f67af39b6bbd47e8a15e1c6207ff" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", "cpufeatures", - "hex", "proptest", - "serde", + "serde_core", ] [[package]] @@ -856,7 +851,6 @@ dependencies = [ [[package]] name = "cts-common" version = "0.3.1" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "arrayvec", "axum", @@ -887,8 +881,18 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] @@ -902,7 +906,21 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.107", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.107", ] [[package]] @@ -911,9 +929,20 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", + "quote", + "syn 2.0.107", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -951,7 +980,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "unicode-xid", ] @@ -963,7 +992,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "unicode-xid", ] @@ -975,35 +1004,36 @@ checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" [[package]] name = "diesel" -version = "2.2.11" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a917a9209950404d5be011c81d081a2692a822f73c3d6af586f0cab5ff50f614" +checksum = "e8496eeb328dce26ee9d9b73275d396d9bddb433fa30106cf6056dd8c3c2764c" dependencies = [ "chrono", "diesel_derives", + "downcast-rs", "uuid", ] [[package]] name = "diesel_derives" -version = "2.2.6" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52841e97814f407b895d836fa0012091dff79c6268f39ad8155d384c21ae0d26" +checksum = "09af0e983035368439f1383011cd87c46f41da81d0f21dc3727e2857d5a43c8e" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "diesel_table_macro_syntax" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c" dependencies = [ - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1045,21 +1075,27 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + [[package]] name = "dsl_auto_type" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b" +checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e" dependencies = [ - "darling", + "darling 0.21.3", "either", "heck", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1068,10 +1104,10 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac124e13ae9aa56acc4241f8c8207501d93afdd8d8e62f0c1f2e12f6508c65" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1080,10 +1116,10 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abcba80bdf851db5616e27ff869399468e2d339d7c6480f5887681e6bdfc2186" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1119,12 +1155,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1162,11 +1198,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -1180,9 +1222,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -1255,7 +1297,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1290,9 +1332,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -1307,29 +1349,29 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -1364,9 +1406,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -1446,19 +1488,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1483,9 +1527,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64", "bytes", @@ -1507,9 +1551,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1623,9 +1667,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1644,13 +1688,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -1705,6 +1750,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1717,15 +1771,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -1739,55 +1793,55 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-link", ] [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", ] [[package]] name = "linkme" -version = "0.3.33" +version = "0.3.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b1703c00b2a6a70738920544aa51652532cacddfec2e162d2e29eae01e665c" +checksum = "5e3283ed2d0e50c06dd8602e0ab319bb048b6325d0bba739db64ed8205179898" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.33" +version = "0.3.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" +checksum = "e5cec0ec4228b4853bb129c84dbf093a27e6c7a20526da046defc334a1b017f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1797,19 +1851,18 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lru-slab" @@ -1835,9 +1888,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miette" @@ -1866,7 +1919,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -1888,37 +1941,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "munge" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" -dependencies = [ - "munge_macro", -] - -[[package]] -name = "munge_macro" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1949,7 +1983,7 @@ checksum = "c39e43767817fc963f90f400600967a2b2403602c6440685d09a6bc4e02b70b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -2046,9 +2080,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -2097,9 +2131,9 @@ dependencies = [ [[package]] name = "owo-colors" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" [[package]] name = "parking_lot" @@ -2114,12 +2148,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.11", + "parking_lot_core 0.9.12", ] [[package]] @@ -2138,15 +2172,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.13", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2163,9 +2197,9 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" @@ -2193,21 +2227,21 @@ dependencies = [ [[package]] name = "postgres-derive" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69700ea4603c5ef32d447708e6a19cd3e8ac197a000842e97f527daea5e4175f" +checksum = "56df96f5394370d1b20e49de146f9e6c25aa9ae750f449c9d665eafecb3ccae6" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "postgres-protocol" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ "base64", "byteorder", @@ -2216,16 +2250,16 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand 0.9.1", + "rand 0.9.2", "sha2", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" dependencies = [ "array-init", "bytes", @@ -2236,9 +2270,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -2254,42 +2288,42 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.36" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.7", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "lazy_static", "num-traits", - "rand 0.9.1", + "rand 0.9.2", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -2309,7 +2343,7 @@ dependencies = [ "quickcheck_macros", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc)", ] @@ -2321,7 +2355,7 @@ source = "git+https://github.com/cipherstash/vitaminc?branch=timing-safe-eq#5edd dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -2331,7 +2365,7 @@ source = "git+https://github.com/cipherstash/vitaminc#6d8d4d4677b34897d2dd2a9af3 dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -2340,16 +2374,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ - "ptr_meta_derive 0.1.4", -] - -[[package]] -name = "ptr_meta" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" -dependencies = [ - "ptr_meta_derive 0.3.1", + "ptr_meta_derive", ] [[package]] @@ -2363,17 +2388,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ptr_meta_derive" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "quickcheck" version = "1.0.3" @@ -2393,14 +2407,14 @@ checksum = "f71ee38b42f8459a88d3362be6f9b841ad2d5421844f61eb1c59c11bff3ac14a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -2410,7 +2424,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -2418,20 +2432,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -2439,23 +2453,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -2472,15 +2486,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rancor" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" -dependencies = [ - "ptr_meta 0.3.1", -] - [[package]] name = "rand" version = "0.8.5" @@ -2494,9 +2499,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -2537,7 +2542,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -2552,7 +2557,6 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "aes", "async-trait", @@ -2580,11 +2584,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", ] [[package]] @@ -2600,9 +2604,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2612,9 +2616,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2623,9 +2627,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rend" @@ -2633,23 +2637,14 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ - "bytecheck 0.6.12", -] - -[[package]] -name = "rend" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" -dependencies = [ - "bytecheck 0.8.2", + "bytecheck", ] [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "async-compression", "base64", @@ -2755,36 +2750,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", - "bytecheck 0.6.12", + "bytecheck", "bytes", "hashbrown 0.12.3", - "ptr_meta 0.1.4", - "rend 0.4.2", - "rkyv_derive 0.7.45", + "ptr_meta", + "rend", + "rkyv_derive", "seahash", "tinyvec", "uuid", ] -[[package]] -name = "rkyv" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" -dependencies = [ - "bytecheck 0.8.2", - "bytes", - "hashbrown 0.15.4", - "indexmap", - "munge", - "ptr_meta 0.3.1", - "rancor", - "rend 0.5.3", - "rkyv_derive 0.8.12", - "tinyvec", - "uuid", -] - [[package]] name = "rkyv_derive" version = "0.7.45" @@ -2796,17 +2772,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "rkyv_derive" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "rmp" version = "0.8.14" @@ -2841,25 +2806,25 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.2" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" dependencies = [ "arrayvec", "borsh", "bytes", "num-traits", "rand 0.8.5", - "rkyv 0.7.45", + "rkyv", "serde", "serde_json", ] [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -2869,22 +2834,22 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.29" +version = "0.23.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" +checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" dependencies = [ "once_cell", "ring", @@ -2906,9 +2871,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "ring", "rustls-pki-types", @@ -2917,9 +2882,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2941,9 +2906,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "send_wrapper" @@ -2963,11 +2928,12 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -2997,7 +2963,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -3015,24 +2981,26 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -3092,13 +3060,19 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simdutf8" version = "0.1.5" @@ -3119,19 +3093,19 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.10" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -3202,9 +3176,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -3228,7 +3202,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -3239,12 +3213,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3254,7 +3228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "unicode-linebreak", - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -3268,11 +3242,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -3283,18 +3257,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -3309,9 +3283,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -3324,38 +3298,37 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "parking_lot 0.12.4", + "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -3363,9 +3336,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -3382,8 +3355,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -3395,6 +3368,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -3404,9 +3386,30 @@ dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", - "winnow 0.7.11", + "winnow 0.7.13", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime 0.7.3", + "toml_parser", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow 0.7.13", ] [[package]] @@ -3437,7 +3440,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "bytes", "futures-util", "http", @@ -3481,7 +3484,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -3501,9 +3504,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unarray" @@ -3519,9 +3522,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" @@ -3552,9 +3555,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -3586,9 +3589,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -3622,7 +3625,7 @@ checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "url", "uuid", ] @@ -3634,7 +3637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "atomic", - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "md-5", "serde", @@ -3756,45 +3759,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", @@ -3805,9 +3809,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3815,22 +3819,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -3852,9 +3856,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -3872,9 +3876,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] @@ -3903,67 +3907,61 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -3992,20 +3990,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.53.2", + "windows-link", ] [[package]] @@ -4026,18 +4024,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -4054,9 +4053,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -4072,9 +4071,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -4090,9 +4089,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -4102,9 +4101,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -4120,9 +4119,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -4138,9 +4137,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -4156,9 +4155,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -4174,9 +4173,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -4189,21 +4188,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -4240,28 +4236,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] @@ -4281,15 +4277,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -4302,13 +4298,12 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] [[package]] name = "zerokms-protocol" version = "0.7.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=refactor%2Fminor-cs-client-api#565f01d85311fd0dd6144bf164c46c5d805bab85" dependencies = [ "async-trait", "base64", @@ -4318,7 +4313,6 @@ dependencies = [ "fake 2.10.0", "opaque-debug", "rand 0.8.5", - "rkyv 0.8.12", "serde", "static_assertions", "thiserror 1.0.69", @@ -4339,9 +4333,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -4356,5 +4350,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.107", ] diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 116ab11..0d48614 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", branch = "refactor/minor-cs-client-api" } +cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } hex = "0.4.3" neon = {version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" diff --git a/crates/protect-ffi/src/eql.rs b/crates/protect-ffi/src/eql.rs new file mode 100644 index 0000000..abbfe8f --- /dev/null +++ b/crates/protect-ffi/src/eql.rs @@ -0,0 +1,120 @@ +use cipherstash_client::encryption::{self, IndexTerm, SteVec}; +use serde::{Deserialize, Serialize}; + +use crate::{encrypt_config::Identifier, Error}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(tag = "k")] +pub enum Encrypted { + #[serde(rename = "ct")] + Ciphertext { + #[serde(rename = "c")] + ciphertext: String, + #[serde(rename = "ob")] + ore_index: Option>, + #[serde(rename = "bf")] + match_index: Option>, + #[serde(rename = "hm")] + unique_index: Option, + #[serde(rename = "i")] + identifier: Identifier, + #[serde(rename = "v")] + version: u16, + }, + #[serde(rename = "sv")] + SteVec { + #[serde(rename = "sv")] + ste_vec_index: SteVec<16>, + #[serde(rename = "i")] + identifier: Identifier, + #[serde(rename = "v")] + version: u16, + }, +} + +impl TryFrom<(encryption::Encrypted, &Identifier)> for Encrypted { + type Error = Error; + + fn try_from((encrypted, identifier): (encryption::Encrypted, &Identifier)) -> Result { + match encrypted { + encryption::Encrypted::Record(ciphertext, terms) => { + struct Indexes { + match_index: Option>, + ore_index: Option>, + unique_index: Option, + } + + let mut indexes = Indexes { + match_index: None, + ore_index: None, + unique_index: None, + }; + + for index_term in terms { + match index_term { + IndexTerm::Binary(bytes) => { + indexes.unique_index = Some(format_index_term_binary(&bytes)) + } + IndexTerm::BitMap(inner) => indexes.match_index = Some(inner), + IndexTerm::OreArray(vec_of_bytes) => { + indexes.ore_index = Some(format_index_term_ore_array(&vec_of_bytes)); + } + IndexTerm::OreFull(bytes) => { + indexes.ore_index = Some(format_index_term_ore(&bytes)); + } + IndexTerm::OreLeft(bytes) => { + indexes.ore_index = Some(format_index_term_ore(&bytes)); + } + IndexTerm::Null => {} + term => return Err(Error::Unimplemented(format!("index term `{term:?}`"))), + }; + } + + let ciphertext = ciphertext + .to_mp_base85() + // The error type from `to_mp_base85` isn't public, so we don't derive an error for this one. + // Instead, we use `map_err`. + .map_err(|err| Error::Base85(err.to_string()))?; + + Ok(Encrypted::Ciphertext { + ciphertext, + identifier: identifier.to_owned(), + match_index: indexes.match_index, + ore_index: indexes.ore_index, + unique_index: indexes.unique_index, + version: 2, + }) + } + encryption::Encrypted::SteVec(ste_vec_index) => Ok(Encrypted::SteVec { + identifier: identifier.to_owned(), + ste_vec_index, + version: 2, + }), + } + } +} + +fn format_index_term_binary(bytes: &Vec) -> String { + hex::encode(bytes) +} + +fn format_index_term_ore_bytea(bytes: &Vec) -> String { + hex::encode(bytes) +} + +/// +/// Formats a Vec> into a Vec +/// +fn format_index_term_ore_array(vec_of_bytes: &[Vec]) -> Vec { + vec_of_bytes + .iter() + .map(format_index_term_ore_bytea) + .collect() +} + +/// +/// Formats a Vec> into a single elenent Vec +/// +fn format_index_term_ore(bytes: &Vec) -> Vec { + vec![format_index_term_ore_bytea(bytes)] +} \ No newline at end of file diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index 898ebd9..cfff3ba 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -1,5 +1,7 @@ mod encrypt_config; +mod eql; mod js_plaintext; +mod query; use cipherstash_client::{ config::{ @@ -17,6 +19,7 @@ use cipherstash_client::{ Crn, IdentifiedBy, UnverifiedContext, }; use encrypt_config::{EncryptConfig, Identifier}; +use eql::Encrypted; use js_plaintext::JsPlaintext; use neon::{ prelude::*, @@ -43,34 +46,7 @@ struct Client { impl Finalize for Client {} -#[derive(Debug, Deserialize, Serialize)] -#[serde(tag = "k")] -pub enum Encrypted { - #[serde(rename = "ct")] - Ciphertext { - #[serde(rename = "c")] - ciphertext: String, - #[serde(rename = "ob")] - ore_index: Option>, - #[serde(rename = "bf")] - match_index: Option>, - #[serde(rename = "hm")] - unique_index: Option, - #[serde(rename = "i")] - identifier: Identifier, - #[serde(rename = "v")] - version: u16, - }, - #[serde(rename = "sv")] - SteVec { - #[serde(rename = "sv")] - ste_vec_index: SteVec<16>, - #[serde(rename = "i")] - identifier: Identifier, - #[serde(rename = "v")] - version: u16, - }, -} + #[derive(thiserror::Error, Debug)] pub enum Error { @@ -517,90 +493,13 @@ fn encrypted_record_from_mp_base85( }) } +// Refactoring shim to extract EQL logic into a separate module (and eventually crate) +#[inline] fn to_eql_encrypted( encrypted: encryption::Encrypted, identifier: &Identifier, ) -> Result { - match encrypted { - encryption::Encrypted::Record(ciphertext, terms) => { - struct Indexes { - match_index: Option>, - ore_index: Option>, - unique_index: Option, - } - - let mut indexes = Indexes { - match_index: None, - ore_index: None, - unique_index: None, - }; - - for index_term in terms { - match index_term { - IndexTerm::Binary(bytes) => { - indexes.unique_index = Some(format_index_term_binary(&bytes)) - } - IndexTerm::BitMap(inner) => indexes.match_index = Some(inner), - IndexTerm::OreArray(vec_of_bytes) => { - indexes.ore_index = Some(format_index_term_ore_array(&vec_of_bytes)); - } - IndexTerm::OreFull(bytes) => { - indexes.ore_index = Some(format_index_term_ore(&bytes)); - } - IndexTerm::OreLeft(bytes) => { - indexes.ore_index = Some(format_index_term_ore(&bytes)); - } - IndexTerm::Null => {} - term => return Err(Error::Unimplemented(format!("index term `{term:?}`"))), - }; - } - - let ciphertext = ciphertext - .to_mp_base85() - // The error type from `to_mp_base85` isn't public, so we don't derive an error for this one. - // Instead, we use `map_err`. - .map_err(|err| Error::Base85(err.to_string()))?; - - Ok(Encrypted::Ciphertext { - ciphertext, - identifier: identifier.to_owned(), - match_index: indexes.match_index, - ore_index: indexes.ore_index, - unique_index: indexes.unique_index, - version: 2, - }) - } - encryption::Encrypted::SteVec(ste_vec_index) => Ok(Encrypted::SteVec { - identifier: identifier.to_owned(), - ste_vec_index, - version: 2, - }), - } -} - -fn format_index_term_binary(bytes: &Vec) -> String { - hex::encode(bytes) -} - -fn format_index_term_ore_bytea(bytes: &Vec) -> String { - hex::encode(bytes) -} - -/// -/// Formats a Vec> into a Vec -/// -fn format_index_term_ore_array(vec_of_bytes: &[Vec]) -> Vec { - vec_of_bytes - .iter() - .map(format_index_term_ore_bytea) - .collect() -} - -/// -/// Formats a Vec> into a single elenent Vec -/// -fn format_index_term_ore(bytes: &Vec) -> Vec { - vec![format_index_term_ore_bytea(bytes)] + (encrypted, identifier).try_into() } static RUNTIME: OnceCell = OnceCell::new(); diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs new file mode 100644 index 0000000..3a5c34c --- /dev/null +++ b/crates/protect-ffi/src/query.rs @@ -0,0 +1,57 @@ +use cipherstash_client::encryption::{EncryptedSteVecTerm, SteQueryVec, TokenizedSelector}; +use serde::Serialize; + +#[derive(Serialize, Debug)] +#[serde(untagged)] +pub enum Query { + Json(SteQueryVec<16>), + SteVecSelector(TokenizedSelector<16>), + SteVecTerm(EncryptedSteVecTerm), +} + +#[cfg(test)] +mod tests { + use super::*; + use cipherstash_client::ejsonpath::Selector; + use cipherstash_client::encryption::{JsonIndexer, JsonIndexerOptions}; + use cipherstash_client::zerokms::IndexKey; + use serde_json::json; + + fn indexer() -> JsonIndexer { + let opts = JsonIndexerOptions { prefix: "foo".to_string() }; + JsonIndexer::new(opts) + } + + fn index_key() -> IndexKey { + [0u8; 32].into() + } + + #[test] + fn serialize_ste_query_vec() { + let x = indexer().query(json!({"foo": 1}), &index_key()).map(Query::Json).unwrap(); + let check = json!([ + [ + "814586efb4a86da0ae72f65c87e4b7b3", + "001550590d76040654f5dcf654adfd52da" + ], + [ + "9d1dbec87dd19ab2217426e87d91db06", + "019d5739400872d8378c4002bd922ad7ff296fd9124a8cbfbf64e4803fa6e21d0f8cf8376a034d2735759c7b8e9f39d519b1da4264726e977e2d2df4ccf1b8c41d" + ] + ]); + + assert_eq!(serde_json::to_value(&x).unwrap(), check); + } + + #[test] + fn serialize_ste_vec_selector() { + let selector = Selector::parse("$.foo").unwrap(); + let tokenized_selector = Query::SteVecSelector(indexer().generate_selector(selector, &index_key())); + assert_eq!(serde_json::to_value(&tokenized_selector).unwrap(), json!("9d1dbec87dd19ab2217426e87d91db06")); + } + + #[test] + fn serialize_ste_vec_term() { + + } +} \ No newline at end of file From baf4cfcf547c35d45da45d495d91728290ea1019 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Sun, 19 Oct 2025 21:50:40 +1100 Subject: [PATCH 05/30] refactor: added encryptQuery, update existing query tests --- Cargo.lock | 1 + crates/protect-ffi/Cargo.toml | 1 + crates/protect-ffi/src/lib.rs | 20 ++++-- crates/protect-ffi/src/query.rs | 47 +++++++++++++- integration-tests/tests/postgres.test.ts | 80 +++++++++++++++++++++--- 5 files changed, 132 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc626e9..89b4a65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2336,6 +2336,7 @@ version = "0.1.0" dependencies = [ "chrono", "cipherstash-client", + "const-hex", "hex", "neon", "once_cell", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 0d48614..8453d99 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["cdylib"] [dependencies] cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } +const-hex = "1.17.0" hex = "0.4.3" neon = {version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index cfff3ba..6c4ad88 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -11,8 +11,8 @@ use cipherstash_client::{ }, credentials::{ServiceCredentials, ServiceToken}, encryption::{ - self, EncryptionError, IndexTerm, Plaintext, PlaintextTarget, QueryOp, Queryable, - ReferencedPendingPipeline, ScopedCipher, SteVec, TypeParseError, + self, EncryptionError, Plaintext, PlaintextTarget, QueryOp, Queryable, + ReferencedPendingPipeline, ScopedCipher, TypeParseError, }, schema::{operator::Operator, ColumnConfig}, zerokms::{self, EncryptedRecord, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, @@ -31,6 +31,8 @@ use std::collections::HashMap; use std::sync::Arc; use tokio::runtime::Runtime; +use crate::query::Query; + #[cfg(test)] extern crate quickcheck; #[cfg(test)] @@ -68,6 +70,8 @@ pub enum Error { Parse(#[from] serde_json::Error), #[error("column {}.{} not found in Encrypt config", _0.table, _0.column)] UnknownColumn(Identifier), + #[error("no index found for column {}.{} supporting operator {}", _0.table, _0.column, _1)] + MissingIndexForOperator(Identifier, Operator), #[error(transparent)] RecordDecryptError(#[from] RecordDecryptError), } @@ -330,7 +334,7 @@ async fn encrypt_bulk( async fn encrypt_query( Boxed(client): Boxed, Json(opts): Json, -) -> Result, neon::types::extract::Error> { +) -> Result, neon::types::extract::Error> { let ident = Identifier::new(opts.table, opts.column); let column_config = client @@ -339,10 +343,14 @@ async fn encrypt_query( .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; let plaintext: Plaintext = opts.plaintext.into(); - let index = column_config.index_for_operator(&opts.operator).unwrap(); // TODO: Handle no index found - let term = (index, plaintext).build_queryable(client.cipher, QueryOp::Default)?; + let index = column_config.index_for_operator(&opts.operator) + .ok_or_else(|| Error::MissingIndexForOperator(ident, opts.operator))?; + + let query: Query = (index, plaintext) + .build_queryable(client.cipher, QueryOp::Default)? + .try_into()?; - Ok(Json(term)) + Ok(Json(query)) } #[neon::export] diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index 3a5c34c..9b584dc 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -1,14 +1,57 @@ -use cipherstash_client::encryption::{EncryptedSteVecTerm, SteQueryVec, TokenizedSelector}; +use cipherstash_client::{encryption::{EncryptedSteVecTerm, IndexTerm, SteQueryVec, TokenizedSelector}}; use serde::Serialize; +/// Represents a query term that can be serialized to JSON for use in FFI. #[derive(Serialize, Debug)] -#[serde(untagged)] pub enum Query { + #[serde(rename = "hm", with = "const_hex_sans_prefix")] + Binary(Vec), + #[serde(rename = "bf")] + BitMap(Vec), + + #[serde(rename = "ob")] + OreLeft(Vec), + Json(SteQueryVec<16>), SteVecSelector(TokenizedSelector<16>), SteVecTerm(EncryptedSteVecTerm), } +#[derive(Serialize, Debug)] +#[serde(transparent)] +pub struct OreTerm(#[serde(with = "const_hex_sans_prefix")] Vec); + +impl TryFrom for Query { + type Error = String; + + fn try_from(value: IndexTerm) -> Result { + match value { + IndexTerm::Binary(b) => Ok(Query::Binary(b)), + IndexTerm::BitMap(bm) => Ok(Query::BitMap(bm)), + IndexTerm::OreLeft(ol) => Ok(Query::OreLeft(vec![OreTerm(ol)])), + // TODO: Truncate - or remove entirely? + IndexTerm::OreFull(of) => Ok(Query::OreLeft(vec![OreTerm(of)])), + IndexTerm::SteQueryVec(sqv) => Ok(Query::Json(sqv)), + IndexTerm::SteVecSelector(ts) => Ok(Query::SteVecSelector(ts)), + IndexTerm::SteVecTerm(est) => Ok(Query::SteVecTerm(est)), + unsupported => Err(format!("{unsupported:?} cannot be converted to Query")), + } + } +} + +// The const_hex provides a serde serializer but it prefixes with "0x" which we don't want here. +mod const_hex_sans_prefix { + use serde::Serializer; + + pub fn serialize(bytes: &Vec, serializer: S) -> Result + where + S: Serializer, + { + let hex_string = const_hex::encode(bytes); + serializer.serialize_str(&hex_string) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/integration-tests/tests/postgres.test.ts b/integration-tests/tests/postgres.test.ts index bad8e94..c098329 100644 --- a/integration-tests/tests/postgres.test.ts +++ b/integration-tests/tests/postgres.test.ts @@ -10,6 +10,7 @@ import { type EncryptConfig, } from '@cipherstash/protect-ffi' import { Client, type QueryResult } from 'pg' +import { encryptQuery } from '../../lib/load.cjs' describe('postgres', async () => { const protectClient = await newClient({ encryptConfig: encryptConfig() }) @@ -23,13 +24,17 @@ describe('postgres', async () => { await pg.query(` CREATE TABLE encrypted ( id SERIAL PRIMARY KEY, - encrypted_text eql_v2_encrypted + encrypted_text eql_v2_encrypted, + encrypted_score eql_v2_encrypted ) `) await pg.query( "SELECT eql_v2.add_encrypted_constraint('encrypted', 'encrypted_text')", ) + await pg.query( + "SELECT eql_v2.add_encrypted_constraint('encrypted', 'encrypted_score')", + ) // clean up function, called once after all tests run return async () => { @@ -136,10 +141,11 @@ describe('postgres', async () => { ciphertexts, ) - const search = await encrypt(protectClient, { + const search = await encryptQuery(protectClient, { plaintext: 'ccc', column: 'email', table: 'users', + operator: '~~', }) const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query( @@ -159,6 +165,56 @@ describe('postgres', async () => { expect(decrypted).toEqual(['aaa ccc']) }) + test('can use an ORE query', async () => { + const ciphertexts = await encryptBulk(protectClient, { + plaintexts: [ + { + plaintext: 1000, + column: 'score', + table: 'users', + }, + { + plaintext: 75, + column: 'score', + table: 'users', + }, + { + plaintext: 888, + column: 'score', + table: 'users', + }, + ], + }) + + await pg.query( + 'INSERT INTO encrypted (encrypted_score) VALUES ($1::jsonb), ($2::jsonb), ($3::jsonb)', + ciphertexts, + ) + + const search = await encryptQuery(protectClient, { + plaintext: 500, + column: 'score', + table: 'users', + operator: '>=', + }) + + const res: QueryResult<{ encrypted_score: Encrypted }> = await pg.query( + ` + SELECT encrypted_score::jsonb FROM encrypted + WHERE encrypted_score >= $1::jsonb ORDER BY eql_v2.order_by(encrypted_score) ASC + `, + [search], + ) + + const decrypted = await decryptBulk(protectClient, { + ciphertexts: res.rows.map((row) => ({ + ciphertext: row.encrypted_score, + })), + }) + + expect(decrypted).toEqual([888, 1000]) + }) + test('can use an exact query', async () => { const ciphertexts = await encryptBulk(protectClient, { plaintexts: [ @@ -180,18 +236,19 @@ describe('postgres', async () => { ciphertexts, ) + const query = await encryptQuery(protectClient, { + plaintext: 'b', + column: 'email', + table: 'users', + operator: '=', + }); + const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query( ` SELECT encrypted_text::jsonb FROM encrypted WHERE encrypted_text = $1::jsonb `, - [ - await encrypt(protectClient, { - plaintext: 'b', - column: 'email', - table: 'users', - }), - ], + [query], ) const decrypted = await decryptBulk(protectClient, { @@ -204,6 +261,7 @@ describe('postgres', async () => { }) }) +// TODO: Load the config from common function encryptConfig(): EncryptConfig { return { v: 1, @@ -229,6 +287,10 @@ function encryptConfig(): EncryptConfig { unique: {}, }, }, + score: { + cast_as: 'double', + indexes: { ore: {} }, + }, }, }, } From f43c8f13fdcd98a483c7a6f1f0a4e107be59d2a4 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Mon, 20 Oct 2025 14:07:26 +1100 Subject: [PATCH 06/30] wip: JSON query support --- crates/protect-ffi/src/lib.rs | 24 +++++-- crates/protect-ffi/src/query.rs | 2 + integration-tests/tests/postgres.test.ts | 85 +++++++++++++++++++++++- src/index.cts | 40 ++++++++--- 4 files changed, 138 insertions(+), 13 deletions(-) diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index 6c4ad88..a19aa45 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -11,10 +11,9 @@ use cipherstash_client::{ }, credentials::{ServiceCredentials, ServiceToken}, encryption::{ - self, EncryptionError, Plaintext, PlaintextTarget, QueryOp, Queryable, - ReferencedPendingPipeline, ScopedCipher, TypeParseError, + self, EncryptionError, JsonIndexerOptions, Plaintext, PlaintextTarget, QueryOp, Queryable, ReferencedPendingPipeline, ScopedCipher, TypeParseError }, - schema::{operator::Operator, ColumnConfig}, + schema::{column::IndexType, operator::Operator, ColumnConfig}, zerokms::{self, EncryptedRecord, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, Crn, IdentifiedBy, UnverifiedContext, }; @@ -346,10 +345,27 @@ async fn encrypt_query( let index = column_config.index_for_operator(&opts.operator) .ok_or_else(|| Error::MissingIndexForOperator(ident, opts.operator))?; + dbg!(&index); + let query_op = if let IndexType::SteVec { .. } = index.index_type { + QueryOp::SteVecSelector + } else { + QueryOp::Default + }; + println!("Using query op: {:?}", query_op); + let query: Query = (index, plaintext) - .build_queryable(client.cipher, QueryOp::Default)? + // TODO: Better error + .build_queryable(client.cipher, query_op).map_err(|e| Error::Unimplemented(format!("build queryable failed: {e}")))? + //.build_queryable(client.cipher, QueryOp::SteVecSelector)? .try_into()?; + // JSON is completely different + // TODO: Check the operator (from this crate) and build the JSON query if its a JSON operator + // Find an Index with type SteVec to get the prefix (see cipherstash_config IndexType) and create the JsonIndexerOptions + //let options: JsonIndexerOptions = todo!(); + //let indexer = JsonIndexer::try_init(options)?; + // indexer.generate_selector(selector, &client.cipher.index_key()); + Ok(Json(query)) } diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index 9b584dc..6ff3e2e 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -13,6 +13,8 @@ pub enum Query { OreLeft(Vec), Json(SteQueryVec<16>), + + #[serde(rename = "s")] SteVecSelector(TokenizedSelector<16>), SteVecTerm(EncryptedSteVecTerm), } diff --git a/integration-tests/tests/postgres.test.ts b/integration-tests/tests/postgres.test.ts index c098329..0affb03 100644 --- a/integration-tests/tests/postgres.test.ts +++ b/integration-tests/tests/postgres.test.ts @@ -8,6 +8,7 @@ import { decryptBulk, type Encrypted, type EncryptConfig, + EncryptedSV, } from '@cipherstash/protect-ffi' import { Client, type QueryResult } from 'pg' import { encryptQuery } from '../../lib/load.cjs' @@ -25,7 +26,8 @@ describe('postgres', async () => { CREATE TABLE encrypted ( id SERIAL PRIMARY KEY, encrypted_text eql_v2_encrypted, - encrypted_score eql_v2_encrypted + encrypted_score eql_v2_encrypted, + encrypted_profile eql_v2_encrypted ) `) @@ -35,6 +37,10 @@ describe('postgres', async () => { await pg.query( "SELECT eql_v2.add_encrypted_constraint('encrypted', 'encrypted_score')", ) + // FIXME: This doesn't work for ste_vec - should there be a different function? + //await pg.query( + // "SELECT eql_v2.add_encrypted_constraint('encrypted', 'encrypted_profile')", + //) // clean up function, called once after all tests run return async () => { @@ -259,6 +265,79 @@ describe('postgres', async () => { expect(decrypted).toEqual(['b']) }) + + test.only('can use JSON stabby ->', async () => { + const ciphertexts = await encryptBulk(protectClient, { + plaintexts: [ + { + plaintext: { foo: 'bar', baz: [1, 2, 3] }, + column: 'profile', + table: 'users', + }, + { + plaintext: { foo: 'baz', qux: [4, 5, 6] }, + column: 'profile', + table: 'users', + }, + { + plaintext: { other: 'foo' }, + column: 'profile', + table: 'users', + }, + ], + }) + + console.log("Ciphertexts:", JSON.stringify(ciphertexts[0])); + + await pg.query( + 'INSERT INTO encrypted (encrypted_profile) VALUES ($1::jsonb), ($2::jsonb), ($3::jsonb)', + ciphertexts, + ) + + const query = await encryptQuery(protectClient, { + // FIXME: The first form fails (the selector doesn't map correctly) + // See JsonIndexer::tokenize_selector (the Dot variant behaves differently) + //plaintext: "$.foo", + plaintext: "$['foo']", + column: 'profile', + table: 'users', + operator: '->', + }); + + console.log("Query:", query); + + const res1: QueryResult<{ encrypted_profile: EncryptedSV }> = await pg.query( + ` + SELECT encrypted_profile::jsonb FROM encrypted + ` + ) + + res1.rows[0].encrypted_profile.sv.forEach((entry) => { + console.log("Selector:", entry.s, "Term:", entry.term); + }); + + // Or jsonb_path_query + // eql_v2.jsonb_path_query(encrypted_profile, $1) + + //SELECT eql_v2.jsonb_path_query(encrypted_profile, eql_v2.selector($1::jsonb)) FROM encrypted + // TODO: Use the jsonquery approach from the Json indexer docs + const res: QueryResult<{ encrypted_profile: EncryptedSV }> = await pg.query( + ` + SELECT eql_v2."->"(encrypted_profile, eql_v2.selector($1::jsonb)) FROM encrypted + `, + [query], + ) + + console.log("ROWS:", res.rows); + /*const decrypted = await decryptBulk(protectClient, { + ciphertexts: res.rows.map((row) => ({ + ciphertext: row.encrypted_profile, + })), + }) + + expect(decrypted).toEqual(['bar', 'baz', null])*/ + expect("foo").toBe("food") + }) }) // TODO: Load the config from common @@ -291,6 +370,10 @@ function encryptConfig(): EncryptConfig { cast_as: 'double', indexes: { ore: {} }, }, + profile: { + cast_as: 'jsonb', + indexes: { ste_vec: { prefix: 'users/profile' } }, + }, }, }, } diff --git a/src/index.cts b/src/index.cts index 83f4545..eb56744 100644 --- a/src/index.cts +++ b/src/index.cts @@ -22,7 +22,7 @@ declare module './load.cjs' { function encrypt(client: Client, opts: EncryptOptions): Promise function decrypt(client: Client, opts: DecryptOptions): Promise function isEncrypted(encrypted: Encrypted): boolean - function encryptQuery(client: Client, opts: QueryOptions): Promise + function encryptQuery(client: Client, opts: QueryOptions): Promise function encryptBulk( client: Client, opts: EncryptBulkOptions, @@ -60,7 +60,25 @@ export type Context = { identityClaim: string[] } -export type Encrypted = +// TODO: Make generic and use the identifier utility type +export type Versioned = { i: { c: string; t: string }; v: number }; + +export type EncryptedCT = Versioned & { + k: 'ct'; + c: string; + ob: string[] | null; + bf: number[] | null; + hm: string | null; +}; + +export type EncryptedSV = Versioned & { + k: 'sv'; + sv: SteVecEncryptedEntry[]; +}; + +export type Encrypted = EncryptedCT | EncryptedSV; + +/*export type Encrypted = | { k: 'ct' c: string @@ -81,10 +99,10 @@ export type Encrypted = t: string } v: number - } + }*/ export type SteVecEncryptedEntry = { - tokenized_selector: string + s: string term: string record: string parent_is_array: boolean @@ -219,9 +237,15 @@ export type QueryOperator = | '~~*' | '@>' | '<@' - -export type IndexTerm = - | { type: 'Binary'; value: Uint8Array } + | '->' + +// TODO: Maybe give each variant a more descriptive name via a named type +export type EncryptedQueryTerm = + | { ob: String[] } + | { bf: number[] } + | { hm: string } + | { s: string } + /*| { type: 'Binary'; value: Uint8Array } | { type: 'BinaryVec'; value: Uint8Array[] } | { type: 'BitMap'; value: number[] } // u16 fits safely in JS number | { type: 'OreFull'; value: Uint8Array } @@ -234,4 +258,4 @@ export type IndexTerm = export type TokenizedSelector = string export type EncryptedSteVecTerm = string[] -export type SteQueryVec = string[] +export type SteQueryVec = string[]*/ From 5c4d6152562dfcf335a5d8f3f138d10e74716d1d Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Tue, 21 Oct 2025 08:29:01 +1100 Subject: [PATCH 07/30] feat: refactor types and context handling in encryption and decryption processes --- Cargo.lock | 7 +- crates/protect-ffi/Cargo.toml | 5 + crates/protect-ffi/src/eql.rs | 77 ++++- crates/protect-ffi/src/lib.rs | 324 +++++++++++++++---- crates/protect-ffi/src/query.rs | 2 + integration-tests/tests/json.test.ts | 2 +- integration-tests/tests/lock-context.test.ts | 18 +- integration-tests/tests/postgres.test.ts | 39 ++- integration-tests/tests/scalar-bulk.test.ts | 12 +- src/index.cts | 100 +++--- 10 files changed, 426 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89b4a65..7733a04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1332,9 +1332,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -2334,9 +2334,11 @@ dependencies = [ name = "protect-ffi" version = "0.1.0" dependencies = [ + "anyhow", "chrono", "cipherstash-client", "const-hex", + "generic-array", "hex", "neon", "once_cell", @@ -2346,6 +2348,7 @@ dependencies = [ "serde_json", "thiserror 2.0.17", "tokio", + "uuid", "vitaminc-protected 0.1.0-pre2 (git+https://github.com/cipherstash/vitaminc)", ] diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 8453d99..f8f83fc 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -13,6 +13,9 @@ crate-type = ["cdylib"] [dependencies] cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } const-hex = "1.17.0" +# 0.14.7 introduces deprecations we need to avoid for now +# Protect.rs will not use GenericArray at all +generic-array = "=0.14.6" hex = "0.4.3" neon = {version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" @@ -20,9 +23,11 @@ serde = "1.0.218" serde_json = "1.0.139" thiserror = "2.0.8" tokio = { version = "1", features = ["full"] } +uuid = "1.18.1" vitaminc-protected = { version = "0.1.0-pre2", git = "https://github.com/cipherstash/vitaminc" } [dev-dependencies] +anyhow = "1.0.100" chrono = "0.4.42" quickcheck = "1.0.3" quickcheck_macros = "1.0.3" diff --git a/crates/protect-ffi/src/eql.rs b/crates/protect-ffi/src/eql.rs index abbfe8f..d304bd6 100644 --- a/crates/protect-ffi/src/eql.rs +++ b/crates/protect-ffi/src/eql.rs @@ -1,15 +1,17 @@ -use cipherstash_client::encryption::{self, IndexTerm, SteVec}; +use cipherstash_client::{encryption::{self, EncryptedEntry, EncryptionError, IndexTerm, SteVec}, zerokms::{self, encrypted_record, EncryptedRecord}}; use serde::{Deserialize, Serialize}; +use uuid::Uuid; use crate::{encrypt_config::Identifier, Error}; #[derive(Debug, Deserialize, Serialize)] #[serde(tag = "k")] pub enum Encrypted { + /// A standard EQL payload containing an encrypted record and optional indexes. #[serde(rename = "ct")] Ciphertext { - #[serde(rename = "c")] - ciphertext: String, + #[serde(rename = "c", with = "encrypted_record::formats::mp_base85")] + ciphertext: EncryptedRecord, #[serde(rename = "ob")] ore_index: Option>, #[serde(rename = "bf")] @@ -21,6 +23,8 @@ pub enum Encrypted { #[serde(rename = "v")] version: u16, }, + + /// A SteVec index payload for storage of SteVec indexes. #[serde(rename = "sv")] SteVec { #[serde(rename = "sv")] @@ -30,6 +34,42 @@ pub enum Encrypted { #[serde(rename = "v")] version: u16, }, + + /// A single SteVec entry. + /// This is useful when returning individual entries from queries and wanting to decrypt them. + #[serde(rename = "sve")] + SteVecEntry { + #[serde(rename = "sve")] + entry: EncryptedEntry<16>, + } +} + +impl zerokms::Decryptable for Encrypted { + type Error = EncryptionError; + + fn keyset_id(&self) -> Option { + match self { + Self::Ciphertext { ciphertext, .. } => ciphertext.keyset_id, + Self::SteVec { ste_vec_index, .. } => ste_vec_index.root_ciphertext().ok().and_then(|ct| ct.keyset_id()), + Self::SteVecEntry { entry } => entry.record.keyset_id(), + } + } + + fn into_encrypted_record(self) -> Result { + match self { + Self::Ciphertext { ciphertext, .. } => Ok(ciphertext), + Self::SteVec { ste_vec_index, .. } => ste_vec_index.into_root_ciphertext(), + Self::SteVecEntry { entry } => Ok(entry.record), + } + } + + fn retrieve_key_payload<'a>(&'a self) -> Result, Self::Error> { + match self { + Self::Ciphertext { ciphertext, .. } => ciphertext.retrieve_key_payload().map_err(EncryptionError::from), + Self::SteVec { ste_vec_index, .. } => ste_vec_index.root_ciphertext()?.retrieve_key_payload().map_err(EncryptionError::from), + Self::SteVecEntry { entry } => entry.record.retrieve_key_payload().map_err(EncryptionError::from), + } + } } impl TryFrom<(encryption::Encrypted, &Identifier)> for Encrypted { @@ -70,12 +110,6 @@ impl TryFrom<(encryption::Encrypted, &Identifier)> for Encrypted { }; } - let ciphertext = ciphertext - .to_mp_base85() - // The error type from `to_mp_base85` isn't public, so we don't derive an error for this one. - // Instead, we use `map_err`. - .map_err(|err| Error::Base85(err.to_string()))?; - Ok(Encrypted::Ciphertext { ciphertext, identifier: identifier.to_owned(), @@ -117,4 +151,29 @@ fn format_index_term_ore_array(vec_of_bytes: &[Vec]) -> Vec { /// fn format_index_term_ore(bytes: &Vec) -> Vec { vec![format_index_term_ore_bytea(bytes)] +} + +#[cfg(test)] +mod tests { + use super::*; + + mod deserialize { + use super::*; + + #[test] + fn ste_vec_entry() { + let json_data = serde_json::json!({ + "k": "sve", + "sve": { + "c": "mBbKmZYAVzP6EORkHe`E;VK=(7eXEXplEbxc8;TAEw#iE0n~Ic#Kd6J#2^_sVQ9%b&$!kU_5n2v@s81UBmm7(>-mWRlY|7j7Pg?k", + "s": "d18aa290a20cf6413f50d5ca87a0a6c2", + "ocv": "026d08ef26fd0fb009277f9583fd123f74fae53bc10d5fc00e", + "parent_is_array": false + } + }); + let deserialized: Result = serde_json::from_value(json_data); + println!("deserialized: {:?}", deserialized); + assert!(deserialized.is_ok()); + } + } } \ No newline at end of file diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index a19aa45..b5b5836 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -11,10 +11,10 @@ use cipherstash_client::{ }, credentials::{ServiceCredentials, ServiceToken}, encryption::{ - self, EncryptionError, JsonIndexerOptions, Plaintext, PlaintextTarget, QueryOp, Queryable, ReferencedPendingPipeline, ScopedCipher, TypeParseError + self, EncryptionError, Plaintext, PlaintextTarget, QueryOp, Queryable, ReferencedPendingPipeline, ScopedCipher, TypeParseError }, schema::{column::IndexType, operator::Operator, ColumnConfig}, - zerokms::{self, EncryptedRecord, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, + zerokms::{self, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, Crn, IdentifiedBy, UnverifiedContext, }; use encrypt_config::{EncryptConfig, Identifier}; @@ -47,8 +47,6 @@ struct Client { impl Finalize for Client {} - - #[derive(thiserror::Error, Debug)] pub enum Error { #[error(transparent)] @@ -104,10 +102,8 @@ enum DecryptResult { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct EncryptOptions { - plaintext: JsPlaintext, - column: String, - table: String, - lock_context: Option, + #[serde(flatten)] + plaintext: PlaintextPayload, service_token: Option, unverified_context: Option, } @@ -144,14 +140,15 @@ struct PlaintextPayload { plaintext: JsPlaintext, column: String, table: String, - lock_context: Option, + #[serde(default)] + lock_context: Vec } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct DecryptOptions { - ciphertext: Encrypted, - lock_context: Option, + #[serde(flatten)] + ciphertext: WithContext, service_token: Option, unverified_context: Option, } @@ -159,18 +156,12 @@ struct DecryptOptions { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct DecryptBulkOptions { - ciphertexts: Vec, + ciphertexts: Vec>, service_token: Option, unverified_context: Option, } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct BulkDecryptPayload { - ciphertext: Encrypted, - lock_context: Option, -} - +// TODO: Remove #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct LockContext { @@ -242,15 +233,15 @@ async fn encrypt( Boxed(client): Boxed, Json(opts): Json, ) -> Result, neon::types::extract::Error> { - let ident = Identifier::new(opts.table, opts.column); + let ident = Identifier::new(opts.plaintext.table, opts.plaintext.column); let column_config = client .encrypt_config .get(&ident) .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; - let mut plaintext_target = PlaintextTarget::new(opts.plaintext, column_config.clone()); - plaintext_target.context = opts.lock_context.map(Into::into).unwrap_or_default(); + let mut plaintext_target = PlaintextTarget::new(opts.plaintext.plaintext, column_config.clone()); + plaintext_target.context = opts.plaintext.lock_context; let mut pipeline = ReferencedPendingPipeline::new(client.cipher); @@ -287,7 +278,7 @@ async fn encrypt_bulk( let mut plaintext_target = PlaintextTarget::new(payload.plaintext, column_config.clone()); - plaintext_target.context = payload.lock_context.map(Into::into).unwrap_or_default(); + plaintext_target.context = payload.lock_context; //.map(Into::into).unwrap_or_default(); Ok((plaintext_target, ident)) }) @@ -374,21 +365,32 @@ async fn decrypt( Boxed(client): Boxed, Json(opts): Json, ) -> Result, neon::types::extract::Error> { - let lock_context = opts.lock_context.map(Into::into).unwrap_or_default(); - let encrypted_record = encrypted_record_from_mp_base85(opts.ciphertext, lock_context)?; + //let lock_context = opts.lock_context.map(Into::into).unwrap_or_default(); + //let encrypted_record = encrypted_record_from_mp_base85(opts.ciphertext, lock_context)?; + let DecryptOptions { + ciphertext, + service_token, + unverified_context, + } = opts; + + println!("Decrypting ciphertext: {:?}", ciphertext); let plaintext = client .zerokms .decrypt_single( - encrypted_record, + ciphertext, None, - opts.service_token, - opts.unverified_context, + service_token, + unverified_context, ) .await .map_err(Error::from) + .inspect_err(|e| println!("Got error: {e}")) + .inspect(|o| println!("Got plaintext bytes: {:?}", o)) .and_then(|bytes| Plaintext::from_slice(bytes.as_slice()).map_err(Error::from))?; + println!("Decrypted plaintext: {:?}", plaintext); + JsPlaintext::try_from(plaintext) .map(Json) .map_err(From::from) @@ -399,7 +401,7 @@ async fn decrypt_bulk( Boxed(client): Boxed, Json(opts): Json, ) -> Result>, neon::types::extract::Error> { - let ciphertexts: Vec<(Encrypted, Vec)> = opts + /*let ciphertexts: Vec<(Encrypted, Vec)> = opts .ciphertexts .into_iter() .map(|payload| { @@ -413,12 +415,12 @@ async fn decrypt_bulk( .map(|(ciphertext, encryption_context)| { encrypted_record_from_mp_base85(ciphertext, encryption_context) }) - .collect::, Error>>()?; + .collect::, Error>>()?;*/ let decrypted = client .zerokms .decrypt( - encrypted_records, + opts.ciphertexts, None, opts.service_token, opts.unverified_context, @@ -438,7 +440,7 @@ async fn decrypt_bulk_fallible( Boxed(client): Boxed, Json(opts): Json, ) -> Result>, neon::types::extract::Error> { - let ciphertexts: Vec<(Encrypted, Vec)> = opts + /*let ciphertexts: Vec<(Encrypted, Vec)> = opts .ciphertexts .into_iter() .map(|payload| { @@ -454,12 +456,12 @@ async fn decrypt_bulk_fallible( }) .collect(); - let encrypted_records = encrypted_records?; + let encrypted_records = encrypted_records?;*/ let decrypted = client .zerokms .decrypt_fallible( - encrypted_records, + opts.ciphertexts, opts.service_token, opts.unverified_context, ) @@ -497,26 +499,6 @@ fn is_encrypted( result.is_ok() } -fn encrypted_record_from_mp_base85( - encrypted: Encrypted, - encryption_context: Vec, -) -> Result { - let encrypted_record = match encrypted { - Encrypted::Ciphertext { ciphertext, .. } => EncryptedRecord::from_mp_base85(&ciphertext) - // The error type from `to_mp_base85` isn't public, so we don't derive an error for this one. - // Instead, we use `map_err`. - .map_err(|err| Error::Base85(err.to_string()))?, - Encrypted::SteVec { ste_vec_index, .. } => { - ste_vec_index.into_root_ciphertext().map_err(Error::from)? - } - }; - - Ok(WithContext { - record: encrypted_record, - context: encryption_context, - }) -} - // Refactoring shim to extract EQL logic into a separate module (and eventually crate) #[inline] fn to_eql_encrypted( @@ -543,8 +525,33 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> { #[cfg(test)] mod tests { + use cipherstash_client::{encryption::{JsonIndexer, JsonIndexerOptions, SteVec}, zerokms::{DataKey, DataKeyWithTag, EncryptedRecord}}; use super::*; + fn make_encrypted_record() -> EncryptedRecord { + EncryptedRecord { + keyset_id: None, + iv: [1; 16], + tag: vec![0, 1, 2, 3], + descriptor: "users/email".to_string(), + ciphertext: vec![0, 1, 2, 3], + } + } + + fn make_ste_vec(json: serde_json::Value) -> anyhow::Result> { + let index_key = [0u8; 32]; + let data_key = DataKey { iv: [0u8; 16], key: [0u8; 32] }; + let data_key_with_tag = DataKeyWithTag { + key: data_key, + tag: vec![0u8; 16], + }; + let opts = JsonIndexerOptions { + prefix: "users".to_string(), + }; + let indexer = JsonIndexer::new(opts); + indexer.index(json, &index_key.into())?.encrypt(data_key_with_tag).map_err(|e| e.into()) + } + mod is_encrypted { use serde_json::json; use super::*; @@ -552,7 +559,7 @@ mod tests { #[test] fn valid_ciphertext_is_encrypted() { let encrypted: Encrypted = Encrypted::Ciphertext { - ciphertext: "3q2+7w==".to_string(), + ciphertext: make_encrypted_record(), ore_index: None, match_index: None, unique_index: None, @@ -573,4 +580,207 @@ mod tests { assert!(!is_encrypted(Json(invalid_encrypted))); } } -} + + #[test] + fn test_deserialize_encrypted_with_context() { + let ct = make_encrypted_record().to_mp_base85().unwrap(); + let json_data = serde_json::json!({ + "lockContext": [ + { "IdentityClaim": "sub" }, + ], + "k": "ct", + "c": ct, + "i": { "t": "users", "c": "email" }, + "v": 2 + }); + + let result: Result, _> = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let with_context = result.unwrap(); + assert_eq!(with_context.context.len(), 1); + match &with_context.context[0] { + zerokms::Context::IdentityClaim(claim) => assert_eq!(claim, "sub"), + _ => panic!("Expected IdentityClaim context"), + } + } + + #[test] + fn test_deserialize_encrypted_with_context_lower() { + let ct = make_encrypted_record().to_mp_base85().unwrap(); + let json_data = serde_json::json!({ + "lockContext": [ + { "identityClaim": "sub" }, + ], + "k": "ct", + "c": ct, + "i": { "t": "users", "c": "email" }, + "v": 2 + }); + + let result: Result, _> = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let with_context = result.unwrap(); + assert_eq!(with_context.context.len(), 1); + match &with_context.context[0] { + zerokms::Context::IdentityClaim(claim) => assert_eq!(claim, "sub"), + _ => panic!("Expected IdentityClaim context"), + } + } + + mod decrypt_options { + use super::*; + + #[test] + fn test_deserialize_ciphertext() { + let ct = make_encrypted_record().to_mp_base85().unwrap(); + let json_data = serde_json::json!({ + "ciphertext": { + "k": "ct", + "c": ct, + "i": { "t": "users", "c": "email" }, + "v": 2 + }, + }); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let decrypt_options = result.unwrap(); + assert!(decrypt_options.ciphertext.context.is_empty()); + assert!(decrypt_options.service_token.is_none()); + } + + #[test] + fn test_deserialize_ste_vec() -> anyhow::Result<()> { + let ste_vec = make_ste_vec(serde_json::json!({"email":"foo@bar.com"}))?; + + let json_data = serde_json::json!({ + "ciphertext": { + "k": "sv", + "sv": ste_vec, + "i": { "t": "users", "c": "email" }, + "v": 2 + }, + }); + + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let decrypt_options = result.unwrap(); + assert!(decrypt_options.ciphertext.context.is_empty()); + assert!(decrypt_options.service_token.is_none()); + + Ok(()) + } + } + + mod bulk_decrypt_options { + use super::*; + + #[test] + fn test_deserialize_multiple_ciphertexts() { + let ct1 = make_encrypted_record().to_mp_base85().unwrap(); + let ct2 = make_encrypted_record().to_mp_base85().unwrap(); + let json_data = serde_json::json!({ + "ciphertexts": [ + { + "ciphertext": { + "k": "ct", + "c": ct1, + "i": { "t": "users", "c": "email" }, + "v": 2 + } + }, + { + "ciphertext": { + "k": "ct", + "c": ct2, + "i": { "t": "users", "c": "email" }, + "v": 2 + } + } + ], + }); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let decrypt_options = result.unwrap(); + assert_eq!(decrypt_options.ciphertexts.len(), 2); + assert!(decrypt_options.ciphertexts[0].context.is_empty()); + assert!(decrypt_options.ciphertexts[1].context.is_empty()); + assert!(decrypt_options.service_token.is_none()); + } + + #[test] + fn test_deserialize_multiple_ste_vecs() -> anyhow::Result<()> { + let ste_vec1 = make_ste_vec(serde_json::json!({"email":"foo@bar.com"}))?; + let ste_vec2 = make_ste_vec(serde_json::json!({"email":"bar@foo.com"}))?; + + let json_data = serde_json::json!({ + "ciphertexts": [ + { + "ciphertext": { + "k": "sv", + "sv": ste_vec1, + "i": { "t": "users", "c": "email" }, + "v": 2 + } + }, + { + "ciphertext": { + "k": "sv", + "sv": ste_vec2, + "i": { "t": "users", "c": "email" }, + "v": 2 + } + } + ], + }); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + + let decrypt_options = result.unwrap(); + assert_eq!(decrypt_options.ciphertexts.len(), 2); + assert!(decrypt_options.ciphertexts[0].context.is_empty()); + assert!(decrypt_options.ciphertexts[1].context.is_empty()); + assert!(decrypt_options.service_token.is_none()); + + Ok(()) + } + + #[test] + fn test_mutiple_encrypted_entries() -> anyhow::Result<()> { + let ste_vec = make_ste_vec(serde_json::json!({"email":"bar@foo.com", "name":"Bar Foo"}))?; + let entries = ste_vec.into_iter().collect::>(); + + let json_data = serde_json::json!({ + "ciphertexts": [ + { + "ciphertext": { + "k": "sve", + "sve": entries[0], + } + }, + { + "ciphertext": { + "k": "sve", + "sve": entries[1], + } + }, + ], + }); + + println!("json_data: {}", serde_json::to_string_pretty(&json_data)?); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + + Ok(()) + } + } +} \ No newline at end of file diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index 6ff3e2e..acf58a2 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -85,6 +85,8 @@ mod tests { ] ]); + println!("Serialized Query::Json: {}", serde_json::to_string_pretty(&x).unwrap()); + assert_eq!(serde_json::to_value(&x).unwrap(), check); } diff --git a/integration-tests/tests/json.test.ts b/integration-tests/tests/json.test.ts index 4adad5f..c228581 100644 --- a/integration-tests/tests/json.test.ts +++ b/integration-tests/tests/json.test.ts @@ -31,7 +31,7 @@ describe.each([ 'Can round-trip encrypt & decrypt JSON', async ({ encryptConfig, description }) => { describe(`using ${description} config`, () => { - test('object', async ({ annotate }) => { + test('object', async () => { const client = await newClient({ encryptConfig }) const originalPlaintext = { foo: 'bar', baz: 123 } diff --git a/integration-tests/tests/lock-context.test.ts b/integration-tests/tests/lock-context.test.ts index c91fe77..d2ae91b 100644 --- a/integration-tests/tests/lock-context.test.ts +++ b/integration-tests/tests/lock-context.test.ts @@ -44,9 +44,9 @@ describe('lock context', () => { plaintext: originalPlaintext, column: 'email', table: 'users', - lockContext: { - identityClaim: ['sub'], - }, + lockContext: [ + { identityClaim: 'sub' }, + ], }) // NOTE: New ZeroKMS changes will report this as an authentication error // See https://github.com/cipherstash/cipherstash-suite/pull/1516 @@ -60,16 +60,16 @@ describe('lock context', () => { const ciphertext = await encrypt(client, { plaintext: originalPlaintext, column: 'email', - table: 'users', + table: 'users', }) await expect(async () => { await decrypt(client, { ciphertext, - lockContext: { - identityClaim: ['sub'], - }, - }) - }).rejects.toThrowError(/Failed to send request/) + lockContext: [ + { identityClaim: 'sub' }, + ], + }); + }).rejects.toThrowError(/Failed to retrieve key/) }, 10000) }) diff --git a/integration-tests/tests/postgres.test.ts b/integration-tests/tests/postgres.test.ts index 0affb03..9d3963a 100644 --- a/integration-tests/tests/postgres.test.ts +++ b/integration-tests/tests/postgres.test.ts @@ -9,6 +9,9 @@ import { type Encrypted, type EncryptConfig, EncryptedSV, + EncryptedCT, + SteVecEncryptedEntry, + EncryptedSVE, } from '@cipherstash/protect-ffi' import { Client, type QueryResult } from 'pg' import { encryptQuery } from '../../lib/load.cjs' @@ -73,7 +76,7 @@ describe('postgres', async () => { [ciphertext], ) - const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query( + const res: QueryResult<{ encrypted_text: EncryptedCT }> = await pg.query( 'SELECT encrypted_text::jsonb FROM encrypted', ) @@ -267,7 +270,7 @@ describe('postgres', async () => { }) test.only('can use JSON stabby ->', async () => { - const ciphertexts = await encryptBulk(protectClient, { + const toStore = await encryptBulk(protectClient, { plaintexts: [ { plaintext: { foo: 'bar', baz: [1, 2, 3] }, @@ -287,11 +290,11 @@ describe('postgres', async () => { ], }) - console.log("Ciphertexts:", JSON.stringify(ciphertexts[0])); + console.log("Ciphertexts:", JSON.stringify(toStore[0])); await pg.query( 'INSERT INTO encrypted (encrypted_profile) VALUES ($1::jsonb), ($2::jsonb), ($3::jsonb)', - ciphertexts, + toStore, ) const query = await encryptQuery(protectClient, { @@ -313,30 +316,34 @@ describe('postgres', async () => { ) res1.rows[0].encrypted_profile.sv.forEach((entry) => { - console.log("Selector:", entry.s, "Term:", entry.term); + console.log("Selector:", entry.s); }); // Or jsonb_path_query // eql_v2.jsonb_path_query(encrypted_profile, $1) - //SELECT eql_v2.jsonb_path_query(encrypted_profile, eql_v2.selector($1::jsonb)) FROM encrypted // TODO: Use the jsonquery approach from the Json indexer docs - const res: QueryResult<{ encrypted_profile: EncryptedSV }> = await pg.query( + //SELECT eql_v2."->"(encrypted_profile, eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted + const res: QueryResult<{ value: SteVecEncryptedEntry | null }> = await pg.query( ` - SELECT eql_v2."->"(encrypted_profile, eql_v2.selector($1::jsonb)) FROM encrypted + SELECT (encrypted_profile->eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted `, [query], ) - console.log("ROWS:", res.rows); - /*const decrypted = await decryptBulk(protectClient, { - ciphertexts: res.rows.map((row) => ({ - ciphertext: row.encrypted_profile, - })), - }) + console.log("ROWS:", res.rows[0].value); + let ciphertexts = res.rows.flatMap((row) => (row.value === null ? [] : [{ + ciphertext: { k: 'sve', sve: row.value } as EncryptedSVE, + }])); - expect(decrypted).toEqual(['bar', 'baz', null])*/ - expect("foo").toBe("food") + console.log("Ciphertexts:", JSON.stringify(ciphertexts)); + const decrypted = await decryptBulk(protectClient, { + ciphertexts, + }) + //const decrypted = await decrypt(protectClient, ciphertexts[0]) + //expect(decrypted).toEqual('bar') + // FIXME: we should handle null as an input and just return null + expect(decrypted).toEqual(['bar', 'baz']) }) }) diff --git a/integration-tests/tests/scalar-bulk.test.ts b/integration-tests/tests/scalar-bulk.test.ts index 3bbc497..8a93db3 100644 --- a/integration-tests/tests/scalar-bulk.test.ts +++ b/integration-tests/tests/scalar-bulk.test.ts @@ -123,9 +123,9 @@ describe('encryptBulk and decryptBulk', async () => { await encryptBulk(client, { plaintexts: payloads.map((p) => ({ ...p, - lockContext: { - identityClaim: ['sub'], - }, + lockContext: [ + {identityClaim: 'sub' }, + ], })), }) // NOTE: New ZeroKMS changes will report this as an authentication error @@ -144,9 +144,9 @@ describe('encryptBulk and decryptBulk', async () => { await decryptBulk(client, { ciphertexts: ciphertexts.map((ciphertext) => ({ ciphertext, - lockContext: { - identityClaim: ['sub'], - }, + lockContext: [{ + identityClaim: 'sub', + }], })), }) }).rejects.toThrowError(/Failed to send request/) diff --git a/src/index.cts b/src/index.cts index eb56744..85a561f 100644 --- a/src/index.cts +++ b/src/index.cts @@ -43,12 +43,12 @@ export type EncryptPayload = { plaintext: JsPlaintext column: string table: string - lockContext?: Context + lockContext?: Context[] } export type BulkDecryptPayload = { ciphertext: Encrypted - lockContext?: Context + lockContext?: Context[] } export type CtsToken = { @@ -56,57 +56,51 @@ export type CtsToken = { expiry: number } -export type Context = { - identityClaim: string[] -} +// TODO: Handle the Value type as well +export type Context = { identityClaim: string } | { tag: string } + +export type Versioned = { v: number }; -// TODO: Make generic and use the identifier utility type -export type Versioned = { i: { c: string; t: string }; v: number }; +// Named term types +export type Base85Ciphertext = string; +export type BloomFilter = number[]; +export type HMAC = string; +export type EncodedBlockOREArray = string[]; +export type EncodedFixedLengthORE = string; +export type EncodedVariableLengthORE = string; +export type JSONPathSelector = string; export type EncryptedCT = Versioned & { k: 'ct'; - c: string; - ob: string[] | null; - bf: number[] | null; - hm: string | null; + c: Base85Ciphertext; + ob: EncodedBlockOREArray | null; + bf: BloomFilter | null; + hm: HMAC | null; + i: { c: string; t: string }; }; export type EncryptedSV = Versioned & { k: 'sv'; sv: SteVecEncryptedEntry[]; + i: { c: string; t: string }; }; -export type Encrypted = EncryptedCT | EncryptedSV; - -/*export type Encrypted = - | { - k: 'ct' - c: string - ob: string[] | null - bf: number[] | null - hm: string | null - i: { - c: string - t: string - } - v: number - } - | { - k: 'sv' - sv: SteVecEncryptedEntry[] - i: { - c: string - t: string - } - v: number - }*/ +// NOTE: We don't currently get the version or identifiers back from an SteVec entry +// This is a limitation of EQL v2 +export type EncryptedSVE = { + k: 'sve'; + sve: SteVecEncryptedEntry; +} + +export type Encrypted = EncryptedCT | EncryptedSV | EncryptedSVE; export type SteVecEncryptedEntry = { - s: string - term: string - record: string + s: JSONPathSelector + c: Base85Ciphertext parent_is_array: boolean -} +} & SteVecTerm; + +export type SteVecTerm = { hm: HMAC } | { ocf: EncodedFixedLengthORE } | { ocv: EncodedVariableLengthORE }; export type EncryptConfig = { v: number @@ -196,7 +190,7 @@ export type EncryptOptions = { plaintext: JsPlaintext column: string table: string - lockContext?: Context + lockContext?: Context[] serviceToken?: CtsToken unverifiedContext?: Record } @@ -209,7 +203,7 @@ export type EncryptBulkOptions = { export type DecryptOptions = { ciphertext: Encrypted - lockContext?: Context + lockContext?: Context[] serviceToken?: CtsToken unverifiedContext?: Record } @@ -239,23 +233,9 @@ export type QueryOperator = | '<@' | '->' -// TODO: Maybe give each variant a more descriptive name via a named type +// These types are included in responses from encryptQuery export type EncryptedQueryTerm = - | { ob: String[] } - | { bf: number[] } - | { hm: string } - | { s: string } - /*| { type: 'Binary'; value: Uint8Array } - | { type: 'BinaryVec'; value: Uint8Array[] } - | { type: 'BitMap'; value: number[] } // u16 fits safely in JS number - | { type: 'OreFull'; value: Uint8Array } - | { type: 'OreArray'; value: Uint8Array[] } - | { type: 'OreLeft'; value: Uint8Array } - | { type: 'SteVecSelector'; value: TokenizedSelector } - | { type: 'SteVecTerm'; value: EncryptedSteVecTerm } - | { type: 'SteQueryVec'; value: SteQueryVec } - | { type: 'Null' } - -export type TokenizedSelector = string -export type EncryptedSteVecTerm = string[] -export type SteQueryVec = string[]*/ + | { ob: EncodedBlockOREArray } + | { bf: BloomFilter } + | { hm: HMAC } + | { s: JSONPathSelector } From cb6d0c230e872d9e3780d934056549a2543886e8 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Tue, 21 Oct 2025 20:57:08 +1100 Subject: [PATCH 08/30] feat: enhance query handling with new operators and improve test coverage --- crates/protect-ffi/src/lib.rs | 50 ++++- crates/protect-ffi/src/query.rs | 1 - integration-tests/tests/common.ts | 4 +- integration-tests/tests/lock-context.test.ts | 12 +- integration-tests/tests/postgres.test.ts | 109 ++++++----- integration-tests/tests/query.test.ts | 185 +++++++++++++++++++ integration-tests/tests/scalar-bulk.test.ts | 12 +- mise.toml | 6 +- src/index.cts | 146 ++++++++------- 9 files changed, 376 insertions(+), 149 deletions(-) create mode 100644 integration-tests/tests/query.test.ts diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index b5b5836..c79229e 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -13,7 +13,7 @@ use cipherstash_client::{ encryption::{ self, EncryptionError, Plaintext, PlaintextTarget, QueryOp, Queryable, ReferencedPendingPipeline, ScopedCipher, TypeParseError }, - schema::{column::IndexType, operator::Operator, ColumnConfig}, + schema::{column::IndexType, operator::{Operator, STEVecOperator}, ColumnConfig}, zerokms::{self, RecordDecryptError, WithContext, ZeroKMSWithClientKey}, Crn, IdentifiedBy, UnverifiedContext, }; @@ -332,13 +332,18 @@ async fn encrypt_query( .get(&ident) .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; + println!("Operator: {:?}", opts.operator); let plaintext: Plaintext = opts.plaintext.into(); let index = column_config.index_for_operator(&opts.operator) .ok_or_else(|| Error::MissingIndexForOperator(ident, opts.operator))?; dbg!(&index); let query_op = if let IndexType::SteVec { .. } = index.index_type { - QueryOp::SteVecSelector + // NOTE: We don't currently use the QueryOp::SteVecTerm variant because a simpler approach was taken for proxy + match opts.operator { + Operator::STEVecOperator(STEVecOperator::Selector) => QueryOp::SteVecSelector, + _ => QueryOp::Default, + } } else { QueryOp::Default }; @@ -783,4 +788,45 @@ mod tests { Ok(()) } } + + mod query_options { + use cipherstash_client::schema::operator; + use super::*; + + #[test] + fn test_deserialize_operator_selector() { + let json_data = serde_json::json!({ + "plaintext": "$.foo", + "column": "profile", + "table": "users", + "operator": "->" + }); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + let query_options = result.unwrap(); + assert_eq!(query_options.plaintext, JsPlaintext::String("$.foo".to_string())); + assert_eq!(query_options.column, "profile"); + assert_eq!(query_options.table, "users"); + assert_eq!(query_options.operator, Operator::STEVecOperator(operator::STEVecOperator::Selector)); + } + + #[test] + fn test_deserialize_operator_contains() { + let json_data = serde_json::json!({ + "plaintext": {"foo": "bar"}, + "column": "profile", + "table": "users", + "operator": "@>" + }); + + let result: Result = serde_json::from_value(json_data); + assert!(result.is_ok()); + let query_options = result.unwrap(); + assert_eq!(query_options.plaintext, JsPlaintext::JsonB(serde_json::json!({"foo": "bar"}))); + assert_eq!(query_options.column, "profile"); + assert_eq!(query_options.table, "users"); + assert_eq!(query_options.operator, Operator::STEVecOperator(operator::STEVecOperator::LeftContainsRight)); + } + } } \ No newline at end of file diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index acf58a2..c41c3b0 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -31,7 +31,6 @@ impl TryFrom for Query { IndexTerm::Binary(b) => Ok(Query::Binary(b)), IndexTerm::BitMap(bm) => Ok(Query::BitMap(bm)), IndexTerm::OreLeft(ol) => Ok(Query::OreLeft(vec![OreTerm(ol)])), - // TODO: Truncate - or remove entirely? IndexTerm::OreFull(of) => Ok(Query::OreLeft(vec![OreTerm(of)])), IndexTerm::SteQueryVec(sqv) => Ok(Query::Json(sqv)), IndexTerm::SteVecSelector(ts) => Ok(Query::SteVecSelector(ts)), diff --git a/integration-tests/tests/common.ts b/integration-tests/tests/common.ts index 7012c1a..da0a299 100644 --- a/integration-tests/tests/common.ts +++ b/integration-tests/tests/common.ts @@ -1,6 +1,8 @@ import type { EncryptConfig } from '../../lib/index.cjs' -export const encryptConfig: EncryptConfig = { +export interface User extends EncryptConfig {} + +export const encryptConfig: User = { v: 1, tables: { users: { diff --git a/integration-tests/tests/lock-context.test.ts b/integration-tests/tests/lock-context.test.ts index d2ae91b..1b39bff 100644 --- a/integration-tests/tests/lock-context.test.ts +++ b/integration-tests/tests/lock-context.test.ts @@ -44,9 +44,7 @@ describe('lock context', () => { plaintext: originalPlaintext, column: 'email', table: 'users', - lockContext: [ - { identityClaim: 'sub' }, - ], + lockContext: [{ identityClaim: 'sub' }], }) // NOTE: New ZeroKMS changes will report this as an authentication error // See https://github.com/cipherstash/cipherstash-suite/pull/1516 @@ -60,16 +58,14 @@ describe('lock context', () => { const ciphertext = await encrypt(client, { plaintext: originalPlaintext, column: 'email', - table: 'users', + table: 'users', }) await expect(async () => { await decrypt(client, { ciphertext, - lockContext: [ - { identityClaim: 'sub' }, - ], - }); + lockContext: [{ identityClaim: 'sub' }], + }) }).rejects.toThrowError(/Failed to retrieve key/) }, 10000) }) diff --git a/integration-tests/tests/postgres.test.ts b/integration-tests/tests/postgres.test.ts index 9d3963a..6cb3d91 100644 --- a/integration-tests/tests/postgres.test.ts +++ b/integration-tests/tests/postgres.test.ts @@ -6,12 +6,11 @@ import { newClient, encryptBulk, decryptBulk, - type Encrypted, + type EncryptedCell, + type EncryptedSV, + type SteVecEncryptedEntry, + type EncryptedSVE, type EncryptConfig, - EncryptedSV, - EncryptedCT, - SteVecEncryptedEntry, - EncryptedSVE, } from '@cipherstash/protect-ffi' import { Client, type QueryResult } from 'pg' import { encryptQuery } from '../../lib/load.cjs' @@ -47,18 +46,18 @@ describe('postgres', async () => { // clean up function, called once after all tests run return async () => { - await pg.query('DROP TABLE ENCRYPTED') + //await pg.query('DROP TABLE ENCRYPTED') await pg.end() } }) beforeEach(async () => { // called once before each test run - await pg.query('BEGIN') + //await pg.query('BEGIN') // clean up function, called once after each test run return async () => { - await pg.query('ROLLBACK') + //await pg.query('ROLLBACK') } }) @@ -76,9 +75,8 @@ describe('postgres', async () => { [ciphertext], ) - const res: QueryResult<{ encrypted_text: EncryptedCT }> = await pg.query( - 'SELECT encrypted_text::jsonb FROM encrypted', - ) + const res: QueryResult<{ encrypted_text: EncryptedCell }> = + await pg.query('SELECT encrypted_text::jsonb FROM encrypted') expect(res.rowCount).toBe(1) @@ -115,7 +113,8 @@ describe('postgres', async () => { ciphertexts, ) - const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query(` + const res: QueryResult<{ encrypted_text: EncryptedCell }> = + await pg.query(` SELECT encrypted_text::jsonb FROM encrypted ORDER BY eql_v2.order_by(encrypted_text) ASC `) @@ -157,13 +156,14 @@ describe('postgres', async () => { operator: '~~', }) - const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query( - ` + const res: QueryResult<{ encrypted_text: EncryptedCell }> = + await pg.query( + ` SELECT encrypted_text::jsonb FROM encrypted WHERE encrypted_text LIKE $1::jsonb `, - [search], - ) + [search], + ) const decrypted = await decryptBulk(protectClient, { ciphertexts: res.rows.map((row) => ({ @@ -207,13 +207,14 @@ describe('postgres', async () => { operator: '>=', }) - const res: QueryResult<{ encrypted_score: Encrypted }> = await pg.query( - ` + const res: QueryResult<{ encrypted_score: EncryptedCell }> = + await pg.query( + ` SELECT encrypted_score::jsonb FROM encrypted WHERE encrypted_score >= $1::jsonb ORDER BY eql_v2.order_by(encrypted_score) ASC `, - [search], - ) + [search], + ) const decrypted = await decryptBulk(protectClient, { ciphertexts: res.rows.map((row) => ({ @@ -250,15 +251,16 @@ describe('postgres', async () => { column: 'email', table: 'users', operator: '=', - }); + }) - const res: QueryResult<{ encrypted_text: Encrypted }> = await pg.query( - ` + const res: QueryResult<{ encrypted_text: EncryptedCell }> = + await pg.query( + ` SELECT encrypted_text::jsonb FROM encrypted WHERE encrypted_text = $1::jsonb `, - [query], - ) + [query], + ) const decrypted = await decryptBulk(protectClient, { ciphertexts: res.rows.map((row) => ({ @@ -269,7 +271,7 @@ describe('postgres', async () => { expect(decrypted).toEqual(['b']) }) - test.only('can use JSON stabby ->', async () => { + test('can use JSON stabby ->', async () => { const toStore = await encryptBulk(protectClient, { plaintexts: [ { @@ -290,8 +292,6 @@ describe('postgres', async () => { ], }) - console.log("Ciphertexts:", JSON.stringify(toStore[0])); - await pg.query( 'INSERT INTO encrypted (encrypted_profile) VALUES ($1::jsonb), ($2::jsonb), ($3::jsonb)', toStore, @@ -305,50 +305,45 @@ describe('postgres', async () => { column: 'profile', table: 'users', operator: '->', - }); - - console.log("Query:", query); - - const res1: QueryResult<{ encrypted_profile: EncryptedSV }> = await pg.query( - ` - SELECT encrypted_profile::jsonb FROM encrypted - ` - ) - - res1.rows[0].encrypted_profile.sv.forEach((entry) => { - console.log("Selector:", entry.s); - }); - - // Or jsonb_path_query - // eql_v2.jsonb_path_query(encrypted_profile, $1) + }) + // SELECT jsonb_path_query(encrypted_profile::jsonb, '$.sv[*] ? (exists(@ ? (@.s == "d18aa290a20cf6413f50d5ca87a0a6c2"))).c') FROM encrypted // TODO: Use the jsonquery approach from the Json indexer docs //SELECT eql_v2."->"(encrypted_profile, eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted - const res: QueryResult<{ value: SteVecEncryptedEntry | null }> = await pg.query( - ` + const res: QueryResult<{ value: SteVecEncryptedEntry | null }> = + await pg.query( + ` SELECT (encrypted_profile->eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted `, - [query], - ) + [query], + ) - console.log("ROWS:", res.rows[0].value); - let ciphertexts = res.rows.flatMap((row) => (row.value === null ? [] : [{ - ciphertext: { k: 'sve', sve: row.value } as EncryptedSVE, - }])); + console.log('ROWS:', res.rows[0].value) + const ciphertexts = res.rows.flatMap((row) => + row.value === null + ? [] + : [ + { + ciphertext: { k: 'sve', sve: row.value } as EncryptedSVE, + }, + ], + ) - console.log("Ciphertexts:", JSON.stringify(ciphertexts)); + console.log('Ciphertexts:', JSON.stringify(ciphertexts)) const decrypted = await decryptBulk(protectClient, { ciphertexts, }) //const decrypted = await decrypt(protectClient, ciphertexts[0]) - //expect(decrypted).toEqual('bar') - // FIXME: we should handle null as an input and just return null - expect(decrypted).toEqual(['bar', 'baz']) + //expect(decrypted).toEqual('bar') + // FIXME: we should handle null as an input and just return null + expect(decrypted).toEqual(['bar', 'baz']) }) }) +interface User extends EncryptConfig {} + // TODO: Load the config from common -function encryptConfig(): EncryptConfig { +function encryptConfig(): User { return { v: 1, tables: { diff --git a/integration-tests/tests/query.test.ts b/integration-tests/tests/query.test.ts new file mode 100644 index 0000000..3b22f01 --- /dev/null +++ b/integration-tests/tests/query.test.ts @@ -0,0 +1,185 @@ +import 'dotenv/config' +import { describe, expect, test } from 'vitest' + +import { + newClient, + type StringOperator, + type NumericOperator, + type JsonbOperator, + type JsPlaintext, +} from '@cipherstash/protect-ffi' + +// Import a shared encryptConfig from common.js +import { encryptConfig } from './common.js' +import { encryptQuery } from '../../lib/load.cjs' + +const emailValidOperators: { op: StringOperator; index: string }[] = [ + { op: '=', index: 'hm' }, + { op: '~~', index: 'bf' }, + { op: '~~*', index: 'bf' }, + // TODO: What should we do with these? Technically valid, right? + /*{ op: '>=', index: 'ob' }, + { op: '<=', index: 'ob' }, + { op: '>', index: 'ob' }, + { op: '<', index: 'ob' },*/ +] + +const scoreValidOperators: { op: NumericOperator; index: string }[] = [ + // NOTE: CipherStash client will use an ORE index for equality queries on numeric types if available + { op: '=', index: 'ob' }, + { op: '>=', index: 'ob' }, + { op: '<=', index: 'ob' }, + { op: '>', index: 'ob' }, + { op: '<', index: 'ob' }, +] + +const jsonValidOperators: { + op: JsonbOperator + index: string + v: JsPlaintext +}[] = [ + { op: '->', index: 's', v: '$.foo' }, + { op: '@>', index: 'sv', v: { foo: 'bar' } }, + // TODO: The rest +] + +const emailInvalidOperators: { op: NumericOperator | JsonbOperator }[] = [ + { op: '@>' }, + { op: '<@' }, + { op: '->' }, +] + +const scoreInvalidOperators: { op: StringOperator | JsonbOperator }[] = [ + { op: '@>' }, + { op: '<@' }, + { op: '->' }, + { op: '~~' }, + { op: '~~*' }, +] + +const jsonInvalidOperators: { op: StringOperator | NumericOperator }[] = [ + { op: '~~' }, + { op: '~~*' }, + { op: '=' }, + { op: '>=' }, + { op: '<=' }, + { op: '>' }, + { op: '<' }, +] + +describe('query encryption', () => { + describe.each(emailValidOperators)( + 'using operator $op for email column', + ({ op, index }) => { + test(`generates the correct query type: '${index}'`, async () => { + const client = await newClient({ encryptConfig }) + + const query = await encryptQuery(client, { + plaintext: 'foo@example.net', + column: 'email', + table: 'users', + operator: op, + }) + + expect(query).toHaveProperty(index) + }) + }, + ) + + describe.each(emailInvalidOperators)( + 'using operator $op for email column', + ({ op }) => { + test('fails to generate a query term', async () => { + const client = await newClient({ encryptConfig }) + + expect(async () => { + await encryptQuery(client, { + plaintext: 'foo@example.net', + column: 'email', + table: 'users', + operator: op, + }) + }).rejects.toThrowError( + /no index found for column users.email supporting operator/, + ) + }) + }, + ) + + describe.each(scoreValidOperators)( + 'using operator $op for score column', + ({ op, index }) => { + test(`generates the correct query type: '${index}'`, async () => { + const client = await newClient({ encryptConfig }) + + const query = await encryptQuery(client, { + plaintext: 1000, + column: 'score', + table: 'users', + operator: op, + }) + + expect(query).toHaveProperty(index) + }) + }, + ) + + describe.each(scoreInvalidOperators)( + 'using operator $op for score column', + ({ op }) => { + test('fails to generate a query term', async () => { + const client = await newClient({ encryptConfig }) + + expect(async () => { + await encryptQuery(client, { + plaintext: 5000, + column: 'score', + table: 'users', + operator: op, + }) + }).rejects.toThrowError( + /no index found for column users.score supporting operator/, + ) + }) + }, + ) + + describe.each(jsonValidOperators)( + 'using operator $op for json column', + ({ op, index, v }) => { + test(`generates the correct query type: '${index}'`, async () => { + const client = await newClient({ encryptConfig }) + + const query = await encryptQuery(client, { + // TODO: This plaintext is _different_ to the JSON type + plaintext: v, + column: 'profile', + table: 'users', + operator: op, + }) + + expect(query).toHaveProperty(index) + }) + }, + ) + + describe.each(jsonInvalidOperators)( + 'using operator $op for json column', + ({ op }) => { + test('fails to generate a query term', async () => { + const client = await newClient({ encryptConfig }) + + expect(async () => { + await encryptQuery(client, { + plaintext: '$["foo"]', + column: 'profile', + table: 'users', + operator: op, + }) + }).rejects.toThrowError( + /no index found for column users.profile supporting operator/, + ) + }) + }, + ) +}) diff --git a/integration-tests/tests/scalar-bulk.test.ts b/integration-tests/tests/scalar-bulk.test.ts index 8a93db3..3b5bf36 100644 --- a/integration-tests/tests/scalar-bulk.test.ts +++ b/integration-tests/tests/scalar-bulk.test.ts @@ -123,9 +123,7 @@ describe('encryptBulk and decryptBulk', async () => { await encryptBulk(client, { plaintexts: payloads.map((p) => ({ ...p, - lockContext: [ - {identityClaim: 'sub' }, - ], + lockContext: [{ identityClaim: 'sub' }], })), }) // NOTE: New ZeroKMS changes will report this as an authentication error @@ -144,9 +142,11 @@ describe('encryptBulk and decryptBulk', async () => { await decryptBulk(client, { ciphertexts: ciphertexts.map((ciphertext) => ({ ciphertext, - lockContext: [{ - identityClaim: 'sub', - }], + lockContext: [ + { + identityClaim: 'sub', + }, + ], })), }) }).rejects.toThrowError(/Failed to send request/) diff --git a/mise.toml b/mise.toml index ed2f69d..99e8a1f 100644 --- a/mise.toml +++ b/mise.toml @@ -9,9 +9,7 @@ PGPASSWORD = "password" PGHOST = "localhost" [task_config] -includes = [ - "integration-tests/tasks.toml", -] +includes = ["integration-tests/tasks.toml"] [tasks."build:debug"] description = "Build the project in debug mode" @@ -23,4 +21,4 @@ run = "cargo clippy --no-deps --tests --all-features --all-targets -- -D warning [tasks."fmt"] description = "Format code with rustfmt" -run = "cargo fmt" \ No newline at end of file +run = "cargo fmt" diff --git a/src/index.cts b/src/index.cts index 85a561f..9798d4e 100644 --- a/src/index.cts +++ b/src/index.cts @@ -19,35 +19,44 @@ export type Client = { readonly [sym]: unknown } // which otherwise default to `any`. declare module './load.cjs' { function newClient(opts: NewClientOptions): Promise - function encrypt(client: Client, opts: EncryptOptions): Promise - function decrypt(client: Client, opts: DecryptOptions): Promise - function isEncrypted(encrypted: Encrypted): boolean - function encryptQuery(client: Client, opts: QueryOptions): Promise - function encryptBulk( + function encrypt( client: Client, - opts: EncryptBulkOptions, - ): Promise - function decryptBulk( + opts: EncryptOptions, + ): Promise> + function decrypt( client: Client, - opts: DecryptBulkOptions, + opts: DecryptOptions, + ): Promise + function isEncrypted( + encrypted: AnyEncrypted, + ): boolean + function encryptQuery( + client: Client, + opts: QueryOptions, + ): Promise + function encryptBulk( + client: Client, + opts: EncryptBulkOptions, + ): Promise[]> + function decryptBulk( + client: Client, + opts: DecryptBulkOptions, ): Promise - function decryptBulkFallible( + function decryptBulkFallible( client: Client, - opts: DecryptBulkOptions, + opts: DecryptBulkOptions, ): Promise } export type DecryptResult = { data: string } | { error: string } -export type EncryptPayload = { +export type EncryptPayload = { plaintext: JsPlaintext - column: string - table: string lockContext?: Context[] -} +} & Identifier -export type BulkDecryptPayload = { - ciphertext: Encrypted +export type BulkDecryptPayload = { + ciphertext: AnyEncrypted lockContext?: Context[] } @@ -59,48 +68,54 @@ export type CtsToken = { // TODO: Handle the Value type as well export type Context = { identityClaim: string } | { tag: string } -export type Versioned = { v: number }; +export type Versioned = { v: number } // Named term types -export type Base85Ciphertext = string; -export type BloomFilter = number[]; -export type HMAC = string; -export type EncodedBlockOREArray = string[]; -export type EncodedFixedLengthORE = string; -export type EncodedVariableLengthORE = string; -export type JSONPathSelector = string; - -export type EncryptedCT = Versioned & { - k: 'ct'; - c: Base85Ciphertext; - ob: EncodedBlockOREArray | null; - bf: BloomFilter | null; - hm: HMAC | null; - i: { c: string; t: string }; -}; - -export type EncryptedSV = Versioned & { - k: 'sv'; - sv: SteVecEncryptedEntry[]; - i: { c: string; t: string }; -}; +export type Base85Ciphertext = string +export type BloomFilter = number[] +export type HMAC = string +export type EncodedBlockOREArray = string[] +export type EncodedFixedLengthORE = string +export type EncodedVariableLengthORE = string +export type JSONPathSelector = string + +export type EncryptedCell = Versioned & { + k: 'ct' + c: Base85Ciphertext + ob: EncodedBlockOREArray | null + bf: BloomFilter | null + hm: HMAC | null + i: Identifier +} + +export type EncryptedSV = Versioned & { + k: 'sv' + sv: SteVecEncryptedEntry[] + i: Identifier +} // NOTE: We don't currently get the version or identifiers back from an SteVec entry // This is a limitation of EQL v2 export type EncryptedSVE = { - k: 'sve'; - sve: SteVecEncryptedEntry; + k: 'sve' + sve: SteVecEncryptedEntry } -export type Encrypted = EncryptedCT | EncryptedSV | EncryptedSVE; +export type AnyEncrypted = + | EncryptedCell + | EncryptedSV + | EncryptedSVE export type SteVecEncryptedEntry = { s: JSONPathSelector c: Base85Ciphertext parent_is_array: boolean -} & SteVecTerm; +} & SteVecTerm -export type SteVecTerm = { hm: HMAC } | { ocf: EncodedFixedLengthORE } | { ocv: EncodedVariableLengthORE }; +export type SteVecTerm = + | { hm: HMAC } + | { ocf: EncodedFixedLengthORE } + | { ocv: EncodedVariableLengthORE } export type EncryptConfig = { v: number @@ -186,52 +201,43 @@ export type JsPlaintext = | Record | JsPlaintext[] -export type EncryptOptions = { +export type EncryptOptions = { plaintext: JsPlaintext - column: string - table: string lockContext?: Context[] serviceToken?: CtsToken unverifiedContext?: Record -} +} & Identifier -export type EncryptBulkOptions = { - plaintexts: EncryptPayload[] +export type EncryptBulkOptions = { + plaintexts: EncryptPayload[] serviceToken?: CtsToken unverifiedContext?: Record } -export type DecryptOptions = { - ciphertext: Encrypted +export type DecryptOptions = { + ciphertext: AnyEncrypted lockContext?: Context[] serviceToken?: CtsToken unverifiedContext?: Record } -export type DecryptBulkOptions = { - ciphertexts: BulkDecryptPayload[] +export type DecryptBulkOptions = { + ciphertexts: BulkDecryptPayload[] serviceToken?: CtsToken unverifiedContext?: Record } -export type QueryOptions = { +export type QueryOptions = { plaintext: JsPlaintext - column: string - table: string operator: QueryOperator -} +} & Identifier + +// TODO: Limit these based on the encrypt config +export type NumericOperator = '>' | '>=' | '<' | '<=' | '=' +export type StringOperator = '~~' | '~~*' | '=' +export type JsonbOperator = '@>' | '<@' | '->' -export type QueryOperator = - | '<' - | '<=' - | '=' - | '>=' - | '>' - | '~~' - | '~~*' - | '@>' - | '<@' - | '->' +export type QueryOperator = NumericOperator | StringOperator | JsonbOperator // These types are included in responses from encryptQuery export type EncryptedQueryTerm = From 6ee7e4795a0e47f1ec835cde4efcf1c426006282 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Tue, 21 Oct 2025 22:33:13 +1100 Subject: [PATCH 09/30] feat: add git fetch configuration and update cipherstash-client to use git branch --- .cargo/config.toml | 2 ++ Cargo.lock | 7 +++++++ crates/protect-ffi/Cargo.toml | 3 ++- mise.toml | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..656e08b --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[net] +git-fetch-with-cli = true \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7733a04..1427a98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -646,6 +646,7 @@ dependencies = [ [[package]] name = "cipherstash-client" version = "0.28.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "aes-gcm-siv", "anyhow", @@ -703,6 +704,7 @@ dependencies = [ [[package]] name = "cipherstash-config" version = "0.2.4" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "serde", "thiserror 1.0.69", @@ -711,6 +713,7 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "hmac", "lazy_static", @@ -735,6 +738,7 @@ dependencies = [ [[package]] name = "cllw-ore" version = "0.1.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "bit-vec", "bitvec", @@ -851,6 +855,7 @@ dependencies = [ [[package]] name = "cts-common" version = "0.3.1" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "arrayvec", "axum", @@ -2561,6 +2566,7 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "aes", "async-trait", @@ -4308,6 +4314,7 @@ dependencies = [ [[package]] name = "zerokms-protocol" version = "0.7.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "async-trait", "base64", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index f8f83fc..d1dba48 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } +#cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } +cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", package = "cipherstash-client", branch = "fix/jsonindexer-fixes" } const-hex = "1.17.0" # 0.14.7 introduces deprecations we need to avoid for now # Protect.rs will not use GenericArray at all diff --git a/mise.toml b/mise.toml index 99e8a1f..c52af8d 100644 --- a/mise.toml +++ b/mise.toml @@ -7,6 +7,7 @@ PGDATABASE = "cipherstash" PGUSER = "cipherstash" PGPASSWORD = "password" PGHOST = "localhost" +GIT_FETCH_WITH_CLI = "true" [task_config] includes = ["integration-tests/tasks.toml"] From b22684f4d8fb413575d150c6c35227a66a2092d9 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Wed, 22 Oct 2025 00:49:16 +1100 Subject: [PATCH 10/30] feat: update query handling to support JSON operators and refactor related types --- Cargo.lock | 7 -- crates/protect-ffi/Cargo.toml | 4 +- crates/protect-ffi/src/lib.rs | 53 -------------- crates/protect-ffi/src/query.rs | 12 ++-- integration-tests/tests/postgres.test.ts | 88 +++++++++++++++++------ integration-tests/tests/query.test.ts | 89 ++++++++++++++++-------- src/index.cts | 37 +++++++--- 7 files changed, 162 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1427a98..7733a04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -646,7 +646,6 @@ dependencies = [ [[package]] name = "cipherstash-client" version = "0.28.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "aes-gcm-siv", "anyhow", @@ -704,7 +703,6 @@ dependencies = [ [[package]] name = "cipherstash-config" version = "0.2.4" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "serde", "thiserror 1.0.69", @@ -713,7 +711,6 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "hmac", "lazy_static", @@ -738,7 +735,6 @@ dependencies = [ [[package]] name = "cllw-ore" version = "0.1.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "bit-vec", "bitvec", @@ -855,7 +851,6 @@ dependencies = [ [[package]] name = "cts-common" version = "0.3.1" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "arrayvec", "axum", @@ -2566,7 +2561,6 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "aes", "async-trait", @@ -4314,7 +4308,6 @@ dependencies = [ [[package]] name = "zerokms-protocol" version = "0.7.0" -source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#f622eb78b46dc9534193d2292ab457a26e2d3b19" dependencies = [ "async-trait", "base64", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index d1dba48..84e292a 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,8 +11,8 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -#cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } -cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", package = "cipherstash-client", branch = "fix/jsonindexer-fixes" } +cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } +#cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", package = "cipherstash-client", branch = "fix/jsonindexer-fixes" } const-hex = "1.17.0" # 0.14.7 introduces deprecations we need to avoid for now # Protect.rs will not use GenericArray at all diff --git a/crates/protect-ffi/src/lib.rs b/crates/protect-ffi/src/lib.rs index c79229e..6d532dc 100644 --- a/crates/protect-ffi/src/lib.rs +++ b/crates/protect-ffi/src/lib.rs @@ -332,12 +332,10 @@ async fn encrypt_query( .get(&ident) .ok_or_else(|| Error::UnknownColumn(ident.clone()))?; - println!("Operator: {:?}", opts.operator); let plaintext: Plaintext = opts.plaintext.into(); let index = column_config.index_for_operator(&opts.operator) .ok_or_else(|| Error::MissingIndexForOperator(ident, opts.operator))?; - dbg!(&index); let query_op = if let IndexType::SteVec { .. } = index.index_type { // NOTE: We don't currently use the QueryOp::SteVecTerm variant because a simpler approach was taken for proxy match opts.operator { @@ -347,21 +345,11 @@ async fn encrypt_query( } else { QueryOp::Default }; - println!("Using query op: {:?}", query_op); let query: Query = (index, plaintext) - // TODO: Better error .build_queryable(client.cipher, query_op).map_err(|e| Error::Unimplemented(format!("build queryable failed: {e}")))? - //.build_queryable(client.cipher, QueryOp::SteVecSelector)? .try_into()?; - // JSON is completely different - // TODO: Check the operator (from this crate) and build the JSON query if its a JSON operator - // Find an Index with type SteVec to get the prefix (see cipherstash_config IndexType) and create the JsonIndexerOptions - //let options: JsonIndexerOptions = todo!(); - //let indexer = JsonIndexer::try_init(options)?; - // indexer.generate_selector(selector, &client.cipher.index_key()); - Ok(Json(query)) } @@ -370,16 +358,12 @@ async fn decrypt( Boxed(client): Boxed, Json(opts): Json, ) -> Result, neon::types::extract::Error> { - //let lock_context = opts.lock_context.map(Into::into).unwrap_or_default(); - //let encrypted_record = encrypted_record_from_mp_base85(opts.ciphertext, lock_context)?; let DecryptOptions { ciphertext, service_token, unverified_context, } = opts; - println!("Decrypting ciphertext: {:?}", ciphertext); - let plaintext = client .zerokms .decrypt_single( @@ -390,12 +374,8 @@ async fn decrypt( ) .await .map_err(Error::from) - .inspect_err(|e| println!("Got error: {e}")) - .inspect(|o| println!("Got plaintext bytes: {:?}", o)) .and_then(|bytes| Plaintext::from_slice(bytes.as_slice()).map_err(Error::from))?; - println!("Decrypted plaintext: {:?}", plaintext); - JsPlaintext::try_from(plaintext) .map(Json) .map_err(From::from) @@ -406,21 +386,6 @@ async fn decrypt_bulk( Boxed(client): Boxed, Json(opts): Json, ) -> Result>, neon::types::extract::Error> { - /*let ciphertexts: Vec<(Encrypted, Vec)> = opts - .ciphertexts - .into_iter() - .map(|payload| { - let lock_context = payload.lock_context.map(Into::into).unwrap_or_default(); - (payload.ciphertext, lock_context) - }) - .collect(); - - let encrypted_records = ciphertexts - .into_iter() - .map(|(ciphertext, encryption_context)| { - encrypted_record_from_mp_base85(ciphertext, encryption_context) - }) - .collect::, Error>>()?;*/ let decrypted = client .zerokms @@ -445,24 +410,6 @@ async fn decrypt_bulk_fallible( Boxed(client): Boxed, Json(opts): Json, ) -> Result>, neon::types::extract::Error> { - /*let ciphertexts: Vec<(Encrypted, Vec)> = opts - .ciphertexts - .into_iter() - .map(|payload| { - let lock_context = payload.lock_context.map(Into::into).unwrap_or_default(); - (payload.ciphertext, lock_context) - }) - .collect(); - - let encrypted_records: Result, Error> = ciphertexts - .into_iter() - .map(|(ciphertext, encryption_context)| { - encrypted_record_from_mp_base85(ciphertext, encryption_context) - }) - .collect(); - - let encrypted_records = encrypted_records?;*/ - let decrypted = client .zerokms .decrypt_fallible( diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index c41c3b0..26c3395 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -12,10 +12,14 @@ pub enum Query { #[serde(rename = "ob")] OreLeft(Vec), - Json(SteQueryVec<16>), + // NOTE: This type doesn't current exist in the EQL spec but its convenient to give it the sv name + // even though its the query type and not the full encrypted entry. + #[serde(rename = "sv")] + SteQuery(SteQueryVec<16>), #[serde(rename = "s")] SteVecSelector(TokenizedSelector<16>), + SteVecTerm(EncryptedSteVecTerm), } @@ -32,7 +36,7 @@ impl TryFrom for Query { IndexTerm::BitMap(bm) => Ok(Query::BitMap(bm)), IndexTerm::OreLeft(ol) => Ok(Query::OreLeft(vec![OreTerm(ol)])), IndexTerm::OreFull(of) => Ok(Query::OreLeft(vec![OreTerm(of)])), - IndexTerm::SteQueryVec(sqv) => Ok(Query::Json(sqv)), + IndexTerm::SteQueryVec(sqv) => Ok(Query::SteQuery(sqv)), IndexTerm::SteVecSelector(ts) => Ok(Query::SteVecSelector(ts)), IndexTerm::SteVecTerm(est) => Ok(Query::SteVecTerm(est)), unsupported => Err(format!("{unsupported:?} cannot be converted to Query")), @@ -72,7 +76,7 @@ mod tests { #[test] fn serialize_ste_query_vec() { - let x = indexer().query(json!({"foo": 1}), &index_key()).map(Query::Json).unwrap(); + let x = indexer().query(json!({"foo": 1}), &index_key()).map(Query::SteQuery).unwrap(); let check = json!([ [ "814586efb4a86da0ae72f65c87e4b7b3", @@ -84,8 +88,6 @@ mod tests { ] ]); - println!("Serialized Query::Json: {}", serde_json::to_string_pretty(&x).unwrap()); - assert_eq!(serde_json::to_value(&x).unwrap(), check); } diff --git a/integration-tests/tests/postgres.test.ts b/integration-tests/tests/postgres.test.ts index 6cb3d91..daaf832 100644 --- a/integration-tests/tests/postgres.test.ts +++ b/integration-tests/tests/postgres.test.ts @@ -11,6 +11,8 @@ import { type SteVecEncryptedEntry, type EncryptedSVE, type EncryptConfig, + type JsonSelect, + type JsonContainsQuery, } from '@cipherstash/protect-ffi' import { Client, type QueryResult } from 'pg' import { encryptQuery } from '../../lib/load.cjs' @@ -46,18 +48,18 @@ describe('postgres', async () => { // clean up function, called once after all tests run return async () => { - //await pg.query('DROP TABLE ENCRYPTED') + await pg.query('DROP TABLE ENCRYPTED') await pg.end() } }) beforeEach(async () => { // called once before each test run - //await pg.query('BEGIN') + await pg.query('BEGIN') // clean up function, called once after each test run return async () => { - //await pg.query('ROLLBACK') + await pg.query('ROLLBACK') } }) @@ -297,7 +299,7 @@ describe('postgres', async () => { toStore, ) - const query = await encryptQuery(protectClient, { + const query: JsonSelect = await encryptQuery(protectClient, { // FIXME: The first form fails (the selector doesn't map correctly) // See JsonIndexer::tokenize_selector (the Dot variant behaves differently) //plaintext: "$.foo", @@ -307,37 +309,77 @@ describe('postgres', async () => { operator: '->', }) - // SELECT jsonb_path_query(encrypted_profile::jsonb, '$.sv[*] ? (exists(@ ? (@.s == "d18aa290a20cf6413f50d5ca87a0a6c2"))).c') FROM encrypted - // TODO: Use the jsonquery approach from the Json indexer docs - //SELECT eql_v2."->"(encrypted_profile, eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted + // NOTE: I realise this is pretty horrendous but the current EQL implementation isn't correct const res: QueryResult<{ value: SteVecEncryptedEntry | null }> = await pg.query( ` - SELECT (encrypted_profile->eql_v2.selector($1::jsonb))::jsonb as value FROM encrypted + SELECT jsonb_path_query(encrypted_profile::jsonb, '$.sv[*] ? (exists(@ ? (@.s == $v)))', jsonb_build_object('v', to_jsonb($1::text))) as value FROM encrypted `, - [query], + [query.s], ) - console.log('ROWS:', res.rows[0].value) - const ciphertexts = res.rows.flatMap((row) => - row.value === null - ? [] - : [ - { - ciphertext: { k: 'sve', sve: row.value } as EncryptedSVE, - }, - ], - ) + expect(res.rowCount).toBe(2) + const ciphertexts = res.rows.map((row) => ({ + ciphertext: { k: 'sve', sve: row.value } as EncryptedSVE, + })) - console.log('Ciphertexts:', JSON.stringify(ciphertexts)) const decrypted = await decryptBulk(protectClient, { ciphertexts, }) - //const decrypted = await decrypt(protectClient, ciphertexts[0]) - //expect(decrypted).toEqual('bar') - // FIXME: we should handle null as an input and just return null expect(decrypted).toEqual(['bar', 'baz']) }) + + test('can use JSON contains @>', async () => { + const toStore = await encryptBulk(protectClient, { + plaintexts: [ + { + plaintext: { foo: 'bar', baz: [1, 2, 3] }, + column: 'profile', + table: 'users', + }, + { + plaintext: { foo: 'baz', qux: [4, 5, 6] }, + column: 'profile', + table: 'users', + }, + { + plaintext: { other: 'foo' }, + column: 'profile', + table: 'users', + }, + ], + }) + + await pg.query( + 'INSERT INTO encrypted (encrypted_profile) VALUES ($1::jsonb), ($2::jsonb), ($3::jsonb)', + toStore, + ) + + const query: JsonContainsQuery = await encryptQuery(protectClient, { + plaintext: { foo: 'bar' }, + column: 'profile', + table: 'users', + operator: '@>', + }) + + // NOTE: I realise this is pretty horrendous but the current EQL implementation isn't correct + const res: QueryResult<{ value: EncryptedSV | null }> = + await pg.query( + ` + SELECT encrypted_profile::jsonb as value from encrypted where encrypted_profile::jsonb @> $1::jsonb + `, + [query], + ) + + const ciphertexts = res.rows.map((row) => ({ + ciphertext: row.value as EncryptedSV, + })) + + const decrypted = await decryptBulk(protectClient, { + ciphertexts, + }) + expect(decrypted).toEqual([{ foo: 'bar', baz: [1, 2, 3] }]) + }) }) interface User extends EncryptConfig {} diff --git a/integration-tests/tests/query.test.ts b/integration-tests/tests/query.test.ts index 3b22f01..d2f6c8a 100644 --- a/integration-tests/tests/query.test.ts +++ b/integration-tests/tests/query.test.ts @@ -7,6 +7,9 @@ import { type NumericOperator, type JsonbOperator, type JsPlaintext, + type JsonContainsQuery, + type JsonIsContainedByQuery, + type JsonSelect, } from '@cipherstash/protect-ffi' // Import a shared encryptConfig from common.js @@ -32,17 +35,6 @@ const scoreValidOperators: { op: NumericOperator; index: string }[] = [ { op: '>', index: 'ob' }, { op: '<', index: 'ob' }, ] - -const jsonValidOperators: { - op: JsonbOperator - index: string - v: JsPlaintext -}[] = [ - { op: '->', index: 's', v: '$.foo' }, - { op: '@>', index: 'sv', v: { foo: 'bar' } }, - // TODO: The rest -] - const emailInvalidOperators: { op: NumericOperator | JsonbOperator }[] = [ { op: '@>' }, { op: '<@' }, @@ -92,7 +84,7 @@ describe('query encryption', () => { test('fails to generate a query term', async () => { const client = await newClient({ encryptConfig }) - expect(async () => { + await expect(async () => { await encryptQuery(client, { plaintext: 'foo@example.net', column: 'email', @@ -130,7 +122,7 @@ describe('query encryption', () => { test('fails to generate a query term', async () => { const client = await newClient({ encryptConfig }) - expect(async () => { + await expect(async () => { await encryptQuery(client, { plaintext: 5000, column: 'score', @@ -144,24 +136,63 @@ describe('query encryption', () => { }, ) - describe.each(jsonValidOperators)( - 'using operator $op for json column', - ({ op, index, v }) => { - test(`generates the correct query type: '${index}'`, async () => { - const client = await newClient({ encryptConfig }) + // JSON operators are all special cases + describe('Valid JSON operators', () => { + test('-> generates an ejsonpath selector', async () => { + const client = await newClient({ encryptConfig }) + + const query: JsonSelect = await encryptQuery(client, { + // TODO: This plaintext is _different_ to the JSON type + plaintext: '$.foo', + column: 'profile', + table: 'users', + operator: '->', + }) - const query = await encryptQuery(client, { - // TODO: This plaintext is _different_ to the JSON type - plaintext: v, - column: 'profile', - table: 'users', - operator: op, - }) + // Should have a selector in the response + expect(query).toHaveProperty('s') + }) - expect(query).toHaveProperty(index) + test('@> generates ste_query_vec', async () => { + const client = await newClient({ encryptConfig }) + + const query: JsonContainsQuery = await encryptQuery(client, { + plaintext: { foo: 'bar' } as JsPlaintext, + column: 'profile', + table: 'users', + operator: '@>', }) - }, - ) + + // Should have a ste_query_vec in the response + expect(query).toHaveProperty('sv') + expect(query.sv).toBeInstanceOf(Array) + expect(query.sv.length).toEqual(2) + expect(query.sv[0]).toHaveProperty('s') + expect(query.sv[0]).toHaveProperty('hm') + expect(query.sv[1]).toHaveProperty('s') + expect(query.sv[1]).toHaveProperty('ocv') + }) + + test('<@ generates ste_query_vec', async () => { + const client = await newClient({ encryptConfig }) + + const query: JsonIsContainedByQuery = await encryptQuery(client, { + plaintext: { foo: 'bar' } as JsPlaintext, + column: 'profile', + table: 'users', + operator: '<@', + }) + + // Should have a ste_query_vec in the response + expect(query).toHaveProperty('sv') + expect(query.sv).toBeInstanceOf(Array) + expect(query.sv.length).toEqual(2) + expect(query.sv[0]).toHaveProperty('s') + expect(query.sv[0]).toHaveProperty('hm') + expect(query.sv[1]).toHaveProperty('s') + expect(query.sv[1]).toHaveProperty('ocv') + }) + }) describe.each(jsonInvalidOperators)( 'using operator $op for json column', @@ -169,7 +200,7 @@ describe('query encryption', () => { test('fails to generate a query term', async () => { const client = await newClient({ encryptConfig }) - expect(async () => { + await expect(async () => { await encryptQuery(client, { plaintext: '$["foo"]', column: 'profile', diff --git a/src/index.cts b/src/index.cts index 9798d4e..923ff38 100644 --- a/src/index.cts +++ b/src/index.cts @@ -30,10 +30,10 @@ declare module './load.cjs' { function isEncrypted( encrypted: AnyEncrypted, ): boolean - function encryptQuery( + function encryptQuery( client: Client, opts: QueryOptions, - ): Promise + ): Promise function encryptBulk( client: Client, opts: EncryptBulkOptions, @@ -107,10 +107,12 @@ export type AnyEncrypted = | EncryptedSVE export type SteVecEncryptedEntry = { - s: JSONPathSelector c: Base85Ciphertext parent_is_array: boolean -} & SteVecTerm +} & SteVecTerm & { s: JSONPathSelector } + +export type SteVecQuery = { svq: SteQueryVecEntry[] } +export type SteQueryVecEntry = { s: JSONPathSelector } & SteVecTerm export type SteVecTerm = | { hm: HMAC } @@ -240,8 +242,25 @@ export type JsonbOperator = '@>' | '<@' | '->' export type QueryOperator = NumericOperator | StringOperator | JsonbOperator // These types are included in responses from encryptQuery -export type EncryptedQueryTerm = - | { ob: EncodedBlockOREArray } - | { bf: BloomFilter } - | { hm: HMAC } - | { s: JSONPathSelector } +export type EncryptedQueryTerm = {} +export interface RangeQuery extends EncryptedQueryTerm { + ob: EncodedBlockOREArray +} +export interface MatchQuery extends EncryptedQueryTerm { + bf: BloomFilter +} +export interface ExactQuery extends EncryptedQueryTerm { + hm: HMAC +} +// Used for stabby queries (->) +export interface JsonSelect extends EncryptedQueryTerm { + s: JSONPathSelector +} +// Used for contains queries (@>) +export interface JsonContainsQuery extends EncryptedQueryTerm { + sv: SteQueryVecEntry[] +} +// Used for is-contained-by queries (<@) +export interface JsonIsContainedByQuery extends EncryptedQueryTerm { + sv: SteQueryVecEntry[] +} From e5f626954917a3d3beb7f847dfcea57d2cf0c146 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 14:47:54 +0000 Subject: [PATCH 11/30] v0.18.0-0 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfd925b..675019f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.17.0", + "version": "0.18.0-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.17.0", + "version": "0.18.0-0", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index bc652b0..73d1ed1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.17.0", + "version": "0.18.0-0", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index bdf9311..dd79afb 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.17.0", + "version": "0.18.0-0", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index d6ae5ff..70204a1 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.17.0", + "version": "0.18.0-0", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 26d051b..96983d1 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.17.0", + "version": "0.18.0-0", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 608e9a1..0b3fa69 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.17.0", + "version": "0.18.0-0", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index 0fd2426..6a816a2 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.17.0", + "version": "0.18.0-0", "os": [ "win32" ], From 30d612add2f63e14607d29018bbd083c1430dfd0 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 10:03:44 -0600 Subject: [PATCH 12/30] chore: use github cipherstash-client --- Cargo.lock | 7 +++++++ crates/protect-ffi/Cargo.toml | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7733a04..8636032 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -646,6 +646,7 @@ dependencies = [ [[package]] name = "cipherstash-client" version = "0.28.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "aes-gcm-siv", "anyhow", @@ -703,6 +704,7 @@ dependencies = [ [[package]] name = "cipherstash-config" version = "0.2.4" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "serde", "thiserror 1.0.69", @@ -711,6 +713,7 @@ dependencies = [ [[package]] name = "cipherstash-core" version = "0.1.2" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "hmac", "lazy_static", @@ -735,6 +738,7 @@ dependencies = [ [[package]] name = "cllw-ore" version = "0.1.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "bit-vec", "bitvec", @@ -851,6 +855,7 @@ dependencies = [ [[package]] name = "cts-common" version = "0.3.1" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "arrayvec", "axum", @@ -2561,6 +2566,7 @@ dependencies = [ [[package]] name = "recipher" version = "0.1.3" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "aes", "async-trait", @@ -4308,6 +4314,7 @@ dependencies = [ [[package]] name = "zerokms-protocol" version = "0.7.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=fix%2Fjsonindexer-fixes#2279441799de7576827c805406f6d61d216ef07b" dependencies = [ "async-trait", "base64", diff --git a/crates/protect-ffi/Cargo.toml b/crates/protect-ffi/Cargo.toml index 84e292a..e5f4357 100644 --- a/crates/protect-ffi/Cargo.toml +++ b/crates/protect-ffi/Cargo.toml @@ -11,14 +11,13 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cipherstash-client = { path = "../../../cipherstash-suite/packages/cipherstash-client", version = "0.28.0" } -#cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", package = "cipherstash-client", branch = "fix/jsonindexer-fixes" } +cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", version = "0.28.0", package = "cipherstash-client", branch = "fix/jsonindexer-fixes" } const-hex = "1.17.0" # 0.14.7 introduces deprecations we need to avoid for now # Protect.rs will not use GenericArray at all generic-array = "=0.14.6" hex = "0.4.3" -neon = {version = "1", features = ["serde", "tokio"] } +neon = { version = "1", features = ["serde", "tokio"] } once_cell = "1.20.2" serde = "1.0.218" serde_json = "1.0.139" From 0c92bccebddcb94ad978a79f46a720a4062427a2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 16:08:43 +0000 Subject: [PATCH 13/30] v0.18.0-1 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 675019f..b43d1b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-0", + "version": "0.18.0-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-0", + "version": "0.18.0-1", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 73d1ed1..07a8752 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-0", + "version": "0.18.0-1", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index dd79afb..39a43b6 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-0", + "version": "0.18.0-1", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 70204a1..4fb194e 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-0", + "version": "0.18.0-1", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 96983d1..7821ce9 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-0", + "version": "0.18.0-1", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 0b3fa69..5749048 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-0", + "version": "0.18.0-1", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index 6a816a2..ec6c167 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-0", + "version": "0.18.0-1", "os": [ "win32" ], From 4d6484757b0b81ff9ce23ad2e6822091f6430bb7 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 10:22:27 -0600 Subject: [PATCH 14/30] fix(ci): add temp build creds --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a74d770..6f37e81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,7 +96,10 @@ jobs: env: CARGO_BUILD_TARGET: ${{ steps.neon.outputs.target }} NEON_BUILD_PLATFORM: ${{ matrix.cfg.platform }} - run: npm run ${{ matrix.cfg.script }} + run: | + eval `ssh-agent -s` + ssh-add - <<< "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" + npm run ${{ matrix.cfg.script }} - name: Pack id: pack shell: bash From f9fbcd7341bdd8f44e287e0e36a3feb3c7ff3a7c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 16:23:48 +0000 Subject: [PATCH 15/30] v0.18.0-2 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b43d1b0..772699d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-1", + "version": "0.18.0-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-1", + "version": "0.18.0-2", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 07a8752..7d9c481 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-1", + "version": "0.18.0-2", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index 39a43b6..5a2e63b 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-1", + "version": "0.18.0-2", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 4fb194e..31d369e 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-1", + "version": "0.18.0-2", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 7821ce9..eaab553 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-1", + "version": "0.18.0-2", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 5749048..8d2ce14 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-1", + "version": "0.18.0-2", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index ec6c167..72ad287 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-1", + "version": "0.18.0-2", "os": [ "win32" ], From 8e1511a6283e5f87f5fcf4ab83f183c3bf56c4a2 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 10:32:47 -0600 Subject: [PATCH 16/30] fix(ci): load key --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f37e81..d59f94e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,7 +98,7 @@ jobs: NEON_BUILD_PLATFORM: ${{ matrix.cfg.platform }} run: | eval `ssh-agent -s` - ssh-add - <<< "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" + echo "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" | ssh-add - npm run ${{ matrix.cfg.script }} - name: Pack id: pack From 575fbb9662b61c65e09a0873530033c4e3377da1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 16:34:05 +0000 Subject: [PATCH 17/30] v0.18.0-3 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 772699d..50181f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-2", + "version": "0.18.0-3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-2", + "version": "0.18.0-3", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 7d9c481..1335d09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-2", + "version": "0.18.0-3", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index 5a2e63b..8263490 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-2", + "version": "0.18.0-3", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 31d369e..fd07009 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-2", + "version": "0.18.0-3", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index eaab553..72a24c1 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-2", + "version": "0.18.0-3", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 8d2ce14..06dfb4d 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-2", + "version": "0.18.0-3", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index 72ad287..dc82701 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-2", + "version": "0.18.0-3", "os": [ "win32" ], From 8b396b0c39ae6b1a2f6036987b72ca4a9ad578c1 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 10:39:44 -0600 Subject: [PATCH 18/30] fix(ci): load key --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d59f94e..498efcd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,7 +98,10 @@ jobs: NEON_BUILD_PLATFORM: ${{ matrix.cfg.platform }} run: | eval `ssh-agent -s` - echo "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" | ssh-add - + echo "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" | base64 -d > /tmp/ssh_key + chmod 600 /tmp/ssh_key + ssh-add /tmp/ssh_key + rm -f /tmp/ssh_key npm run ${{ matrix.cfg.script }} - name: Pack id: pack From d598a7531ec34431c3375719ade8e358335cf1e6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 16:40:48 +0000 Subject: [PATCH 19/30] v0.18.0-4 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50181f3..e9dcede 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-3", + "version": "0.18.0-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-3", + "version": "0.18.0-4", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 1335d09..6a067c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-3", + "version": "0.18.0-4", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index 8263490..3627c1e 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-3", + "version": "0.18.0-4", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index fd07009..478d1c1 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-3", + "version": "0.18.0-4", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 72a24c1..641ab50 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-3", + "version": "0.18.0-4", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 06dfb4d..43c0006 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-3", + "version": "0.18.0-4", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index dc82701..e330bfa 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-3", + "version": "0.18.0-4", "os": [ "win32" ], From 5bd71757d4e93a0c8ec102ea468ffc2bbc4753de Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 11:44:32 -0600 Subject: [PATCH 20/30] fix(ci): use ssh agent step --- .github/workflows/build.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 498efcd..732dd72 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -84,6 +84,10 @@ jobs: with: use-cross: ${{ matrix.cfg.script == 'cross' }} platform: ${{ matrix.cfg.platform }} + - name: Setup SSH Agent + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }} - name: Update Version if: ${{ inputs.update-version }} shell: bash @@ -96,13 +100,7 @@ jobs: env: CARGO_BUILD_TARGET: ${{ steps.neon.outputs.target }} NEON_BUILD_PLATFORM: ${{ matrix.cfg.platform }} - run: | - eval `ssh-agent -s` - echo "${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }}" | base64 -d > /tmp/ssh_key - chmod 600 /tmp/ssh_key - ssh-add /tmp/ssh_key - rm -f /tmp/ssh_key - npm run ${{ matrix.cfg.script }} + run: npm run ${{ matrix.cfg.script }} - name: Pack id: pack shell: bash From d134d39bf67a9e330283c41efc471274891bc89f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 18:04:31 +0000 Subject: [PATCH 21/30] v0.18.0-5 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index e9dcede..7a2cf34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-4", + "version": "0.18.0-5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-4", + "version": "0.18.0-5", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 6a067c0..d094588 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-4", + "version": "0.18.0-5", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index 3627c1e..b3504a7 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-4", + "version": "0.18.0-5", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 478d1c1..217b5ee 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-4", + "version": "0.18.0-5", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 641ab50..14551d5 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-4", + "version": "0.18.0-5", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 43c0006..2baf5b4 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-4", + "version": "0.18.0-5", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index e330bfa..dc9b1f0 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-4", + "version": "0.18.0-5", "os": [ "win32" ], From 24d7719d675bea407bdda7ecad8e5378b0c2714d Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 12:10:24 -0600 Subject: [PATCH 22/30] fix(ci): pass secrets to build --- .github/workflows/build.yml | 3 +++ .github/workflows/release.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 732dd72..48242d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,9 @@ on: required: false type: string default: '' + secrets: + CIPHERSTASH_SUITE_PRIVATE_SSH_KEY: + required: true jobs: matrix: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cc1c6e8..5ceabda 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -106,6 +106,8 @@ jobs: permissions: contents: write uses: ./.github/workflows/build.yml + secrets: + CIPHERSTASH_SUITE_PRIVATE_SSH_KEY: ${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }} with: ref: ${{ needs.setup.outputs.ref }} tag: ${{ needs.setup.outputs.tag }} From 4ce19b0158ea03f3352f34dca8b24c53738ecb23 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 18:11:32 +0000 Subject: [PATCH 23/30] v0.18.0-6 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a2cf34..ec72323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-5", + "version": "0.18.0-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-5", + "version": "0.18.0-6", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index d094588..2403a4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-5", + "version": "0.18.0-6", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index b3504a7..c479515 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-5", + "version": "0.18.0-6", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 217b5ee..85c4863 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-5", + "version": "0.18.0-6", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 14551d5..72d2c75 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-5", + "version": "0.18.0-6", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 2baf5b4..ab9eed4 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-5", + "version": "0.18.0-6", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index dc9b1f0..9776342 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-5", + "version": "0.18.0-6", "os": [ "win32" ], From cc62d4950b1ad103356fe25ee73a324862c98686 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 12:18:21 -0600 Subject: [PATCH 24/30] fix(ci): known hosts --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48242d6..3c239ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,6 +91,11 @@ jobs: uses: webfactory/ssh-agent@v0.9.0 with: ssh-private-key: ${{ secrets.CIPHERSTASH_SUITE_PRIVATE_SSH_KEY }} + - name: Configure SSH for GitHub + shell: bash + run: | + mkdir -p ~/.ssh + ssh-keyscan github.com >> ~/.ssh/known_hosts - name: Update Version if: ${{ inputs.update-version }} shell: bash From bff02e9a3d9c5d495e7e85ca3370fc1aaf514db2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 18:19:42 +0000 Subject: [PATCH 25/30] v0.18.0-7 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec72323..bcfefea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-6", + "version": "0.18.0-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-6", + "version": "0.18.0-7", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 2403a4b..60bfb46 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-6", + "version": "0.18.0-7", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index c479515..6d747c8 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-6", + "version": "0.18.0-7", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 85c4863..1dcbf64 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-6", + "version": "0.18.0-7", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 72d2c75..bf5639a 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-6", + "version": "0.18.0-7", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index ab9eed4..2632e53 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-6", + "version": "0.18.0-7", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index 9776342..8d56f1e 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-6", + "version": "0.18.0-7", "os": [ "win32" ], From 23698613a8ad2406887e649de9dc40778eb9f7a8 Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 13:32:49 -0600 Subject: [PATCH 26/30] fix(ci): windows git config --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c239ba..0c75478 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,6 +81,10 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ inputs.ref }} + - name: Enable Long Paths (Windows) + if: runner.os == 'Windows' + shell: bash + run: git config --system core.longpaths true - name: Setup Neon Environment id: neon uses: ./.github/actions/setup From d7e82317043617c9513ffa01d5212399748aaa75 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 19:35:02 +0000 Subject: [PATCH 27/30] v0.18.0-8 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index bcfefea..27715d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-7", + "version": "0.18.0-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-7", + "version": "0.18.0-8", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 60bfb46..31d05d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-7", + "version": "0.18.0-8", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index 6d747c8..dfc0d80 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-7", + "version": "0.18.0-8", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index 1dcbf64..ac450b8 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-7", + "version": "0.18.0-8", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index bf5639a..2df3bf6 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-7", + "version": "0.18.0-8", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 2632e53..22be1e6 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-7", + "version": "0.18.0-8", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index 8d56f1e..acccea1 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-7", + "version": "0.18.0-8", "os": [ "win32" ], From 7f9f10580ee984c22680834407ce2b462bbf457f Mon Sep 17 00:00:00 2001 From: CJ Brewer Date: Tue, 21 Oct 2025 13:56:53 -0600 Subject: [PATCH 28/30] feat(ci): publish next tag if pre release --- .github/workflows/release.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ceabda..2a120c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -143,5 +143,15 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | for p in ./dist/*.tgz ; do - npm publish --access public $p + # Extract version from package tarball + version=$(tar -xOf "$p" package/package.json | jq -r '.version') + + # Check if this is a prerelease version (contains hyphen) + if [[ "$version" == *-* ]]; then + echo "Publishing prerelease version $version with tag 'next'" + npm publish --access public --tag next "$p" + else + echo "Publishing stable version $version" + npm publish --access public "$p" + fi done From 1f1e4f4d6760b7f11b121f50c2d63d8e86dd3366 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Oct 2025 20:00:28 +0000 Subject: [PATCH 29/30] v0.18.0-9 --- package-lock.json | 4 ++-- package.json | 2 +- platforms/darwin-arm64/package.json | 2 +- platforms/darwin-x64/package.json | 2 +- platforms/linux-arm64-gnu/package.json | 2 +- platforms/linux-x64-gnu/package.json | 2 +- platforms/win32-x64-msvc/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 27715d4..3b4af8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-8", + "version": "0.18.0-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-8", + "version": "0.18.0-9", "license": "ISC", "dependencies": { "@neon-rs/load": "^0.1.82" diff --git a/package.json b/package.json index 31d05d2..f0902ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cipherstash/protect-ffi", - "version": "0.18.0-8", + "version": "0.18.0-9", "description": "", "main": "./lib/index.cjs", "scripts": { diff --git a/platforms/darwin-arm64/package.json b/platforms/darwin-arm64/package.json index dfc0d80..aa96c02 100644 --- a/platforms/darwin-arm64/package.json +++ b/platforms/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-arm64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-arm64`.", - "version": "0.18.0-8", + "version": "0.18.0-9", "os": [ "darwin" ], diff --git a/platforms/darwin-x64/package.json b/platforms/darwin-x64/package.json index ac450b8..747bd66 100644 --- a/platforms/darwin-x64/package.json +++ b/platforms/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-darwin-x64", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `darwin-x64`.", - "version": "0.18.0-8", + "version": "0.18.0-9", "os": [ "darwin" ], diff --git a/platforms/linux-arm64-gnu/package.json b/platforms/linux-arm64-gnu/package.json index 2df3bf6..a13b77b 100644 --- a/platforms/linux-arm64-gnu/package.json +++ b/platforms/linux-arm64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-arm64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-arm64-gnu`.", - "version": "0.18.0-8", + "version": "0.18.0-9", "os": [ "linux" ], diff --git a/platforms/linux-x64-gnu/package.json b/platforms/linux-x64-gnu/package.json index 22be1e6..f5ce0e8 100644 --- a/platforms/linux-x64-gnu/package.json +++ b/platforms/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-linux-x64-gnu", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `linux-x64-gnu`.", - "version": "0.18.0-8", + "version": "0.18.0-9", "os": [ "linux" ], diff --git a/platforms/win32-x64-msvc/package.json b/platforms/win32-x64-msvc/package.json index acccea1..b2c8744 100644 --- a/platforms/win32-x64-msvc/package.json +++ b/platforms/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@cipherstash/protect-ffi-win32-x64-msvc", "description": "Prebuilt binary package for `@cipherstash/protect-ffi` on `win32-x64-msvc`.", - "version": "0.18.0-8", + "version": "0.18.0-9", "os": [ "win32" ], From 34379ec12d22daec69b66075a1b49fdf861205e8 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 23 Oct 2025 13:01:52 +1100 Subject: [PATCH 30/30] fix(query): rename OreLeft to OreFull for consistency in Query enum --- crates/protect-ffi/src/query.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/protect-ffi/src/query.rs b/crates/protect-ffi/src/query.rs index 26c3395..5bac8e2 100644 --- a/crates/protect-ffi/src/query.rs +++ b/crates/protect-ffi/src/query.rs @@ -10,7 +10,7 @@ pub enum Query { BitMap(Vec), #[serde(rename = "ob")] - OreLeft(Vec), + OreFull(Vec), // NOTE: This type doesn't current exist in the EQL spec but its convenient to give it the sv name // even though its the query type and not the full encrypted entry. @@ -34,8 +34,9 @@ impl TryFrom for Query { match value { IndexTerm::Binary(b) => Ok(Query::Binary(b)), IndexTerm::BitMap(bm) => Ok(Query::BitMap(bm)), - IndexTerm::OreLeft(ol) => Ok(Query::OreLeft(vec![OreTerm(ol)])), - IndexTerm::OreFull(of) => Ok(Query::OreLeft(vec![OreTerm(of)])), + IndexTerm::OreLeft(ol) => Ok(Query::OreFull(vec![OreTerm(ol)])), + IndexTerm::OreFull(of) => Ok(Query::OreFull(vec![OreTerm(of)])), + IndexTerm::OreArray(of) => Ok(Query::OreFull(of.into_iter().map(OreTerm).collect())), IndexTerm::SteQueryVec(sqv) => Ok(Query::SteQuery(sqv)), IndexTerm::SteVecSelector(ts) => Ok(Query::SteVecSelector(ts)), IndexTerm::SteVecTerm(est) => Ok(Query::SteVecTerm(est)),