diff --git a/.cargo/audit.toml b/.cargo/audit.toml index d8fc779..f73feec 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -1,21 +1,10 @@ # cargo-audit configuration. # -# Each ignored advisory below has been triaged and is either unreachable in our -# build, has no upstream fix, or the fix is a deferred breaking migration. Every -# other advisory must fail CI (see .github/workflows/ci.yml `audit` job) so new -# ones are caught. Re-review this list when dependencies are updated. +# The single ignored advisory below has been triaged and has no upstream fix. +# Every other advisory must fail CI (see .github/workflows/ci.yml `audit` job) so +# new ones are caught. Re-review this list when dependencies are updated. [advisories] ignore = [ - # rsa (Marvin timing side-channel). Pulled in ONLY by sqlx-mysql, an optional - # sqlx dependency that is NOT enabled — `cargo tree` confirms rsa is never in - # the build graph, so it is never compiled or linked. No upstream fix exists. - "RUSTSEC-2023-0071", - # hickory-proto: no fixed upstream release is available. - "RUSTSEC-2026-0118", - # hickory-proto: fixed in hickory-resolver 0.26, but that removes the - # `txt_lookup` API and requires an (untested-in-CI) rewrite of DNS handle - # resolution. Deferred; revisit with the hickory 0.26 upgrade. - "RUSTSEC-2026-0119", # fxhash: unmaintained (warning, not a vulnerability). Transitive dependency # of wasmtime (via fxprof-processed-profile); not removable independently. "RUSTSEC-2025-0057", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dd3f70..fa66021 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: -v "$HOME/.cargo/git:/usr/local/cargo/git" \ -w /app \ -e SQLX_OFFLINE=true \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload server binary @@ -368,7 +368,7 @@ jobs: -v "$HOME/.cargo/git:/usr/local/cargo/git" \ -w /app \ -e SQLX_OFFLINE=true \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload artifact @@ -561,7 +561,7 @@ jobs: -w /app \ -e SQLX_OFFLINE=true \ -e HAPPYVIEW_VERSION="v${{ needs.release.outputs.version }}" \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload binary to release diff --git a/Cargo.lock b/Cargo.lock index 10ea568..8b0b21e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,30 +19,30 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ - "crypto-common", - "generic-array", + "crypto-common 0.2.2", + "inout", ] [[package]] name = "aes" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" dependencies = [ - "cfg-if", "cipher", - "cpufeatures 0.2.17", + "cpubits", + "cpufeatures 0.3.0", ] [[package]] name = "aes-gcm" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +checksum = "fdf011db2e21ce0d575593d749db5554b47fed37aff429e4dc50bc91ac93a028" dependencies = [ "aead", "aes", @@ -118,6 +118,45 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -264,17 +303,17 @@ dependencies = [ "base64", "chrono", "dashmap", - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "jose-jwa", "jose-jwk", - "p256", + "p256 0.13.2", "rand 0.8.6", - "reqwest", + "reqwest 0.12.28", "serde", "serde_html_form", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tokio", "trait-variant", @@ -378,22 +417,22 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" dependencies = [ "axum", "axum-core", "bytes", "cookie", "form_urlencoded", + "futures-core", "futures-util", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "serde_core", "serde_html_form", "serde_path_to_error", @@ -414,6 +453,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base256emoji" version = "1.0.2" @@ -442,6 +487,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.0" @@ -474,6 +528,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bstr" version = "1.12.3" @@ -532,6 +595,23 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.45" @@ -588,11 +668,12 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "crypto-common", + "block-buffer 0.12.1", + "crypto-common 0.2.2", "inout", ] @@ -605,6 +686,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cobs" version = "0.3.0" @@ -614,6 +701,16 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "compression-codecs" version = "0.4.38" @@ -646,6 +743,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const-str" version = "0.4.3" @@ -665,11 +768,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ "base64", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "percent-encoding", "rand 0.8.6", - "sha2", + "sha2 0.10.9", "subtle", "time", "version_check", @@ -710,6 +813,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -957,6 +1066,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +dependencies = [ + "cpubits", + "ctutils", + "getrandom 0.4.3", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -964,19 +1089,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "getrandom 0.4.3", + "hybrid-array", + "rand_core 0.10.1", +] + [[package]] name = "ctr" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" dependencies = [ "cipher", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "dashmap" version = "6.2.1" @@ -1050,11 +1195,35 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", "pem-rfc7468", "zeroize", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1067,12 +1236,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "directories-next" version = "2.0.0" @@ -1123,12 +1304,26 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", +] + +[[package]] +name = "ecdsa" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" +dependencies = [ + "der 0.8.0", + "digest 0.11.3", + "elliptic-curve 0.14.1", + "rfc6979 0.6.0", + "signature 3.0.0", "spki", + "zeroize", ] [[package]] @@ -1146,16 +1341,35 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.1", "generic-array", - "group", + "group 0.13.0", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "digest 0.11.3", + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", - "sec1", + "rand_core 0.10.1", + "sec1 0.8.1", "subtle", "zeroize", ] @@ -1181,18 +1395,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1222,13 +1424,12 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.8.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" dependencies = [ "cfg-if", - "home", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1274,6 +1475,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" +dependencies = [ + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1292,9 +1503,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", @@ -1513,17 +1724,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "opaque-debug", "polyval", ] @@ -1544,11 +1757,22 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "group" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" +dependencies = [ + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "h2" version = "0.4.15" @@ -1607,8 +1831,8 @@ dependencies = [ "futures-util", "hex", "hickory-resolver", - "hkdf", - "hmac", + "hkdf 0.13.0", + "hmac 0.13.0", "http-body-util", "ipnet", "jose-jwk", @@ -1616,18 +1840,18 @@ dependencies = [ "k256", "mlua", "multibase", - "p256", - "rand 0.9.4", + "p256 0.14.0", + "rand 0.10.2", "rcgen", "regex", - "reqwest", + "reqwest 0.13.4", "rustls", "semver", "serde", "serde_ipld_dagcbor", "serde_json", "serial_test", - "sha2", + "sha2 0.11.0", "sqlparser", "sqlx", "thiserror 2.0.18", @@ -1635,13 +1859,13 @@ dependencies = [ "tokio-rustls", "tokio-tungstenite", "tower", - "tower-http", + "tower-http 0.7.0", "tracing", "tracing-subscriber", "urlencoding", "uuid", "wasmtime", - "webpki-roots 0.26.11", + "webpki-roots 1.0.8", "wiremock", ] @@ -1657,8 +1881,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", "serde", ] @@ -1682,11 +1904,11 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hashlink" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -1708,46 +1930,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-proto" -version = "0.25.2" +name = "hickory-net" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183" dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", + "hickory-proto", + "idna", + "ipnet", + "jni", + "rand 0.10.2", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-proto" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643" +dependencies = [ + "data-encoding", "idna", "ipnet", + "jni", "once_cell", - "rand 0.9.4", + "prefix-trie", + "rand 0.10.2", "ring", "thiserror 2.0.18", "tinyvec", - "tokio", "tracing", "url", ] [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni", "moka", + "ndk-context", "once_cell", "parking_lot", - "rand 0.9.4", + "rand 0.10.2", "resolv-conf", "smallvec", + "system-configuration", "thiserror 2.0.18", "tokio", "tracing", @@ -1759,7 +2005,16 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac 0.13.0", ] [[package]] @@ -1768,16 +2023,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] -name = "home" -version = "0.5.12" +name = "hmac" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "windows-sys 0.61.2", + "digest 0.11.3", ] [[package]] @@ -1831,6 +2086,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.10.1" @@ -2056,11 +2322,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -2092,6 +2358,9 @@ name = "ipnet" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +dependencies = [ + "serde", +] [[package]] name = "itertools" @@ -2128,6 +2397,55 @@ dependencies = [ "cc", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "jobserver" version = "0.1.35" @@ -2167,7 +2485,7 @@ checksum = "280fa263807fe0782ecb6f2baadc28dffc04e00558a58e33bfdb801d11fd58e7" dependencies = [ "jose-b64", "jose-jwa", - "p256", + "p256 0.13.2", "serde", "zeroize", ] @@ -2185,31 +2503,34 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.1" +version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "base64", + "getrandom 0.2.17", "js-sys", "pem", - "ring", "serde", "serde_json", + "signature 2.2.0", "simple_asn1", + "zeroize", ] [[package]] name = "k256" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +checksum = "93f50113171a713f4a4231ef82eb26703607139b35dcb56241f0ceab2ae1f7d8" dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", - "signature", + "cpubits", + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primeorder 0.14.0", + "sha2 0.11.0", + "signature 3.0.0", + "wnaf", ] [[package]] @@ -2226,9 +2547,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "leb128fmt" @@ -2254,10 +2572,7 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ - "bitflags", "libc", - "plain", - "redox_syscall 0.9.0", ] [[package]] @@ -2307,20 +2622,26 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lua-src" -version = "550.0.0" +version = "550.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e836dc8ae16806c9bdcf42003a88da27d163433e3f9684c52f0301258004a4fb" +checksum = "75c110c2fa33f34e0de05448e1f3eb2e0631e7a69e2d8ae1586cffc9fc9f9949" dependencies = [ "cc", ] [[package]] name = "luajit-src" -version = "210.6.6+707c12b" +version = "210.7.2+b925b3e" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" +checksum = "920cf654b23d217c550ceea57c32cd2a413ea27b6d47ed77b5ee0cf655adefa6" dependencies = [ "cc", "which", @@ -2363,12 +2684,12 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest", + "digest 0.11.3", ] [[package]] @@ -2402,6 +2723,12 @@ dependencies = [ "unicase", ] +[[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" @@ -2425,9 +2752,9 @@ dependencies = [ [[package]] name = "mlua" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +checksum = "ad72ffa037cf5970c9860674f32f703fda25d86cf217475fe7a79c5f9961bcaa" dependencies = [ "bstr", "either", @@ -2438,16 +2765,15 @@ dependencies = [ "num-traits", "parking_lot", "rustc-hash", - "rustversion", "serde", "serde-value", ] [[package]] name = "mlua-sys" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" +checksum = "92136787b906d4e55cfe96cd6c62e010bb1a56889d0d6cf83eb016dbad07576b" dependencies = [ "cc", "cfg-if", @@ -2534,6 +2860,22 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[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 = "nu-ansi-term" version = "0.50.3" @@ -2553,22 +2895,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.2.2" @@ -2584,16 +2910,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2601,7 +2917,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2626,6 +2941,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -2636,12 +2960,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.81" @@ -2700,10 +3018,23 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] @@ -2730,7 +3061,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.18", + "redox_syscall", "smallvec", "windows-link", ] @@ -2747,9 +3078,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] @@ -2766,24 +3097,13 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - [[package]] name = "pkcs8" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ - "der", + "der 0.8.0", "spki", ] @@ -2793,21 +3113,14 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "polyval" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", + "cpubits", + "cpufeatures 0.3.0", "universal-hash", ] @@ -2853,13 +3166,51 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prefix-trie" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" +dependencies = [ + "either", + "ipnet", + "num-traits", +] + +[[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primeorder" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06" +dependencies = [ + "elliptic-curve 0.14.1", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] @@ -2904,6 +3255,63 @@ dependencies = [ "syn", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.46" @@ -2946,6 +3354,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -2984,6 +3403,21 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rayon" version = "1.12.0" @@ -3006,14 +3440,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" dependencies = [ "pem", "ring", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -3046,15 +3481,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_syscall" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -3114,6 +3540,42 @@ name = "reqwest" version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http 0.6.11", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -3125,23 +3587,24 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", "mime", - "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower", - "tower-http", + "tower-http 0.6.11", "tower-service", "url", "wasm-bindgen", @@ -3161,10 +3624,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] +[[package]] +name = "rfc6979" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" +dependencies = [ + "crypto-bigint 0.7.5", + "hmac 0.13.0", +] + [[package]] name = "ring" version = "0.17.14" @@ -3179,26 +3652,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rsa" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.28" @@ -3211,6 +3664,24 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -3240,15 +3711,55 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.103.13" @@ -3273,6 +3784,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.29" @@ -3294,10 +3814,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", + "base16ct 0.2.0", + "der 0.7.10", "generic-array", - "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.0", + "hybrid-array", "subtle", "zeroize", ] @@ -3455,6 +3988,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" +dependencies = [ + "base16ct 1.0.0", + "serde", +] + [[package]] name = "serial_test" version = "3.5.0" @@ -3488,7 +4031,18 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3499,7 +4053,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3533,16 +4098,42 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "digest 0.11.3", + "rand_core 0.10.1", +] + [[package]] name = "simd-adler32" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "simple_asn1" version = "0.6.4" @@ -3591,12 +4182,12 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", - "der", + "der 0.8.0", ] [[package]] @@ -3611,9 +4202,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3624,12 +4215,13 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" dependencies = [ "base64", "bytes", + "cfg-if", "chrono", "crc", "crossbeam-queue", @@ -3639,31 +4231,30 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "hashlink", "indexmap", "log", "memchr", - "once_cell", "percent-encoding", "rustls", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.18", "tokio", "tokio-stream", "tracing", "url", - "webpki-roots 0.26.11", + "webpki-roots 1.0.8", ] [[package]] name = "sqlx-macros" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" dependencies = [ "proc-macro2", "quote", @@ -3674,77 +4265,62 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" dependencies = [ + "cfg-if", "dotenvy", "either", "heck", "hex", - "once_cell", "proc-macro2", "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", "syn", + "thiserror 2.0.18", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" dependencies = [ - "atoi", - "base64", "bitflags", "byteorder", "bytes", "chrono", "crc", - "digest", + "digest 0.11.3", "dotenvy", "either", - "futures-channel", "futures-core", - "futures-io", "futures-util", "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", "log", - "md-5", - "memchr", - "once_cell", "percent-encoding", - "rand 0.8.6", - "rsa", "serde", - "sha1", - "sha2", - "smallvec", + "sha1 0.11.0", + "sha2 0.11.0", "sqlx-core", - "stringprep", "thiserror 2.0.18", "tracing", - "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" dependencies = [ "atoi", "base64", @@ -3758,18 +4334,16 @@ dependencies = [ "futures-core", "futures-util", "hex", - "hkdf", - "hmac", - "home", + "hkdf 0.13.0", + "hmac 0.13.0", "itoa", "log", "md-5", "memchr", - "once_cell", - "rand 0.8.6", + "rand 0.10.2", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "smallvec", "sqlx-core", "stringprep", @@ -3780,13 +4354,14 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" dependencies = [ "atoi", "chrono", "flume", + "form_urlencoded", "futures-channel", "futures-core", "futures-executor", @@ -3796,7 +4371,6 @@ dependencies = [ "log", "percent-encoding", "serde", - "serde_urlencoded", "sqlx-core", "thiserror 2.0.18", "tracing", @@ -4090,9 +4664,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -4181,6 +4755,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +dependencies = [ "bitflags", "bytes", "futures-core", @@ -4196,11 +4792,9 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", "tower-layer", "tower-service", "tracing", - "url", ] [[package]] @@ -4309,9 +4903,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", @@ -4321,9 +4915,8 @@ dependencies = [ "rand 0.9.4", "rustls", "rustls-pki-types", - "sha1", + "sha1 0.10.6", "thiserror 2.0.18", - "utf-8", ] [[package]] @@ -4385,12 +4978,12 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" dependencies = [ - "crypto-common", - "subtle", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -4423,12 +5016,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4464,6 +5051,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4488,12 +5085,6 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.126" @@ -4709,7 +5300,7 @@ dependencies = [ "rustix", "serde", "serde_derive", - "sha2", + "sha2 0.10.9", "toml", "windows-sys 0.60.2", "zstd", @@ -4914,6 +5505,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.11" @@ -4943,13 +5543,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", -] +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" [[package]] name = "widestring" @@ -5078,15 +5674,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -5114,21 +5701,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -5162,12 +5734,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5180,12 +5746,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5198,12 +5758,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5228,12 +5782,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5246,12 +5794,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5264,12 +5806,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5282,12 +5818,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5356,18 +5886,48 @@ dependencies = [ "wasmparser 0.236.1", ] +[[package]] +name = "wnaf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +dependencies = [ + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", +] + [[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -5442,6 +6002,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 571d79d..7bc93bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,11 @@ name = "happyview" version = "0.1.0" edition = "2024" +rust-version = "1.96" default-run = "happyview" [dependencies] -aes-gcm = "0.10" +aes-gcm = "0.11" anyhow = "1" arc-swap = "1" atrium-oauth = { version = "0.1", features = ["default-client"] } @@ -14,7 +15,7 @@ atrium-common = "0.1" atrium-api = { version = "0.25", features = ["agent"] } atrium-xrpc = "0.12" axum = { version = "0.8", features = ["multipart"] } -axum-extra = { version = "0.10", features = ["cookie", "cookie-signed", "cookie-key-expansion", "query"] } +axum-extra = { version = "0.12", features = ["cookie", "cookie-signed", "cookie-key-expansion", "query"] } base64 = "0.22" dashmap = "6" data-encoding = "2" @@ -22,44 +23,44 @@ dotenvy = "0.15" hex = "0.4" futures-util = "0.3" jose-jwk = { version = "0.1", default-features = false, features = ["p256"] } -jsonwebtoken = "9" +jsonwebtoken = "10" bytes = "1" chrono = { version = "0.4", features = ["serde"] } cid = "0.11" ciborium = "0.2" -k256 = { version = "0.13", features = ["ecdsa"] } +k256 = { version = "0.14", features = ["ecdsa"] } multibase = "0.9" -p256 = { version = "0.13", features = ["pkcs8", "ecdsa"] } +p256 = { version = "0.14", features = ["pkcs8", "ecdsa"] } uuid = { version = "1", features = ["v4"] } -rand = "0.9" -reqwest = { version = "0.12", features = ["json"] } +rand = "0.10" +reqwest = { version = "0.13", features = ["json", "form"] } rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } serde = { version = "1", features = ["derive"] } serde_ipld_dagcbor = "0.6" serde_json = "1" -sha2 = "0.10" -sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "sqlite", "any", "json", "chrono", "migrate"] } +sha2 = "0.11" +sqlx = { version = "0.9", features = ["runtime-tokio", "tls-rustls", "postgres", "sqlite", "any", "json", "chrono", "migrate"] } tokio = { version = "1", features = ["full"] } tokio-rustls = "0.26" -tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] } +tokio-tungstenite = { version = "0.29", features = ["rustls-tls-webpki-roots"] } thiserror = "2" tower = { version = "0.5", features = ["util"] } -tower-http = { version = "0.6", features = ["cors", "fs", "trace"] } +tower-http = { version = "0.7", features = ["cors", "fs", "trace"] } http-body-util = "0.1" -hickory-resolver = "0.25" +hickory-resolver = "0.26" ipnet = "2" -mlua = { version = "0.11", features = ["lua54", "async", "serialize", "vendored", "send"] } +mlua = { version = "0.12", features = ["lua54", "async", "serialize", "vendored", "send"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } urlencoding = "2.1.3" -webpki-roots = "0.26" +webpki-roots = "1.0" wasmtime = { version = ">=36.0.7, <37", features = ["async"] } regex = "1.12.3" semver = "1.0" async-stream = "0.3.6" blake3 = "1" -hkdf = "0.12" -hmac = "0.12" +hkdf = "0.13" +hmac = "0.13" sqlparser = "0.62.0" [[bin]] @@ -73,4 +74,4 @@ http-body-util = "0.1" serial_test = "3" urlencoding = "2.1.3" futures = "0.3" -rcgen = "0.13" +rcgen = "0.14" diff --git a/Dockerfile b/Dockerfile index b2d8e91..971edbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ COPY web/ . ENV NEXT_PUBLIC_BASE_PATH=/__HAPPYVIEW_BP__ RUN npm run build -FROM rust:1.93-bookworm AS builder +FROM rust:1.96.1-bookworm AS builder WORKDIR /app diff --git a/docker-compose.yml b/docker-compose.yml index a2c843f..786a9bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: # retries: 5 happyview: - image: rust:1.93 + image: rust:1.96.1 working_dir: /app entrypoint: ["sh", "/scripts/entrypoint.sh"] command: cargo watch -x run diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..9403822 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.96.1" +components = ["clippy", "rustfmt"] diff --git a/src/admin/api_clients.rs b/src/admin/api_clients.rs index 891bd3f..3dcfd2e 100644 --- a/src/admin/api_clients.rs +++ b/src/admin/api_clients.rs @@ -41,13 +41,13 @@ pub(super) async fn create_api_client( // Generate the client key: "hvc_" + 32 random hex chars. let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let client_key = format!("hvc_{}", hex::encode(random_bytes)); // Generate the client secret for confidential clients only. let (client_secret, client_secret_hash) = if body.client_type == "confidential" { let mut secret_bytes = [0u8; 32]; - rand::rng().fill(&mut secret_bytes); + rand::rng().fill_bytes(&mut secret_bytes); let secret = format!("hvs_{}", hex::encode(secret_bytes)); let hash = hex::encode(Sha256::digest(secret.as_bytes())); (Some(secret), hash) @@ -70,7 +70,7 @@ pub(super) async fn create_api_client( state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&client_key) .bind(&client_secret_hash) @@ -188,7 +188,7 @@ pub(super) async fn list_api_clients( ) }; - let q = sqlx::query(&select_sql); + let q = crate::db::query(&select_sql); let q = if let Some(ref pid) = parent_filter { q.bind(pid) } else { @@ -249,7 +249,7 @@ pub(super) async fn get_api_client( state.db_backend, ); - let row = sqlx::query(&select_sql) + let row = crate::db::query(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -316,7 +316,7 @@ pub(super) async fn update_api_client( Option, i32, ); - let row: Option = sqlx::query_as(&select_sql) + let row: Option = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -366,7 +366,7 @@ pub(super) async fn update_api_client( state.db_backend, ); - sqlx::query(&update_sql) + crate::db::query(&update_sql) .bind(&name) .bind(&client_uri) .bind(&redirect_uris_json) @@ -438,7 +438,7 @@ pub(super) async fn update_api_client( "UPDATE happyview_api_clients SET is_active = 0, updated_at = ? WHERE parent_client_id = ? AND is_active = 1", state.db_backend, ); - let _ = sqlx::query(&deactivate_children_sql) + let _ = crate::db::query(&deactivate_children_sql) .bind(&now) .bind(&id) .execute(&state.db) @@ -448,7 +448,7 @@ pub(super) async fn update_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - if let Ok(children) = sqlx::query_as::<_, (String, String)>(&children_sql) + if let Ok(children) = crate::db::query_as::<(String, String)>(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -490,7 +490,7 @@ pub(super) async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE id = ?", state.db_backend, ); - let client_info: Option<(String, String)> = sqlx::query_as(&lookup_sql) + let client_info: Option<(String, String)> = crate::db::query_as(&lookup_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -501,7 +501,7 @@ pub(super) async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - let children: Vec<(String, String)> = sqlx::query_as(&children_sql) + let children: Vec<(String, String)> = crate::db::query_as(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -512,7 +512,7 @@ pub(super) async fn delete_api_client( state.db_backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -557,7 +557,7 @@ mod tests { #[test] fn test_client_key_prefix() { let mut random_bytes = [0u8; 16]; - rand::Rng::fill(&mut rand::rng(), &mut random_bytes); + rand::Rng::fill_bytes(&mut rand::rng(), &mut random_bytes); let key = format!("hvc_{}", hex::encode(random_bytes)); assert!(key.starts_with("hvc_")); assert_eq!(key.len(), 4 + 32); // "hvc_" + 32 hex chars diff --git a/src/admin/api_keys.rs b/src/admin/api_keys.rs index e46150c..6e5277a 100644 --- a/src/admin/api_keys.rs +++ b/src/admin/api_keys.rs @@ -41,7 +41,7 @@ pub(super) async fn create_api_key( // Generate the raw key: "hv_" + 32 random hex chars. let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let raw_key = format!("hv_{}", hex::encode(random_bytes)); // SHA-256 hash for storage. @@ -60,7 +60,7 @@ pub(super) async fn create_api_key( state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&auth.user_id) .bind(&body.name) @@ -118,7 +118,7 @@ pub(super) async fn list_api_keys( String, Option, Option, - )> = sqlx::query_as(&select_sql) + )> = crate::db::query_as(&select_sql) .bind(&auth.did) .fetch_all(&state.db) .await @@ -160,7 +160,7 @@ pub(super) async fn revoke_api_key( state.db_backend, ); - let result = sqlx::query(&update_sql) + let result = crate::db::query(&update_sql) .bind(&now) .bind(&id) .bind(&auth.did) diff --git a/src/admin/auth.rs b/src/admin/auth.rs index d6a1536..9801306 100644 --- a/src/admin/auth.rs +++ b/src/admin/auth.rs @@ -57,7 +57,7 @@ impl UserAuth { "SELECT permission FROM happyview_user_permissions WHERE user_id = ?", backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .bind(user_id) .fetch_all(db) .await @@ -110,7 +110,7 @@ impl FromRequestParts for UserAuth { let did = claims.did().to_string(); let backend = state.db_backend; - let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_users") + let count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_users") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("user count query failed: {e}")))?; @@ -125,7 +125,7 @@ impl FromRequestParts for UserAuth { backend, ); - let result = sqlx::query(&insert_sql) + let result = crate::db::query(&insert_sql) .bind(&id) .bind(&did) .bind(1_i32) @@ -139,7 +139,7 @@ impl FromRequestParts for UserAuth { backend, ); for perm in Permission::all() { - let _ = sqlx::query(&perm_sql) + let _ = crate::db::query(&perm_sql) .bind(&id) .bind(perm.as_str()) .bind(&now) @@ -168,7 +168,7 @@ impl FromRequestParts for UserAuth { "SELECT id, is_super FROM happyview_users WHERE did = ?", backend, ); - let found: Option<(String, i32)> = sqlx::query_as(&select_sql) + let found: Option<(String, i32)> = crate::db::query_as(&select_sql) .bind(&did) .fetch_optional(&state.db) .await @@ -193,7 +193,7 @@ impl FromRequestParts for UserAuth { backend, ); tokio::spawn(async move { - let _ = sqlx::query(&update_sql) + let _ = crate::db::query(&update_sql) .bind(&now) .bind(&uid) .execute(&db) @@ -239,7 +239,7 @@ impl UserAuth { backend, ); - let row: Option<(String, String, String, i32, String)> = sqlx::query_as(&select_sql) + let row: Option<(String, String, String, i32, String)> = crate::db::query_as(&select_sql) .bind(&hash) .fetch_optional(&state.db) .await @@ -272,7 +272,7 @@ impl UserAuth { backend, ); tokio::spawn(async move { - let _ = sqlx::query(&update_sql) + let _ = crate::db::query(&update_sql) .bind(&now) .bind(&key_id) .execute(&db) diff --git a/src/admin/backfill.rs b/src/admin/backfill.rs index 8c0844e..2f4e00f 100644 --- a/src/admin/backfill.rs +++ b/src/admin/backfill.rs @@ -12,7 +12,7 @@ use serde_json::Value; use tokio::sync::mpsc; use uuid::Uuid; -use rand::Rng; +use rand::RngExt; use crate::AppState; use crate::db::{adapt_sql, now_rfc3339}; @@ -62,7 +62,7 @@ async fn set_stage(state: &AppState, job_id: &str, stage: &str) { "UPDATE happyview_backfill_jobs SET stage = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(stage) .bind(job_id) .execute(&state.backfill_db) @@ -91,7 +91,7 @@ async fn update_job_counter(state: &AppState, job_id: &str, column: &str, value: } }; let sql = adapt_sql(query, state.db_backend); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(value) .bind(job_id) .execute(&state.backfill_db) @@ -103,7 +103,7 @@ async fn count_repos(state: &AppState, job_id: &str) -> i32 { "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ?", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -163,7 +163,7 @@ async fn fail_job(state: &AppState, job_id: &str, error: &str) { "UPDATE happyview_backfill_jobs SET status = 'failed', completed_at = ?, error = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(error) .bind(job_id) @@ -184,7 +184,7 @@ async fn should_stop(state: &AppState, job_id: &str) -> Option<&'static str> { "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let status = sqlx::query_as::<_, (String,)>(&sql) + let status = crate::db::query_as::<(String,)>(&sql) .bind(job_id) .fetch_optional(&state.backfill_db) .await @@ -207,7 +207,7 @@ async fn request_cancel(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'cancelling' WHERE id = ? AND status IN ('running', 'paused')", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -219,7 +219,7 @@ async fn finalise_cancel(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'cancelled', completed_at = ?, error = 'cancelled by user' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(job_id) .execute(&state.backfill_db) @@ -239,7 +239,7 @@ async fn request_pause(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'pausing' WHERE id = ? AND status = 'running'", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -250,7 +250,7 @@ async fn finalise_pause(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'paused' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -276,7 +276,7 @@ async fn complete_job( "UPDATE happyview_backfill_jobs SET status = 'completed', stage = 'completed', completed_at = ?, processed_repos = ?, total_records = ?, error = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(processed_repos) .bind(total_records) @@ -311,7 +311,7 @@ async fn run_discovery_phase( "INSERT INTO happyview_backfill_repos (job_id, did) VALUES (?, ?) ON CONFLICT DO NOTHING", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .bind(did) .execute(&state.backfill_db) @@ -422,7 +422,7 @@ async fn discover_repos_from_relay( placeholders.join(", ") ); - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); for repo in chunk { query = query.bind(job_id).bind(&repo.did); } @@ -475,7 +475,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND pds_endpoint IS NOT NULL", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -488,7 +488,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND status = 'completed'", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -504,7 +504,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT total_records FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - sqlx::query_as::<_, (Option,)>(&sql) + crate::db::query_as::<(Option,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -534,7 +534,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT did FROM happyview_backfill_repos WHERE job_id = ? AND pds_endpoint IS NULL", resolver_state.db_backend, ); - let unresolved: Vec<(String,)> = sqlx::query_as(&sql) + let unresolved: Vec<(String,)> = crate::db::query_as(&sql) .bind(&resolver_job_id) .fetch_all(&resolver_state.backfill_db) .await @@ -573,7 +573,7 @@ async fn run_pipelined_resolve_and_fetch( "UPDATE happyview_backfill_repos SET pds_endpoint = ? WHERE job_id = ? AND did = ?", resolver_state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&pds) .bind(&resolver_job_id) .bind(&did) @@ -647,7 +647,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT did, pds_endpoint FROM happyview_backfill_repos WHERE job_id = ? AND status = 'pending' AND pds_endpoint IS NOT NULL", state.db_backend, ); - let pending_rows: Vec<(String, String)> = sqlx::query_as(&pending_sql) + let pending_rows: Vec<(String, String)> = crate::db::query_as(&pending_sql) .bind(job_id) .fetch_all(&state.backfill_db) .await @@ -830,7 +830,7 @@ async fn run_pipelined_resolve_and_fetch( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(final_repos) .bind(final_records) .bind(job_id) @@ -877,7 +877,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(records) .bind(job_id.as_str()) .bind(&did) @@ -898,7 +898,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(repos) .bind(records) .bind(job_id.as_str()) @@ -976,7 +976,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(records) .bind(job_id.as_str()) .bind(&did) @@ -1014,7 +1014,7 @@ async fn run_fetching_phase( "SELECT did, pds_endpoint FROM happyview_backfill_repos WHERE job_id = ? AND status = 'pending' AND pds_endpoint IS NOT NULL", state.db_backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .bind(job_id) .fetch_all(&state.backfill_db) .await @@ -1030,7 +1030,7 @@ async fn run_fetching_phase( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND status = 'completed'", state.db_backend, ); - let already_completed: i32 = sqlx::query_as::<_, (i32,)>(&sql) + let already_completed: i32 = crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -1046,7 +1046,7 @@ async fn run_fetching_phase( "SELECT total_records FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - sqlx::query_as::<_, (Option,)>(&sql) + crate::db::query_as::<(Option,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -1130,7 +1130,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(did_records) .bind(job_id.as_str()) .bind(&did) @@ -1149,7 +1149,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(repos) .bind(records) .bind(job_id.as_str()) @@ -1183,7 +1183,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(final_repos) .bind(final_records) .bind(job_id) @@ -1220,7 +1220,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { ); let sql = adapt_sql(&raw_sql, backend); - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); for rec in batch { query = query .bind(&rec.uri) @@ -1245,7 +1245,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { delete_placeholders.join(", ") ); let delete_sql = adapt_sql(&delete_raw, backend); - let mut del_query = sqlx::query(&delete_sql); + let mut del_query = crate::db::query(&delete_sql); for uri in &uris { del_query = del_query.bind(*uri); } @@ -1269,7 +1269,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { ref_placeholders.join(", ") ); let ref_sql = adapt_sql(&ref_raw, backend); - let mut ref_query = sqlx::query(&ref_sql); + let mut ref_query = crate::db::query(&ref_sql); for (source, target, collection) in chunk { ref_query = ref_query.bind(*source).bind(target).bind(*collection); } @@ -1278,7 +1278,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { // Queue label backfill only if there are active labeler subscriptions. // Check once per batch instead of spawning a task per record. - let has_subscriptions: bool = sqlx::query_as::<_, (i64,)>( + let has_subscriptions: bool = crate::db::query_as::<(i64,)>( "SELECT COUNT(*) FROM happyview_labeler_subscriptions WHERE status = 'active'", ) .fetch_one(&state.db) @@ -1398,7 +1398,7 @@ async fn run_backfill_job(state: AppState, job_id: String) { "SELECT collection, did, stage FROM happyview_backfill_jobs WHERE id = ?", backend, ); - let job: Option<(Option, Option, String)> = sqlx::query_as(&sql) + let job: Option<(Option, Option, String)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1428,7 +1428,10 @@ async fn run_backfill_job(state: AppState, job_id: String) { "SELECT id FROM happyview_lexicons WHERE json_extract(lexicon_json, '$.defs.main.type') = 'record'", backend, ); - let rows: Vec<(String,)> = match sqlx::query_as(&sql).fetch_all(&state.backfill_db).await { + let rows: Vec<(String,)> = match crate::db::query_as(&sql) + .fetch_all(&state.backfill_db) + .await + { Ok(rows) => rows, Err(e) => { let error = format!("failed to query backfill-eligible lexicons: {e}"); @@ -1556,7 +1559,7 @@ pub(super) async fn create_backfill( "INSERT INTO happyview_backfill_jobs (id, collection, did, status, stage, started_at, created_at) VALUES (?, ?, ?, 'running', 'pending', ?, ?) RETURNING id", backend, ); - let row: (String,) = sqlx::query_as(&sql) + let row: (String,) = crate::db::query_as(&sql) .bind(&job_id) .bind(&body.collection) .bind(&body.did) @@ -1610,7 +1613,7 @@ pub(super) async fn cancel_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.db) .await @@ -1675,7 +1678,7 @@ pub(super) async fn pause_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1722,7 +1725,7 @@ pub(super) async fn resume_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1738,7 +1741,7 @@ pub(super) async fn resume_backfill( "UPDATE happyview_backfill_jobs SET status = 'running' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&job_id) .execute(&state.backfill_db) .await; @@ -1795,7 +1798,7 @@ pub(super) async fn backfill_status( Option, Option, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.backfill_db) .await .map_err(|e| AppError::Internal(format!("failed to list backfill jobs: {e}")))?; @@ -1925,7 +1928,7 @@ pub(super) async fn backfill_repos( ); let sql = adapt_sql(&sql_str, state.db_backend); - let mut q = sqlx::query_as::<_, (String, Option, String, i32)>(&sql).bind(&job_id); + let mut q = crate::db::query_as::<(String, Option, String, i32)>(&sql).bind(&job_id); if let Some(ref cursor) = query.cursor { q = q.bind(cursor); } @@ -1971,7 +1974,7 @@ pub(super) async fn backfill_pds_summary( state.db_backend, ); - let rows: Vec<(String, i32, i32, i64)> = sqlx::query_as(&sql) + let rows: Vec<(String, i32, i32, i64)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_all(&state.backfill_db) .await @@ -2009,7 +2012,7 @@ pub(super) async fn flush_backfill_details( "DELETE FROM happyview_backfill_repos WHERE job_id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&job_id) .execute(&state.backfill_db) .await; @@ -2027,7 +2030,7 @@ pub(super) async fn flush_all_backfill_details( "DELETE FROM happyview_backfill_repos WHERE job_id IN (SELECT id FROM happyview_backfill_jobs WHERE status IN ('completed', 'cancelled', 'failed'))", state.db_backend, ); - let _ = sqlx::query(&sql).execute(&state.backfill_db).await; + let _ = crate::db::query(&sql).execute(&state.backfill_db).await; Ok(StatusCode::NO_CONTENT) } @@ -2064,7 +2067,7 @@ pub async fn run_backfill_retention_cleanup(state: &AppState) { "DELETE FROM happyview_backfill_repos WHERE job_id IN (SELECT id FROM happyview_backfill_jobs WHERE completed_at IS NOT NULL AND completed_at < ?)", state.db_backend, ); - match sqlx::query(&sql) + match crate::db::query(&sql) .bind(&cutoff_str) .execute(&state.backfill_db) .await @@ -2097,7 +2100,7 @@ pub async fn resume_backfill_jobs(state: &AppState) { "SELECT id, status FROM happyview_backfill_jobs WHERE status IN ('running', 'cancelling', 'pausing')", state.db_backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .fetch_all(&state.backfill_db) .await .unwrap_or_default(); diff --git a/src/admin/dead_letters.rs b/src/admin/dead_letters.rs index 8838727..774af84 100644 --- a/src/admin/dead_letters.rs +++ b/src/admin/dead_letters.rs @@ -224,7 +224,7 @@ pub(super) async fn count( &format!("SELECT COUNT(*) FROM {table} WHERE 1=1{resolved_clause}{collection_clause}"), backend, ); - let mut q = sqlx::query_as::<_, (i64,)>(&sql); + let mut q = crate::db::query_as::<(i64,)>(&sql); if let Some(ref c) = query.collection { q = q.bind(c); } @@ -303,7 +303,7 @@ pub(super) async fn bulk_dismiss( sql.push_str(" AND collection = ?"); } let sql = adapt_sql(&sql, backend); - let mut q = sqlx::query(&sql).bind(&now); + let mut q = crate::db::query(&sql).bind(&now); if let Some(ref c) = body.collection { q = q.bind(c); } @@ -383,22 +383,19 @@ async fn list_legacy( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - String, - String, - String, - String, - String, - i64, - String, - Option, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + String, + String, + String, + String, + String, + i64, + String, + Option, + )>(&sql); if let Some(c) = collection { q = q.bind(c); } @@ -457,20 +454,17 @@ async fn list_scripts( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - i64, - String, - String, - String, - String, - String, - i64, - String, - Option, - ), - >(&sql); + let mut q = crate::db::query_as::<( + i64, + String, + String, + String, + String, + String, + i64, + String, + Option, + )>(&sql); if let Some(c) = collection { q = q.bind(c); } @@ -595,7 +589,7 @@ async fn detail_legacy(state: &AppState, id: &str) -> Result, Option, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -642,7 +636,7 @@ async fn detail_scripts(state: &AppState, id: &str) -> Result, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id_int) .fetch_optional(&state.db) .await @@ -703,7 +697,7 @@ async fn fetch_dead_letter_for_action( Option, String, i64, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -731,7 +725,7 @@ async fn fetch_dead_letter_for_action( WHERE id = ? AND resolved_at IS NULL", backend, ); - let row: (i64, String, String) = sqlx::query_as(&sql) + let row: (i64, String, String) = crate::db::query_as(&sql) .bind(id_int) .fetch_optional(&state.db) .await @@ -781,7 +775,7 @@ async fn mark_resolved( &format!("UPDATE {table} SET resolved_at = ? WHERE id = ?"), backend, ); - let q = sqlx::query(&sql).bind(&now); + let q = crate::db::query(&sql).bind(&now); let q = match source { // Scripts table has INTEGER ids; bind as i64 to avoid sqlite's // implicit-conversion quirks. @@ -810,7 +804,7 @@ async fn update_error( &format!("UPDATE {table} SET error = ?, attempts = attempts + 1 WHERE id = ?"), backend, ); - let q = sqlx::query(&sql).bind(error); + let q = crate::db::query(&sql).bind(error); let q = match source { DeadLetterSource::Scripts => q.bind(id.parse::().unwrap_or(0)), DeadLetterSource::LegacyHooks => q.bind(id), @@ -833,7 +827,7 @@ async fn resolve_bulk_ids(state: &AppState, body: &BulkRequest) -> Result(&sql); + let mut q = crate::db::query_as::<(String,)>(&sql); if let Some(ref c) = body.collection { q = q.bind(c); } @@ -851,7 +845,7 @@ async fn resolve_bulk_ids(state: &AppState, body: &BulkRequest) -> Result(&sql); + let mut q = crate::db::query_as::<(i64,)>(&sql); if let Some(ref c) = body.collection { q = q.bind(c); } diff --git a/src/admin/domains.rs b/src/admin/domains.rs index 7b2c9bc..a4cb02e 100644 --- a/src/admin/domains.rs +++ b/src/admin/domains.rs @@ -33,7 +33,7 @@ pub(super) async fn list( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains ORDER BY created_at", state.db_backend, ); - let rows: Vec<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, i32, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list domains: {e}")))?; @@ -84,7 +84,7 @@ pub(super) async fn create( } // Check for duplicates - let existing: Option<(String,)> = sqlx::query_as(&adapt_sql( + let existing: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT id FROM happyview_domains WHERE url = ?", state.db_backend, )) @@ -106,7 +106,7 @@ pub(super) async fn create( "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, 0, ?, ?)", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(&url) .bind(&now) @@ -198,7 +198,7 @@ pub(super) async fn delete( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains WHERE id = ?", state.db_backend, ); - let row: Option<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, i32, String, String)> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -217,7 +217,7 @@ pub(super) async fn delete( "DELETE FROM happyview_domains WHERE id = ?", state.db_backend, ); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -264,7 +264,7 @@ pub(super) async fn set_primary( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains WHERE id = ?", state.db_backend, ); - let row: Option<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, i32, String, String)> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -278,7 +278,7 @@ pub(super) async fn set_primary( "UPDATE happyview_domains SET is_primary = 0, updated_at = ? WHERE is_primary = 1", state.db_backend, ); - sqlx::query(&unset_sql) + crate::db::query(&unset_sql) .bind(&now) .execute(&state.db) .await @@ -288,7 +288,7 @@ pub(super) async fn set_primary( "UPDATE happyview_domains SET is_primary = 1, updated_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&set_sql) + crate::db::query(&set_sql) .bind(&now) .bind(&id) .execute(&state.db) diff --git a/src/admin/events.rs b/src/admin/events.rs index a051293..e248efa 100644 --- a/src/admin/events.rs +++ b/src/admin/events.rs @@ -82,18 +82,15 @@ pub(super) async fn list_events( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - Option, - Option, - String, - String, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + Option, + Option, + String, + String, + )>(&sql); if let Some(ref event_type) = query.event_type { q = q.bind(event_type); diff --git a/src/admin/labelers.rs b/src/admin/labelers.rs index 0aa9bf6..0582616 100644 --- a/src/admin/labelers.rs +++ b/src/admin/labelers.rs @@ -23,7 +23,7 @@ pub(super) async fn list( "SELECT did, status, cursor, created_at, updated_at FROM happyview_labeler_subscriptions ORDER BY created_at", backend, ); - let rows: Vec<(String, String, Option, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, Option, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list labeler subscriptions: {e}")))?; @@ -62,7 +62,7 @@ pub(super) async fn add( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.did) .bind(&now) .bind(&now) @@ -104,7 +104,7 @@ pub(super) async fn update( "UPDATE happyview_labeler_subscriptions SET status = ?, updated_at = ? WHERE did = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&body.status) .bind(&now) .bind(&did) @@ -149,7 +149,7 @@ pub(super) async fn delete( "DELETE FROM happyview_labeler_subscriptions WHERE did = ?", backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&did) .execute(&state.db) .await @@ -163,7 +163,7 @@ pub(super) async fn delete( // Also remove all labels from this labeler. let delete_labels_sql = adapt_sql("DELETE FROM happyview_labels WHERE src = ?", backend); - let _ = sqlx::query(&delete_labels_sql) + let _ = crate::db::query(&delete_labels_sql) .bind(&did) .execute(&state.db) .await; diff --git a/src/admin/lexicons.rs b/src/admin/lexicons.rs index 054d94d..aceff54 100644 --- a/src/admin/lexicons.rs +++ b/src/admin/lexicons.rs @@ -86,7 +86,7 @@ pub(super) async fn upload_lexicon( "#, backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = crate::db::query_as(&sql) .bind(&id) .bind(&lexicon_json_str) .bind(if body.backfill { 1_i32 } else { 0_i32 }) @@ -178,7 +178,7 @@ pub(super) async fn list_lexicons( String, String, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list lexicons: {e}")))?; @@ -260,7 +260,7 @@ pub(super) async fn get_lexicon( String, String, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -319,7 +319,7 @@ pub(super) async fn delete_lexicon( auth.require(Permission::LexiconsDelete).await?; let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_lexicons WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .execute(&state.db) .await diff --git a/src/admin/network_lexicons.rs b/src/admin/network_lexicons.rs index ca7d43c..64b1d29 100644 --- a/src/admin/network_lexicons.rs +++ b/src/admin/network_lexicons.rs @@ -96,7 +96,7 @@ pub(super) async fn add( "#, backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = crate::db::query_as(&sql) .bind(nsid) .bind(&lexicon_json_str) .bind(&body.target_collection) @@ -156,7 +156,7 @@ pub(super) async fn list( Option, Option, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list network lexicons: {e}")))?; @@ -192,7 +192,7 @@ pub(super) async fn remove( "DELETE FROM happyview_lexicons WHERE id = ? AND source = 'network'", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&nsid) .execute(&state.db) .await diff --git a/src/admin/plugins.rs b/src/admin/plugins.rs index 59df06b..4d11721 100644 --- a/src/admin/plugins.rs +++ b/src/admin/plugins.rs @@ -93,7 +93,7 @@ pub(super) async fn list( "SELECT plugin_id FROM happyview_plugin_configs WHERE config IS NOT NULL", state.db_backend, ); - sqlx::query_scalar::<_, String>(&sql) + crate::db::query_scalar::(&sql) .fetch_all(&state.db) .await .unwrap_or_default() @@ -312,7 +312,7 @@ pub(super) async fn remove( "DELETE FROM happyview_plugins WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin_id) .execute(&state.db) .await @@ -404,7 +404,7 @@ pub(super) async fn reload( "SELECT 1 FROM happyview_plugin_configs WHERE plugin_id = ?", state.db_backend, ); - sqlx::query_scalar::<_, i32>(&sql) + crate::db::query_scalar::(&sql) .bind(&plugin.info.id) .fetch_optional(&state.db) .await @@ -435,7 +435,7 @@ pub(super) async fn reload( "UPDATE happyview_plugins SET url = ?, sha256 = NULL WHERE id = ?", state.db_backend, ); - sqlx::query(&persist_sql) + crate::db::query(&persist_sql) .bind(&url) .bind(&plugin.info.id) .execute(&state.db) @@ -488,7 +488,7 @@ pub(super) async fn get_secrets( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&plugin_id) .fetch_optional(&state.db) .await @@ -558,7 +558,7 @@ pub(super) async fn update_secrets( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&plugin_id) .fetch_optional(&state.db) .await @@ -613,7 +613,7 @@ pub(super) async fn update_secrets( state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin_id) .bind(&config_json) .bind(now_rfc3339()) diff --git a/src/admin/proxy_config.rs b/src/admin/proxy_config.rs index 4b1f4e6..1ed87d9 100644 --- a/src/admin/proxy_config.rs +++ b/src/admin/proxy_config.rs @@ -55,7 +55,7 @@ pub(super) async fn put( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(SETTING_KEY) .bind(&json) .bind(&now) diff --git a/src/admin/records.rs b/src/admin/records.rs index 36a1887..9cfa6ad 100644 --- a/src/admin/records.rs +++ b/src/admin/records.rs @@ -80,7 +80,7 @@ pub(super) async fn list_records( "SELECT uri, did, collection, rkey, cid, indexed_at, record FROM happyview_records WHERE collection = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(¶ms.collection) .bind(limit + 1) .bind(offset) @@ -106,7 +106,7 @@ pub(super) async fn list_records( "SELECT uri, src, val, cts FROM happyview_labels WHERE uri IN ({ph_str}) AND (exp IS NULL OR exp > ?)" ); let sql = adapt_sql(&raw_sql, backend); - let mut q = sqlx::query_as(&sql); + let mut q = crate::db::query_as(&sql); for uri in &uris { q = q.bind(*uri); } @@ -190,7 +190,7 @@ pub(super) async fn delete_collection_records( "DELETE FROM happyview_records WHERE collection = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(¶ms.collection) .execute(&state.db) .await @@ -210,7 +210,7 @@ pub(super) async fn delete_record( auth.require(Permission::RecordsDelete).await?; let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(¶ms.uri) .execute(&state.db) .await @@ -234,7 +234,7 @@ pub(super) async fn list_collections( "SELECT id FROM happyview_lexicons WHERE json_extract(lexicon_json, '$.defs.main.type') = 'record' ORDER BY id", state.db_backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list collections: {e}")))?; diff --git a/src/admin/script_variables.rs b/src/admin/script_variables.rs index 5c71e5c..11e53d6 100644 --- a/src/admin/script_variables.rs +++ b/src/admin/script_variables.rs @@ -23,7 +23,7 @@ pub(super) async fn list( "SELECT key, value, created_at, updated_at FROM happyview_script_variables ORDER BY key", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list script variables: {e}")))?; @@ -62,7 +62,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.key) .bind(&body.value) .bind(&now) @@ -101,7 +101,7 @@ pub(super) async fn delete( "DELETE FROM happyview_script_variables WHERE key = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&key) .execute(&state.db) .await diff --git a/src/admin/scripts.rs b/src/admin/scripts.rs index 8a25d71..def2ce4 100644 --- a/src/admin/scripts.rs +++ b/src/admin/scripts.rs @@ -116,18 +116,15 @@ pub(super) async fn list( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - Option, - Option, - String, - String, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + Option, + Option, + String, + String, + )>(&sql); if let Some(ref suffix) = query.suffix { q = q.bind(format!("%:{suffix}")); } @@ -207,7 +204,7 @@ pub(super) async fn upsert( let description = body.description.as_deref().filter(|s| !s.is_empty()); // Distinguish create vs update so we can return 201 vs 200. - let pre_exists: Option<(String,)> = sqlx::query_as(&adapt_sql( + let pre_exists: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT id FROM happyview_scripts WHERE id = ?", backend, )) @@ -230,7 +227,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.id) .bind(script_type.as_str()) .bind(&body.body) @@ -343,7 +340,7 @@ pub(super) async fn patch( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&new_script_type) .bind(&new_body) .bind(new_description.as_deref()) @@ -384,7 +381,7 @@ pub(super) async fn delete( let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_scripts WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .execute(&state.db) .await @@ -429,7 +426,7 @@ async fn fetch_one(state: &AppState, id: &str) -> Result, String, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await diff --git a/src/admin/service_entries.rs b/src/admin/service_entries.rs index 097f905..7bdfcc7 100644 --- a/src/admin/service_entries.rs +++ b/src/admin/service_entries.rs @@ -263,7 +263,7 @@ pub(super) async fn sync_plc( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&rotation_key_enc_sql) + let row: Option<(Option,)> = crate::db::query_as(&rotation_key_enc_sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -272,7 +272,7 @@ pub(super) async fn sync_plc( .ok_or_else(|| AppError::Internal("no rotation key stored".into()))?; let rotation_key_bytes = crate::plc::decrypt_key(&rotation_key_enc, encryption_key)?; let rotation_signing_key = - p256::ecdsa::SigningKey::from_bytes(rotation_key_bytes.as_slice().into()) + p256::ecdsa::SigningKey::from_slice(rotation_key_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid rotation key: {e}")))?; let signed = crate::plc::sign_operation(&unsigned, &rotation_signing_key)?; @@ -313,7 +313,7 @@ pub(super) async fn sync_plc_request( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -377,7 +377,7 @@ pub(super) async fn sync_plc_submit( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; diff --git a/src/admin/settings.rs b/src/admin/settings.rs index 848fe90..00d8b00 100644 --- a/src/admin/settings.rs +++ b/src/admin/settings.rs @@ -40,7 +40,7 @@ pub async fn get_setting(pool: &AnyPool, key: &str, backend: DatabaseBackend) -> "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(key) .fetch_optional(pool) .await @@ -73,7 +73,7 @@ pub(super) async fn list( "SELECT key, value FROM happyview_instance_settings ORDER BY key", backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list settings: {e}")))?; @@ -124,7 +124,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&key) .bind(&body.value) .bind(&now) @@ -163,7 +163,7 @@ pub(super) async fn delete( "DELETE FROM happyview_instance_settings WHERE key = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&key) .execute(&state.db) .await @@ -197,7 +197,7 @@ pub(super) async fn db_info( auth.require(Permission::SettingsManage).await?; let server_max: Option = if state.db_backend == DatabaseBackend::Postgres { - sqlx::query_as::<_, (String,)>("SHOW max_connections") + crate::db::query_as::<(String,)>("SHOW max_connections") .fetch_optional(&state.db) .await .ok() @@ -290,7 +290,7 @@ pub(super) async fn upload_logo( ("logo_data", encoded.as_str()), ("logo_content_type", content_type.as_str()), ] { - sqlx::query(&sql) + crate::db::query(&sql) .bind(key) .bind(value) .bind(&now) @@ -329,7 +329,7 @@ pub(super) async fn delete_logo( "DELETE FROM happyview_instance_settings WHERE key IN (?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind("logo_data") .bind("logo_content_type") .execute(&state.db) @@ -361,7 +361,7 @@ pub(crate) async fn serve_logo( "SELECT key, value FROM happyview_instance_settings WHERE key IN (?, ?)", backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .bind("logo_data") .bind("logo_content_type") .fetch_all(&state.db) diff --git a/src/admin/stats.rs b/src/admin/stats.rs index 461c40b..a14060a 100644 --- a/src/admin/stats.rs +++ b/src/admin/stats.rs @@ -15,7 +15,7 @@ pub(super) async fn stats( auth: UserAuth, ) -> Result, AppError> { auth.require(Permission::StatsRead).await?; - let total: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_records") + let total: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_records") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to count records: {e}")))?; @@ -35,7 +35,7 @@ pub(super) async fn stats( state.db_backend, ); - let collections: Vec<(String, i64)> = sqlx::query_as(&collection_sql) + let collections: Vec<(String, i64)> = crate::db::query_as(&collection_sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to count by collection: {e}")))?; diff --git a/src/admin/users.rs b/src/admin/users.rs index cf82b98..197febf 100644 --- a/src/admin/users.rs +++ b/src/admin/users.rs @@ -64,7 +64,7 @@ pub(super) async fn create_user( backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&user_id) .bind(&body.did) .bind(0_i32) @@ -79,7 +79,7 @@ pub(super) async fn create_user( ); for perm_str in &perms_to_grant { - sqlx::query(&perm_sql) + crate::db::query(&perm_sql) .bind(&user_id) .bind(perm_str) .bind(&auth.user_id) @@ -133,7 +133,7 @@ pub(super) async fn list_users( backend, ); - let rows: Vec<(String, String, i32, String, Option)> = sqlx::query_as(&select_sql) + let rows: Vec<(String, String, i32, String, Option)> = crate::db::query_as(&select_sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list users: {e}")))?; @@ -145,7 +145,7 @@ pub(super) async fn list_users( let mut users = Vec::new(); for (id, did, is_super_int, created_at, last_used_at) in rows { - let perm_rows: Vec<(String,)> = sqlx::query_as(&perm_sql) + let perm_rows: Vec<(String,)> = crate::db::query_as(&perm_sql) .bind(&id) .fetch_all(&state.db) .await @@ -179,11 +179,12 @@ pub(super) async fn get_user( backend, ); - let found: Option<(String, String, i32, String, Option)> = sqlx::query_as(&select_sql) - .bind(&id) - .fetch_optional(&state.db) - .await - .map_err(|e| AppError::Internal(format!("failed to get user: {e}")))?; + let found: Option<(String, String, i32, String, Option)> = + crate::db::query_as(&select_sql) + .bind(&id) + .fetch_optional(&state.db) + .await + .map_err(|e| AppError::Internal(format!("failed to get user: {e}")))?; let Some((uid, did, is_super_int, created_at, last_used_at)) = found else { return Err(AppError::NotFound(format!("user '{id}' not found"))); @@ -194,7 +195,7 @@ pub(super) async fn get_user( backend, ); - let perm_rows: Vec<(String,)> = sqlx::query_as(&perm_sql) + let perm_rows: Vec<(String,)> = crate::db::query_as(&perm_sql) .bind(&uid) .fetch_all(&state.db) .await @@ -230,7 +231,7 @@ pub(super) async fn update_permissions( // Cannot modify super user's permissions let select_sql = adapt_sql("SELECT is_super FROM happyview_users WHERE id = ?", backend); - let target: Option<(i32,)> = sqlx::query_as(&select_sql) + let target: Option<(i32,)> = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -281,7 +282,7 @@ pub(super) async fn update_permissions( ); for perm_str in &body.grant { - sqlx::query(&grant_sql) + crate::db::query(&grant_sql) .bind(&id) .bind(perm_str) .bind(&auth.user_id) @@ -297,7 +298,7 @@ pub(super) async fn update_permissions( ); for perm_str in &body.revoke { - sqlx::query(&revoke_sql) + crate::db::query(&revoke_sql) .bind(&id) .bind(perm_str) .execute(&state.db) @@ -341,7 +342,7 @@ pub(super) async fn delete_user( // Cannot delete super user let select_sql = adapt_sql("SELECT is_super FROM happyview_users WHERE id = ?", backend); - let target: Option<(i32,)> = sqlx::query_as(&select_sql) + let target: Option<(i32,)> = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -363,7 +364,7 @@ pub(super) async fn delete_user( backend, ); - sqlx::query(&revoke_keys_sql) + crate::db::query(&revoke_keys_sql) .bind(&now) .bind(&id) .execute(&state.db) @@ -372,7 +373,7 @@ pub(super) async fn delete_user( let delete_sql = adapt_sql("DELETE FROM happyview_users WHERE id = ?", backend); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -428,7 +429,7 @@ pub(super) async fn transfer_super( "UPDATE happyview_users SET is_super = ? WHERE id = ?", backend, ); - let result = sqlx::query(&set_super_sql) + let result = crate::db::query(&set_super_sql) .bind(1_i32) .bind(&body.target_user_id) .execute(&mut *tx) @@ -449,7 +450,7 @@ pub(super) async fn transfer_super( "UPDATE happyview_users SET is_super = ? WHERE id = ?", backend, ); - sqlx::query(&remove_super_sql) + crate::db::query(&remove_super_sql) .bind(0_i32) .bind(&auth.user_id) .execute(&mut *tx) @@ -464,7 +465,7 @@ pub(super) async fn transfer_super( ); for perm in Permission::all() { - sqlx::query(&perm_sql) + crate::db::query(&perm_sql) .bind(&body.target_user_id) .bind(perm.as_str()) .bind(&auth.user_id) diff --git a/src/auth/client_registry.rs b/src/auth/client_registry.rs index 7062772..e00c1f4 100644 --- a/src/auth/client_registry.rs +++ b/src/auth/client_registry.rs @@ -247,7 +247,7 @@ impl OAuthClientRegistry { ); let rows: Vec<(String, String, String, String)> = - match sqlx::query_as(&sql).fetch_all(db).await { + match crate::db::query_as(&sql).fetch_all(db).await { Ok(r) => r, Err(e) => { tracing::error!("Failed to load API clients from database: {e}"); diff --git a/src/auth/middleware.rs b/src/auth/middleware.rs index aecc3df..cdcebb0 100644 --- a/src/auth/middleware.rs +++ b/src/auth/middleware.rs @@ -158,7 +158,7 @@ async fn resolve_api_key_did(state: &AppState, token: &str) -> Result = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&hash) .fetch_optional(&state.db) .await diff --git a/src/auth/oauth_store.rs b/src/auth/oauth_store.rs index 6b548b9..3bb216b 100644 --- a/src/auth/oauth_store.rs +++ b/src/auth/oauth_store.rs @@ -62,7 +62,7 @@ impl Store for DbSessionStore { type Error = StoreError; async fn get(&self, key: &Did) -> Result, Self::Error> { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT session_data FROM happyview_oauth_sessions WHERE did = ?", self.backend, )) @@ -78,7 +78,7 @@ impl Store for DbSessionStore { async fn set(&self, key: Did, value: Session) -> Result<(), Self::Error> { let json = serde_json::to_string(&value)?; - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "INSERT INTO happyview_oauth_sessions (did, session_data, updated_at) VALUES (?, ?, datetime('now')) ON CONFLICT (did) DO UPDATE SET session_data = EXCLUDED.session_data, updated_at = datetime('now')", self.backend, @@ -91,7 +91,7 @@ impl Store for DbSessionStore { } async fn del(&self, key: &Did) -> Result<(), Self::Error> { - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "DELETE FROM happyview_oauth_sessions WHERE did = ?", self.backend, )) @@ -102,7 +102,7 @@ impl Store for DbSessionStore { } async fn clear(&self) -> Result<(), Self::Error> { - sqlx::query("DELETE FROM happyview_oauth_sessions") + crate::db::query("DELETE FROM happyview_oauth_sessions") .execute(&self.pool) .await?; Ok(()) @@ -145,7 +145,7 @@ impl Store for DbStateStore { type Error = StoreError; async fn get(&self, key: &String) -> Result, Self::Error> { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT state_data FROM happyview_oauth_state WHERE state_key = ?", self.backend, )) @@ -161,7 +161,7 @@ impl Store for DbStateStore { async fn set(&self, key: String, value: InternalStateData) -> Result<(), Self::Error> { let json = serde_json::to_string(&value)?; - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "INSERT INTO happyview_oauth_state (state_key, state_data) VALUES (?, ?) ON CONFLICT (state_key) DO UPDATE SET state_data = EXCLUDED.state_data", self.backend, @@ -175,7 +175,7 @@ impl Store for DbStateStore { } async fn del(&self, key: &String) -> Result<(), Self::Error> { - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "DELETE FROM happyview_oauth_state WHERE state_key = ?", self.backend, )) @@ -186,7 +186,7 @@ impl Store for DbStateStore { } async fn clear(&self) -> Result<(), Self::Error> { - sqlx::query("DELETE FROM happyview_oauth_state") + crate::db::query("DELETE FROM happyview_oauth_state") .execute(&self.pool) .await?; Ok(()) diff --git a/src/auth/routes.rs b/src/auth/routes.rs index 5d2ad8c..90d2c2c 100644 --- a/src/auth/routes.rs +++ b/src/auth/routes.rs @@ -140,7 +140,7 @@ async fn login( "INSERT INTO happyview_auth_login_redirects (state, redirect_uri, client_id, created_at, expires_at) VALUES (?, ?, ?, ?, ?)", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&oauth_state) .bind(redirect_uri) .bind(effective_client_id.as_deref()) @@ -178,7 +178,7 @@ async fn callback( state.db_backend, ); let now = now_rfc3339(); - let row: Option<(String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, Option)> = crate::db::query_as(&sql) .bind(oauth_state) .bind(&now) .fetch_optional(&state.db) @@ -191,7 +191,7 @@ async fn callback( "DELETE FROM happyview_auth_login_redirects WHERE state = ?", state.db_backend, ); - let _ = sqlx::query(&delete_sql) + let _ = crate::db::query(&delete_sql) .bind(oauth_state) .execute(&state.db) .await; @@ -234,13 +234,13 @@ async fn callback( // Allow login when no users exist yet (first user will be bootstrapped as admin). // Also allow login for the configured attached account DID (setup attach-auth flow). // Otherwise, only allow users already in the users table. - let user_count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_users") + let user_count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_users") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("user count query failed: {e}")))?; if user_count.0 > 0 { - let user_exists: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let user_exists: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", state.db_backend, )) @@ -251,7 +251,7 @@ async fn callback( if user_exists.is_none() { // Allow login if this DID is the configured attached account (setup flow) - let is_attached_account: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let is_attached_account: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_service_identity WHERE attached_account_did = ?", state.db_backend, )) @@ -279,7 +279,7 @@ async fn callback( "SELECT client_key FROM happyview_api_clients WHERE client_id_url = ? AND is_active = 1", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(cid) .fetch_optional(&state.db) .await @@ -376,7 +376,7 @@ async fn me( let did = raw.split('\n').next().unwrap_or(&raw).to_string(); let backend = state.db_backend; - let user: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let user: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", backend, )) diff --git a/src/auth/service_auth.rs b/src/auth/service_auth.rs index 7edaaa8..b0254d7 100644 --- a/src/auth/service_auth.rs +++ b/src/auth/service_auth.rs @@ -268,15 +268,14 @@ fn verify_es256(msg: &[u8], sig_bytes: &[u8], key_bytes: &[u8]) -> bool { return false; }; - if let Ok(sig) = P256Signature::from_bytes(sig_bytes.into()) + if let Ok(sig) = P256Signature::from_slice(sig_bytes) && verifying_key.verify(msg, &sig).is_ok() { return true; } - if let Ok(sig) = P256Signature::from_bytes(sig_bytes.into()) - && let Some(normalized) = sig.normalize_s() - && verifying_key.verify(msg, &normalized).is_ok() + if let Ok(sig) = P256Signature::from_slice(sig_bytes) + && verifying_key.verify(msg, &sig.normalize_s()).is_ok() { return true; } @@ -316,15 +315,14 @@ fn verify_es256k(msg: &[u8], sig_bytes: &[u8], key_bytes: &[u8]) -> bool { return false; }; - if let Ok(sig) = K256Signature::from_bytes(sig_bytes.into()) + if let Ok(sig) = K256Signature::from_slice(sig_bytes) && verifying_key.verify(msg, &sig).is_ok() { return true; } - if let Ok(sig) = K256Signature::from_bytes(sig_bytes.into()) - && let Some(normalized) = sig.normalize_s() - && verifying_key.verify(msg, &normalized).is_ok() + if let Ok(sig) = K256Signature::from_slice(sig_bytes) + && verifying_key.verify(msg, &sig.normalize_s()).is_ok() { return true; } diff --git a/src/db.rs b/src/db.rs index a4a6938..e381034 100644 --- a/src/db.rs +++ b/src/db.rs @@ -3,11 +3,48 @@ use chrono::{DateTime, Utc}; use regex::Regex; use serde::Deserialize; use sqlx::AnyPool; +use sqlx::any::{AnyArguments, AnyRow}; use sqlx::migrate::Migrator; use sqlx::pool::PoolOptions; +use sqlx::query::{Query, QueryAs, QueryScalar}; +use sqlx::{Any, AssertSqlSafe, FromRow}; +use sqlx::{query as sqlx_query, query_as as sqlx_query_as, query_scalar as sqlx_query_scalar}; use std::path::Path; use std::sync::LazyLock; +// --------------------------------------------------------------------------- +// SQL query helpers (sqlx 0.9 `SqlSafeStr`) +// --------------------------------------------------------------------------- +// +// sqlx 0.9 requires the SQL passed to `query*` to implement `SqlSafeStr`, which +// only `&'static str` satisfies directly — runtime strings must be wrapped in +// `AssertSqlSafe`. HappyView builds every query from a static SQLite template +// run through `adapt_sql` (only bound `?` placeholders vary; no user input is +// concatenated into the SQL), so the strings are safe to assert. Routing all +// dynamic queries through these three helpers keeps that assertion in one +// audited place instead of at ~460 call sites. Backend is always `Any`. + +/// `sqlx::query` for a runtime-built (adapted) SQL string. +pub fn query<'q>(sql: &str) -> Query<'q, Any, AnyArguments> { + sqlx_query(AssertSqlSafe(sql.to_owned())) +} + +/// `sqlx::query_as` for a runtime-built (adapted) SQL string. +pub fn query_as<'q, O>(sql: &str) -> QueryAs<'q, Any, O, AnyArguments> +where + O: for<'r> FromRow<'r, AnyRow>, +{ + sqlx_query_as(AssertSqlSafe(sql.to_owned())) +} + +/// `sqlx::query_scalar` for a runtime-built (adapted) SQL string. +pub fn query_scalar<'q, O>(sql: &str) -> QueryScalar<'q, Any, O, AnyArguments> +where + (O,): for<'r> FromRow<'r, AnyRow>, +{ + sqlx_query_scalar(AssertSqlSafe(sql.to_owned())) +} + /// Database backend type, auto-detected from DATABASE_URL or set via DATABASE_BACKEND. #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)] #[serde(rename_all = "lowercase")] @@ -252,17 +289,17 @@ pub async fn connect(url: &str, backend: DatabaseBackend) -> AnyPool { // Enable foreign keys and WAL mode for SQLite if backend == DatabaseBackend::Sqlite { - sqlx::query("PRAGMA foreign_keys = ON") + crate::db::query("PRAGMA foreign_keys = ON") .execute(&pool) .await .expect("Failed to enable foreign keys"); - sqlx::query("PRAGMA journal_mode = WAL") + crate::db::query("PRAGMA journal_mode = WAL") .execute(&pool) .await .expect("Failed to enable WAL mode"); - sqlx::query("PRAGMA busy_timeout = 5000") + crate::db::query("PRAGMA busy_timeout = 5000") .execute(&pool) .await .expect("Failed to set busy timeout"); @@ -336,17 +373,17 @@ pub async fn connect_backfill_pool(url: &str, backend: DatabaseBackend) -> AnyPo .expect("Failed to connect backfill database pool"); if backend == DatabaseBackend::Sqlite { - sqlx::query("PRAGMA foreign_keys = ON") + crate::db::query("PRAGMA foreign_keys = ON") .execute(&pool) .await .expect("Failed to enable foreign keys on backfill pool"); - sqlx::query("PRAGMA journal_mode = WAL") + crate::db::query("PRAGMA journal_mode = WAL") .execute(&pool) .await .expect("Failed to enable WAL mode on backfill pool"); - sqlx::query("PRAGMA busy_timeout = 5000") + crate::db::query("PRAGMA busy_timeout = 5000") .execute(&pool) .await .expect("Failed to set busy timeout on backfill pool"); diff --git a/src/delegation/db.rs b/src/delegation/db.rs index d6a4fdb..2f5afc5 100644 --- a/src/delegation/db.rs +++ b/src/delegation/db.rs @@ -16,7 +16,7 @@ pub async fn create_delegated_account( "INSERT INTO happyview_delegated_accounts (account_did, linked_by, api_client_id, created_at) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(linked_by) .bind(api_client_id) @@ -36,7 +36,7 @@ pub async fn delete_delegated_account( "DELETE FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .execute(pool) .await @@ -53,7 +53,7 @@ pub async fn get_delegated_account_owner( "SELECT linked_by FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .fetch_optional(pool) .await @@ -79,7 +79,7 @@ pub async fn get_api_client_id( "SELECT api_client_id FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .fetch_optional(pool) .await @@ -100,7 +100,7 @@ pub async fn add_delegate( "INSERT INTO happyview_account_delegates (account_did, user_did, role, granted_by, created_at) VALUES (?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(user_did) .bind(role.as_str()) @@ -122,7 +122,7 @@ pub async fn remove_delegate( "DELETE FROM happyview_account_delegates WHERE account_did = ? AND user_did = ?", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(user_did) .execute(pool) @@ -141,7 +141,7 @@ pub async fn get_delegate_role( "SELECT role FROM happyview_account_delegates WHERE account_did = ? AND user_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .bind(user_did) .fetch_optional(pool) @@ -160,7 +160,7 @@ pub async fn list_accounts_for_user( "SELECT ad.account_did, ad.role, ad.created_at FROM happyview_account_delegates ad JOIN happyview_delegated_accounts da ON da.account_did = ad.account_did WHERE ad.user_did = ? AND da.api_client_id = ? ORDER BY ad.created_at DESC", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = crate::db::query_as(&sql) .bind(user_did) .bind(api_client_id) .fetch_all(pool) @@ -187,7 +187,7 @@ pub async fn get_account_for_user( "SELECT da.linked_by, ad.role, ad.created_at FROM happyview_delegated_accounts da JOIN happyview_account_delegates ad ON da.account_did = ad.account_did WHERE da.account_did = ? AND ad.user_did = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(account_did) .bind(user_did) .fetch_optional(pool) @@ -205,7 +205,7 @@ pub async fn list_delegates( "SELECT user_did, role, granted_by, created_at FROM happyview_account_delegates WHERE account_did = ? ORDER BY created_at ASC", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .bind(account_did) .fetch_all(pool) .await diff --git a/src/delegation/link_account.rs b/src/delegation/link_account.rs index 7ad8b74..8101784 100644 --- a/src/delegation/link_account.rs +++ b/src/delegation/link_account.rs @@ -50,7 +50,7 @@ pub async fn link_account( "SELECT id FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", state.db_backend, ); - let session_exists: Option<(String,)> = sqlx::query_as(&session_check_sql) + let session_exists: Option<(String,)> = crate::db::query_as(&session_check_sql) .bind(&api_client_id) .bind(account_did) .fetch_optional(&state.db) diff --git a/src/dev_happyview/create_client.rs b/src/dev_happyview/create_client.rs index 3ff3d61..3cc40ad 100644 --- a/src/dev_happyview/create_client.rs +++ b/src/dev_happyview/create_client.rs @@ -64,7 +64,7 @@ pub async fn create_api_client( "SELECT parent_client_id, created_by FROM happyview_api_clients WHERE id = ?", state.db_backend, ); - let parent_row: Option<(Option, String)> = sqlx::query_as(&parent_check_sql) + let parent_row: Option<(Option, String)> = crate::db::query_as(&parent_check_sql) .bind(&parent_client.id) .fetch_optional(&state.db) .await @@ -94,7 +94,7 @@ pub async fn create_api_client( "SELECT id FROM happyview_api_clients WHERE client_id_url = ?", state.db_backend, ); - let dup: Option<(String,)> = sqlx::query_as(&dup_check_sql) + let dup: Option<(String,)> = crate::db::query_as(&dup_check_sql) .bind(&input.client_id_url) .fetch_optional(&state.db) .await @@ -108,12 +108,12 @@ pub async fn create_api_client( // 6. Generate `hvc_` client key and optional `hvs_` client secret let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let child_client_key = format!("hvc_{}", hex::encode(random_bytes)); let (client_secret, client_secret_hash) = if input.client_type == "confidential" { let mut secret_bytes = [0u8; 32]; - rand::rng().fill(&mut secret_bytes); + rand::rng().fill_bytes(&mut secret_bytes); let secret = format!("hvs_{}", hex::encode(secret_bytes)); let hash = hex::encode(Sha256::digest(secret.as_bytes())); (Some(secret), hash) @@ -135,7 +135,7 @@ pub async fn create_api_client( "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, rate_limit_capacity, rate_limit_refill_rate, client_type, allowed_origins, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, 1, ?, ?, ?, ?, ?)", state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&child_client_key) .bind(&client_secret_hash) diff --git a/src/dev_happyview/delete_client.rs b/src/dev_happyview/delete_client.rs index f4b92b8..6e2fef6 100644 --- a/src/dev_happyview/delete_client.rs +++ b/src/dev_happyview/delete_client.rs @@ -51,7 +51,7 @@ pub async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE id = ? AND owner_did = ?", state.db_backend, ); - let client_info: Option<(String, String)> = sqlx::query_as(&lookup_sql) + let client_info: Option<(String, String)> = crate::db::query_as(&lookup_sql) .bind(&id) .bind(&user_did) .fetch_optional(&state.db) @@ -63,7 +63,7 @@ pub async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - let children: Vec<(String, String)> = sqlx::query_as(&children_sql) + let children: Vec<(String, String)> = crate::db::query_as(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -74,7 +74,7 @@ pub async fn delete_api_client( "DELETE FROM happyview_api_clients WHERE id = ? AND owner_did = ?", state.db_backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .bind(&user_did) .execute(&state.db) diff --git a/src/dev_happyview/get_client.rs b/src/dev_happyview/get_client.rs index 47ced61..aa6f627 100644 --- a/src/dev_happyview/get_client.rs +++ b/src/dev_happyview/get_client.rs @@ -55,7 +55,7 @@ pub async fn get_api_client( state.db_backend, ); - let row = sqlx::query(&sql) + let row = crate::db::query(&sql) .bind(¶ms.id) .bind(did) .fetch_optional(&state.db) diff --git a/src/dev_happyview/list_clients.rs b/src/dev_happyview/list_clients.rs index 4b0a6d9..bfc06c7 100644 --- a/src/dev_happyview/list_clients.rs +++ b/src/dev_happyview/list_clients.rs @@ -47,7 +47,7 @@ pub async fn list_api_clients( "SELECT parent_client_id FROM happyview_api_clients WHERE client_key = $1", state.db_backend, ); - let parent_check: Option> = sqlx::query_scalar(&sql) + let parent_check: Option> = crate::db::query_scalar(&sql) .bind(client_key) .fetch_optional(&state.db) .await @@ -69,7 +69,7 @@ pub async fn list_api_clients( state.db_backend, ); - let rows = sqlx::query(&sql) + let rows = crate::db::query(&sql) .bind(did) .fetch_all(&state.db) .await diff --git a/src/dns.rs b/src/dns.rs index 9a26260..1283819 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -1,5 +1,6 @@ use atrium_identity::handle::DnsTxtResolver; use hickory_resolver::TokioResolver; +use hickory_resolver::proto::rr::RData; /// Native DNS TXT resolver using system DNS configuration. /// Implements atrium's `DnsTxtResolver` trait for use with `AtprotoHandleResolver`, @@ -20,7 +21,8 @@ impl NativeDnsResolver { Self { resolver: TokioResolver::builder_tokio() .expect("Failed to read system DNS config") - .build(), + .build() + .expect("Failed to build DNS resolver"), } } @@ -32,7 +34,14 @@ impl NativeDnsResolver { .await .map_err(|e| format!("DNS TXT lookup failed for {name}: {e}"))?; - Ok(response.iter().map(|txt| txt.to_string()).collect()) + Ok(response + .answers() + .iter() + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt.to_string()), + _ => None, + }) + .collect()) } } diff --git a/src/event_log.rs b/src/event_log.rs index 7a9aa51..0a16c24 100644 --- a/src/event_log.rs +++ b/src/event_log.rs @@ -56,7 +56,7 @@ pub async fn spawn_retention_cleanup(db: AnyPool, retention_days: u32, backend: loop { tokio::time::sleep(interval).await; - let result = sqlx::query(&cleanup_sql) + let result = crate::db::query(&cleanup_sql) .bind(retention_days as i32) .execute(&db) .await; @@ -86,7 +86,7 @@ pub async fn log_event(db: &AnyPool, event: EventLog, backend: DatabaseBackend) backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .bind(&event.event_type) .bind(&severity) diff --git a/src/external_auth/routes.rs b/src/external_auth/routes.rs index 56127f0..834b151 100644 --- a/src/external_auth/routes.rs +++ b/src/external_auth/routes.rs @@ -465,7 +465,7 @@ async fn load_plugin_secrets( db_backend, ); - if let Ok(Some((config_json,))) = sqlx::query_as::<_, (String,)>(&sql) + if let Ok(Some((config_json,))) = crate::db::query_as::<(String,)>(&sql) .bind(plugin_id) .fetch_optional(db) .await diff --git a/src/external_auth/state.rs b/src/external_auth/state.rs index d8b7674..4b8a5b1 100644 --- a/src/external_auth/state.rs +++ b/src/external_auth/state.rs @@ -43,7 +43,7 @@ pub async fn store_state( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(state) .bind(did) .bind(plugin_id) @@ -72,7 +72,7 @@ pub async fn consume_state( backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(state) .bind(&now) .fetch_optional(db) @@ -85,7 +85,10 @@ pub async fn consume_state( "DELETE FROM happyview_external_auth_state WHERE state = ?", backend, ); - sqlx::query(&delete_sql).bind(state).execute(db).await?; + crate::db::query(&delete_sql) + .bind(state) + .execute(db) + .await?; Ok(StoredState { did, @@ -105,7 +108,7 @@ pub async fn cleanup_expired( "DELETE FROM happyview_external_auth_state WHERE expires_at <= ?", backend, ); - let result = sqlx::query(&sql).bind(&now).execute(db).await?; + let result = crate::db::query(&sql).bind(&now).execute(db).await?; Ok(result.rows_affected()) } diff --git a/src/external_auth/sync.rs b/src/external_auth/sync.rs index a6ea24f..45bc179 100644 --- a/src/external_auth/sync.rs +++ b/src/external_auth/sync.rs @@ -39,7 +39,7 @@ pub async fn process_sync_records( db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(plugin_id) .bind(user_did) .bind(dedup_key) diff --git a/src/external_auth/tokens.rs b/src/external_auth/tokens.rs index 86dbe2e..a6c7650 100644 --- a/src/external_auth/tokens.rs +++ b/src/external_auth/tokens.rs @@ -69,7 +69,7 @@ pub async fn store_tokens( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(did) .bind(plugin_id) @@ -102,7 +102,7 @@ pub async fn get_tokens( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -144,7 +144,7 @@ pub async fn delete_tokens( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(did) .bind(plugin_id) .execute(db) @@ -165,7 +165,7 @@ pub async fn is_linked( backend, ); - let exists: Option<(i32,)> = sqlx::query_as(&sql) + let exists: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -186,7 +186,7 @@ pub async fn get_account_id( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -216,7 +216,7 @@ pub async fn list_linked_accounts( ); let rows: Vec<(String, String, String, String)> = - sqlx::query_as(&sql).bind(did).fetch_all(db).await?; + crate::db::query_as(&sql).bind(did).fetch_all(db).await?; Ok(rows .into_iter() diff --git a/src/jetstream.rs b/src/jetstream.rs index 8acfd98..43fd5b2 100644 --- a/src/jetstream.rs +++ b/src/jetstream.rs @@ -51,7 +51,7 @@ async fn load_cursor(db: &AnyPool, backend: DatabaseBackend) -> Option { "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind("jetstream_cursor") .fetch_optional(db) .await @@ -69,7 +69,7 @@ async fn save_cursor(db: &AnyPool, backend: DatabaseBackend, cursor: i64) { "#, backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind("jetstream_cursor") .bind(cursor.to_string()) .bind(&now) diff --git a/src/jobs/db.rs b/src/jobs/db.rs index 6d00d6a..bb89962 100644 --- a/src/jobs/db.rs +++ b/src/jobs/db.rs @@ -70,7 +70,7 @@ pub async fn create_job( "INSERT INTO happyview_jobs (id, job_type, status, input, created_by, created_at, inherit_auth) VALUES (?, ?, 'pending', ?, ?, ?, ?)", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(job_type) .bind(&input_str) @@ -89,7 +89,7 @@ pub async fn get_job(state: &AppState, id: &str) -> Result, AppError "SELECT * FROM happyview_jobs WHERE id = ?", state.db_backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -120,7 +120,7 @@ pub async fn list_jobs( adapt_sql(base, state.db_backend) }; - let mut query = sqlx::query_as::<_, JobRow>(&sql); + let mut query = crate::db::query_as::(&sql); if let Some(status) = status_filter { query = query.bind(status); @@ -170,7 +170,7 @@ pub async fn set_status(state: &AppState, id: &str, status: &str) -> Result<(), match status { "running" | "completed" | "failed" | "cancelled" => { - sqlx::query(&sql) + crate::db::query(&sql) .bind(status) .bind(&now) .bind(id) @@ -183,7 +183,7 @@ pub async fn set_status(state: &AppState, id: &str, status: &str) -> Result<(), "UPDATE happyview_jobs SET status = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(status) .bind(id) .execute(&state.db) @@ -202,7 +202,7 @@ pub async fn update_progress(state: &AppState, id: &str, progress: &Value) -> Re "UPDATE happyview_jobs SET progress = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&progress_str) .bind(id) .execute(&state.db) @@ -219,7 +219,7 @@ pub async fn set_result(state: &AppState, id: &str, result: &Value) -> Result<() "UPDATE happyview_jobs SET status = 'completed', result = ?, completed_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&result_str) .bind(&now) .bind(id) @@ -235,7 +235,7 @@ pub async fn set_error(state: &AppState, id: &str, error: &str) -> Result<(), Ap "UPDATE happyview_jobs SET status = 'failed', error = ?, completed_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(error) .bind(&now) .bind(id) @@ -252,7 +252,7 @@ pub async fn should_stop(state: &AppState, id: &str) -> Option<&'static str> { "SELECT status FROM happyview_jobs WHERE id = ?", state.db_backend, ); - let status = sqlx::query_as::<_, (String,)>(&sql) + let status = crate::db::query_as::<(String,)>(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -272,7 +272,7 @@ pub async fn find_interrupted_jobs(state: &AppState) -> Vec { "SELECT * FROM happyview_jobs WHERE status IN ('running', 'cancelling', 'pausing')", state.db_backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(&state.db) .await .unwrap_or_default(); @@ -295,7 +295,7 @@ pub async fn claim_next_job(state: &AppState) -> Result, AppError> { ), }; - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(&now) .fetch_optional(&state.db) .await diff --git a/src/jobs/worker.rs b/src/jobs/worker.rs index 89a8051..8abf2ee 100644 --- a/src/jobs/worker.rs +++ b/src/jobs/worker.rs @@ -331,7 +331,7 @@ async fn load_env_vars( backend: crate::db::DatabaseBackend, ) -> std::collections::HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() diff --git a/src/labeler.rs b/src/labeler.rs index ceea642..ffda327 100644 --- a/src/labeler.rs +++ b/src/labeler.rs @@ -59,7 +59,7 @@ pub fn spawn(state: AppState, mut subscriptions_rx: watch::Receiver<()>) { loop { // Read all active subscriptions from the database. - let active: Vec<(String,)> = sqlx::query_as( + let active: Vec<(String,)> = crate::db::query_as( "SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'", ) .fetch_all(&state.db) @@ -153,7 +153,7 @@ async fn run_subscription_once( "SELECT cursor FROM happyview_labeler_subscriptions WHERE did = ?", state.db_backend, ); - let cursor: Option<(Option,)> = sqlx::query_as(&cursor_sql) + let cursor: Option<(Option,)> = crate::db::query_as(&cursor_sql) .bind(did) .fetch_optional(&state.db) .await?; @@ -362,7 +362,7 @@ async fn apply_label(state: &AppState, label: &Label) { "DELETE FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - if let Err(e) = sqlx::query(&delete_sql) + if let Err(e) = crate::db::query(&delete_sql) .bind(&final_label.src) .bind(&final_label.uri) .bind(&final_label.val) @@ -387,7 +387,7 @@ async fn apply_label(state: &AppState, label: &Label) { backend, ); - if let Err(e) = sqlx::query(&insert_sql) + if let Err(e) = crate::db::query(&insert_sql) .bind(&final_label.src) .bind(&final_label.uri) .bind(&final_label.val) @@ -410,7 +410,7 @@ async fn persist_cursor(db: &sqlx::AnyPool, did: &str, seq: i64, backend: Databa "UPDATE happyview_labeler_subscriptions SET cursor = ?, updated_at = ? WHERE did = ?", backend, ); - if let Err(e) = sqlx::query(&update_sql) + if let Err(e) = crate::db::query(&update_sql) .bind(seq) .bind(&now) .bind(did) @@ -439,10 +439,11 @@ async fn backfill_labels_for_uri_inner( state: &AppState, uri: &str, ) -> Result<(), Box> { - let subscriptions: Vec<(String,)> = - sqlx::query_as("SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'") - .fetch_all(&state.db) - .await?; + let subscriptions: Vec<(String,)> = crate::db::query_as( + "SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'", + ) + .fetch_all(&state.db) + .await?; for (labeler_did,) in subscriptions { if let Err(e) = backfill_from_labeler(state, &labeler_did, uri).await { @@ -515,7 +516,7 @@ pub async fn spawn_label_gc(db: sqlx::AnyPool, backend: DatabaseBackend) { tokio::time::sleep(interval).await; // Delete expired labels. - let expired = sqlx::query(&expired_sql).execute(&db).await; + let expired = crate::db::query(&expired_sql).execute(&db).await; let expired_count = match expired { Ok(r) => r.rows_affected(), @@ -526,7 +527,7 @@ pub async fn spawn_label_gc(db: sqlx::AnyPool, backend: DatabaseBackend) { }; // Delete orphaned labels (no matching record). - let orphaned = sqlx::query( + let orphaned = crate::db::query( "DELETE FROM happyview_labels WHERE NOT EXISTS (SELECT 1 FROM happyview_records WHERE happyview_records.uri = happyview_labels.uri)", ) .execute(&db) diff --git a/src/lexicon.rs b/src/lexicon.rs index 7374f81..a4b25dc 100644 --- a/src/lexicon.rs +++ b/src/lexicon.rs @@ -219,7 +219,7 @@ impl LexiconRegistry { Option, Option, Option, - )> = sqlx::query_as( + )> = crate::db::query_as( "SELECT id, lexicon_json, revision, target_collection, action, token_cost FROM happyview_lexicons", ) .fetch_all(db) diff --git a/src/lua/atproto_api.rs b/src/lua/atproto_api.rs index e58f8b8..e5d1f6f 100644 --- a/src/lua/atproto_api.rs +++ b/src/lua/atproto_api.rs @@ -122,7 +122,7 @@ pub fn register_atproto_api( "SELECT src, uri, val, cts FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .bind(&now) .fetch_all(&state.db) @@ -144,7 +144,7 @@ pub fn register_atproto_api( // Check for self-labels in the record itself. let record_sql = adapt_sql("SELECT did, record FROM happyview_records WHERE uri = ?", backend); - let record: Option<(String, String)> = sqlx::query_as(&record_sql) + let record: Option<(String, String)> = crate::db::query_as(&record_sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -197,7 +197,7 @@ pub fn register_atproto_api( let mut rows: Vec<(String, String, String, String)> = Vec::new(); for uri in &uri_list { let mut uri_rows: Vec<(String, String, String, String)> = - sqlx::query_as(&label_sql) + crate::db::query_as(&label_sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -215,7 +215,7 @@ pub fn register_atproto_api( ); let mut records: Vec<(String, String, String)> = Vec::new(); for uri in &uri_list { - let mut uri_records: Vec<(String, String, String)> = sqlx::query_as(&record_sql) + let mut uri_records: Vec<(String, String, String)> = crate::db::query_as(&record_sql) .bind(uri) .fetch_all(&state.db) .await diff --git a/src/lua/db_api.rs b/src/lua/db_api.rs index 2c44261..1e9e6a9 100644 --- a/src/lua/db_api.rs +++ b/src/lua/db_api.rs @@ -295,7 +295,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { &format!("SELECT uri, did, record FROM happyview_records WHERE collection = ?{did_clause}{filter_clause} ORDER BY {order_expr} LIMIT ? OFFSET ?"), backend, ); - let mut q = sqlx::query_as(&sql).bind(&collection); + let mut q = crate::db::query_as(&sql).bind(&collection); if let Some(ref did) = did { q = q.bind(did); } for val in &filter_binds { q = q.bind(val); } let rows: Vec<(String, String, String)> = q @@ -351,7 +351,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { ), backend, ); - let mut q = sqlx::query_as::<_, RowType>(&sql).bind(&collection); + let mut q = crate::db::query_as::(&sql).bind(&collection); if let Some(ref did) = did { q = q.bind(did); } if let Some((cursor_ts, cursor_uri)) = &cursor_parts { q = q.bind(cursor_ts).bind(cursor_ts).bind(cursor_uri); @@ -407,7 +407,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT record FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -463,7 +463,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { json_extract(record, '$.{field}') \ LIMIT ?" ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(&like_pattern) .bind(&query) @@ -487,7 +487,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { record::jsonb->>'{field}' \ LIMIT $4" ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(&like_pattern) .bind(&query) @@ -536,7 +536,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT COUNT(*) FROM happyview_records WHERE collection = ? AND did = ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(did) .fetch_one(&state.db) @@ -547,7 +547,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT COUNT(*) FROM happyview_records WHERE collection = ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .fetch_one(&state.db) .await @@ -586,7 +586,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(did) @@ -607,7 +607,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(did) @@ -626,7 +626,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(cursor_ts) @@ -646,7 +646,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(limit) @@ -699,7 +699,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { // AppView bookkeeping) from raw access; own tables are fine. check_raw_sql_tables(&sql).map_err(mlua::Error::runtime)?; - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); if let Some(ref params_table) = params { for value in params_table.sequence_values::() { let value = value?; diff --git a/src/lua/execute.rs b/src/lua/execute.rs index 5997665..b275cd4 100644 --- a/src/lua/execute.rs +++ b/src/lua/execute.rs @@ -24,7 +24,7 @@ use super::sandbox; /// Load all script variables from the database as a key-value map. async fn load_env_vars(db: &sqlx::AnyPool, backend: DatabaseBackend) -> HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() diff --git a/src/lua/record.rs b/src/lua/record.rs index 6bd1298..a58a983 100644 --- a/src/lua/record.rs +++ b/src/lua/record.rs @@ -156,7 +156,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -219,7 +219,7 @@ pub(crate) fn register_record_api( cid = EXCLUDED.cid"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -318,7 +318,10 @@ pub(crate) fn register_record_api( // Always delete locally — operator's logical action is // "remove this record from view" regardless of PDS outcome. let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let _ = sqlx::query(&delete_sql).bind(&uri).execute(&state.db).await; + let _ = crate::db::query(&delete_sql) + .bind(&uri) + .execute(&state.db) + .await; this.raw_set("_uri", mlua::Value::Nil)?; this.raw_set("_cid", mlua::Value::Nil)?; @@ -425,7 +428,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - sqlx::query(&upsert_sql) + crate::db::query(&upsert_sql) .bind(&uri) .bind(&repo) .bind(&collection) @@ -463,7 +466,7 @@ pub(crate) fn register_record_api( })?; let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(&uri) .execute(&state.db) .await @@ -757,7 +760,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri.as_str()) .bind(repo) .bind(&collection) @@ -825,7 +828,7 @@ pub(crate) fn register_record_api( cid = EXCLUDED.cid"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -877,7 +880,7 @@ pub(crate) fn register_record_api( "SELECT collection, record, cid FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -944,7 +947,7 @@ pub(crate) fn register_record_api( "SELECT collection, record, cid FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -1021,7 +1024,7 @@ pub(crate) fn register_record_api( async move { let backend = state.db_backend; let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let res = sqlx::query(&delete_sql) + let res = crate::db::query(&delete_sql) .bind(&uri) .execute(&state.db) .await diff --git a/src/lua/scripts.rs b/src/lua/scripts.rs index 439c7c0..c60f491 100644 --- a/src/lua/scripts.rs +++ b/src/lua/scripts.rs @@ -250,7 +250,7 @@ pub async fn resolve(state: &AppState, trigger_id: &str) -> Option = match sqlx::query_as(&sql) + let row: Option<(String, String, String)> = match crate::db::query_as(&sql) .bind(trigger_id) .fetch_optional(&state.db) .await @@ -818,7 +818,7 @@ async fn load_env_vars( backend: DatabaseBackend, ) -> std::collections::HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() @@ -844,7 +844,7 @@ async fn write_dead_letter(state: &AppState, entry: &DeadLetterEntry<'_>) { VALUES (?, ?, ?, ?, ?, ?, ?, ?)", state.db_backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind(entry.script.id.as_str()) .bind(entry.host_kind) .bind(entry.host_id) diff --git a/src/lua/xrpc_api.rs b/src/lua/xrpc_api.rs index baaecf0..5ffe128 100644 --- a/src/lua/xrpc_api.rs +++ b/src/lua/xrpc_api.rs @@ -311,7 +311,7 @@ mod tests { /// inert (kept on the struct for forward-compat with row loaders but /// not consulted by dispatch). async fn seed_script(state: &AppState, trigger: &str, body: &str) { - sqlx::query( + crate::db::query( r#" CREATE TABLE IF NOT EXISTS happyview_scripts ( id TEXT PRIMARY KEY, @@ -326,7 +326,7 @@ mod tests { .execute(&state.db) .await .unwrap(); - sqlx::query( + crate::db::query( "INSERT OR REPLACE INTO happyview_scripts (id, body, script_type, created_at, updated_at) VALUES (?, ?, 'lua', datetime('now'), datetime('now'))", ) diff --git a/src/main.rs b/src/main.rs index c5baa94..25ce22e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,14 +53,14 @@ async fn main() { let db_bg = db_pool.clone(); let backend = db_backend; tokio::spawn(async move { - let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_record_refs") + let count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_record_refs") .fetch_one(&db_bg) .await .expect("failed to count record_refs"); if count.0 == 0 { info!("backfilling record_refs table in background..."); - let total: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_records") + let total: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_records") .fetch_one(&db_bg) .await .expect("failed to count records"); @@ -76,7 +76,7 @@ async fn main() { ); loop { - let batch: Vec<(String, String, String)> = sqlx::query_as(&query) + let batch: Vec<(String, String, String)> = crate::db::query_as(&query) .bind(batch_size) .bind(offset) .fetch_all(&db_bg) @@ -120,7 +120,7 @@ async fn main() { // Re-fetch all network lexicons from their respective PDSes. let http = reqwest::Client::new(); - let network_rows: Vec<(String, Option, Option)> = sqlx::query_as( + let network_rows: Vec<(String, Option, Option)> = crate::db::query_as( "SELECT id, authority_did, target_collection FROM happyview_lexicons WHERE source = 'network'", ) .fetch_all(&db_pool) @@ -147,7 +147,7 @@ async fn main() { ); let lexicon_json_str = serde_json::to_string(&lexicon_json).unwrap_or_default(); - if let Err(e) = sqlx::query(&update_sql) + if let Err(e) = crate::db::query(&update_sql) .bind(&lexicon_json_str) .bind(&now) .bind(&now) @@ -282,7 +282,7 @@ async fn main() { Option, Option, ); - let client_rows: Vec = sqlx::query_as( + let client_rows: Vec = crate::db::query_as( "SELECT client_key, client_secret_hash, client_uri, rate_limit_capacity, rate_limit_refill_rate, parent_client_id FROM happyview_api_clients WHERE is_active = 1", ) .fetch_all(&db_pool) @@ -328,7 +328,7 @@ async fn main() { { let count_sql = happyview::db::adapt_sql("SELECT COUNT(*) FROM happyview_domains", db_backend); - let row = sqlx::query(&count_sql) + let row = crate::db::query(&count_sql) .fetch_one(&db_pool) .await .expect("Failed to count domains"); @@ -341,7 +341,7 @@ async fn main() { "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, 1, ?, ?)", db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&config.public_url) .bind(&now) @@ -356,7 +356,7 @@ async fn main() { "SELECT id, url FROM happyview_domains WHERE is_primary = 1", db_backend, ); - if let Some(row) = sqlx::query(&primary_sql) + if let Some(row) = crate::db::query(&primary_sql) .fetch_optional(&db_pool) .await .expect("Failed to check primary domain") @@ -369,7 +369,7 @@ async fn main() { "UPDATE happyview_domains SET url = ?, updated_at = ? WHERE id = ?", db_backend, ); - sqlx::query(&update_sql) + crate::db::query(&update_sql) .bind(&config.public_url) .bind(&now) .bind(&primary_id) @@ -388,7 +388,7 @@ async fn main() { "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains", db_backend, ); - let rows = sqlx::query(&select_sql) + let rows = crate::db::query(&select_sql) .fetch_all(&db_pool) .await .expect("Failed to load domains"); @@ -734,7 +734,7 @@ async fn seed_and_load_rate_limit_defaults( "INSERT INTO happyview_instance_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT (key) DO NOTHING", backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind(key) .bind(seed.to_string()) .bind(&now) diff --git a/src/oauth/client_auth.rs b/src/oauth/client_auth.rs index 8149645..36841c1 100644 --- a/src/oauth/client_auth.rs +++ b/src/oauth/client_auth.rs @@ -27,7 +27,7 @@ pub async fn authenticate_confidential( ); let row: Option<(String, String, String, String, Option, String)> = - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await @@ -71,7 +71,7 @@ pub async fn authenticate_public( backend, ); - let row: Option<(String, String, String, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, String, String, Option)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await @@ -130,7 +130,7 @@ pub async fn resolve_client_by_key( backend, ); - let row: Option<(String, String, String, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, String, String, Option)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await diff --git a/src/oauth/dpop_proof.rs b/src/oauth/dpop_proof.rs index f97e819..0280c0a 100644 --- a/src/oauth/dpop_proof.rs +++ b/src/oauth/dpop_proof.rs @@ -221,7 +221,7 @@ fn verify_es256_jwk( let verifying_key = VerifyingKey::from_sec1_bytes(&sec1) .map_err(|_| AppError::Auth("invalid DPoP public key".into()))?; - let signature = Signature::from_bytes(sig_bytes.into()) + let signature = Signature::from_slice(sig_bytes) .map_err(|_| AppError::Auth("invalid DPoP signature format".into()))?; verifying_key diff --git a/src/oauth/keys.rs b/src/oauth/keys.rs index b2d3baf..c993a46 100644 --- a/src/oauth/keys.rs +++ b/src/oauth/keys.rs @@ -1,5 +1,5 @@ use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use serde::Serialize; use sha2::{Digest, Sha256}; @@ -23,11 +23,11 @@ pub fn generate_dpop_keypair() -> Result { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let public_point = verifying_key.to_encoded_point(false); + let public_point = verifying_key.to_sec1_point(false); let x_bytes = public_point .x() @@ -121,7 +121,7 @@ pub async fn store_dpop_key( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(id) .bind(provision_id) .bind(api_client_id) @@ -150,7 +150,7 @@ pub async fn get_dpop_key( ); #[allow(clippy::type_complexity)] - let row: Option<(String, String, Vec, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, Vec, String, Option)> = crate::db::query_as(&sql) .bind(provision_id) .fetch_optional(pool) .await @@ -179,7 +179,7 @@ pub async fn get_dpop_key_thumbprint( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(key_id) .fetch_optional(pool) .await @@ -201,7 +201,7 @@ pub async fn get_dpop_key_id_by_thumbprint( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(api_client_id) .bind(thumbprint) .fetch_optional(pool) @@ -223,13 +223,13 @@ pub async fn delete_dpop_key( "DELETE FROM happyview_dpop_sessions WHERE dpop_key_id = ?", backend, ); - let _ = sqlx::query(&session_sql) + let _ = crate::db::query(&session_sql) .bind(dpop_key_id) .execute(pool) .await; let key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&key_sql) + crate::db::query(&key_sql) .bind(dpop_key_id) .execute(pool) .await diff --git a/src/oauth/pds_write.rs b/src/oauth/pds_write.rs index a104271..7f172c1 100644 --- a/src/oauth/pds_write.rs +++ b/src/oauth/pds_write.rs @@ -50,7 +50,7 @@ async fn resolve_credentials( "SELECT private_key_enc FROM happyview_dpop_keys WHERE id = ?", backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&key_sql) + let row: Option<(Vec,)> = crate::db::query_as(&key_sql) .bind(&session.dpop_key_id) .fetch_optional(pool) .await @@ -596,7 +596,7 @@ async fn lookup_client_id_url( "SELECT client_id_url FROM happyview_api_clients WHERE id = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(api_client_id) .fetch_optional(pool) .await @@ -649,7 +649,7 @@ fn generate_dpop_proof_inner( .decode(d_b64) .map_err(|_| AppError::Internal("invalid DPoP key d parameter".into()))?; - let signing_key = SigningKey::from_bytes((&d_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&d_bytes[..]) .map_err(|e| AppError::Internal(format!("invalid DPoP signing key: {e}")))?; let public_jwk = serde_json::json!({ diff --git a/src/oauth/sessions.rs b/src/oauth/sessions.rs index 4588dab..a258cd4 100644 --- a/src/oauth/sessions.rs +++ b/src/oauth/sessions.rs @@ -70,7 +70,7 @@ pub async fn store_dpop_session( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(id) .bind(api_client_id) .bind(dpop_key_id) @@ -113,7 +113,7 @@ pub async fn get_dpop_session( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .bind(dpop_key_id) @@ -177,7 +177,7 @@ pub async fn get_dpop_session_by_key_id( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(dpop_key_id) .fetch_optional(pool) @@ -228,7 +228,7 @@ pub async fn delete_dpop_session( "DELETE FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ? AND dpop_key_id = ?", backend, ); - sqlx::query(&del_session_sql) + crate::db::query(&del_session_sql) .bind(api_client_id) .bind(user_did) .bind(dpop_key_id) @@ -237,7 +237,7 @@ pub async fn delete_dpop_session( .map_err(|e| AppError::Internal(format!("failed to delete DPoP session: {e}")))?; let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&del_key_sql) + crate::db::query(&del_key_sql) .bind(dpop_key_id) .execute(pool) .await @@ -257,7 +257,7 @@ pub async fn delete_all_dpop_sessions( "SELECT dpop_key_id FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", backend, ); - let key_ids: Vec<(String,)> = sqlx::query_as(&key_ids_sql) + let key_ids: Vec<(String,)> = crate::db::query_as(&key_ids_sql) .bind(api_client_id) .bind(user_did) .fetch_all(pool) @@ -268,7 +268,7 @@ pub async fn delete_all_dpop_sessions( "DELETE FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", backend, ); - sqlx::query(&del_sessions_sql) + crate::db::query(&del_sessions_sql) .bind(api_client_id) .bind(user_did) .execute(pool) @@ -277,7 +277,10 @@ pub async fn delete_all_dpop_sessions( let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); for (key_id,) in key_ids { - let _ = sqlx::query(&del_key_sql).bind(&key_id).execute(pool).await; + let _ = crate::db::query(&del_key_sql) + .bind(&key_id) + .execute(pool) + .await; } Ok(()) @@ -295,7 +298,7 @@ pub async fn list_dpop_sessions( backend, ); - let rows: Vec<(String, String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String, String)> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .fetch_all(pool) @@ -341,7 +344,7 @@ pub async fn get_dpop_session_for_user( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .fetch_optional(pool) @@ -392,7 +395,7 @@ pub async fn delete_dpop_session_by_id( "SELECT dpop_key_id FROM happyview_dpop_sessions WHERE id = ? AND api_client_id = ? AND user_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&lookup_sql) + let row: Option<(String,)> = crate::db::query_as(&lookup_sql) .bind(session_id) .bind(api_client_id) .bind(user_did) @@ -403,14 +406,14 @@ pub async fn delete_dpop_session_by_id( let (dpop_key_id,) = row.ok_or_else(|| AppError::NotFound("DPoP session not found".into()))?; let del_session_sql = adapt_sql("DELETE FROM happyview_dpop_sessions WHERE id = ?", backend); - sqlx::query(&del_session_sql) + crate::db::query(&del_session_sql) .bind(session_id) .execute(pool) .await .map_err(|e| AppError::Internal(format!("failed to delete DPoP session: {e}")))?; let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&del_key_sql) + crate::db::query(&del_key_sql) .bind(&dpop_key_id) .execute(pool) .await diff --git a/src/plc.rs b/src/plc.rs index 7000272..32e00eb 100644 --- a/src/plc.rs +++ b/src/plc.rs @@ -188,10 +188,10 @@ pub fn decrypt_key(enc_b64: &str, encryption_key: &[u8; 32]) -> Result, /// Uses the same multikey format as `extract_public_key_multibase` in server.rs: /// multicodec varint prefix 0x8024 (P-256) + compressed public key, base58btc-encoded. pub fn private_key_to_did_key(key_bytes: &[u8]) -> Result { - let signing_key = SigningKey::from_bytes(key_bytes.into()) + let signing_key = SigningKey::from_slice(key_bytes) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); // Multikey: 0x8024 varint prefix for P-256 + compressed public key bytes let mut multikey_bytes = vec![0x80, 0x24]; @@ -203,14 +203,14 @@ pub fn private_key_to_did_key(key_bytes: &[u8]) -> Result { #[cfg(test)] mod tests { use super::*; - use rand::RngCore; + use rand::Rng; /// Generate a test P-256 signing key using rand 0.9 (avoids rand_core version mismatch /// with p256's SigningKey::random which expects rand_core 0.6). fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; rand::rng().fill_bytes(&mut bytes); - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } #[test] diff --git a/src/plugin/attestation.rs b/src/plugin/attestation.rs index cdcd58f..d89e20b 100644 --- a/src/plugin/attestation.rs +++ b/src/plugin/attestation.rs @@ -48,7 +48,7 @@ impl AttestationSigner { let key_bytes = hex::decode(private_key_hex) .map_err(|e| AttestationError::InvalidKey(format!("invalid hex: {}", e)))?; - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&key_bytes[..]) .map_err(|e| AttestationError::InvalidKey(format!("invalid key: {}", e)))?; Ok(Self { @@ -63,8 +63,7 @@ impl AttestationSigner { pub fn for_testing(key_id: String, sig_type: String) -> Self { // Fixed test key (32 bytes of 0x01) - DO NOT USE IN PRODUCTION let test_key_bytes = [0x01u8; 32]; - let signing_key = - SigningKey::from_bytes((&test_key_bytes[..]).into()).expect("valid test key"); + let signing_key = SigningKey::from_slice(&test_key_bytes[..]).expect("valid test key"); Self { signing_key, key_id, @@ -76,7 +75,7 @@ impl AttestationSigner { pub fn public_key_bytes(&self) -> Vec { use k256::ecdsa::VerifyingKey; let verifying_key = VerifyingKey::from(&self.signing_key); - verifying_key.to_encoded_point(true).as_bytes().to_vec() + verifying_key.to_sec1_point(true).as_bytes().to_vec() } /// Sign a record and add the signature to the signatures array. @@ -222,7 +221,7 @@ impl AttestationSigner { base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sig_bytes_b64) .map_err(|e| AttestationError::Encoding(format!("invalid base64: {e}")))?; - let signature = Signature::from_bytes((&sig_bytes[..]).into()) + let signature = Signature::from_slice(&sig_bytes[..]) .map_err(|e| AttestationError::Signing(format!("invalid signature bytes: {e}")))?; // Recompute CID from record (same as signing) @@ -366,7 +365,7 @@ pub async fn load_or_generate( "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let existing: Option<(String,)> = sqlx::query_as(&sql) + let existing: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_private_key") .fetch_optional(db) .await @@ -374,12 +373,12 @@ pub async fn load_or_generate( if let Some((hex_key,)) = existing { // Load key_id and sig_type from DB too (or use defaults) - let key_id: Option<(String,)> = sqlx::query_as(&sql) + let key_id: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_key_id") .fetch_optional(db) .await .map_err(|e| AttestationError::Encoding(format!("db query failed: {e}")))?; - let sig_type: Option<(String,)> = sqlx::query_as(&sql) + let sig_type: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_sig_type") .fetch_optional(db) .await @@ -397,11 +396,11 @@ pub async fn load_or_generate( tracing::info!("Generating new attestation signing key"); let hex_key = { // Generate 32 random bytes for a K-256 private key - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); // Validate it's a valid K-256 scalar by trying to construct a SigningKey - let _ = SigningKey::from_bytes((&key_bytes[..]).into()) + let _ = SigningKey::from_slice(&key_bytes[..]) .map_err(|e| AttestationError::InvalidKey(format!("generated invalid key: {e}")))?; hex::encode(key_bytes) }; @@ -418,7 +417,7 @@ pub async fn load_or_generate( ("attestation_key_id", default_key_id.as_str()), ("attestation_sig_type", default_sig_type.as_str()), ] { - sqlx::query(&upsert_sql) + crate::db::query(&upsert_sql) .bind(k) .bind(v) .bind(&now) @@ -598,7 +597,7 @@ mod tests { .connect("sqlite::memory:") .await .unwrap(); - sqlx::query( + crate::db::query( "CREATE TABLE happyview_instance_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL DEFAULT '')", ) .execute(&pool) @@ -637,7 +636,7 @@ mod tests { .connect("sqlite::memory:") .await .unwrap(); - sqlx::query( + crate::db::query( "CREATE TABLE happyview_instance_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL DEFAULT '')", ) .execute(&pool) diff --git a/src/plugin/encryption.rs b/src/plugin/encryption.rs index 951c60b..875ea36 100644 --- a/src/plugin/encryption.rs +++ b/src/plugin/encryption.rs @@ -2,7 +2,7 @@ use aes_gcm::{ Aes256Gcm, Nonce, aead::{Aead, KeyInit}, }; -use rand::RngCore; +use rand::Rng; #[derive(Debug, thiserror::Error)] pub enum EncryptionError { diff --git a/src/plugin/host/kv.rs b/src/plugin/host/kv.rs index 1ec7d39..d492347 100644 --- a/src/plugin/host/kv.rs +++ b/src/plugin/host/kv.rs @@ -17,7 +17,7 @@ pub async fn kv_get(ctx: &HostContext, key: &str) -> Result>, KvE ctx.db_backend, ); - let result: Option<(Vec,)> = sqlx::query_as(&sql) + let result: Option<(Vec,)> = crate::db::query_as(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) @@ -52,7 +52,7 @@ pub async fn kv_set( ctx.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) @@ -70,7 +70,7 @@ pub async fn kv_delete(ctx: &HostContext, key: &str) -> Result<(), KvError> { ctx.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) diff --git a/src/plugin/host/lookup.rs b/src/plugin/host/lookup.rs index 9e62818..0a35536 100644 --- a/src/plugin/host/lookup.rs +++ b/src/plugin/host/lookup.rs @@ -47,7 +47,7 @@ pub async fn lookup_record( ctx.db_backend, ); - let result: Option<(String, String)> = sqlx::query_as(&sql) + let result: Option<(String, String)> = crate::db::query_as(&sql) .bind(collection) .bind(&json_path) .bind(external_id_value) diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index f838b56..2008a09 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -93,7 +93,7 @@ impl PluginRegistry { self.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin.info.id) .bind(source) .bind(url) @@ -130,7 +130,7 @@ impl PluginRegistry { self.db_backend, ); - let rows: Vec<(String, String, Option, Option)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, Option, Option)> = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| format!("Failed to load plugins from DB: {}", e))?; diff --git a/src/plugin/sync.rs b/src/plugin/sync.rs index 3d391bb..672453c 100644 --- a/src/plugin/sync.rs +++ b/src/plugin/sync.rs @@ -231,7 +231,7 @@ async fn lookup_game_by_external_id( backend, ); - let result: Option<(String, String)> = sqlx::query_as(&sql) + let result: Option<(String, String)> = crate::db::query_as(&sql) .bind(external_id) .fetch_optional(db) .await diff --git a/src/record_handler.rs b/src/record_handler.rs index 2f73cd7..a93035c 100644 --- a/src/record_handler.rs +++ b/src/record_handler.rs @@ -112,7 +112,7 @@ pub async fn handle_record_event(state: &AppState, record: &RecordEvent) { "#, backend, ); - match sqlx::query(&insert_sql) + match crate::db::query(&insert_sql) .bind(&uri) .bind(&record.did) .bind(&record.collection) @@ -217,7 +217,7 @@ pub async fn handle_record_event(state: &AppState, record: &RecordEvent) { } let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - match sqlx::query(&delete_sql).bind(&uri).execute(db).await { + match crate::db::query(&delete_sql).bind(&uri).execute(db).await { Ok(_) => { if state.verbose_event_logging.load(Ordering::Relaxed) { log_event( @@ -278,7 +278,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "SELECT target_collection FROM happyview_lexicons WHERE id = ? AND source = 'network' AND authority_did = ?", backend, ); - let tracked: Option<(Option,)> = sqlx::query_as(&select_sql) + let tracked: Option<(Option,)> = crate::db::query_as(&select_sql) .bind(nsid) .bind(did) .fetch_optional(db) @@ -328,7 +328,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "#, backend, ); - if let Err(e) = sqlx::query(&upsert_sql) + if let Err(e) = crate::db::query(&upsert_sql) .bind(nsid) .bind(serde_json::to_string(rec).unwrap_or_default()) .bind(&target_collection) @@ -355,7 +355,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "delete" => { // Remove from lexicons table and registry. let delete_sql = adapt_sql("DELETE FROM happyview_lexicons WHERE id = ?", backend); - let _ = sqlx::query(&delete_sql).bind(nsid).execute(db).await; + let _ = crate::db::query(&delete_sql).bind(nsid).execute(db).await; let was_present = lexicons.remove(nsid).await; if was_present { diff --git a/src/record_refs.rs b/src/record_refs.rs index dfc3ccf..a48ab2b 100644 --- a/src/record_refs.rs +++ b/src/record_refs.rs @@ -44,7 +44,7 @@ pub async fn sync_refs( "DELETE FROM happyview_record_refs WHERE source_uri = ?", backend, ); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(source_uri) .execute(db) .await?; @@ -55,7 +55,7 @@ pub async fn sync_refs( backend, ); for target_uri in &uris { - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(source_uri) .bind(target_uri) .bind(collection) diff --git a/src/repo/session.rs b/src/repo/session.rs index bc66a96..e9bbbfa 100644 --- a/src/repo/session.rs +++ b/src/repo/session.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_dpop_client_id( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(&state.db) .await diff --git a/src/resolve.rs b/src/resolve.rs index e01bace..f67b738 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -1,4 +1,5 @@ use hickory_resolver::Resolver; +use hickory_resolver::proto::rr::RData; use crate::error::AppError; use crate::profile::resolve_pds_endpoint; @@ -30,15 +31,21 @@ pub async fn resolve_nsid_authority( let resolver = Resolver::builder_tokio() .map_err(|e| AppError::Internal(format!("failed to create DNS resolver: {e}")))? - .build(); + .build() + .map_err(|e| AppError::Internal(format!("failed to build DNS resolver: {e}")))?; let txt_lookup = resolver.txt_lookup(&lookup_name).await.map_err(|e| { AppError::BadRequest(format!("DNS TXT lookup failed for {lookup_name}: {e}")) })?; let did = txt_lookup + .answers() .iter() - .flat_map(|txt| txt.txt_data().iter()) + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt), + _ => None, + }) + .flat_map(|txt| txt.txt_data.iter()) .filter_map(|data| { let s = std::str::from_utf8(data).ok()?; s.strip_prefix("did=") diff --git a/src/server.rs b/src/server.rs index 2bab835..dddfa2b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -431,10 +431,10 @@ fn extract_public_key_multibase( let private_bytes = crate::plugin::encryption::decrypt(encryption_key, &encrypted) .map_err(|e| AppError::Internal(format!("failed to decrypt signing key: {e}")))?; - let signing_key = p256::ecdsa::SigningKey::from_bytes(private_bytes.as_slice().into()) + let signing_key = p256::ecdsa::SigningKey::from_slice(private_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); // Multikey format: multicodec varint prefix for P-256 (0x1200) then base58btc with 'z' prefix let mut multikey_bytes = vec![0x80, 0x24]; diff --git a/src/service_entries.rs b/src/service_entries.rs index a272187..377d260 100644 --- a/src/service_entries.rs +++ b/src/service_entries.rs @@ -63,7 +63,7 @@ pub async fn list_entries( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| AppError::Internal(format!("failed to list service entries: {e}")))?; @@ -84,7 +84,7 @@ pub async fn create_entry( backend, ); - let row: (i64,) = sqlx::query_as(&insert_sql) + let row: (i64,) = crate::db::query_as(&insert_sql) .bind(&body.fragment_id) .bind(&body.service_type) .bind(&now) @@ -100,7 +100,7 @@ pub async fn create_entry( backend, ); - let entry_row: ServiceEntryRow = sqlx::query_as(&fetch_sql) + let entry_row: ServiceEntryRow = crate::db::query_as(&fetch_sql) .bind(id) .fetch_one(db) .await @@ -145,7 +145,7 @@ pub async fn update_entry( "SELECT id, fragment_id, service_type, access_mode, created_at, updated_at FROM happyview_service_entries WHERE id = ?", backend, ); - let row: Option = sqlx::query_as(&fetch_sql) + let row: Option = crate::db::query_as(&fetch_sql) .bind(id) .fetch_optional(db) .await @@ -161,7 +161,7 @@ pub async fn update_entry( ); let update_sql = adapt_sql(&raw, backend); - let mut query = sqlx::query(&update_sql); + let mut query = crate::db::query(&update_sql); if let Some(v) = &body.fragment_id { query = query.bind(v.as_str()); } @@ -186,7 +186,7 @@ pub async fn update_entry( "SELECT id, fragment_id, service_type, access_mode, created_at, updated_at FROM happyview_service_entries WHERE id = ?", backend, ); - let row: ServiceEntryRow = sqlx::query_as(&fetch_sql) + let row: ServiceEntryRow = crate::db::query_as(&fetch_sql) .bind(id) .fetch_one(db) .await @@ -206,7 +206,7 @@ pub async fn delete_entry( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(db) .await @@ -230,7 +230,7 @@ pub async fn list_entry_xrpcs( backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .bind(entry_id) .fetch_all(db) .await @@ -252,7 +252,7 @@ pub async fn add_entry_xrpcs( ); for lexicon_id in lexicon_ids { - sqlx::query(&sql) + crate::db::query(&sql) .bind(entry_id) .bind(lexicon_id.as_str()) .execute(db) @@ -276,7 +276,7 @@ pub async fn remove_entry_xrpcs( ); for lexicon_id in lexicon_ids { - sqlx::query(&sql) + crate::db::query(&sql) .bind(entry_id) .bind(lexicon_id.as_str()) .execute(db) @@ -306,7 +306,7 @@ pub async fn check_access( backend, ); - let row: Option<(i64, String)> = sqlx::query_as(&sql) + let row: Option<(i64, String)> = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -327,7 +327,7 @@ pub async fn check_access( backend, ); - let found: Option<(i32,)> = sqlx::query_as(&check_sql) + let found: Option<(i32,)> = crate::db::query_as(&check_sql) .bind(entry_id) .bind(xrpc_method) .fetch_optional(db) @@ -350,7 +350,7 @@ pub async fn services_for_lexicon( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(lexicon_id) .fetch_all(db) .await diff --git a/src/service_identity.rs b/src/service_identity.rs index ee72032..744d220 100644 --- a/src/service_identity.rs +++ b/src/service_identity.rs @@ -86,7 +86,7 @@ pub async fn get_identity( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .fetch_optional(db) .await .map_err(|e| AppError::Internal(format!("failed to get service identity: {e}")))?; @@ -152,7 +152,7 @@ pub async fn upsert_identity( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(mode.as_str()) .bind(did) .bind(signing_key_enc) @@ -175,7 +175,7 @@ pub async fn mark_setup_complete(db: &AnyPool, backend: DatabaseBackend) -> Resu backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&now) .execute(db) .await diff --git a/src/setup.rs b/src/setup.rs index 2923f14..99578cd 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -8,7 +8,7 @@ use axum::{ routing::{get, post}, }; use axum_extra::extract::cookie::{Cookie, Key, SignedCookieJar}; -use rand::RngCore; +use rand::Rng; use serde::Deserialize; use crate::admin::auth::UserAuth; @@ -124,7 +124,7 @@ fn generate_encrypted_signing_key(state: &AppState) -> Result rand::rng().fill_bytes(&mut rng_bytes); // Validate the key bytes produce a valid signing key - SigningKey::from_bytes((&rng_bytes[..]).into()) + SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let encryption_key = state @@ -194,7 +194,7 @@ async fn plc_register( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -205,7 +205,7 @@ async fn plc_register( let rotation_key_did = crate::plc::private_key_to_did_key(&rotation_key_bytes)?; let rotation_signing_key = - p256::ecdsa::SigningKey::from_bytes(rotation_key_bytes.as_slice().into()) + p256::ecdsa::SigningKey::from_slice(rotation_key_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid rotation key: {e}")))?; // Build service entries from the database @@ -263,7 +263,7 @@ async fn plc_request( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -321,7 +321,7 @@ async fn plc_submit( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -495,7 +495,7 @@ async fn attach_auth_confirm( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -517,7 +517,7 @@ async fn attach_auth_confirm( } // Verify the original DID is a known admin user - let user_exists: Option<(i32,)> = sqlx::query_as(&crate::db::adapt_sql( + let user_exists: Option<(i32,)> = crate::db::query_as(&crate::db::adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", state.db_backend, )) @@ -567,7 +567,7 @@ async fn export_rotation_key( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -711,13 +711,19 @@ async fn resolve_handle_to_did(http: &reqwest::Client, handle: &str) -> Option` use hickory_resolver::Resolver; + use hickory_resolver::proto::rr::RData; let lookup_name = format!("_atproto.{}.", handle); - if let Ok(resolver) = Resolver::builder_tokio().map(|b| b.build()) + if let Ok(resolver) = Resolver::builder_tokio().and_then(|b| b.build()) && let Ok(txt_lookup) = resolver.txt_lookup(&lookup_name).await { let did = txt_lookup + .answers() .iter() - .flat_map(|txt| txt.txt_data().iter()) + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt), + _ => None, + }) + .flat_map(|txt| txt.txt_data.iter()) .filter_map(|data| { let s = std::str::from_utf8(data).ok()?; s.strip_prefix("did=") diff --git a/src/spaces/auth.rs b/src/spaces/auth.rs index 7b4abdc..a8a041a 100644 --- a/src/spaces/auth.rs +++ b/src/spaces/auth.rs @@ -1,7 +1,7 @@ use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use sha2::{Digest, Sha256}; use uuid::Uuid; @@ -268,7 +268,7 @@ async fn get_or_create_signing_key( "SELECT signing_key_enc FROM happyview_space_dids WHERE space_id = ?", backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&sql) + let row: Option<(Vec,)> = crate::db::query_as(&sql) .bind(&space.id) .fetch_optional(pool) .await @@ -301,7 +301,7 @@ async fn get_or_create_signing_key( backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(Uuid::new_v4().to_string()) .bind(&space.did) .bind(&space.id) @@ -324,11 +324,11 @@ fn generate_space_keypair() -> Result { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let public_point = verifying_key.to_encoded_point(false); + let public_point = verifying_key.to_sec1_point(false); let x_bytes = public_point .x() @@ -370,7 +370,7 @@ async fn store_credential_record( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(Uuid::new_v4().to_string()) .bind(space_id) .bind(issued_to) diff --git a/src/spaces/client_attestation.rs b/src/spaces/client_attestation.rs index d635340..2a42c4e 100644 --- a/src/spaces/client_attestation.rs +++ b/src/spaces/client_attestation.rs @@ -112,7 +112,7 @@ pub async fn verify_client_attestation( let sig_bytes = URL_SAFE_NO_PAD .decode(parts[2]) .map_err(|_| AppError::Auth("invalid attestation signature encoding".into()))?; - let sig = p256::ecdsa::Signature::from_bytes(sig_bytes.as_slice().into()) + let sig = p256::ecdsa::Signature::from_slice(sig_bytes.as_slice()) .map_err(|_| AppError::Auth("invalid attestation signature format".into()))?; use p256::ecdsa::signature::Verifier; jwk.verify(message.as_bytes(), &sig) diff --git a/src/spaces/commit.rs b/src/spaces/commit.rs index bfc6810..e7e90b1 100644 --- a/src/spaces/commit.rs +++ b/src/spaces/commit.rs @@ -1,6 +1,7 @@ use hkdf::Hkdf; -use hmac::{Hmac, Mac}; +use hmac::{Hmac, KeyInit, Mac}; use k256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Signer, signature::Verifier}; +use rand::Rng; use sha2::Sha256; use crate::error::AppError; @@ -50,7 +51,7 @@ pub fn sign_commit( signing_key: &SigningKey, ) -> Result { let mut ikm = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut ikm); + rand::rng().fill_bytes(&mut ikm); let ctx = build_context(space_uri, author_did, rev, &ikm); @@ -63,7 +64,7 @@ pub fn sign_commit( hk.expand(&ctx, &mut derived_key) .map_err(|e| AppError::Internal(format!("HKDF expand failed: {e}")))?; - let mut mac_hasher = as Mac>::new_from_slice(&derived_key) + let mut mac_hasher = as KeyInit>::new_from_slice(&derived_key) .map_err(|e| AppError::Internal(format!("HMAC init failed: {e}")))?; mac_hasher.update(hash); let mac: [u8; 32] = mac_hasher.finalize().into_bytes().into(); @@ -93,7 +94,7 @@ pub fn verify_commit( let ctx = build_context(space_uri, author_did, &commit.rev, &commit.ikm); - let sig = Signature::from_bytes(commit.sig.as_slice().into()) + let sig = Signature::from_slice(commit.sig.as_slice()) .map_err(|_| AppError::Auth("invalid commit signature format".into()))?; verifying_key .verify(&ctx, &sig) @@ -105,7 +106,7 @@ pub fn verify_commit( hk.expand(&ctx, &mut derived_key) .map_err(|e| AppError::Internal(format!("HKDF expand failed: {e}")))?; - let mut mac_hasher = as Mac>::new_from_slice(&derived_key) + let mut mac_hasher = as KeyInit>::new_from_slice(&derived_key) .map_err(|e| AppError::Internal(format!("HMAC init failed: {e}")))?; mac_hasher.update(&commit.hash); @@ -124,7 +125,7 @@ mod tests { fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; bytes[31] = 1; // valid non-zero scalar - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } #[test] @@ -226,7 +227,7 @@ mod tests { let sk1 = test_signing_key(); let mut bytes2 = [0u8; 32]; bytes2[31] = 2; - let sk2 = SigningKey::from_bytes((&bytes2[..]).into()).unwrap(); + let sk2 = SigningKey::from_slice(&bytes2[..]).unwrap(); let vk2 = *sk2.verifying_key(); let hash = [0xDD; 32]; diff --git a/src/spaces/credential.rs b/src/spaces/credential.rs index beb02f2..05d2ec0 100644 --- a/src/spaces/credential.rs +++ b/src/spaces/credential.rs @@ -109,15 +109,13 @@ pub fn verify_delegation_token( .map_err(|_| AppError::Auth("invalid delegation token signature encoding".into()))?; // Try direct verify, then with low-S normalization - let verified = if let Ok(sig) = K256Signature::from_bytes(sig_bytes.as_slice().into()) { + let verified = if let Ok(sig) = K256Signature::from_slice(sig_bytes.as_slice()) { if verifying_key.verify(message.as_bytes(), &sig).is_ok() { true - } else if let Some(normalized) = sig.normalize_s() { + } else { verifying_key - .verify(message.as_bytes(), &normalized) + .verify(message.as_bytes(), &sig.normalize_s()) .is_ok() - } else { - false } } else { false @@ -174,7 +172,7 @@ pub fn sign_credential( .decode(d_b64) .map_err(|_| AppError::Internal("invalid signing key d parameter".into()))?; - let signing_key = SigningKey::from_bytes((&d_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&d_bytes[..]) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let header = serde_json::json!({ @@ -224,7 +222,7 @@ pub fn verify_credential( let sig_bytes = URL_SAFE_NO_PAD .decode(parts[2]) .map_err(|_| AppError::Auth("invalid credential signature encoding".into()))?; - let signature = Signature::from_bytes(sig_bytes.as_slice().into()) + let signature = Signature::from_slice(sig_bytes.as_slice()) .map_err(|_| AppError::Auth("invalid credential signature format".into()))?; verifying_key @@ -291,7 +289,7 @@ pub fn multikey_to_p256_jwk(public_key_multibase: &str) -> Result K256SigningKey { let key_bytes = [0x42u8; 32]; - K256SigningKey::from_bytes((&key_bytes[..]).into()).expect("valid key") + K256SigningKey::from_slice(&key_bytes[..]).expect("valid key") } fn make_delegation_claims() -> DelegationTokenClaims { @@ -477,7 +475,7 @@ mod tests { #[test] fn delegation_rejects_wrong_key() { let signing_key = make_k256_signing_key(); - let other_key = K256SigningKey::from_bytes((&[0x99u8; 32][..]).into()).unwrap(); + let other_key = K256SigningKey::from_slice(&[0x99u8; 32][..]).unwrap(); let verifying_key = K256VerifyingKey::from(&other_key); let claims = make_delegation_claims(); @@ -591,7 +589,7 @@ mod tests { let d_b64 = keypair.private_jwk["d"].as_str().unwrap(); let d_bytes = URL_SAFE_NO_PAD.decode(d_b64).unwrap(); - let signing_key = p256::ecdsa::SigningKey::from_bytes((&d_bytes[..]).into()).unwrap(); + let signing_key = p256::ecdsa::SigningKey::from_slice(&d_bytes[..]).unwrap(); let header = serde_json::json!({ "alg": "ES256", "typ": "JWT" }); let header_b64 = URL_SAFE_NO_PAD.encode(serde_json::to_vec(&header).unwrap()); diff --git a/src/spaces/db.rs b/src/spaces/db.rs index ace617c..2ebb75c 100644 --- a/src/spaces/db.rs +++ b/src/spaces/db.rs @@ -22,7 +22,7 @@ pub async fn create_space( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&space.id) .bind(&space.did) .bind(&space.authority_did) @@ -54,7 +54,7 @@ pub async fn get_space( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(id) .fetch_optional(pool) .await @@ -75,7 +75,7 @@ pub async fn get_space_by_address( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(did) .bind(type_nsid) .bind(skey) @@ -96,7 +96,7 @@ pub async fn list_spaces_by_owner( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(authority_did) .fetch_all(pool) .await @@ -132,7 +132,7 @@ pub async fn list_spaces_for_user( ) }; - let mut query = sqlx::query_as::<_, (String, String, String, String, String)>(&sql).bind(did); + let mut query = crate::db::query_as::<(String, String, String, String, String)>(&sql).bind(did); if let Some((ref ts, ref uri)) = decoded_cursor { query = query.bind(ts.as_str()).bind(ts.as_str()).bind(uri.as_str()); } @@ -179,7 +179,7 @@ pub async fn update_space( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&space.display_name) .bind(&space.description) .bind(space.mint_policy.as_str()) @@ -202,7 +202,7 @@ pub async fn delete_space( ) -> Result { let sql = adapt_sql("DELETE FROM happyview_spaces WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(pool) .await @@ -271,7 +271,7 @@ pub async fn add_member( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&member.id) .bind(&member.space_id) .bind(&member.did) @@ -297,7 +297,7 @@ pub async fn remove_member( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(space_id) .bind(did) .execute(pool) @@ -317,7 +317,7 @@ pub async fn is_space_credential_revoked( "SELECT revoked_at FROM happyview_space_credentials WHERE token_hash = ? AND revoked_at IS NOT NULL LIMIT 1", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(token_hash) .fetch_optional(pool) .await @@ -337,7 +337,7 @@ pub async fn revoke_space_credentials_for_member( "UPDATE happyview_space_credentials SET revoked_at = ? WHERE space_id = ? AND issued_to = ? AND revoked_at IS NULL", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(now_rfc3339()) .bind(space_id) .bind(did) @@ -358,7 +358,7 @@ pub async fn get_member( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(did) .fetch_optional(pool) @@ -378,7 +378,7 @@ pub async fn list_direct_members( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await @@ -397,7 +397,7 @@ pub async fn list_spaces_for_member( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(did) .fetch_all(pool) .await @@ -446,7 +446,7 @@ pub async fn upsert_space_record( ), }; - sqlx::query(&sql) + crate::db::query(&sql) .bind(&record.uri) .bind(&record.space_id) .bind(&record.author_did) @@ -472,7 +472,7 @@ pub async fn get_space_record( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(uri) .fetch_optional(pool) .await @@ -493,7 +493,7 @@ pub async fn get_space_record_by_parts( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(collection) .bind(rkey) @@ -538,7 +538,7 @@ pub async fn list_space_records( ); let sql = adapt_sql(&raw, backend); - let mut query = sqlx::query_as::<_, RecordRow>(&sql).bind(space_id); + let mut query = crate::db::query_as::(&sql).bind(space_id); if let Some(r) = repo { query = query.bind(r); } @@ -580,7 +580,7 @@ pub async fn list_all_space_records( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .bind(author_did) .fetch_all(pool) @@ -604,7 +604,7 @@ pub async fn insert_space_record( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&record.uri) .bind(&record.space_id) .bind(&record.author_did) @@ -642,7 +642,7 @@ pub async fn upsert_space_record_with_swap( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&record_json) .bind(&record.cid) .bind(&now) @@ -670,7 +670,7 @@ pub async fn delete_space_record( ) -> Result { let sql = adapt_sql("DELETE FROM happyview_space_records WHERE uri = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(uri) .execute(pool) .await @@ -690,7 +690,7 @@ pub async fn delete_space_record_with_swap( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(uri) .bind(swap_cid) .execute(pool) @@ -720,7 +720,7 @@ pub async fn update_space_revision( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(revision) .bind(&now) .bind(space_id) @@ -746,7 +746,7 @@ pub async fn get_or_create_repo_state( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(author_did) .fetch_optional(pool) @@ -764,7 +764,7 @@ pub async fn get_or_create_repo_state( "INSERT INTO happyview_space_repo_state (id, space_id, author_did, lthash_state, rev, hash, ikm, sig, mac, updated_at) VALUES (?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, ?)", backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(space_id) .bind(author_did) @@ -799,7 +799,7 @@ pub async fn update_repo_state( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&state.lthash_state) .bind(&state.rev) .bind(&state.hash) @@ -858,7 +858,7 @@ pub async fn register_notify( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(®.id) .bind(®.space_id) .bind(®.author_did) @@ -891,7 +891,7 @@ pub async fn list_notify_registrations( ) }; - let mut query = sqlx::query_as::<_, NotifyRow>(&sql).bind(space_id); + let mut query = crate::db::query_as::(&sql).bind(space_id); if let Some(did) = author_did { query = query.bind(did); } @@ -914,7 +914,7 @@ pub async fn delete_notify_registration( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(pool) .await @@ -986,7 +986,7 @@ pub async fn find_blob_author_did( "SELECT author_did FROM happyview_space_records WHERE space_id = ? AND record LIKE ? LIMIT 1", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(space_id) .bind(&pattern) .fetch_optional(pool) @@ -1009,7 +1009,7 @@ pub async fn list_space_repos( backend, ); - let rows: Vec<(String, Option)> = sqlx::query_as(&sql) + let rows: Vec<(String, Option)> = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await @@ -1036,7 +1036,7 @@ pub async fn create_invite( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&invite.id) .bind(&invite.space_id) .bind(&invite.token_hash) @@ -1064,7 +1064,7 @@ pub async fn get_invite_by_token_hash( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(token_hash) .fetch_optional(pool) .await @@ -1083,7 +1083,7 @@ pub async fn increment_invite_uses( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(invite_id) .execute(pool) .await @@ -1102,7 +1102,7 @@ pub async fn revoke_invite( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(invite_id) .execute(pool) .await @@ -1121,7 +1121,7 @@ pub async fn list_invites( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await diff --git a/src/spaces/integration_tests.rs b/src/spaces/integration_tests.rs index c5afda8..84914e6 100644 --- a/src/spaces/integration_tests.rs +++ b/src/spaces/integration_tests.rs @@ -14,7 +14,7 @@ mod tests { fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; bytes[31] = 1; - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } /// Add two records, generate a commit over the hash, verify it. @@ -117,7 +117,7 @@ mod tests { use k256::ecdsa::{SigningKey as K256SigningKey, VerifyingKey as K256VerifyingKey}; fn k256_key() -> K256SigningKey { - K256SigningKey::from_bytes((&[0x42u8; 32][..]).into()).unwrap() + K256SigningKey::from_slice(&[0x42u8; 32][..]).unwrap() } fn now_secs() -> u64 { @@ -530,7 +530,7 @@ mod tests { // Can reconstruct verifying key from public JWK let vk = p256_jwk_to_verifying_key(&keypair.public_jwk).unwrap(); - let point = vk.to_encoded_point(false); + let point = vk.to_sec1_point(false); assert!(point.x().is_some()); assert!(point.y().is_some()); } diff --git a/src/spaces/oplog.rs b/src/spaces/oplog.rs index 2beb320..3c9299d 100644 --- a/src/spaces/oplog.rs +++ b/src/spaces/oplog.rs @@ -11,7 +11,7 @@ pub async fn append_op( "INSERT INTO happyview_space_record_oplog (id, space_id, author_did, rev, idx, action, collection, rkey, cid, prev, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&entry.id) .bind(&entry.space_id) .bind(&entry.author_did) @@ -63,7 +63,7 @@ pub async fn list_ops( String, ); - let mut query = sqlx::query_as::<_, OplogRow>(&sql) + let mut query = crate::db::query_as::(&sql) .bind(space_id) .bind(author_did); if let Some(rev) = since_rev { @@ -133,7 +133,7 @@ pub async fn list_ops_with_values( Option, ); - let mut query = sqlx::query_as::<_, OplogWithValueRow>(&sql) + let mut query = crate::db::query_as::(&sql) .bind(space_id) .bind(author_did); if let Some(rev) = since_rev { diff --git a/src/spaces/routes.rs b/src/spaces/routes.rs index a602a80..d96b1a4 100644 --- a/src/spaces/routes.rs +++ b/src/spaces/routes.rs @@ -428,7 +428,7 @@ async fn require_space_admin(state: &AppState, space: &Space, did: &str) -> Resu "SELECT is_super FROM happyview_users WHERE did = ?", state.db_backend, ); - let row: Option<(i32,)> = sqlx::query_as(&sql) + let row: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .fetch_optional(&state.db) .await @@ -508,7 +508,7 @@ async fn resolve_client_id_url( "SELECT client_id_url FROM happyview_api_clients WHERE client_key = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(&state.db) .await @@ -974,7 +974,7 @@ async fn create_invite( require_space_admin(&state, &space, claims.did()).await?; let mut token_bytes = [0u8; 24]; - rand::Fill::fill(&mut token_bytes, &mut rand::rng()); + rand::Rng::fill_bytes(&mut rand::rng(), &mut token_bytes); let token = hex::encode(token_bytes); let token_hash = hex::encode(Sha256::digest(token.as_bytes())); @@ -1137,7 +1137,7 @@ async fn get_delegation_token( AppError::Internal("TOKEN_ENCRYPTION_KEY is required for space credentials".into()) })?; - let signing_key = k256::ecdsa::SigningKey::from_bytes(encryption_key.into()) + let signing_key = k256::ecdsa::SigningKey::from_slice(encryption_key) .map_err(|e| AppError::Internal(format!("failed to derive delegation signing key: {e}")))?; let now = std::time::SystemTime::now() @@ -1522,10 +1522,9 @@ async fn get_space_credential( })?; let verifying_key = { - let signing_key = - k256::ecdsa::SigningKey::from_bytes(encryption_key.into()).map_err(|e| { - AppError::Internal(format!("failed to derive delegation signing key: {e}")) - })?; + let signing_key = k256::ecdsa::SigningKey::from_slice(encryption_key).map_err(|e| { + AppError::Internal(format!("failed to derive delegation signing key: {e}")) + })?; k256::ecdsa::VerifyingKey::from(&signing_key) }; diff --git a/src/spaces/simplespace.rs b/src/spaces/simplespace.rs index 8b7c8f5..17b94c4 100644 --- a/src/spaces/simplespace.rs +++ b/src/spaces/simplespace.rs @@ -182,7 +182,7 @@ async fn require_space_admin(state: &AppState, space: &Space, did: &str) -> Resu "SELECT is_super FROM happyview_users WHERE did = ?", state.db_backend, ); - let row: Option<(i32,)> = sqlx::query_as(&sql) + let row: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .fetch_optional(&state.db) .await diff --git a/src/verification_methods.rs b/src/verification_methods.rs index 6916c71..75d5031 100644 --- a/src/verification_methods.rs +++ b/src/verification_methods.rs @@ -2,7 +2,7 @@ use base64::Engine; use base64::engine::general_purpose::STANDARD; use chrono::Utc; use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use serde::{Deserialize, Serialize}; use sqlx::AnyPool; use uuid::Uuid; @@ -50,7 +50,7 @@ pub async fn list_methods( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| AppError::Internal(format!("failed to list verification methods: {e}")))?; @@ -68,7 +68,7 @@ pub async fn get_method_by_fragment( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -97,7 +97,7 @@ pub async fn create_method( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(fragment_id) .bind(&public_key_multibase) @@ -126,7 +126,7 @@ pub async fn delete_method( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(fragment_id) .execute(db) .await @@ -146,7 +146,7 @@ pub async fn get_private_key_bytes( backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&sql) + let row: Option<(Vec,)> = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -175,11 +175,11 @@ fn generate_p256_keypair() -> Result<(Vec, String), AppError> { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate verification key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let compressed = verifying_key.to_encoded_point(true); + let compressed = verifying_key.to_sec1_point(true); // Multikey format: 0x8024 varint for P-256 + compressed public key, base58btc let mut multikey_bytes = vec![0x80, 0x24]; @@ -190,7 +190,7 @@ fn generate_p256_keypair() -> Result<(Vec, String), AppError> { } pub fn private_key_bytes_to_signing_key(key_bytes: &[u8]) -> Result { - SigningKey::from_bytes(key_bytes.into()) + SigningKey::from_slice(key_bytes) .map_err(|e| AppError::Internal(format!("invalid verification signing key: {e}"))) } diff --git a/src/xrpc/procedure.rs b/src/xrpc/procedure.rs index 8dfdf3f..c9c6c86 100644 --- a/src/xrpc/procedure.rs +++ b/src/xrpc/procedure.rs @@ -85,7 +85,7 @@ pub(crate) async fn handle_procedure( "SELECT outbound_xrpcs FROM happyview_scripts WHERE id = ?", state.db_backend, ); - if let Ok(Some((Some(json_str),))) = sqlx::query_as::<_, (Option,)>(&outbound_sql) + if let Ok(Some((Some(json_str),))) = crate::db::query_as::<(Option,)>(&outbound_sql) .bind(&trigger) .fetch_optional(&state.db) .await @@ -278,7 +278,7 @@ async fn handle_create_record( backend, ); let now = now_rfc3339(); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(uri) .bind(claims.did()) .bind(collection) @@ -365,7 +365,7 @@ async fn handle_put_record( "#, backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&uri) .bind(claims.did()) .bind(collection) @@ -423,7 +423,7 @@ async fn handle_delete_record( let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let _ = sqlx::query(&sql).bind(&uri).execute(&state.db).await; + let _ = crate::db::query(&sql).bind(&uri).execute(&state.db).await; Ok(( StatusCode::OK, diff --git a/src/xrpc/query.rs b/src/xrpc/query.rs index 437acc0..3b45a45 100644 --- a/src/xrpc/query.rs +++ b/src/xrpc/query.rs @@ -69,7 +69,7 @@ pub(crate) async fn handle_query( "SELECT uri, did, record FROM happyview_records WHERE collection = ? AND did = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(collection) .bind(did) .bind(limit) @@ -82,7 +82,7 @@ pub(crate) async fn handle_query( "SELECT uri, did, record FROM happyview_records WHERE collection = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(collection) .bind(limit) .bind(offset) @@ -122,7 +122,7 @@ pub(super) async fn handle_get_record(state: &AppState, uri: &str) -> Result = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(uri) .fetch_optional(&state.db) .await diff --git a/tests/common/app.rs b/tests/common/app.rs index a5b9bfd..ba6cbc3 100644 --- a/tests/common/app.rs +++ b/tests/common/app.rs @@ -11,6 +11,7 @@ use happyview::config::Config; use happyview::db::{DatabaseBackend, adapt_sql, now_rfc3339}; use happyview::lexicon::LexiconRegistry; use happyview::{AppState, server}; +use p256::elliptic_curve::sec1::ToSec1Point; use tokio::sync::watch; use wiremock::MockServer; @@ -73,7 +74,7 @@ impl TestApp { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uuid::Uuid::new_v4().to_string()) .bind(&admin_did) .bind(1_i32) @@ -233,7 +234,7 @@ impl TestApp { allowed_origins: Option>, ) -> (String, String, String) { use happyview::db::{adapt_sql, now_rfc3339}; - use rand::RngCore; + use rand::Rng; use sha2::{Digest, Sha256}; let mut key_bytes = [0u8; 16]; @@ -256,7 +257,7 @@ impl TestApp { self.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(&client_key) .bind(&secret_hash) @@ -290,14 +291,14 @@ impl TestApp { pub async fn setup_did_web(&mut self) -> String { use p256::ecdsa::SigningKey; - use rand::RngCore; + use rand::Rng; let encryption_key = [0x42u8; 32]; self.state.config.token_encryption_key = Some(encryption_key); let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let private_bytes = signing_key.to_bytes(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &private_bytes) .expect("encryption failed"); @@ -388,13 +389,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store @@ -441,14 +442,14 @@ impl TestApp { pub async fn setup_did_plc(&mut self) -> String { use p256::ecdsa::SigningKey; - use rand::RngCore; + use rand::Rng; let encryption_key = [0x42u8; 32]; self.state.config.token_encryption_key = Some(encryption_key); let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let private_bytes = signing_key.to_bytes(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &private_bytes) .expect("encryption failed"); @@ -487,13 +488,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store @@ -528,13 +529,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store diff --git a/tests/common/db.rs b/tests/common/db.rs index 1f5dcd0..5194d58 100644 --- a/tests/common/db.rs +++ b/tests/common/db.rs @@ -35,7 +35,7 @@ pub async fn acquire_test_lock() -> Option { .await .expect("failed to create advisory lock pool"); - sqlx::query("SELECT pg_advisory_lock(42)") + happyview::db::query("SELECT pg_advisory_lock(42)") .execute(&lock_pool) .await .expect("failed to acquire advisory lock"); @@ -47,7 +47,7 @@ pub async fn truncate_all(pool: &AnyPool) { let backend = test_backend(); match backend { DatabaseBackend::Postgres => { - sqlx::query( + happyview::db::query( "TRUNCATE happyview_records, happyview_lexicons, happyview_backfill_jobs, happyview_users, happyview_user_permissions, happyview_api_keys, happyview_event_logs, happyview_script_variables, happyview_scripts, happyview_dead_letter_scripts, happyview_dead_letter_hooks, happyview_record_refs, happyview_labeler_subscriptions, happyview_labels, happyview_instance_settings, happyview_domains, happyview_dpop_sessions, happyview_dpop_keys, happyview_api_clients, happyview_delegated_accounts, happyview_account_delegates, happyview_service_identity, happyview_service_entries, happyview_service_entry_xrpcs, happyview_jobs, happyview_spaces, happyview_space_members, happyview_space_records, happyview_space_repo_state, happyview_space_record_oplog, happyview_space_notify_registrations, happyview_space_invites RESTART IDENTITY CASCADE", ) .execute(pool) @@ -93,7 +93,7 @@ pub async fn truncate_all(pool: &AnyPool) { "happyview_jobs", ]; for table in tables { - sqlx::query(&format!("DELETE FROM {table}")) + happyview::db::query(&format!("DELETE FROM {table}")) .execute(pool) .await .unwrap_or_else(|e| panic!("failed to delete from {table}: {e}")); diff --git a/tests/common/tls.rs b/tests/common/tls.rs index 7ab1eb2..e146655 100644 --- a/tests/common/tls.rs +++ b/tests/common/tls.rs @@ -28,7 +28,7 @@ pub async fn start_did_web_server( let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]) .expect("failed to generate self-signed cert"); let cert_der = cert.cert.der().to_vec(); - let key_der = cert.key_pair.serialize_der(); + let key_der = cert.signing_key.serialize_der(); let tls_config = rustls::ServerConfig::builder() .with_no_client_auth() diff --git a/tests/dev_happyview.rs b/tests/dev_happyview.rs index b5797fe..fdf87a9 100644 --- a/tests/dev_happyview.rs +++ b/tests/dev_happyview.rs @@ -305,7 +305,7 @@ async fn delete_api_client_success() { VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&client_id) .bind("hvc_delete_test_key") .bind("dummyhash") @@ -418,7 +418,7 @@ async fn get_api_client_returns_client() { VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&client_id) .bind("hvc_owned_test_key") .bind("dummyhash") diff --git a/tests/e2e_admin.rs b/tests/e2e_admin.rs index 1e5ea6a..1abb938 100644 --- a/tests/e2e_admin.rs +++ b/tests/e2e_admin.rs @@ -220,7 +220,7 @@ async fn admin_auto_bootstrap_first_user() { let backend = app.state.db_backend; // Clear the seeded user so the table is empty. - sqlx::query("DELETE FROM happyview_users") + happyview::db::query("DELETE FROM happyview_users") .execute(&app.state.db) .await .unwrap(); @@ -246,7 +246,7 @@ async fn admin_auto_bootstrap_first_user() { "SELECT COUNT(*) FROM happyview_users WHERE did = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(bootstrap_did) .fetch_one(&app.state.db) .await @@ -524,7 +524,7 @@ async fn stats_with_seeded_records() { "INSERT INTO happyview_lexicons (id, lexicon_json, created_at) VALUES (?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("test.collection") .bind(serde_json::to_string(&lexicon_json_val).unwrap_or_default()) .bind(&now) @@ -538,7 +538,7 @@ async fn stats_with_seeded_records() { "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("at://did:plc:test/test.collection/1") .bind("did:plc:test") .bind("test.collection") @@ -649,7 +649,7 @@ async fn backfill_cancel_running_job() { "INSERT INTO happyview_backfill_jobs (id, status, stage, started_at, created_at) VALUES (?, 'running', 'discovering_repos', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) @@ -687,7 +687,7 @@ async fn backfill_cancel_already_cancelling_is_idempotent() { "INSERT INTO happyview_backfill_jobs (id, status, stage, started_at, created_at) VALUES (?, 'cancelling', 'fetching_records', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) @@ -724,7 +724,7 @@ async fn backfill_cancel_completed_returns_400() { "INSERT INTO happyview_backfill_jobs (id, status, stage, completed_at, created_at) VALUES (?, 'completed', 'completed', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) diff --git a/tests/e2e_admin_service_entries.rs b/tests/e2e_admin_service_entries.rs index 9fe21d5..c4132fe 100644 --- a/tests/e2e_admin_service_entries.rs +++ b/tests/e2e_admin_service_entries.rs @@ -810,9 +810,8 @@ async fn sync_plc_updates_did_document() { let encryption_key = [0x42u8; 32]; let mut rotation_key_bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut rotation_key_bytes); - let _rotation_key = - p256::ecdsa::SigningKey::from_bytes((&rotation_key_bytes[..]).into()).unwrap(); + rand::Rng::fill_bytes(&mut rand::rng(), &mut rotation_key_bytes); + let _rotation_key = p256::ecdsa::SigningKey::from_slice(&rotation_key_bytes[..]).unwrap(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &rotation_key_bytes) .expect("encryption failed"); let rotation_key_enc = @@ -822,7 +821,7 @@ async fn sync_plc_updates_did_document() { "UPDATE happyview_service_identity SET rotation_key_enc = ? WHERE id = 1", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&rotation_key_enc) .execute(&app.state.db) .await diff --git a/tests/e2e_api_clients.rs b/tests/e2e_api_clients.rs index 28c0865..6f92248 100644 --- a/tests/e2e_api_clients.rs +++ b/tests/e2e_api_clients.rs @@ -694,7 +694,7 @@ async fn test_deactivate_parent_cascades_to_children() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) @@ -799,7 +799,7 @@ async fn test_delete_parent_cascades_to_children() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) @@ -919,7 +919,7 @@ async fn test_list_api_clients_filter_by_parent() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child1_id) .bind(&child1_key) .bind(&child1_hash) @@ -947,7 +947,7 @@ async fn test_list_api_clients_filter_by_parent() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql2) + happyview::db::query(&sql2) .bind(&child2_id) .bind(&child2_key) .bind(&child2_hash) @@ -1048,7 +1048,7 @@ async fn test_list_api_clients_includes_parent_and_owner_fields() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) diff --git a/tests/e2e_delegation.rs b/tests/e2e_delegation.rs index 98424c1..b05b207 100644 --- a/tests/e2e_delegation.rs +++ b/tests/e2e_delegation.rs @@ -975,7 +975,7 @@ async fn update_session_pds_url(app: &common::app::TestApp, user_did: &str, pds_ "UPDATE happyview_dpop_sessions SET pds_url = ? WHERE user_did = ?", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(pds_url) .bind(user_did) .execute(&app.state.db) diff --git a/tests/e2e_domains.rs b/tests/e2e_domains.rs index 97de213..5d18aeb 100644 --- a/tests/e2e_domains.rs +++ b/tests/e2e_domains.rs @@ -69,7 +69,7 @@ async fn seed_domain(app: &TestApp, id: &str, url: &str, is_primary: bool) { "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(id) .bind(url) .bind(if is_primary { 1i32 } else { 0i32 }) diff --git a/tests/e2e_jobs.rs b/tests/e2e_jobs.rs index eead318..bd93b7e 100644 --- a/tests/e2e_jobs.rs +++ b/tests/e2e_jobs.rs @@ -50,7 +50,7 @@ async fn seed_job(app: &TestApp, job_type: &str, status: &str) -> String { "INSERT INTO happyview_jobs (id, job_type, status, input, progress, created_by, created_at) VALUES (?, ?, ?, ?, '{}', ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(job_type) .bind(status) @@ -69,7 +69,7 @@ async fn set_job_status(app: &TestApp, id: &str, status: &str) { "UPDATE happyview_jobs SET status = ? WHERE id = ?", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(status) .bind(id) .execute(&app.state.db) diff --git a/tests/e2e_labelers.rs b/tests/e2e_labelers.rs index 21c95f3..e80245d 100644 --- a/tests/e2e_labelers.rs +++ b/tests/e2e_labelers.rs @@ -368,7 +368,7 @@ async fn labeler_delete_removes_labels() { "INSERT INTO happyview_labels (src, uri, val, cts) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("did:plc:lab1") .bind("at://did:plc:user/test.collection/rkey1") .bind("adult-content") @@ -393,7 +393,7 @@ async fn labeler_delete_removes_labels() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:lab1") .fetch_one(&app.state.db) .await diff --git a/tests/e2e_network_lexicons.rs b/tests/e2e_network_lexicons.rs index 9010e1b..3fee0d3 100644 --- a/tests/e2e_network_lexicons.rs +++ b/tests/e2e_network_lexicons.rs @@ -55,7 +55,7 @@ async fn seed_network_lexicon(app: &TestApp, nsid: &str, authority_did: &str) { backend, ); let now = now_rfc3339(); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(nsid) .bind(serde_json::to_string(&lexicon_json).unwrap_or_default()) .bind(authority_did) @@ -139,7 +139,7 @@ async fn network_lexicon_delete_removes_tracking_and_lexicon() { "SELECT COUNT(*) FROM happyview_lexicons WHERE id = ? AND source = 'network'", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(nsid) .fetch_one(&app.state.db) .await diff --git a/tests/e2e_scripts.rs b/tests/e2e_scripts.rs index 654821a..cb78016 100644 --- a/tests/e2e_scripts.rs +++ b/tests/e2e_scripts.rs @@ -147,7 +147,7 @@ async fn seed_record_row( VALUES (?, ?, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -161,7 +161,7 @@ async fn seed_record_row( } async fn count_records(app: &TestApp, uri: &str) -> i64 { - let (count,): (i64,) = sqlx::query_as(&adapt_sql( + let (count,): (i64,) = happyview::db::query_as(&adapt_sql( "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", app.state.db_backend, )) @@ -173,7 +173,7 @@ async fn count_records(app: &TestApp, uri: &str) -> i64 { } async fn fetch_record_body(app: &TestApp, uri: &str) -> Option { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = happyview::db::query_as(&adapt_sql( "SELECT record FROM happyview_records WHERE uri = ?", app.state.db_backend, )) @@ -588,7 +588,7 @@ async fn record_event_script_log_writes_event_log_row() { // The script's log("hello from script") should land in event_logs // as a `script.log` row whose subject is the trigger id. - let row: (String, String) = sqlx::query_as(&adapt_sql( + let row: (String, String) = happyview::db::query_as(&adapt_sql( "SELECT subject, detail FROM happyview_event_logs WHERE event_type = 'script.log' ORDER BY id DESC LIMIT 1", @@ -736,10 +736,11 @@ async fn label_script_uri_routes_actor_special_case() { assert!(matches!(outcome, LabelHookOutcome::Continue(_))); // Sentinel row should exist if the script ran. - let (count,): (i64,) = sqlx::query_as("SELECT COUNT(*) FROM script_sentinel WHERE k = 'fired'") - .fetch_one(&app.state.db) - .await - .unwrap(); + let (count,): (i64,) = + happyview::db::query_as("SELECT COUNT(*) FROM script_sentinel WHERE k = 'fired'") + .fetch_one(&app.state.db) + .await + .unwrap(); assert_eq!( count, 1, "labeler.apply:_actor should have fired for bare-DID label" @@ -795,7 +796,7 @@ async fn label_script_calling_record_save_dead_letters_with_clear_message() { assert_eq!(body["text"], "untouched"); // A dead-letter row exists with the NO_PDS_AUTH message. - let dl: (String,) = sqlx::query_as(&adapt_sql( + let dl: (String,) = happyview::db::query_as(&adapt_sql( "SELECT error FROM happyview_dead_letter_scripts WHERE host_kind = 'label' \ AND host_id = 'did:plc:labeler' ORDER BY id DESC LIMIT 1", app.state.db_backend, diff --git a/tests/e2e_service_identity.rs b/tests/e2e_service_identity.rs index 0941e98..4c468b3 100644 --- a/tests/e2e_service_identity.rs +++ b/tests/e2e_service_identity.rs @@ -3,6 +3,7 @@ mod common; use axum::body::Body; use axum::http::{Request, StatusCode}; use http_body_util::BodyExt; +use p256::elliptic_curve::sec1::ToSec1Point; use serde_json::{Value, json}; use serial_test::serial; use tower::ServiceExt; @@ -1448,11 +1449,10 @@ async fn did_web_issuer_resolved_via_https() { .await; let mut key_bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut key_bytes); - let issuer_key = p256::ecdsa::SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); - use p256::elliptic_curve::sec1::ToEncodedPoint; + rand::Rng::fill_bytes(&mut rand::rng(), &mut key_bytes); + let issuer_key = p256::ecdsa::SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = p256::PublicKey::from(issuer_key.verifying_key()); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let pub_bytes = compressed.as_bytes().to_vec(); let server = @@ -1581,13 +1581,13 @@ async fn service_auth_es256k_query_allowed() { // Generate a secp256k1 key pair use k256::ecdsa::{SigningKey as K256SigningKey, signature::Signer as K256Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let k256_signing_key = K256SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let k256_signing_key = K256SigningKey::from_slice(&key_bytes[..]).unwrap(); let k256_verifying_key = k256_signing_key.verifying_key(); - let compressed = k256_verifying_key.to_encoded_point(true); + let compressed = k256_verifying_key.to_sec1_point(true); let pub_bytes = compressed.as_bytes(); // Build a DID document with secp256k1 key using EcdsaSecp256k1VerificationKey2019 @@ -2027,11 +2027,11 @@ async fn did_doc_missing_atproto_vm_rejected() { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let issuer_did = "did:plc:noatprotovm"; let did_doc = json!({ @@ -2098,11 +2098,11 @@ async fn did_doc_missing_public_key_multibase_rejected() { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let issuer_did = "did:plc:nokeymultibase"; let did_doc = json!({ @@ -2215,7 +2215,7 @@ async fn seed_super_user(app: &TestApp, did: &str) { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uuid::Uuid::new_v4().to_string()) .bind(did) .bind(1_i32) diff --git a/tests/e2e_xrpc.rs b/tests/e2e_xrpc.rs index b051edf..6f8d364 100644 --- a/tests/e2e_xrpc.rs +++ b/tests/e2e_xrpc.rs @@ -90,7 +90,7 @@ async fn seed_record(app: &TestApp, uri: &str, did: &str, collection: &str, reco "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -443,7 +443,7 @@ async fn xrpc_delete_procedure_removes_record() { "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(uri) .fetch_one(&app.state.db) .await diff --git a/tests/lua_atproto_api.rs b/tests/lua_atproto_api.rs index 5fe1d80..30b82c7 100644 --- a/tests/lua_atproto_api.rs +++ b/tests/lua_atproto_api.rs @@ -118,7 +118,7 @@ async fn seed_record( "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind("test.collection") @@ -144,7 +144,7 @@ async fn seed_label( "INSERT INTO happyview_labels (src, uri, val, cts, exp) VALUES (?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(src) .bind(uri) .bind(val) @@ -158,7 +158,7 @@ async fn seed_label( "INSERT INTO happyview_labels (src, uri, val, cts) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(src) .bind(uri) .bind(val) @@ -208,7 +208,7 @@ async fn get_labels_returns_external_labels() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -258,7 +258,7 @@ async fn get_labels_filters_expired() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -293,7 +293,7 @@ async fn get_labels_includes_self_labels() { "SELECT did, record FROM happyview_records WHERE uri = ?", backend, ); - let fetched: Option<(String, String)> = sqlx::query_as(&sql) + let fetched: Option<(String, String)> = happyview::db::query_as(&sql) .bind(uri) .fetch_optional(&pool) .await @@ -338,7 +338,7 @@ async fn get_labels_empty_for_unlabeled_record() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&pool) @@ -376,7 +376,7 @@ async fn get_labels_batch_returns_labels_per_uri() { "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri2) .bind("did:plc:test") .bind("test.collection") @@ -397,7 +397,7 @@ async fn get_labels_batch_returns_labels_per_uri() { "SELECT src, uri, val FROM happyview_labels WHERE uri IN (?, ?) AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri1) .bind(uri2) .bind(&now) @@ -430,7 +430,7 @@ async fn get_labels_batch_empty_for_no_labels() { "SELECT src, uri, val FROM happyview_labels WHERE uri IN (?, ?) AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri1) .bind(uri2) .bind(&now) @@ -463,7 +463,7 @@ async fn label_negation_removes_row() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -477,7 +477,7 @@ async fn label_negation_removes_row() { "DELETE FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -490,7 +490,7 @@ async fn label_negation_removes_row() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -525,7 +525,7 @@ async fn label_upsert_is_idempotent() { // Insert same label twice (upsert pattern from labeler.rs) for _ in 0..2 { - sqlx::query(&upsert_sql) + happyview::db::query(&upsert_sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -539,7 +539,7 @@ async fn label_upsert_is_idempotent() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") diff --git a/tests/lua_db_api.rs b/tests/lua_db_api.rs index d0d4cda..91a51c5 100644 --- a/tests/lua_db_api.rs +++ b/tests/lua_db_api.rs @@ -144,7 +144,7 @@ async fn seed_records(pool: &sqlx::AnyPool, backend: DatabaseBackend) { backend, ); for (uri, did, collection, rkey, record, cid) in &records { - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) diff --git a/tests/lua_record_api.rs b/tests/lua_record_api.rs index f64c592..fd54e63 100644 --- a/tests/lua_record_api.rs +++ b/tests/lua_record_api.rs @@ -129,7 +129,7 @@ async fn seed_record( VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -147,7 +147,7 @@ async fn count_records(pool: &sqlx::AnyPool, backend: DatabaseBackend, uri: &str "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", backend, ); - let (count,): (i64,) = sqlx::query_as(&sql) + let (count,): (i64,) = happyview::db::query_as(&sql) .bind(uri) .fetch_one(pool) .await @@ -164,7 +164,7 @@ async fn fetch_record_body( "SELECT record FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = happyview::db::query_as(&sql) .bind(uri) .fetch_optional(pool) .await diff --git a/tests/plugin_logging.rs b/tests/plugin_logging.rs index fa029cf..a915a27 100644 --- a/tests/plugin_logging.rs +++ b/tests/plugin_logging.rs @@ -64,7 +64,7 @@ async fn plugin_log_writes_all_four_levels_to_event_logs() { "SELECT severity, subject, detail FROM happyview_event_logs WHERE event_type = ? ORDER BY created_at ASC", backend, ); - let rows: Vec<(String, Option, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, Option, String)> = happyview::db::query_as(&sql) .bind("plugin.log") .fetch_all(&pool) .await @@ -125,7 +125,7 @@ async fn plugin_log_with_none_db_does_not_write_event_log() { "SELECT COUNT(*) FROM happyview_event_logs WHERE event_type = ?", backend, ); - let count: i64 = sqlx::query_scalar(&sql) + let count: i64 = happyview::db::query_scalar(&sql) .bind("plugin.log") .fetch_one(&pool) .await diff --git a/tests/spaces_credential_revocation.rs b/tests/spaces_credential_revocation.rs index f6df382..ed2abd5 100644 --- a/tests/spaces_credential_revocation.rs +++ b/tests/spaces_credential_revocation.rs @@ -94,7 +94,7 @@ async fn remove_member_revokes_credentials() { "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(Uuid::new_v4().to_string()) .bind(&space_id) .bind(MEMBER) diff --git a/tests/spaces_db.rs b/tests/spaces_db.rs index 363532b..ae6d6d0 100644 --- a/tests/spaces_db.rs +++ b/tests/spaces_db.rs @@ -577,7 +577,7 @@ async fn space_credential_revocation_round_trip() { "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(new_id()) .bind(&space_id) .bind(member) diff --git a/tests/transfer_super.rs b/tests/transfer_super.rs index a33caa7..333bcb9 100644 --- a/tests/transfer_super.rs +++ b/tests/transfer_super.rs @@ -14,7 +14,7 @@ async fn user_id_for_did(app: &TestApp, did: &str) -> String { "SELECT id FROM happyview_users WHERE did = ?", app.state.db_backend, ); - let row: (String,) = sqlx::query_as(&sql) + let row: (String,) = happyview::db::query_as(&sql) .bind(did) .fetch_one(&app.state.db) .await @@ -27,7 +27,7 @@ async fn is_super(app: &TestApp, user_id: &str) -> bool { "SELECT is_super FROM happyview_users WHERE id = ?", app.state.db_backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = happyview::db::query_as(&sql) .bind(user_id) .fetch_one(&app.state.db) .await @@ -41,7 +41,7 @@ async fn insert_user(app: &TestApp, did: &str) -> String { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(did) .bind(0_i32) @@ -93,7 +93,7 @@ async fn transfer_super_moves_super_and_grants_permissions() { "SELECT COUNT(*) FROM happyview_user_permissions WHERE user_id = ?", app.state.db_backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(&target_id) .fetch_one(&app.state.db) .await