From 38d246d886953dcf3fa2ca233ff85cd002c2879d Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Fri, 31 Jan 2025 09:34:55 -0500 Subject: [PATCH 1/7] Add a server mode to gel-stream (#8282) This adds a server mode to `gel-stream`, gated on a feature. We wrap up a significant amount of network and TLS complexity behind two simple concepts: the `Connector` and the `Acceptor`. OpenSSL and Rustls are supported for both client and server modes. Tests were added to ensure that they work with all combinations (which also shook out some additional bugs). In addition, synchronous lookup of TLS parameters by SNI is supported -- async lookup will probably be necessary in the future but is currently not implemented yet. In addition, `tests/certs` were regenerated as one of the certs wasn't v3, so rustls didn't like it. Note that client-side certificate validation is implemented, but there is no current way to read the accepted certificate on the server side. This will be added in a later patch. Accept and connect have similar APIs. Both also have TLS override forms where keys, verification modes and more may be specified. ``` let mut acceptor = Acceptor::new_tcp(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0)) .bind() .await?; let addr = acceptor.local_address()?; let accept_task = tokio::spawn(async move { let mut connection = acceptor.next().await.unwrap().unwrap(); let mut buf = String::new(); connection.read_to_string(&mut buf).await.unwrap(); assert_eq!(buf, "Hello, world!"); }); let connect_task = tokio::spawn(async move { let target = Target::new_resolved(addr); let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); stm.write_all(b"Hello, world!").await?; Ok::<_, std::io::Error>(()) }); ``` --- Cargo.lock | 398 ++++++------ rust/auth/src/lib.rs | 5 +- rust/gel-stream/Cargo.toml | 34 +- rust/gel-stream/src/client/connection.rs | 31 +- rust/gel-stream/src/client/mod.rs | 594 ------------------ rust/gel-stream/src/client/openssl.rs | 177 ------ rust/gel-stream/src/client/stream.rs | 240 ------- rust/gel-stream/src/common/mod.rs | 16 + rust/gel-stream/src/common/openssl.rs | 521 +++++++++++++++ .../src/{client => common}/rustls.rs | 285 ++++++--- rust/gel-stream/src/common/stream.rs | 343 ++++++++++ .../src/{client => common}/target.rs | 15 +- rust/gel-stream/src/common/tls.rs | 259 ++++++++ .../src/{client => common}/tokio_stream.rs | 79 ++- rust/gel-stream/src/lib.rs | 128 +++- rust/gel-stream/src/server/acceptor.rs | 178 ++++++ rust/gel-stream/src/server/mod.rs | 6 + rust/gel-stream/tests/socket.rs | 66 ++ rust/gel-stream/tests/tls.rs | 451 +++++++++++++ rust/pgrust/Cargo.toml | 3 +- rust/pgrust/examples/connect.rs | 2 +- rust/pgrust/src/connection/conn.rs | 4 +- rust/pgrust/src/connection/dsn/host.rs | 2 +- rust/pgrust/src/connection/mod.rs | 3 +- rust/pgrust/src/connection/raw_conn.rs | 37 +- rust/pgrust/src/handshake/edgedb_server.rs | 2 + rust/pgrust/src/handshake/mod.rs | 2 +- rust/pgrust/src/python.rs | 2 +- rust/pgrust/tests/query_real_postgres.rs | 2 +- rust/pgrust/tests/real_postgres.rs | 2 +- tests/certs/ca.cert.pem | 58 +- tests/certs/ca.crl.pem | 30 +- tests/certs/ca.key.pem | 100 +-- tests/certs/client.cert.pem | 65 +- tests/certs/client.csr.pem | 46 +- tests/certs/client.key.pem | 100 +-- tests/certs/client.key.protected.pem | 104 +-- tests/certs/client_ca.cert.pem | 56 +- tests/certs/client_ca.cert.srl | 2 +- tests/certs/client_ca.key.pem | 100 +-- tests/certs/gen.sh | 2 +- tests/certs/server.cert.pem | 54 +- tests/certs/server.key.pem | 100 +-- 43 files changed, 2922 insertions(+), 1782 deletions(-) delete mode 100644 rust/gel-stream/src/client/openssl.rs delete mode 100644 rust/gel-stream/src/client/stream.rs create mode 100644 rust/gel-stream/src/common/mod.rs create mode 100644 rust/gel-stream/src/common/openssl.rs rename rust/gel-stream/src/{client => common}/rustls.rs (53%) create mode 100644 rust/gel-stream/src/common/stream.rs rename rust/gel-stream/src/{client => common}/target.rs (97%) create mode 100644 rust/gel-stream/src/common/tls.rs rename rust/gel-stream/src/{client => common}/tokio_stream.rs (61%) create mode 100644 rust/gel-stream/src/server/acceptor.rs create mode 100644 rust/gel-stream/src/server/mod.rs create mode 100644 rust/gel-stream/tests/socket.rs create mode 100644 rust/gel-stream/tests/tls.rs diff --git a/Cargo.lock b/Cargo.lock index 46ad27739c5..1eab733d036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,37 +4,19 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -61,15 +43,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -82,49 +64,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "append-only-vec" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d9f7083455f1a474276ccd32374958d2cb591024aac45101c7623b10271347" +checksum = "7992085ec035cfe96992dd31bfd495a2ebd31969bb95f624471cb6c0b349e571" [[package]] name = "approx" @@ -149,9 +131,9 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "async-compression" -version = "0.4.13" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e614738943d3f68c628ae3dbce7c3daffb196665f82f8c8ea6b65de73c79429" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -180,23 +162,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -213,9 +195,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bigdecimal" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" dependencies = [ "autocfg", "libm", @@ -287,9 +269,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -313,9 +295,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "captive_postgres" @@ -340,9 +322,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "shlex", ] @@ -367,18 +349,18 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.16" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -388,9 +370,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -400,15 +382,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -456,7 +438,7 @@ dependencies = [ "statrs", "strum", "test-log", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -500,9 +482,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -595,7 +577,7 @@ dependencies = [ "derive_more", "paste", "pretty_assertions", - "thiserror 1.0.63", + "thiserror 1.0.69", "uuid", ] @@ -657,13 +639,13 @@ dependencies = [ "combine 3.8.1", "num-bigint 0.2.6", "num-traits", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] name = "edgedb-errors" version = "0.4.2" -source = "git+https://github.com/edgedb/edgedb-rust#b38fb4af07ae0017329eb3cce30ca37fe12acd29" +source = "git+https://github.com/edgedb/edgedb-rust#84c2fa7d78fe8dbbc8e3e4da136ad2eff2f2e465" dependencies = [ "bytes", ] @@ -671,7 +653,7 @@ dependencies = [ [[package]] name = "edgedb-protocol" version = "0.6.1" -source = "git+https://github.com/edgedb/edgedb-rust#b38fb4af07ae0017329eb3cce30ca37fe12acd29" +source = "git+https://github.com/edgedb/edgedb-rust#84c2fa7d78fe8dbbc8e3e4da136ad2eff2f2e465" dependencies = [ "bigdecimal", "bitflags", @@ -701,7 +683,7 @@ dependencies = [ "serde_json", "sha2", "snafu", - "thiserror 1.0.63", + "thiserror 1.0.69", "unicode-width", ] @@ -830,18 +812,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -850,6 +832,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -876,9 +864,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -891,9 +879,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -901,15 +889,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -918,15 +906,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -935,15 +923,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -953,9 +941,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -975,6 +963,8 @@ version = "0.1.0" dependencies = [ "derive_more", "foreign-types", + "futures", + "gel-stream", "hickory-resolver", "ntest", "openssl", @@ -1055,9 +1045,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1075,7 +1065,7 @@ dependencies = [ "num-traits", "pretty_assertions", "pyo3", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -1099,12 +1089,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -1151,7 +1142,7 @@ dependencies = [ "ipnet", "once_cell", "rand", - "thiserror 1.0.63", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -1174,7 +1165,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -1256,9 +1247,9 @@ checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -1452,9 +1443,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -1492,9 +1483,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "iter-read" -version = "0.3.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c397ca3ea05ad509c4ec451fea28b4771236a376ca1c69fd5143aae0cf8f93c4" +checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" [[package]] name = "itertools" @@ -1516,9 +1507,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -1531,7 +1522,7 @@ dependencies = [ "combine 4.6.7", "jni-sys", "log", - "thiserror 1.0.63", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1559,15 +1550,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.165" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linked-hash-map" @@ -1605,9 +1596,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown", ] @@ -1679,15 +1670,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1891,24 +1873,24 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags", "cfg-if", @@ -1937,9 +1919,9 @@ source = "git+https://github.com/edgedb/openssl-probe/?rev=e5ed593600d1f81286295 [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -2016,7 +1998,7 @@ dependencies = [ "serde", "serde_derive", "test-log", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tokio-openssl", "tracing", @@ -2068,9 +2050,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2080,15 +2062,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "ppv-lite86" @@ -2101,9 +2083,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -2198,7 +2180,7 @@ dependencies = [ "nix", "pyo3", "scopeguard", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", "tracing-subscriber", @@ -2348,14 +2330,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2369,13 +2351,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2386,9 +2368,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -2574,9 +2556,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -2659,9 +2641,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-tokio-stream" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" +checksum = "faa7dc7c991d9164e55bbf1558029eb5b84d32cc4d61a7df5b8641b2deedc4b3" dependencies = [ "futures", "rustls", @@ -2682,9 +2664,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2712,9 +2694,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -2756,18 +2738,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde-pickle" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762ad136a26407c6a80825813600ceeab5e613660d93d79a41f0ec877171e71" +checksum = "b641fdc8bcf2781ee78b30c599700d64ad4f412976143e4c5d0b9df906bb4843" dependencies = [ "byteorder", "iter-read", @@ -2778,9 +2760,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -2789,9 +2771,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap", "itoa", @@ -2894,9 +2876,9 @@ dependencies = [ [[package]] name = "snafu" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b835cb902660db3415a672d862905e791e54d306c6e8189168c7f3d9ae1c79d" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" dependencies = [ "backtrace", "snafu-derive", @@ -2904,9 +2886,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d1e02fca405f6280643174a50c942219f0bbf4dbf7d480f1dd864d6f211ae5" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ "heck", "proc-macro2", @@ -3015,9 +2997,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -3041,15 +3023,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.11.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3076,11 +3058,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.63", + "thiserror-impl 1.0.69", ] [[package]] @@ -3094,9 +3076,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -3221,9 +3203,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", @@ -3281,9 +3263,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -3332,36 +3314,36 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unindent" @@ -3415,9 +3397,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -3537,9 +3519,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -3589,9 +3571,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.28" +version = "0.7.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" +checksum = "58e6db2670d2be78525979e9a5f9c69d296fd7d670549fe9ebf70f8708cb5019" dependencies = [ "bytemuck", "safe_arch", @@ -3880,9 +3862,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -3920,9 +3902,9 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" diff --git a/rust/auth/src/lib.rs b/rust/auth/src/lib.rs index b4b51a700d3..4310b15e060 100644 --- a/rust/auth/src/lib.rs +++ b/rust/auth/src/lib.rs @@ -34,7 +34,7 @@ pub enum AuthType { ScramSha256, } -#[derive(Debug, Clone)] +#[derive(derive_more::Debug, Clone)] pub enum CredentialData { /// A credential that always succeeds, regardless of input password. Due to /// the design of SCRAM-SHA-256, this cannot be used with that auth type. @@ -42,10 +42,13 @@ pub enum CredentialData { /// A credential that always fails, regardless of the input password. Deny, /// A plain-text password. + #[debug("Plain(...)")] Plain(String), /// A stored MD5 hash + salt. + #[debug("Md5(...)")] Md5(md5::StoredHash), /// A stored SCRAM-SHA-256 key. + #[debug("Scram(...)")] Scram(scram::StoredKey), } diff --git a/rust/gel-stream/Cargo.toml b/rust/gel-stream/Cargo.toml index 164d21125bd..d18dacf3a6e 100644 --- a/rust/gel-stream/Cargo.toml +++ b/rust/gel-stream/Cargo.toml @@ -7,7 +7,9 @@ description = "A library for streaming data between clients and servers." [features] # rustls or openssl imply tokio, and tokio is the only stream we support # at this time. -default = ["tokio", "rustls"] +default = ["tokio"] +client = [] +server = [] tokio = ["dep:tokio"] rustls = ["tokio", "dep:rustls", "dep:rustls-tokio-stream", "dep:rustls-platform-verifier", "dep:webpki"] openssl = ["tokio", "dep:openssl", "dep:tokio-openssl", "dep:foreign-types", "dep:openssl-sys"] @@ -17,29 +19,39 @@ __manual_tests = [] [dependencies] derive_more = { version = "1", features = ["full"] } thiserror = "2" -rustls-pki-types = "1" +futures = "0.3" -tokio = { version = "1", optional = true, features = ["full"] } +# Given that this library may be used in multiple contexts, we want to limit the +# features we enable by default. + +rustls-pki-types = { version = "1", default-features = false, features = ["std"] } + +# feature = "tokio" +tokio = { version = "1", optional = true, default-features = false, features = ["net", "rt"] } +hickory-resolver = { version = "0.24.2", optional = true, default-features = false, features = ["tokio-runtime", "system-config"] } + +# feature = "rustls" rustls = { version = "0.23", optional = true, default-features = false, features = ["ring", "logging", "std", "tls12"] } -openssl = { version = "0.10.55", optional = true } -tokio-openssl = { version = "0.6.5", optional = true } -hickory-resolver = { version = "0.24.2", optional = true } -rustls-tokio-stream = { version = "0.3.0", optional = true } +rustls-tokio-stream = { version = "0.5.0", optional = true } rustls-platform-verifier = { version = "0.5.0", optional = true } webpki = { version = "0.22", optional = true } +# feature = "openssl" +openssl = { version = "0.10.55", optional = true, default-features = false } +tokio-openssl = { version = "0.6.5", optional = true, default-features = false } # Get these from openssl -foreign-types = { version = "*", optional = true } -openssl-sys = { version = "*", optional = true } +foreign-types = { version = "*", optional = true, default-features = false } +openssl-sys = { version = "*", optional = true, default-features = false } [dev-dependencies] +# Run tests with all features enabled +gel-stream = { workspace = true, features = ["client", "server", "tokio", "rustls", "openssl"] } + tokio = { version = "1", features = ["full"] } tempfile = "3" ntest = "0.9.3" rustls-pemfile = "2" - rstest = "0.24.0" -rustls-tokio-stream = "0.3.0" [lints] workspace = true diff --git a/rust/gel-stream/src/client/connection.rs b/rust/gel-stream/src/client/connection.rs index 4b358d4e8a8..a51611ea453 100644 --- a/rust/gel-stream/src/client/connection.rs +++ b/rust/gel-stream/src/client/connection.rs @@ -1,27 +1,37 @@ +use std::marker::PhantomData; use std::net::SocketAddr; -use super::stream::UpgradableStream; -use super::target::{MaybeResolvedTarget, ResolvedTarget}; -use super::tokio_stream::Resolver; -use super::{ConnectionError, Ssl, Target, TlsInit}; +use crate::common::tokio_stream::{Resolver, TokioStream}; +use crate::{ConnectionError, Ssl, StreamUpgrade, TlsDriver, UpgradableStream}; +use crate::{MaybeResolvedTarget, ResolvedTarget, Target}; -type Connection = UpgradableStream>; +type Connection = UpgradableStream; /// A connector can be used to connect multiple times to the same target. -pub struct Connector { +#[allow(private_bounds)] +pub struct Connector { target: Target, resolver: Resolver, + driver: PhantomData, } -impl Connector { +impl Connector { pub fn new(target: Target) -> Result { + Self::new_explicit(target) + } +} + +#[allow(private_bounds)] +impl Connector { + pub fn new_explicit(target: Target) -> Result { Ok(Self { target, resolver: Resolver::new()?, + driver: PhantomData, }) } - pub async fn connect(&self) -> Result { + pub async fn connect(&self) -> Result, ConnectionError> { let stream = match self.target.maybe_resolved() { MaybeResolvedTarget::Resolved(target) => target.connect().await?, MaybeResolvedTarget::Unresolved(host, port, _) => { @@ -36,13 +46,14 @@ impl Connector { }; if let Some(ssl) = self.target.maybe_ssl() { - let mut stm = UpgradableStream::new(stream, Some(Ssl::init(ssl, self.target.name())?)); + let ssl = D::init_client(ssl, self.target.name())?; + let mut stm = UpgradableStream::new_client(stream, Some(ssl)); if !self.target.is_starttls() { stm.secure_upgrade().await?; } Ok(stm) } else { - Ok(UpgradableStream::new(stream, None)) + Ok(UpgradableStream::new_client(stream, None)) } } } diff --git a/rust/gel-stream/src/client/mod.rs b/rust/gel-stream/src/client/mod.rs index 4f1688e18ab..93d91fc99a6 100644 --- a/rust/gel-stream/src/client/mod.rs +++ b/rust/gel-stream/src/client/mod.rs @@ -1,597 +1,3 @@ -use std::borrow::Cow; - -#[cfg(feature = "openssl")] -pub mod openssl; -#[cfg(feature = "rustls")] -pub mod rustls; -#[cfg(feature = "tokio")] -pub mod tokio_stream; - -pub mod stream; - mod connection; -pub(crate) mod target; pub use connection::Connector; -pub use target::{ResolvedTarget, Target, TargetName}; - -macro_rules! __invalid_state { - ($error:literal) => {{ - eprintln!( - "Invalid connection state: {}\n{}", - $error, - ::std::backtrace::Backtrace::capture() - ); - #[allow(deprecated)] - $crate::client::ConnectionError::__InvalidState - }}; -} -pub(crate) use __invalid_state as invalid_state; -use rustls_pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer, ServerName}; - -#[derive(Debug, thiserror::Error)] -pub enum ConnectionError { - /// Invalid state error, suggesting a logic error in code rather than a server or client failure. - /// Use the `invalid_state!` macro instead which will print a backtrace. - #[error("Invalid state")] - #[deprecated = "Use invalid_state!"] - __InvalidState, - - /// I/O error encountered during connection operations. - #[error("I/O error: {0}")] - Io(#[from] std::io::Error), - - /// UTF-8 decoding error. - #[error("UTF8 error: {0}")] - Utf8Error(#[from] std::str::Utf8Error), - - /// SSL-related error. - #[error("SSL error: {0}")] - SslError(#[from] SslError), -} - -#[derive(Debug, thiserror::Error)] -pub enum SslError { - #[error("SSL is not supported by this client transport")] - SslUnsupportedByClient, - - #[cfg(feature = "openssl")] - #[error("OpenSSL error: {0}")] - OpenSslError(#[from] ::openssl::ssl::Error), - #[cfg(feature = "openssl")] - #[error("OpenSSL error: {0}")] - OpenSslErrorStack(#[from] ::openssl::error::ErrorStack), - #[cfg(feature = "openssl")] - #[error("OpenSSL certificate verification error: {0}")] - OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult), - - #[cfg(feature = "rustls")] - #[error("Rustls error: {0}")] - RustlsError(#[from] ::rustls::Error), - - #[cfg(feature = "rustls")] - #[error("Webpki error: {0}")] - WebpkiError(::webpki::Error), - - #[cfg(feature = "rustls")] - #[error("Verifier builder error: {0}")] - VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError), - - #[error("Invalid DNS name: {0}")] - InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError), - - #[error("SSL I/O error: {0}")] - SslIoError(#[from] std::io::Error), -} - -impl SslError { - /// Returns a common error for any time of crypto backend. - pub fn common_error(&self) -> Option { - match self { - #[cfg(feature = "rustls")] - SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => { - match cert_err { - ::rustls::CertificateError::NotValidForName => { - Some(CommonError::InvalidCertificateForName) - } - ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked), - ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired), - ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer), - _ => None, - } - } - #[cfg(feature = "openssl")] - SslError::OpenSslErrorVerify(e) => match e.as_raw() { - openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => { - Some(CommonError::InvalidCertificateForName) - } - openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => { - Some(CommonError::InvalidCertificateForName) - } - openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked), - openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired), - openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT - | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => { - Some(CommonError::InvalidIssuer) - } - _ => None, - }, - _ => None, - } - } -} - -#[derive(Debug, thiserror::Error, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] -pub enum CommonError { - #[error("The certificate's subject name(s) do not match the name of the host")] - InvalidCertificateForName, - #[error("The certificate has been revoked")] - CertificateRevoked, - #[error("The certificate has expired")] - CertificateExpired, - #[error("The certificate was issued by an untrusted authority")] - InvalidIssuer, -} - -// Note that we choose rustls when both openssl and rustls are enabled. - -#[cfg(all(feature = "openssl", not(feature = "rustls")))] -pub type Ssl = ::openssl::ssl::Ssl; -#[cfg(feature = "rustls")] -pub type Ssl = ::rustls::ClientConnection; - -#[cfg(feature = "tokio")] -pub type Stream = tokio_stream::TokioStream; - -/// Verification modes for TLS that are a superset of both PostgreSQL and EdgeDB/Gel. -/// -/// Postgres offers six levels: `disable`, `allow`, `prefer`, `require`, `verify-ca` and `verify-full`. -/// -/// EdgeDB/Gel offers three levels: `insecure`, `no_host_verification' and 'strict'. -/// -/// This table maps the various levels: -/// -/// | Postgres | EdgeDB/Gel | `TlsServerCertVerify` enum | -/// | -------- | ----------- | ----------------- | -/// | require | insecure | `Insecure` | -/// | verify-ca | no_host_verification | `IgnoreHostname` | -/// | verify-full | strict | `VerifyFull` | -/// -/// Note that both EdgeDB/Gel and Postgres may alter certificate validation levels -/// when custom root certificates are provided. This must be done in the -/// `TlsParameters` struct by the caller. -#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] -pub enum TlsServerCertVerify { - /// Do not verify the server's certificate. Only confirm that the server is - /// using TLS. - Insecure, - /// Verify the server's certificate using the CA (ignore hostname). - IgnoreHostname, - /// Verify the server's certificate using the CA and hostname. - #[default] - VerifyFull, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub enum TlsCert { - /// Use the system's default certificate. - #[default] - System, - /// Use a custom root certificate only. - Custom(CertificateDer<'static>), -} - -#[derive(Default, Debug, PartialEq, Eq)] -pub struct TlsParameters { - pub server_cert_verify: TlsServerCertVerify, - pub cert: Option>, - pub key: Option>, - pub root_cert: TlsCert, - pub crl: Vec>, - pub min_protocol_version: Option, - pub max_protocol_version: Option, - pub enable_keylog: bool, - pub sni_override: Option>, - pub alpn: Option]>>, -} - -impl TlsParameters { - pub fn insecure() -> Self { - Self { - server_cert_verify: TlsServerCertVerify::Insecure, - ..Default::default() - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum SslVersion { - Tls1, - Tls1_1, - Tls1_2, - Tls1_3, -} - -trait TlsInit { - type Tls; - fn init(params: &TlsParameters, name: Option) -> Result; -} - -#[cfg(test)] -mod tests { - use std::{net::SocketAddr, sync::Arc}; - - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - - use super::*; - - #[cfg(unix)] - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_unix() -> Result<(), std::io::Error> { - use tokio::io::AsyncReadExt; - - let tempdir = tempfile::tempdir().unwrap(); - let path = tempdir.path().join("gel-stream-test"); - - // Create a unix socket and connect to it - let socket = tokio::net::UnixListener::bind(&path)?; - - let accept_task = tokio::spawn(async move { - let (mut stream, _) = socket.accept().await.unwrap(); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - }); - - let connect_task = tokio::spawn(async { - let target = Target::new_unix_path(path)?; - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp() -> Result<(), std::io::Error> { - // Create a TCP listener on a random port - let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?; - let addr = listener.local_addr()?; - - let accept_task = tokio::spawn(async move { - let (mut stream, _) = listener.accept().await.unwrap(); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - }); - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp(("127.0.0.1", addr.port())); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - fn load_test_cert() -> rustls_pki_types::CertificateDer<'static> { - rustls_pemfile::certs( - &mut include_str!("../../../../tests/certs/server.cert.pem").as_bytes(), - ) - .next() - .unwrap() - .unwrap() - } - - fn load_test_ca() -> rustls_pki_types::CertificateDer<'static> { - rustls_pemfile::certs(&mut include_str!("../../../../tests/certs/ca.cert.pem").as_bytes()) - .next() - .unwrap() - .unwrap() - } - - fn load_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { - rustls_pemfile::private_key( - &mut include_str!("../../../../tests/certs/server.key.pem").as_bytes(), - ) - .unwrap() - .unwrap() - } - - fn load_test_crls() -> Vec> { - rustls_pemfile::crls(&mut include_str!("../../../../tests/certs/ca.crl.pem").as_bytes()) - .collect::, _>>() - .unwrap() - } - - async fn spawn_tls_server( - expected_hostname: Option<&str>, - server_alpn: Option<&[&str]>, - expected_alpn: Option<&str>, - ) -> Result< - ( - SocketAddr, - tokio::task::JoinHandle>, - ), - std::io::Error, - > { - use ::rustls::{ServerConfig, ServerConnection}; - - let _ = ::rustls::crypto::ring::default_provider().install_default(); - - // Create a TCP listener on a random port - let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?; - let addr = listener.local_addr()?; - - // Load TLS cert and key - let cert = load_test_cert(); - let key = load_test_key(); - - // Configure rustls server - let mut config = ServerConfig::builder() - .with_no_client_auth() - .with_single_cert(vec![cert], key) - .unwrap(); - config.alpn_protocols = server_alpn - .map(|alpn| alpn.iter().map(|s| s.as_bytes().to_vec()).collect()) - .unwrap_or_default(); - - let tls_config = Arc::new(config); - let expected_alpn = expected_alpn.map(|alpn| alpn.as_bytes().to_vec()); - let expected_hostname = expected_hostname.map(|sni| sni.to_string()); - let accept_task = tokio::spawn(async move { - let (tcp_stream, _) = listener.accept().await.unwrap(); - let tls_conn = ServerConnection::new(tls_config).unwrap(); - let mut stream = - rustls_tokio_stream::TlsStream::new_server_side_from(tcp_stream, tls_conn, None); - let handshake = stream.handshake().await?; - eprintln!("handshake: {:?}", handshake); - assert_eq!(handshake.alpn, expected_alpn); - assert_eq!(handshake.sni, expected_hostname); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - stream.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - Ok((addr, accept_task)) - } - - /// The certificate is not valid for 127.0.0.1, so the connection should fail. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_fails() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidIssuer)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// The certificate is not valid for 127.0.0.1, so the connection should fail. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_fails_name() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidCertificateForName)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// The certificate is valid for "localhost", so the connection should succeed. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_ok() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("localhost"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("localhost", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await?; - stm.write_all(b"Hello, world!").await?; - stm.shutdown().await?; - Ok::<_, ConnectionError>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_insecure() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_crl() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("localhost"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("localhost", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - crl: load_test_crls(), - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::CertificateRevoked)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// Test that we can override the SNI. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_sni_override() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("www.google.com"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - sni_override: Some(Cow::Borrowed("www.google.com")), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await.unwrap(); - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// Test that we can override the ALPN. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_alpn_override() -> Result<(), std::io::Error> { - let (addr, accept_task) = - spawn_tls_server(None, Some(&["nope", "accepted"]), Some("accepted")).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - alpn: Some(Cow::Borrowed(&[ - Cow::Borrowed("accepted"), - Cow::Borrowed("fake"), - ])), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await.unwrap(); - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[cfg(feature = "__manual_tests")] - #[tokio::test] - async fn test_live_server_manual_google_com() { - let target = Target::new_tcp_tls(("www.google.com", 443), TlsParameters::default()); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); - // HTTP/1. ..... - assert_eq!(stm.read_u8().await.unwrap(), b'H'); - } - - /// Normally connecting to Google's IP will send an invalid SNI and fail. - /// This test ensures that we can override the SNI to the correct hostname. - #[cfg(feature = "__manual_tests")] - #[tokio::test] - async fn test_live_server_google_com_override_sni() { - use std::net::ToSocketAddrs; - - let addr = "www.google.com:443" - .to_socket_addrs() - .unwrap() - .into_iter() - .next() - .unwrap(); - let target = Target::new_tcp_tls( - addr, - TlsParameters { - sni_override: Some(Cow::Borrowed("www.google.com")), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); - // HTTP/1. ..... - assert_eq!(stm.read_u8().await.unwrap(), b'H'); - } -} diff --git a/rust/gel-stream/src/client/openssl.rs b/rust/gel-stream/src/client/openssl.rs deleted file mode 100644 index b020b4026e5..00000000000 --- a/rust/gel-stream/src/client/openssl.rs +++ /dev/null @@ -1,177 +0,0 @@ -use std::pin::Pin; - -use openssl::{ - ssl::{SslContextBuilder, SslMethod, SslVerifyMode}, - x509::{verify::X509VerifyFlags, X509VerifyResult}, -}; -use rustls_pki_types::ServerName; - -use super::{ - stream::{Stream, StreamWithUpgrade}, - SslError, SslVersion, TlsCert, TlsInit, TlsParameters, TlsServerCertVerify, -}; - -impl StreamWithUpgrade for (S, Option) { - type Base = S; - type Config = openssl::ssl::Ssl; - type Upgrade = tokio_openssl::SslStream; - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - let Some(tls) = self.1 else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let mut stream = tokio_openssl::SslStream::new(tls, self.0)?; - let res = Pin::new(&mut stream).do_handshake().await; - if res.is_err() { - if stream.ssl().verify_result() != X509VerifyResult::OK { - return Err(SslError::OpenSslErrorVerify(stream.ssl().verify_result())); - } - } - res.map_err(SslError::OpenSslError)?; - Ok(stream) - } -} - -impl From for openssl::ssl::SslVersion { - fn from(val: SslVersion) -> Self { - match val { - SslVersion::Tls1 => openssl::ssl::SslVersion::TLS1, - SslVersion::Tls1_1 => openssl::ssl::SslVersion::TLS1_1, - SslVersion::Tls1_2 => openssl::ssl::SslVersion::TLS1_2, - SslVersion::Tls1_3 => openssl::ssl::SslVersion::TLS1_3, - } - } -} - -impl TlsInit for openssl::ssl::Ssl { - type Tls = openssl::ssl::Ssl; - - fn init(parameters: &TlsParameters, name: Option) -> Result { - let TlsParameters { - server_cert_verify, - root_cert, - cert, - key, - crl, - min_protocol_version, - max_protocol_version, - alpn, - sni_override, - enable_keylog, - } = parameters; - - let mut ssl = SslContextBuilder::new(SslMethod::tls_client())?; - - // Load root cert - if let TlsCert::Custom(root) = root_cert { - let root = openssl::x509::X509::from_der(root.as_ref())?; - ssl.cert_store_mut().add_cert(root)?; - ssl.set_verify(SslVerifyMode::PEER); - } else if *server_cert_verify == TlsServerCertVerify::Insecure { - ssl.set_verify(SslVerifyMode::NONE); - } - - // Load CRL - if !crl.is_empty() { - // The openssl crate doesn't yet have add_crl, so we need to use the raw FFI - use foreign_types::ForeignTypeRef; - let ptr = ssl.cert_store_mut().as_ptr(); - - extern "C" { - pub fn X509_STORE_add_crl( - store: *mut openssl_sys::X509_STORE, - x: *mut openssl_sys::X509_CRL, - ) -> openssl_sys::c_int; - } - - for crl in crl { - let crl = openssl::x509::X509Crl::from_der(crl.as_ref())?; - let crl_ptr = crl.as_ptr(); - let res = unsafe { X509_STORE_add_crl(ptr, crl_ptr) }; - if res != 1 { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to add CRL to store", - ) - .into()); - } - } - - ssl.verify_param_mut() - .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; - ssl.cert_store_mut() - .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; - } - - // Load certificate chain and private key - if let (Some(cert), Some(key)) = (cert.as_ref(), key.as_ref()) { - let builder = openssl::x509::X509::from_der(cert.as_ref())?; - ssl.set_certificate(&builder)?; - let builder = openssl::pkey::PKey::private_key_from_pem(&key.secret_der())?; - ssl.set_private_key(&builder)?; - } - - // Configure hostname verification - if *server_cert_verify == TlsServerCertVerify::VerifyFull { - ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); - } - - ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; - ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; - - // Configure key log filename - if *enable_keylog { - if let Ok(path) = std::env::var("SSLKEYLOGFILE") { - // "The callback is invoked whenever TLS key material is generated, and is passed a line of NSS SSLKEYLOGFILE-formatted text. - // This can be used by tools like Wireshark to decrypt message traffic. The line does not contain a trailing newline. - ssl.set_keylog_callback(move |_ssl, msg| { - let Ok(mut file) = std::fs::OpenOptions::new().append(true).open(&path) else { - return; - }; - let _ = std::io::Write::write_all(&mut file, msg.as_bytes()); - }); - } - } - - if *server_cert_verify == TlsServerCertVerify::VerifyFull { - if let Some(hostname) = sni_override { - ssl.verify_param_mut().set_host(hostname)?; - } else if let Some(ServerName::DnsName(hostname)) = &name { - ssl.verify_param_mut().set_host(hostname.as_ref())?; - } else if let Some(ServerName::IpAddress(ip)) = &name { - ssl.verify_param_mut().set_ip((*ip).into())?; - } - } - - let mut ssl = openssl::ssl::Ssl::new(&ssl.build())?; - ssl.set_connect_state(); - - // Set hostname if it's not an IP address - if let Some(hostname) = sni_override { - ssl.set_hostname(hostname)?; - } else if let Some(ServerName::DnsName(hostname)) = &name { - ssl.set_hostname(hostname.as_ref())?; - } - - if let Some(alpn) = alpn { - let alpn = alpn - .iter() - .map(|s| { - let bytes = s.as_bytes(); - let mut vec = Vec::with_capacity(bytes.len() + 1); - vec.push(bytes.len() as u8); - vec.extend_from_slice(bytes); - vec - }) - .flatten() - .collect::>(); - ssl.set_alpn_protos(&alpn)?; - } - - Ok(ssl) - } -} diff --git a/rust/gel-stream/src/client/stream.rs b/rust/gel-stream/src/client/stream.rs deleted file mode 100644 index f8e175895ef..00000000000 --- a/rust/gel-stream/src/client/stream.rs +++ /dev/null @@ -1,240 +0,0 @@ -use super::{invalid_state, ConnectionError, SslError}; -use std::pin::Pin; - -pub trait Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin {} -impl Stream for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin {} - -/// A trait for streams that can be upgraded to a secure connection. -/// -/// This trait is usually implemented by tuples that represent a connection that can be -/// upgraded from an insecure to a secure state, typically through SSL/TLS. -pub trait StreamWithUpgrade: Unpin { - type Base: Stream; - type Upgrade: Stream; - type Config: Unpin; - - /// Perform a secure upgrade operation and return the new, wrapped connection. - #[allow(async_fn_in_trait)] - async fn secure_upgrade(self) -> Result - where - Self: Sized; -} - -impl StreamWithUpgrade for (S, ()) { - type Base = S; - type Upgrade = S; - type Config = (); - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - Err(SslError::SslUnsupportedByClient) - } -} - -#[derive(derive_more::Debug)] -pub struct UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - inner: UpgradableStreamInner, -} - -impl From<(B, C)> for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn from(value: (B, C)) -> Self { - Self::new(value.0, value.1) - } -} - -impl UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - pub fn new(base: B, config: C) -> Self { - UpgradableStream { - inner: UpgradableStreamInner::Base(base, config), - } - } - - pub async fn secure_upgrade(&mut self) -> Result<(), ConnectionError> - where - (B, C): StreamWithUpgrade, - { - match std::mem::replace(&mut self.inner, UpgradableStreamInner::Upgrading) { - UpgradableStreamInner::Base(base, config) => { - self.inner = - UpgradableStreamInner::Upgraded((base, config).secure_upgrade().await?); - Ok(()) - } - UpgradableStreamInner::Upgraded(..) => Err(invalid_state!( - "Attempted to upgrade an already upgraded stream" - )), - UpgradableStreamInner::Upgrading => Err(invalid_state!( - "Attempted to upgrade a stream that is already in the process of upgrading" - )), - } - } - - /// Convert the inner stream into a choice between the base and the upgraded stream. - /// - /// If the inner stream is in the process of upgrading, return an error containing `self`. - pub fn into_choice(self) -> Result, Self> { - match self.inner { - UpgradableStreamInner::Base(base, _) => Ok(UpgradableStreamChoice::Base(base)), - UpgradableStreamInner::Upgraded(upgraded) => { - Ok(UpgradableStreamChoice::Upgrade(upgraded)) - } - UpgradableStreamInner::Upgrading => Err(self), - } - } -} - -impl tokio::io::AsyncRead for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn poll_read( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_read(cx, buf), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_read(cx, buf), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot read while upgrading", - ))), - } - } -} - -impl tokio::io::AsyncWrite for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn poll_write( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &[u8], - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_write(cx, buf), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_write(cx, buf), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot write while upgrading", - ))), - } - } - - #[inline(always)] - fn poll_flush( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_flush(cx), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_flush(cx), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot flush while upgrading", - ))), - } - } - - #[inline(always)] - fn poll_shutdown( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_shutdown(cx), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_shutdown(cx), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot shutdown while upgrading", - ))), - } - } - - #[inline(always)] - fn is_write_vectored(&self) -> bool { - match &self.inner { - UpgradableStreamInner::Base(base, _) => base.is_write_vectored(), - UpgradableStreamInner::Upgraded(upgraded) => upgraded.is_write_vectored(), - UpgradableStreamInner::Upgrading => false, - } - } - - #[inline(always)] - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - bufs: &[std::io::IoSlice<'_>], - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_write_vectored(cx, bufs), - UpgradableStreamInner::Upgraded(upgraded) => { - Pin::new(upgraded).poll_write_vectored(cx, bufs) - } - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot write vectored while upgrading", - ))), - } - } -} - -#[derive(derive_more::Debug)] -enum UpgradableStreamInner -where - (B, C): StreamWithUpgrade, -{ - #[debug("Base(..)")] - Base(B, C), - #[debug("Upgraded(..)")] - Upgraded(<(B, C) as StreamWithUpgrade>::Upgrade), - #[debug("Upgrading")] - Upgrading, -} - -#[derive(derive_more::Debug)] -pub enum UpgradableStreamChoice -where - (B, C): StreamWithUpgrade, -{ - #[debug("Base(..)")] - Base(B), - #[debug("Upgrade(..)")] - Upgrade(<(B, C) as StreamWithUpgrade>::Upgrade), -} - -impl UpgradableStreamChoice -where - (B, C): StreamWithUpgrade, - B: 'static, - <(B, C) as StreamWithUpgrade>::Base: 'static, - <(B, C) as StreamWithUpgrade>::Upgrade: 'static, -{ - /// Take the inner stream as a boxed `Stream` - pub fn into_boxed(self) -> Box { - match self { - UpgradableStreamChoice::Base(base) => Box::new(base), - UpgradableStreamChoice::Upgrade(upgrade) => Box::new(upgrade), - } - } -} diff --git a/rust/gel-stream/src/common/mod.rs b/rust/gel-stream/src/common/mod.rs new file mode 100644 index 00000000000..c2a6bed0368 --- /dev/null +++ b/rust/gel-stream/src/common/mod.rs @@ -0,0 +1,16 @@ +pub mod stream; +pub mod target; +pub mod tls; + +#[cfg(feature = "openssl")] +pub mod openssl; +#[cfg(feature = "rustls")] +pub mod rustls; +#[cfg(feature = "tokio")] +pub mod tokio_stream; + +#[cfg(feature = "tokio")] +pub type BaseStream = tokio_stream::TokioStream; + +#[cfg(not(feature = "tokio"))] +pub type BaseStream = (); diff --git a/rust/gel-stream/src/common/openssl.rs b/rust/gel-stream/src/common/openssl.rs new file mode 100644 index 00000000000..40d39587fc6 --- /dev/null +++ b/rust/gel-stream/src/common/openssl.rs @@ -0,0 +1,521 @@ +use openssl::{ + ssl::{ + AlpnError, NameType, SniError, Ssl, SslAcceptor, SslContextBuilder, SslMethod, SslRef, + SslVerifyMode, + }, + x509::{verify::X509VerifyFlags, X509VerifyResult}, +}; +use rustls_pki_types::ServerName; +use std::{ + borrow::Cow, + io::IoSlice, + pin::Pin, + sync::{Arc, Mutex, MutexGuard, OnceLock}, + task::{ready, Poll}, +}; +use tokio::{ + io::{AsyncRead, AsyncWrite, ReadBuf}, + net::TcpStream, +}; + +use crate::{ + RewindStream, SslError, SslVersion, Stream, TlsCert, TlsClientCertVerify, TlsDriver, + TlsHandshake, TlsParameters, TlsServerCertVerify, TlsServerParameterProvider, + TlsServerParameters, +}; + +use super::tokio_stream::TokioStream; + +#[derive(Debug, Clone, Default)] +struct HandshakeData { + server_alpn: Option>, + handshake: TlsHandshake, +} + +impl HandshakeData { + fn from_ssl(ssl: &SslRef) -> Option> { + let Some(handshake) = ssl.ex_data(get_ssl_ex_data_index()) else { + return None; + }; + let Ok(handshake) = handshake.lock() else { + return None; + }; + Some(handshake) + } +} + +static SSL_EX_DATA_INDEX: OnceLock>>> = + OnceLock::new(); + +fn get_ssl_ex_data_index() -> openssl::ex_data::Index>> { + *SSL_EX_DATA_INDEX + .get_or_init(|| Ssl::new_ex_index().expect("Failed to create SSL ex_data index")) +} + +#[derive(Default)] + +pub struct OpensslDriver; + +pub struct TlsStream(tokio_openssl::SslStream); + +impl AsyncRead for TlsStream { + #[inline(always)] + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_read(cx, buf) + } +} + +impl AsyncWrite for TlsStream { + #[inline(always)] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_write(cx, buf) + } + + #[inline(always)] + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + bufs: &[IoSlice<'_>], + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_write_vectored(cx, bufs) + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + #[inline(always)] + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_flush(cx) + } + + #[inline(always)] + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let res = ready!(Pin::new(&mut self.0).poll_shutdown(cx)); + if let Err(e) = &res { + // Swallow NotConnected errors here + if e.kind() == std::io::ErrorKind::NotConnected { + return Poll::Ready(Ok(())); + } + } + Poll::Ready(res) + } +} + +impl TlsDriver for OpensslDriver { + type Stream = TlsStream; + type ClientParams = openssl::ssl::Ssl; + type ServerParams = openssl::ssl::SslContext; + + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result { + let TlsParameters { + server_cert_verify, + root_cert, + cert, + key, + crl, + min_protocol_version, + max_protocol_version, + alpn, + sni_override, + enable_keylog, + } = params; + + // let mut ssl = SslConnector::builder(SslMethod::tls_client())?; + let mut ssl = SslContextBuilder::new(SslMethod::tls_client())?; + + // Load root cert + if let TlsCert::Custom(root) = root_cert { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + ssl.set_verify(SslVerifyMode::PEER); + } else if *server_cert_verify == TlsServerCertVerify::Insecure { + ssl.set_verify(SslVerifyMode::NONE); + } + + // Load CRL + if !crl.is_empty() { + // The openssl crate doesn't yet have add_crl, so we need to use the raw FFI + use foreign_types::ForeignTypeRef; + let ptr = ssl.cert_store_mut().as_ptr(); + + extern "C" { + pub fn X509_STORE_add_crl( + store: *mut openssl_sys::X509_STORE, + x: *mut openssl_sys::X509_CRL, + ) -> openssl_sys::c_int; + } + + for crl in crl { + let crl = openssl::x509::X509Crl::from_der(crl.as_ref())?; + let crl_ptr = crl.as_ptr(); + let res = unsafe { X509_STORE_add_crl(ptr, crl_ptr) }; + if res != 1 { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to add CRL to store", + ) + .into()); + } + } + + ssl.verify_param_mut() + .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; + ssl.cert_store_mut() + .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; + } + + // Load certificate chain and private key + if let (Some(cert), Some(key)) = (cert.as_ref(), key.as_ref()) { + let builder = openssl::x509::X509::from_der(cert.as_ref())?; + ssl.set_certificate(&builder)?; + let builder = openssl::pkey::PKey::private_key_from_der(&key.secret_der())?; + ssl.set_private_key(&builder)?; + } + + // Configure hostname verification + if *server_cert_verify == TlsServerCertVerify::VerifyFull { + ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); + } + + ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; + ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; + + // Configure key log filename + if *enable_keylog { + if let Ok(path) = std::env::var("SSLKEYLOGFILE") { + ssl.set_keylog_callback(move |_ssl, msg| { + let Ok(mut file) = std::fs::OpenOptions::new().append(true).open(&path) else { + return; + }; + let _ = std::io::Write::write_all(&mut file, msg.as_bytes()); + }); + } + } + + if *server_cert_verify == TlsServerCertVerify::VerifyFull { + if let Some(hostname) = sni_override { + ssl.verify_param_mut().set_host(hostname)?; + } else if let Some(ServerName::DnsName(hostname)) = &name { + ssl.verify_param_mut().set_host(hostname.as_ref())?; + } else if let Some(ServerName::IpAddress(ip)) = &name { + ssl.verify_param_mut().set_ip((*ip).into())?; + } + } + + let mut ssl = openssl::ssl::Ssl::new(&ssl.build())?; + ssl.set_connect_state(); + + // Set hostname if it's not an IP address + if let Some(hostname) = sni_override { + ssl.set_hostname(hostname)?; + } else if let Some(ServerName::DnsName(hostname)) = &name { + ssl.set_hostname(hostname.as_ref())?; + } + + if !alpn.is_empty() { + ssl.set_alpn_protos(&alpn.as_bytes())?; + } + + Ok(ssl) + } + + fn init_server(params: &TlsServerParameters) -> Result { + let TlsServerParameters { + client_cert_verify, + min_protocol_version, + max_protocol_version, + server_certificate, + // Handled elsewhere + alpn: _alpn, + } = params; + + let mut ssl = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server())?; + let cert = openssl::x509::X509::from_der(&server_certificate.cert.as_ref())?; + let key = openssl::pkey::PKey::private_key_from_der(&server_certificate.key.secret_der())?; + ssl.set_certificate(&cert)?; + ssl.set_private_key(&key)?; + ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; + ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; + match client_cert_verify { + TlsClientCertVerify::Ignore => ssl.set_verify(SslVerifyMode::NONE), + TlsClientCertVerify::Optional(root) => { + ssl.set_verify(SslVerifyMode::PEER); + for root in root { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + } + } + TlsClientCertVerify::Validate(root) => { + ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); + for root in root { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + } + } + } + create_alpn_callback(&mut ssl); + + Ok(ssl.build().into_context()) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut stream = tokio_openssl::SslStream::new(params, stream)?; + let res = Pin::new(&mut stream).do_handshake().await; + if res.is_err() { + if stream.ssl().verify_result() != X509VerifyResult::OK { + return Err(SslError::OpenSslErrorVerify(stream.ssl().verify_result())); + } + } + + let alpn = stream + .ssl() + .selected_alpn_protocol() + .map(|p| Cow::Owned(p.to_vec())); + + res.map_err(SslError::OpenSslError)?; + Ok(( + TlsStream(stream), + TlsHandshake { + alpn, + sni: None, + cert: None, + }, + )) + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::>() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let (stream, buffer) = stream.into_inner(); + if !buffer.is_empty() { + // TODO: We should also be able to support rewinding + return Err(crate::SslError::SslUnsupportedByClient); + } + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let handshake = Arc::new(Mutex::new(HandshakeData::default())); + + let mut ssl = SslContextBuilder::new(SslMethod::tls_server())?; + create_alpn_callback(&mut ssl); + create_sni_callback(&mut ssl, params); + + let mut ssl = Ssl::new(&ssl.build())?; + ssl.set_accept_state(); + ssl.set_ex_data(get_ssl_ex_data_index(), handshake.clone()); + + let mut stream = tokio_openssl::SslStream::new(ssl, stream)?; + let res = Pin::new(&mut stream).do_handshake().await; + res.map_err(SslError::OpenSslError)?; + + let handshake = handshake.lock().unwrap().handshake.clone(); + + Ok((TlsStream(stream), handshake)) + } +} + +fn ssl_select_next_proto<'a, 'b>(server: &'a [u8], client: &'b [u8]) -> Option<&'b [u8]> { + let mut server_packet = server; + while !server_packet.is_empty() { + let server_proto_len = *server_packet.get(0)? as usize; + let server_proto = server_packet.get(1..1 + server_proto_len)?; + let mut client_packet = client; + while !client_packet.is_empty() { + let client_proto_len = *client_packet.get(0)? as usize; + let client_proto = client_packet.get(1..1 + client_proto_len)?; + if client_proto == server_proto { + return Some(client_proto); + } + client_packet = client_packet.get(1 + client_proto_len..)?; + } + server_packet = server_packet.get(1 + server_proto_len..)?; + } + None +} + +/// Create an ALPN callback for the [`SslContextBuilder`]. +fn create_alpn_callback(ssl: &mut SslContextBuilder) { + ssl.set_alpn_select_callback(|ssl_ref, alpn| { + let Some(mut handshake) = HandshakeData::from_ssl(ssl_ref) else { + return Err(AlpnError::ALERT_FATAL); + }; + + if let Some(server) = handshake.server_alpn.take() { + eprintln!("server: {:?} alpn: {:?}", server, alpn); + let Some(selected) = ssl_select_next_proto(&server, alpn) else { + return Err(AlpnError::NOACK); + }; + handshake.handshake.alpn = Some(Cow::Owned(selected.to_vec())); + + Ok(selected) + } else { + Err(AlpnError::NOACK) + } + }) +} + +/// Create an SNI callback for the [`SslContextBuilder`]. +fn create_sni_callback(ssl: &mut SslContextBuilder, params: TlsServerParameterProvider) { + ssl.set_servername_callback(move |ssl_ref, _alert| { + let Some(mut handshake) = HandshakeData::from_ssl(ssl_ref) else { + return Ok(()); + }; + + if let Some(servername) = ssl_ref.servername_raw(NameType::HOST_NAME) { + handshake.handshake.sni = + Some(Cow::Owned(String::from_utf8_lossy(servername).to_string())); + } + + let params = params.lookup(None); + if !params.alpn.is_empty() { + handshake.server_alpn = Some(params.alpn.as_bytes().to_vec()); + } + + drop(handshake); + + let Ok(ssl) = OpensslDriver::init_server(¶ms) else { + return Err(SniError::ALERT_FATAL); + }; + let Ok(_) = ssl_ref.set_ssl_context(&ssl) else { + return Err(SniError::ALERT_FATAL); + }; + Ok(()) + }); +} + +impl From for openssl::ssl::SslVersion { + fn from(val: SslVersion) -> Self { + match val { + SslVersion::Tls1 => openssl::ssl::SslVersion::TLS1, + SslVersion::Tls1_1 => openssl::ssl::SslVersion::TLS1_1, + SslVersion::Tls1_2 => openssl::ssl::SslVersion::TLS1_2, + SslVersion::Tls1_3 => openssl::ssl::SslVersion::TLS1_3, + } + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ssl_select_next_proto() { + let server = b"\x02h2\x08http/1.1"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_empty() { + let server = b""; + let client = b""; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_invalid_length() { + let server = b"\x08h2"; // Claims 8 bytes but only has 2 + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_zero_length() { + let server = b"\x00h2"; // Zero length but has data + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_truncated() { + let server = b"\x02h2\x08http/1"; // Second protocol truncated + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_overflow() { + let server = b"\xFFh2"; // Length that would overflow buffer + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_no_match() { + let server = b"\x02h2"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_multiple_server() { + let server = b"\x02h2\x06spdy/2\x08http/1.1"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_multiple_client() { + let server = b"\x08http/1.1"; + let client = b"\x02h2\x06spdy/2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_first_match() { + let server = b"\x02h2\x06spdy/2\x08http/1.1"; + let client = b"\x06spdy/2\x02h2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"h2".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_first_match_2() { + let server = b"\x06spdy/2\x02h2\x08http/1.1"; + let client = b"\x02h2\x06spdy/2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"spdy/2".as_slice())); + } +} diff --git a/rust/gel-stream/src/client/rustls.rs b/rust/gel-stream/src/common/rustls.rs similarity index 53% rename from rust/gel-stream/src/client/rustls.rs rename to rust/gel-stream/src/common/rustls.rs index 456dc4818ec..8ec4368a317 100644 --- a/rust/gel-stream/src/client/rustls.rs +++ b/rust/gel-stream/src/common/rustls.rs @@ -1,109 +1,39 @@ +use futures::FutureExt; use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; use rustls::client::WebPkiServerVerifier; +use rustls::server::{Acceptor, ClientHello, WebPkiClientVerifier}; use rustls::{ - ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, SignatureScheme, + ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, ServerConfig, + SignatureScheme, }; use rustls_pki_types::{ CertificateDer, CertificateRevocationListDer, DnsName, ServerName, UnixTime, }; use rustls_platform_verifier::Verifier; +use rustls_tokio_stream::TlsStream; -use super::stream::{Stream, StreamWithUpgrade}; use super::tokio_stream::TokioStream; -use super::{TlsCert, TlsInit, TlsParameters, TlsServerCertVerify}; -use std::any::Any; +use crate::{ + RewindStream, SslError, Stream, TlsClientCertVerify, TlsDriver, TlsHandshake, + TlsServerParameterProvider, TlsServerParameters, +}; +use crate::{TlsCert, TlsParameters, TlsServerCertVerify}; +use std::borrow::Cow; use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; -impl StreamWithUpgrade for (S, Option) { - type Base = S; - type Config = ClientConnection; - type Upgrade = rustls_tokio_stream::TlsStream; - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - let Some(tls) = self.1 else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - // Note that we only support Tokio TcpStream for rustls. - let stream = &mut Some(self.0) as &mut dyn Any; - let Some(stream) = stream.downcast_mut::>() else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let stream = stream.take().unwrap(); - let TokioStream::Tcp(stream) = stream else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let mut stream = rustls_tokio_stream::TlsStream::new_client_side(stream, tls, None); - let res = stream.handshake().await; - - // Potentially unwrap the error to get the underlying error. - if let Err(e) = res { - let kind = e.kind(); - if let Some(e2) = e.into_inner() { - match e2.downcast::<::rustls::Error>() { - Ok(e) => return Err(super::SslError::RustlsError(*e)), - Err(e) => return Err(std::io::Error::new(kind, e).into()), - } - } else { - return Err(std::io::Error::from(kind).into()); - } - } - - Ok(stream) - } -} +#[derive(Default)] +pub struct RustlsDriver; -fn make_verifier( - server_cert_verify: &TlsServerCertVerify, - root_cert: &TlsCert, - crls: Vec>, -) -> Result, super::SslError> { - if *server_cert_verify == TlsServerCertVerify::Insecure { - return Ok(Arc::new(NullVerifier)); - } +impl TlsDriver for RustlsDriver { + type Stream = TlsStream; + type ClientParams = ClientConnection; + type ServerParams = Arc; - if let TlsCert::Custom(root) = root_cert { - let mut roots = RootCertStore::empty(); - let (loaded, ignored) = roots.add_parsable_certificates([root.clone()]); - if loaded == 0 || ignored > 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Invalid certificate", - ) - .into()); - } - - let verifier = WebPkiServerVerifier::builder(Arc::new(roots)) - .with_crls(crls) - .build()?; - if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { - return Ok(Arc::new(IgnoreHostnameVerifier::new(verifier))); - } - return Ok(verifier); - } - - if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { - return Ok(Arc::new(IgnoreHostnameVerifier::new(Arc::new( - Verifier::new(), - )))); - } - - Ok(Arc::new(Verifier::new())) -} - -impl TlsInit for ClientConnection { - type Tls = ClientConnection; - - fn init( - parameters: &TlsParameters, + fn init_client( + params: &TlsParameters, name: Option, - ) -> Result { + ) -> Result { let _ = ::rustls::crypto::ring::default_provider().install_default(); let TlsParameters { @@ -117,7 +47,7 @@ impl TlsInit for ClientConnection { alpn, enable_keylog, sni_override, - } = parameters; + } = params; let verifier = make_verifier(server_cert_verify, root_cert, crl.clone())?; @@ -140,12 +70,7 @@ impl TlsInit for ClientConnection { }; // Configure ALPN if provided - if let Some(alpn_protocols) = alpn { - config.alpn_protocols = alpn_protocols - .iter() - .map(|p| p.as_bytes().to_vec()) - .collect(); - } + config.alpn_protocols = alpn.as_vec_vec(); // Configure keylog if provided if *enable_keylog { @@ -163,6 +88,172 @@ impl TlsInit for ClientConnection { Ok(ClientConnection::new(Arc::new(config), name)?) } + + fn init_server(params: &TlsServerParameters) -> Result { + let builder = match ¶ms.client_cert_verify { + TlsClientCertVerify::Ignore => ServerConfig::builder().with_no_client_auth(), + TlsClientCertVerify::Optional(certs) => { + let mut roots = RootCertStore::empty(); + roots.add_parsable_certificates( + certs.iter().map(|c| CertificateDer::from_slice(c.as_ref())), + ); + ServerConfig::builder().with_client_cert_verifier( + WebPkiClientVerifier::builder(roots.into()) + .allow_unauthenticated() + .build()?, + ) + } + TlsClientCertVerify::Validate(certs) => { + let mut roots = RootCertStore::empty(); + roots.add_parsable_certificates( + certs.iter().map(|c| CertificateDer::from_slice(c.as_ref())), + ); + ServerConfig::builder() + .with_client_cert_verifier(WebPkiClientVerifier::builder(roots.into()).build()?) + } + }; + + let mut config = builder.with_single_cert( + vec![params.server_certificate.cert.clone()], + params.server_certificate.key.clone_key(), + )?; + + config.alpn_protocols = params.alpn.as_vec_vec(); + + Ok(Arc::new(config)) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + // Note that we only support Tokio TcpStream for rustls. + let stream = stream + .downcast::() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut stream = TlsStream::new_client_side(stream, params, None); + + match stream.handshake().await { + Ok(handshake) => Ok(( + stream, + TlsHandshake { + alpn: handshake.alpn.map(|alpn| Cow::Owned(alpn.to_vec())), + sni: handshake.sni.map(|sni| Cow::Owned(sni.to_string())), + cert: None, + }, + )), + Err(e) => { + let kind = e.kind(); + if let Some(e2) = e.into_inner() { + match e2.downcast::<::rustls::Error>() { + Ok(e) => Err(crate::SslError::RustlsError(*e)), + Err(e) => Err(std::io::Error::new(kind, e).into()), + } + } else { + Err(std::io::Error::from(kind).into()) + } + } + } + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::>() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let (stream, buffer) = stream.into_inner(); + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut acceptor = Acceptor::default(); + acceptor.read_tls(&mut buffer.as_slice())?; + let server_config_provider = Arc::new(move |client_hello: ClientHello| { + let params = params.clone(); + let server_name = client_hello + .server_name() + .map(|name| ServerName::DnsName(DnsName::try_from(name.to_string()).unwrap())); + async move { + let params = params.lookup(server_name); + let config = RustlsDriver::init_server(¶ms) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?; + Ok::<_, std::io::Error>(config) + } + .boxed() + }); + let mut stream = TlsStream::new_server_side_from_acceptor( + acceptor, + stream, + server_config_provider, + None, + ); + + match stream.handshake().await { + Ok(handshake) => Ok(( + stream, + TlsHandshake { + alpn: handshake.alpn.map(|alpn| Cow::Owned(alpn.to_vec())), + sni: handshake.sni.map(|sni| Cow::Owned(sni.to_string())), + cert: None, + }, + )), + Err(e) => { + let kind = e.kind(); + if let Some(e2) = e.into_inner() { + match e2.downcast::<::rustls::Error>() { + Ok(e) => Err(crate::SslError::RustlsError(*e)), + Err(e) => Err(std::io::Error::new(kind, e).into()), + } + } else { + Err(std::io::Error::from(kind).into()) + } + } + } + } +} + +fn make_verifier( + server_cert_verify: &TlsServerCertVerify, + root_cert: &TlsCert, + crls: Vec>, +) -> Result, crate::SslError> { + if *server_cert_verify == TlsServerCertVerify::Insecure { + return Ok(Arc::new(NullVerifier)); + } + + if let TlsCert::Custom(root) = root_cert { + let mut roots = RootCertStore::empty(); + let (loaded, ignored) = roots.add_parsable_certificates([root.clone()]); + if loaded == 0 || ignored > 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Invalid certificate", + ) + .into()); + } + + let verifier = WebPkiServerVerifier::builder(Arc::new(roots)) + .with_crls(crls) + .build()?; + if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { + return Ok(Arc::new(IgnoreHostnameVerifier::new(verifier))); + } + return Ok(verifier); + } + + if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { + return Ok(Arc::new(IgnoreHostnameVerifier::new(Arc::new( + Verifier::new(), + )))); + } + + Ok(Arc::new(Verifier::new())) } #[derive(Debug)] diff --git a/rust/gel-stream/src/common/stream.rs b/rust/gel-stream/src/common/stream.rs new file mode 100644 index 00000000000..9b56a25e68a --- /dev/null +++ b/rust/gel-stream/src/common/stream.rs @@ -0,0 +1,343 @@ +#[cfg(feature = "tokio")] +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; + +use std::future::Future; +#[cfg(feature = "tokio")] +use std::{ + any::Any, + io::IoSlice, + pin::Pin, + task::{Context, Poll}, +}; + +use crate::{Ssl, SslError, TlsDriver, TlsHandshake, TlsServerParameterProvider}; + +#[cfg(feature = "tokio")] +pub trait Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static { + fn downcast(self) -> Result + where + Self: Sized + 'static, + { + // Note that we only support Tokio TcpStream for rustls. + let mut holder = Some(self); + let stream = &mut holder as &mut dyn Any; + let Some(stream) = stream.downcast_mut::>() else { + return Err(holder.take().unwrap()); + }; + let stream = stream.take().unwrap(); + Ok(stream) + } +} + +#[cfg(feature = "tokio")] +impl Stream for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static {} + +#[cfg(not(feature = "tokio"))] +pub trait Stream: 'static {} +#[cfg(not(feature = "tokio"))] +impl Stream for UpgradableStream {} +#[cfg(not(feature = "tokio"))] +impl Stream for () {} + +pub trait StreamUpgrade: Stream { + fn secure_upgrade(&mut self) -> impl Future> + Send; + fn handshake(&self) -> Option<&TlsHandshake>; +} + +#[allow(private_bounds)] +#[derive(derive_more::Debug)] +pub struct UpgradableStream { + inner: UpgradableStreamInner, +} + +#[allow(private_bounds)] +impl UpgradableStream { + #[inline(always)] + pub(crate) fn new_client(base: S, config: Option) -> Self { + UpgradableStream { + inner: UpgradableStreamInner::BaseClient(base, config), + } + } + + #[inline(always)] + pub(crate) fn new_server(base: S, config: Option) -> Self { + UpgradableStream { + inner: UpgradableStreamInner::BaseServer(base, config), + } + } + + /// Consume the `UpgradableStream` and return the underlying stream as a [`Box`]. + pub fn into_boxed(self) -> Result, Self> { + match self.inner { + UpgradableStreamInner::BaseClient(base, _) => Ok(Box::new(base)), + UpgradableStreamInner::BaseServer(base, _) => Ok(Box::new(base)), + UpgradableStreamInner::Upgraded(upgraded, _) => Ok(Box::new(upgraded)), + UpgradableStreamInner::Upgrading => Err(self), + } + } +} + +impl StreamUpgrade for UpgradableStream { + async fn secure_upgrade(&mut self) -> Result<(), SslError> { + match std::mem::replace(&mut self.inner, UpgradableStreamInner::Upgrading) { + UpgradableStreamInner::BaseClient(base, config) => { + let Some(config) = config else { + return Err(SslError::SslUnsupportedByClient); + }; + let (upgraded, handshake) = D::upgrade_client(config, base).await?; + self.inner = UpgradableStreamInner::Upgraded(upgraded, handshake); + Ok(()) + } + UpgradableStreamInner::BaseServer(base, config) => { + let Some(config) = config else { + return Err(SslError::SslUnsupportedByClient); + }; + let (upgraded, handshake) = D::upgrade_server(config, base).await?; + self.inner = UpgradableStreamInner::Upgraded(upgraded, handshake); + Ok(()) + } + UpgradableStreamInner::Upgraded(..) => Err(SslError::SslAlreadyUpgraded), + UpgradableStreamInner::Upgrading => Err(SslError::SslAlreadyUpgraded), + } + } + + fn handshake(&self) -> Option<&TlsHandshake> { + match &self.inner { + UpgradableStreamInner::Upgraded(_, handshake) => Some(handshake), + _ => None, + } + } +} + +#[cfg(feature = "tokio")] +impl tokio::io::AsyncRead for UpgradableStream { + #[inline(always)] + fn poll_read( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_read(cx, buf), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_read(cx, buf), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_read(cx, buf), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot read while upgrading", + ))), + } + } +} + +#[cfg(feature = "tokio")] +impl tokio::io::AsyncWrite for UpgradableStream { + #[inline(always)] + fn poll_write( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_write(cx, buf), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_write(cx, buf), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_write(cx, buf), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot write while upgrading", + ))), + } + } + + #[inline(always)] + fn poll_flush( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_flush(cx), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_flush(cx), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_flush(cx), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot flush while upgrading", + ))), + } + } + + #[inline(always)] + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_shutdown(cx), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_shutdown(cx), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_shutdown(cx), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot shutdown while upgrading", + ))), + } + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + match &self.inner { + UpgradableStreamInner::BaseClient(base, _) => base.is_write_vectored(), + UpgradableStreamInner::BaseServer(base, _) => base.is_write_vectored(), + UpgradableStreamInner::Upgraded(upgraded, _) => upgraded.is_write_vectored(), + UpgradableStreamInner::Upgrading => false, + } + } + + #[inline(always)] + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => { + Pin::new(base).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::BaseServer(base, _) => { + Pin::new(base).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::Upgraded(upgraded, _) => { + Pin::new(upgraded).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot write vectored while upgrading", + ))), + } + } +} + +#[derive(derive_more::Debug)] +enum UpgradableStreamInner { + #[debug("BaseClient(..)")] + BaseClient(S, Option), + #[debug("BaseServer(..)")] + BaseServer(S, Option), + #[debug("Upgraded(..)")] + Upgraded(D::Stream, TlsHandshake), + #[debug("Upgrading")] + Upgrading, +} + +pub trait Rewindable { + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()>; +} + +pub struct RewindStream { + buffer: Vec, + inner: S, +} + +impl RewindStream { + pub fn new(inner: S) -> Self { + RewindStream { + buffer: Vec::new(), + inner, + } + } + + pub fn rewind(&mut self, data: &[u8]) { + self.buffer.extend_from_slice(data); + } + + pub fn into_inner(self) -> (S, Vec) { + (self.inner, self.buffer) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for RewindStream { + #[inline(always)] + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + if !self.buffer.is_empty() { + let to_read = std::cmp::min(buf.remaining(), self.buffer.len()); + let data = self.buffer.drain(..to_read).collect::>(); + buf.put_slice(&data); + Poll::Ready(Ok(())) + } else { + Pin::new(&mut self.inner).poll_read(cx, buf) + } + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for RewindStream { + #[inline(always)] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + Pin::new(&mut self.inner).poll_write(cx, buf) + } + + #[inline(always)] + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.inner).poll_flush(cx) + } + + #[inline(always)] + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.inner).poll_shutdown(cx) + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + #[inline(always)] + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + Pin::new(&mut self.inner).poll_write_vectored(cx, bufs) + } +} + +impl Rewindable for RewindStream { + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()> { + self.rewind(bytes); + Ok(()) + } +} + +impl Rewindable for UpgradableStream +where + D::Stream: Rewindable, +{ + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()> { + match &mut self.inner { + UpgradableStreamInner::BaseClient(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::BaseServer(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::Upgraded(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::Upgrading => Err(std::io::Error::new( + std::io::ErrorKind::Unsupported, + "Cannot rewind a stream that is upgrading", + )), + } + } +} diff --git a/rust/gel-stream/src/client/target.rs b/rust/gel-stream/src/common/target.rs similarity index 97% rename from rust/gel-stream/src/client/target.rs rename to rust/gel-stream/src/common/target.rs index 233b03865c5..1eccbdb1cff 100644 --- a/rust/gel-stream/src/client/target.rs +++ b/rust/gel-stream/src/common/target.rs @@ -7,7 +7,7 @@ use std::{ use rustls_pki_types::ServerName; -use super::TlsParameters; +use crate::TlsParameters; /// A target name describes the TCP or Unix socket that a client will connect to. pub struct TargetName { @@ -249,6 +249,19 @@ pub enum ResolvedTarget { UnixSocketAddr(std::os::unix::net::SocketAddr), } +impl ResolvedTarget { + pub fn tcp(&self) -> Option { + match self { + ResolvedTarget::SocketAddr(addr) => Some(*addr), + _ => None, + } + } +} + +pub trait LocalAddress { + fn local_address(&self) -> std::io::Result; +} + trait TcpResolve { fn into(self) -> MaybeResolvedTarget; } diff --git a/rust/gel-stream/src/common/tls.rs b/rust/gel-stream/src/common/tls.rs new file mode 100644 index 00000000000..07c2ead1608 --- /dev/null +++ b/rust/gel-stream/src/common/tls.rs @@ -0,0 +1,259 @@ +use crate::{SslError, Stream}; +use rustls_pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer, ServerName}; +use std::{borrow::Cow, future::Future, sync::Arc}; + +use super::BaseStream; + +// Note that we choose rustls when both openssl and rustls are enabled. + +#[cfg(all(feature = "openssl", not(feature = "rustls")))] +pub type Ssl = crate::common::openssl::OpensslDriver; +#[cfg(feature = "rustls")] +pub type Ssl = crate::common::rustls::RustlsDriver; +#[cfg(not(any(feature = "openssl", feature = "rustls")))] +pub type Ssl = NullTlsDriver; + +pub trait TlsDriver: Default + Send + Sync + Unpin + 'static { + type Stream: Stream + Send; + type ClientParams: Unpin + Send; + type ServerParams: Unpin + Send; + + #[allow(unused)] + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result; + #[allow(unused)] + fn init_server(params: &TlsServerParameters) -> Result; + + fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> impl Future> + Send; + fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> impl Future> + Send; +} + +#[derive(Default)] +pub struct NullTlsDriver; + +#[allow(unused)] +impl TlsDriver for NullTlsDriver { + type Stream = BaseStream; + type ClientParams = (); + type ServerParams = (); + + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result { + Err(SslError::SslUnsupportedByClient) + } + + fn init_server(params: &TlsServerParameters) -> Result { + Err(SslError::SslUnsupportedByClient) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + Err(SslError::SslUnsupportedByClient) + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + Err(SslError::SslUnsupportedByClient) + } +} + +/// Verification modes for TLS that are a superset of both PostgreSQL and EdgeDB/Gel. +/// +/// Postgres offers six levels: `disable`, `allow`, `prefer`, `require`, `verify-ca` and `verify-full`. +/// +/// EdgeDB/Gel offers three levels: `insecure`, `no_host_verification' and 'strict'. +/// +/// This table maps the various levels: +/// +/// | Postgres | EdgeDB/Gel | `TlsServerCertVerify` enum | +/// | -------- | ----------- | ----------------- | +/// | require | insecure | `Insecure` | +/// | verify-ca | no_host_verification | `IgnoreHostname` | +/// | verify-full | strict | `VerifyFull` | +/// +/// Note that both EdgeDB/Gel and Postgres may alter certificate validation levels +/// when custom root certificates are provided. This must be done in the +/// `TlsParameters` struct by the caller. +#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] +pub enum TlsServerCertVerify { + /// Do not verify the server's certificate. Only confirm that the server is + /// using TLS. + Insecure, + /// Verify the server's certificate using the CA (ignore hostname). + IgnoreHostname, + /// Verify the server's certificate using the CA and hostname. + #[default] + VerifyFull, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub enum TlsCert { + /// Use the system's default certificate. + #[default] + System, + /// Use a custom root certificate only. + Custom(CertificateDer<'static>), +} + +#[derive(Default, Debug, PartialEq, Eq)] +pub struct TlsParameters { + pub server_cert_verify: TlsServerCertVerify, + pub cert: Option>, + pub key: Option>, + pub root_cert: TlsCert, + pub crl: Vec>, + pub min_protocol_version: Option, + pub max_protocol_version: Option, + pub enable_keylog: bool, + pub sni_override: Option>, + pub alpn: TlsAlpn, +} + +impl TlsParameters { + pub fn insecure() -> Self { + Self { + server_cert_verify: TlsServerCertVerify::Insecure, + ..Default::default() + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SslVersion { + Tls1, + Tls1_1, + Tls1_2, + Tls1_3, +} + +#[derive(Default, Debug, PartialEq, Eq)] +pub enum TlsClientCertVerify { + /// Do not verify the client's certificate, just ignore it. + #[default] + Ignore, + /// If a client certificate is provided, validate it. + Optional(Vec>), + /// Validate that a client certificate exists and is valid. This configuration + /// may not be ideal, because it does not fail the client-side handshake. + Validate(Vec>), +} + +#[derive(derive_more::Debug, derive_more::Constructor)] +pub struct TlsKey { + #[debug("key(...)")] + pub(crate) key: PrivateKeyDer<'static>, + #[debug("cert(...)")] + pub(crate) cert: CertificateDer<'static>, +} + +#[derive(Debug, Clone)] +pub struct TlsServerParameterProvider { + inner: TlsServerParameterProviderInner, +} + +impl TlsServerParameterProvider { + pub fn new(params: TlsServerParameters) -> Self { + Self { + inner: TlsServerParameterProviderInner::Static(Arc::new(params)), + } + } + + pub fn with_lookup( + lookup: impl Fn(Option) -> Arc + Send + Sync + 'static, + ) -> Self { + Self { + inner: TlsServerParameterProviderInner::Lookup(Arc::new(lookup)), + } + } + + pub fn lookup(&self, name: Option) -> Arc { + match &self.inner { + TlsServerParameterProviderInner::Static(params) => params.clone(), + TlsServerParameterProviderInner::Lookup(lookup) => lookup(name), + } + } +} + +#[derive(derive_more::Debug, Clone)] +enum TlsServerParameterProviderInner { + Static(Arc), + #[debug("Lookup(...)")] + #[allow(clippy::type_complexity)] + Lookup(Arc) -> Arc + Send + Sync + 'static>), +} + +#[derive(Debug)] +pub struct TlsServerParameters { + pub client_cert_verify: TlsClientCertVerify, + pub min_protocol_version: Option, + pub max_protocol_version: Option, + pub server_certificate: TlsKey, + pub alpn: TlsAlpn, +} + +#[derive(Debug, Default, Eq, PartialEq)] +pub struct TlsAlpn { + /// The split form (ie: ["AB", "ABCD"]) + alpn_parts: Cow<'static, [Cow<'static, [u8]>]>, +} + +impl TlsAlpn { + pub fn new(alpn: &'static [&'static [u8]]) -> Self { + let alpn = alpn.iter().map(|s| Cow::Borrowed(*s)).collect::>(); + Self { + alpn_parts: Cow::Owned(alpn), + } + } + + pub fn new_str(alpn: &'static [&'static str]) -> Self { + let alpn = alpn + .iter() + .map(|s| Cow::Borrowed(s.as_bytes())) + .collect::>(); + Self { + alpn_parts: Cow::Owned(alpn), + } + } + + pub fn is_empty(&self) -> bool { + self.alpn_parts.is_empty() + } + + pub fn as_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(self.alpn_parts.len() * 2); + for part in self.alpn_parts.iter() { + bytes.push(part.len() as u8); + bytes.extend_from_slice(part.as_ref()); + } + bytes + } + + pub fn as_vec_vec(&self) -> Vec> { + let mut vec = Vec::with_capacity(self.alpn_parts.len()); + for part in self.alpn_parts.iter() { + vec.push(part.to_vec()); + } + vec + } +} + +#[derive(Debug, Clone, Default)] +pub struct TlsHandshake { + pub alpn: Option>, + pub sni: Option>, + pub cert: Option>, +} diff --git a/rust/gel-stream/src/client/tokio_stream.rs b/rust/gel-stream/src/common/tokio_stream.rs similarity index 61% rename from rust/gel-stream/src/client/tokio_stream.rs rename to rust/gel-stream/src/common/tokio_stream.rs index 3b938e86d28..45b07310708 100644 --- a/rust/gel-stream/src/client/tokio_stream.rs +++ b/rust/gel-stream/src/common/tokio_stream.rs @@ -2,13 +2,13 @@ use std::net::{IpAddr, ToSocketAddrs}; use std::pin::Pin; -use std::task::{Context, Poll}; +use std::task::{ready, Context, Poll}; use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::net::TcpStream; #[cfg(unix)] use tokio::net::UnixStream; +use tokio::net::{TcpListener, TcpStream, UnixListener}; -use super::target::ResolvedTarget; +use super::target::{LocalAddress, ResolvedTarget}; pub(crate) struct Resolver { #[cfg(feature = "hickory")] @@ -51,7 +51,8 @@ impl Resolver { } impl ResolvedTarget { - /// Connects to the socket address and returns a TokioStream + #[cfg(feature = "client")] + /// Connects to the socket address and returns a [`TokioStream`]. pub async fn connect(&self) -> std::io::Result { match self { ResolvedTarget::SocketAddr(addr) => { @@ -66,6 +67,76 @@ impl ResolvedTarget { } } } + + #[cfg(feature = "server")] + pub async fn listen( + &self, + ) -> std::io::Result< + impl futures::Stream> + LocalAddress, + > { + self.listen_raw().await + } + + /// Listens for incoming connections on the socket address and returns a + /// [`futures::Stream`] of [`TokioStream`]s and the incoming address. + #[cfg(feature = "server")] + pub(crate) async fn listen_raw(&self) -> std::io::Result { + match self { + ResolvedTarget::SocketAddr(addr) => { + let listener = TcpListener::bind(addr).await?; + Ok(TokioListenerStream::Tcp(listener)) + } + #[cfg(unix)] + ResolvedTarget::UnixSocketAddr(path) => { + let listener = std::os::unix::net::UnixListener::bind_addr(path)?; + listener.set_nonblocking(true)?; + let listener = tokio::net::UnixListener::from_std(listener)?; + Ok(TokioListenerStream::Unix(listener)) + } + } + } +} + +pub(crate) enum TokioListenerStream { + Tcp(TcpListener), + #[cfg(unix)] + Unix(UnixListener), +} + +impl LocalAddress for TokioListenerStream { + fn local_address(&self) -> std::io::Result { + match self { + TokioListenerStream::Tcp(listener) => { + listener.local_addr().map(ResolvedTarget::SocketAddr) + } + #[cfg(unix)] + TokioListenerStream::Unix(listener) => listener + .local_addr() + .map(|addr| ResolvedTarget::UnixSocketAddr(addr.into())), + } + } +} + +impl futures::Stream for TokioListenerStream { + type Item = std::io::Result<(TokioStream, ResolvedTarget)>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.get_mut() { + TokioListenerStream::Tcp(listener) => { + let (stream, addr) = ready!(listener.poll_accept(cx))?; + let stream = TokioStream::Tcp(stream); + let target = ResolvedTarget::SocketAddr(addr); + Poll::Ready(Some(Ok((stream, target)))) + } + #[cfg(unix)] + TokioListenerStream::Unix(listener) => { + let (stream, addr) = ready!(listener.poll_accept(cx))?; + let stream = TokioStream::Unix(stream); + let target = ResolvedTarget::UnixSocketAddr(addr.into()); + Poll::Ready(Some(Ok((stream, target)))) + } + } + } } /// Represents a connected Tokio stream, either TCP or Unix diff --git a/rust/gel-stream/src/lib.rs b/rust/gel-stream/src/lib.rs index b9babe5bc1d..a8feb5678b8 100644 --- a/rust/gel-stream/src/lib.rs +++ b/rust/gel-stream/src/lib.rs @@ -1 +1,127 @@ -pub mod client; +// We don't want to warn about unused code when 1) either client or server is not +// enabled, or 2) no crypto backend is enabled. +#![cfg_attr( + not(all( + all(feature = "client", feature = "server"), + any(feature = "rustls", feature = "openssl") + )), + allow(unused) +)] + +#[cfg(feature = "client")] +mod client; +#[cfg(feature = "server")] +mod server; + +#[cfg(feature = "client")] +pub use client::Connector; + +#[cfg(feature = "server")] +pub use server::Acceptor; + +mod common; +#[cfg(feature = "openssl")] +pub use common::openssl::OpensslDriver; +#[cfg(feature = "rustls")] +pub use common::rustls::RustlsDriver; +pub use common::{stream::*, target::*, tls::*, BaseStream}; + +#[derive(Debug, thiserror::Error)] +pub enum ConnectionError { + /// I/O error encountered during connection operations. + #[error("I/O error: {0}")] + Io(#[from] std::io::Error), + + /// UTF-8 decoding error. + #[error("UTF8 error: {0}")] + Utf8Error(#[from] std::str::Utf8Error), + + /// SSL-related error. + #[error("SSL error: {0}")] + SslError(#[from] SslError), +} + +#[derive(Debug, thiserror::Error)] +pub enum SslError { + #[error("SSL is not supported by this client transport")] + SslUnsupportedByClient, + #[error("SSL is already upgraded or is in the process of upgrading")] + SslAlreadyUpgraded, + + #[cfg(feature = "openssl")] + #[error("OpenSSL error: {0}")] + OpenSslError(#[from] ::openssl::ssl::Error), + #[cfg(feature = "openssl")] + #[error("OpenSSL error: {0}")] + OpenSslErrorStack(#[from] ::openssl::error::ErrorStack), + #[cfg(feature = "openssl")] + #[error("OpenSSL certificate verification error: {0}")] + OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult), + + #[cfg(feature = "rustls")] + #[error("Rustls error: {0}")] + RustlsError(#[from] ::rustls::Error), + + #[cfg(feature = "rustls")] + #[error("Webpki error: {0}")] + WebpkiError(::webpki::Error), + + #[cfg(feature = "rustls")] + #[error("Verifier builder error: {0}")] + VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError), + + #[error("Invalid DNS name: {0}")] + InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError), + + #[error("SSL I/O error: {0}")] + SslIoError(#[from] std::io::Error), +} + +impl SslError { + /// Returns a common error for any time of crypto backend. + pub fn common_error(&self) -> Option { + match self { + #[cfg(feature = "rustls")] + SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => { + match cert_err { + ::rustls::CertificateError::NotValidForName => { + Some(CommonError::InvalidCertificateForName) + } + ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked), + ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired), + ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer), + _ => None, + } + } + #[cfg(feature = "openssl")] + SslError::OpenSslErrorVerify(e) => match e.as_raw() { + openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => { + Some(CommonError::InvalidCertificateForName) + } + openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => { + Some(CommonError::InvalidCertificateForName) + } + openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked), + openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired), + openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => { + Some(CommonError::InvalidIssuer) + } + _ => None, + }, + _ => None, + } + } +} + +#[derive(Debug, thiserror::Error, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub enum CommonError { + #[error("The certificate's subject name(s) do not match the name of the host")] + InvalidCertificateForName, + #[error("The certificate has been revoked")] + CertificateRevoked, + #[error("The certificate has expired")] + CertificateExpired, + #[error("The certificate was issued by an untrusted authority")] + InvalidIssuer, +} diff --git a/rust/gel-stream/src/server/acceptor.rs b/rust/gel-stream/src/server/acceptor.rs new file mode 100644 index 00000000000..df9c9307653 --- /dev/null +++ b/rust/gel-stream/src/server/acceptor.rs @@ -0,0 +1,178 @@ +use crate::{ + common::tokio_stream::TokioListenerStream, ConnectionError, LocalAddress, ResolvedTarget, + RewindStream, Ssl, SslError, StreamUpgrade, TlsDriver, TlsServerParameterProvider, + UpgradableStream, +}; +use futures::{FutureExt, StreamExt}; +use std::{ + future::Future, + pin::Pin, + task::{ready, Poll}, +}; +use std::{net::SocketAddr, path::Path}; + +use super::Connection; + +pub struct Acceptor { + resolved_target: ResolvedTarget, + tls_provider: Option, + should_upgrade: bool, +} + +impl Acceptor { + pub fn new_tcp(addr: SocketAddr) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: None, + should_upgrade: false, + } + } + + pub fn new_tcp_tls(addr: SocketAddr, provider: TlsServerParameterProvider) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: Some(provider), + should_upgrade: true, + } + } + + pub fn new_tcp_starttls(addr: SocketAddr, provider: TlsServerParameterProvider) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: Some(provider), + should_upgrade: false, + } + } + + #[cfg(unix)] + pub fn new_unix_path(path: impl AsRef) -> Result { + Ok(Self { + resolved_target: ResolvedTarget::from(std::os::unix::net::SocketAddr::from_pathname( + path, + )?), + tls_provider: None, + should_upgrade: false, + }) + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + pub fn new_unix_domain(domain: impl AsRef<[u8]>) -> Result { + use std::os::linux::net::SocketAddrExt; + Ok(Self { + resolved_target: ResolvedTarget::from( + std::os::unix::net::SocketAddr::from_abstract_name(domain)?, + ), + tls_provider: None, + should_upgrade: false, + }) + } + + pub async fn bind( + self, + ) -> Result< + impl ::futures::Stream> + LocalAddress, + ConnectionError, + > { + let stream = self.resolved_target.listen_raw().await?; + Ok(AcceptedStream { + stream, + should_upgrade: self.should_upgrade, + upgrade_future: None, + tls_provider: self.tls_provider, + _phantom: None, + }) + } + + #[allow(private_bounds)] + pub async fn bind_explicit( + self, + ) -> Result< + impl ::futures::Stream, ConnectionError>> + LocalAddress, + ConnectionError, + > { + let stream = self.resolved_target.listen_raw().await?; + Ok(AcceptedStream { + stream, + should_upgrade: self.should_upgrade, + upgrade_future: None, + tls_provider: self.tls_provider, + _phantom: None, + }) + } + + pub async fn accept_one(self) -> Result { + let mut stream = self.resolved_target.listen().await?; + let (stream, _target) = stream.next().await.unwrap()?; + Ok(UpgradableStream::new_server( + RewindStream::new(stream), + None::, + )) + } +} + +struct AcceptedStream { + stream: TokioListenerStream, + should_upgrade: bool, + tls_provider: Option, + #[allow(clippy::type_complexity)] + upgrade_future: + Option, SslError>> + Send + 'static>>>, + // Avoid using PhantomData because it fails to implement certain auto-traits + _phantom: Option<&'static D>, +} + +impl LocalAddress for AcceptedStream { + fn local_address(&self) -> std::io::Result { + self.stream.local_address() + } +} + +impl futures::Stream for AcceptedStream { + type Item = Result, ConnectionError>; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + if let Some(mut upgrade_future) = self.upgrade_future.take() { + match upgrade_future.poll_unpin(cx) { + Poll::Ready(Ok(conn)) => { + return Poll::Ready(Some(Ok(conn))); + } + Poll::Ready(Err(e)) => { + return Poll::Ready(Some(Err(e.into()))); + } + Poll::Pending => { + self.upgrade_future = Some(upgrade_future); + return Poll::Pending; + } + } + } + let r = ready!(self.stream.poll_next_unpin(cx)); + let Some(r) = r else { + return Poll::Ready(None); + }; + let (stream, _target) = r?; + let mut stream = + UpgradableStream::new_server(RewindStream::new(stream), self.tls_provider.clone()); + if self.should_upgrade { + let mut upgrade_future = Box::pin(async move { + stream.secure_upgrade().await?; + Ok::<_, SslError>(stream) + }); + match upgrade_future.poll_unpin(cx) { + Poll::Ready(Ok(stream)) => { + return Poll::Ready(Some(Ok(stream))); + } + Poll::Ready(Err(e)) => { + return Poll::Ready(Some(Err(e.into()))); + } + Poll::Pending => { + self.upgrade_future = Some(upgrade_future); + return Poll::Pending; + } + } + } + Poll::Ready(Some(Ok(stream))) + } +} diff --git a/rust/gel-stream/src/server/mod.rs b/rust/gel-stream/src/server/mod.rs new file mode 100644 index 00000000000..81d15f68943 --- /dev/null +++ b/rust/gel-stream/src/server/mod.rs @@ -0,0 +1,6 @@ +use crate::{RewindStream, Ssl, UpgradableStream}; + +mod acceptor; +pub use acceptor::Acceptor; + +type Connection = UpgradableStream, D>; diff --git a/rust/gel-stream/tests/socket.rs b/rust/gel-stream/tests/socket.rs new file mode 100644 index 00000000000..47f92e3de5d --- /dev/null +++ b/rust/gel-stream/tests/socket.rs @@ -0,0 +1,66 @@ +use futures::StreamExt; +use gel_stream::*; +use std::net::Ipv4Addr; +use std::net::SocketAddr; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +#[cfg(unix)] +#[tokio::test] +#[ntest::timeout(30_000)] +async fn test_target_unix() -> Result<(), ConnectionError> { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("gel-stream-test"); + + // Create a unix socket and connect to it + let mut acceptor = Acceptor::new_unix_path(&path)?.bind().await?; + let addr = acceptor.local_address(); + eprintln!("addr: {:?}", addr); + + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap().unwrap(); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + }); + + let connect_task = tokio::spawn(async { + let target = Target::new_unix_path(path)?; + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) +} + +#[tokio::test] +#[ntest::timeout(30_000)] +async fn test_target_tcp() -> Result<(), ConnectionError> { + // Create a TCP listener on a random port + let mut acceptor = Acceptor::new_tcp(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0)) + .bind() + .await?; + let addr = acceptor.local_address()?; + + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap().unwrap(); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + }); + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved(addr); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) +} diff --git a/rust/gel-stream/tests/tls.rs b/rust/gel-stream/tests/tls.rs new file mode 100644 index 00000000000..b71b2a15386 --- /dev/null +++ b/rust/gel-stream/tests/tls.rs @@ -0,0 +1,451 @@ +use futures::StreamExt; +use gel_stream::*; +use std::borrow::Cow; +use std::net::Ipv4Addr; +use std::net::SocketAddr; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +fn load_client_test_cert() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/client.cert.pem").as_bytes()) + .next() + .expect("no cert") + .expect("cert is bad") +} + +fn load_client_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { + rustls_pemfile::private_key(&mut include_str!("../../../tests/certs/client.key.pem").as_bytes()) + .expect("no client key") + .expect("client key is bad") +} + +fn load_client_test_ca() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/client_ca.cert.pem").as_bytes()) + .next() + .expect("no ca cert") + .expect("ca cert is bad") +} + +fn load_test_cert() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/server.cert.pem").as_bytes()) + .next() + .expect("no cert") + .expect("cert is bad") +} + +fn load_test_ca() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/ca.cert.pem").as_bytes()) + .next() + .expect("no ca cert") + .expect("ca cert is bad") +} + +fn load_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { + rustls_pemfile::private_key(&mut include_str!("../../../tests/certs/server.key.pem").as_bytes()) + .expect("no server key") + .expect("server key is bad") +} + +fn load_test_crls() -> Vec> { + rustls_pemfile::crls(&mut include_str!("../../../tests/certs/ca.crl.pem").as_bytes()) + .collect::, _>>() + .unwrap() +} + +fn tls_server_parameters( + alpn: TlsAlpn, + client_cert_verify: TlsClientCertVerify, +) -> TlsServerParameterProvider { + TlsServerParameterProvider::new(TlsServerParameters { + server_certificate: TlsKey::new(load_test_key(), load_test_cert()), + client_cert_verify, + min_protocol_version: None, + max_protocol_version: None, + alpn, + }) +} + +async fn spawn_tls_server( + expected_hostname: Option<&str>, + server_alpn: TlsAlpn, + expected_alpn: Option<&str>, + client_cert_verify: TlsClientCertVerify, +) -> Result< + ( + ResolvedTarget, + tokio::task::JoinHandle>, + ), + ConnectionError, +> { + let mut acceptor = Acceptor::new_tcp_tls( + SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0), + tls_server_parameters(server_alpn, client_cert_verify), + ) + .bind_explicit::() + .await?; + let addr = acceptor.local_address()?; + + let expected_alpn = expected_alpn.map(|alpn| alpn.as_bytes().to_vec()); + let expected_hostname = expected_hostname.map(|sni| sni.to_string()); + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap()?; + let handshake = connection + .handshake() + .unwrap_or_else(|| panic!("handshake was not available on {connection:?}")); + assert_eq!( + handshake.alpn.as_ref().map(|b| b.as_ref().to_vec()), + expected_alpn + ); + assert_eq!(handshake.sni.as_deref(), expected_hostname.as_deref()); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + connection.shutdown().await?; + Ok::<_, ConnectionError>(()) + }); + Ok((addr, accept_task)) +} + +macro_rules! tls_test ( + ( + $( + $(#[ $attr:meta ])* + async fn $name:ident() -> Result<(), ConnectionError> $body:block + )* + ) => { + mod rustls { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod rustls_server { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod openssl { + use super::*; + + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod openssl_server { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + } +); + +tls_test! { + /// The certificate is not valid for 127.0.0.1, so the connection should fail. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_fails() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidIssuer)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// The certificate is not valid for 127.0.0.1, so the connection should fail. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_fails_name() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidCertificateForName)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// The certificate is valid for "localhost", so the connection should succeed. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_ok() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("localhost"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_tcp_tls( + ("localhost", addr.tcp().unwrap().port()), + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await?; + stm.write_all(b"Hello, world!").await?; + stm.shutdown().await?; + Ok::<_, ConnectionError>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_insecure() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_crl() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("localhost"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_tcp_tls( + ("localhost", addr.tcp().unwrap().port()), + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + crl: load_test_crls(), + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::CertificateRevoked)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// Test that we can override the SNI. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_sni_override() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("www.google.com"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + sni_override: Some(Cow::Borrowed("www.google.com")), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// Test that we can set the ALPN. + #[tokio::test] + async fn test_target_tcp_tls_alpn() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + None, + TlsAlpn::new_str(&["nope", "accepted"]), + Some("accepted"), + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + alpn: TlsAlpn::new_str(&["accepted", "fake"]), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_client_verify_optional() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + None, + TlsAlpn::default(), + None, + TlsClientCertVerify::Optional(vec![load_client_test_ca()]), + ) + .await?; + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + cert: Some(load_client_test_cert()), + key: Some(load_client_test_key()), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + Ok(()) + } +} + +#[cfg(feature = "__manual_tests")] +#[tokio::test] +async fn test_live_server_manual_google_com() { + let target = Target::new_tcp_tls(("www.google.com", 443), TlsParameters::default()); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); + // HTTP/1. ..... + assert_eq!(stm.read_u8().await.unwrap(), b'H'); +} + +/// Normally connecting to Google's IP will send an invalid SNI and fail. +/// This test ensures that we can override the SNI to the correct hostname. +#[cfg(feature = "__manual_tests")] +#[tokio::test] +async fn test_live_server_google_com_override_sni() { + use std::net::ToSocketAddrs; + + let addr = "www.google.com:443" + .to_socket_addrs() + .unwrap() + .into_iter() + .next() + .unwrap(); + let target = Target::new_tcp_tls( + addr, + TlsParameters { + sni_override: Some(Cow::Borrowed("www.google.com")), + ..Default::default() + }, + ); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); + // HTTP/1. ..... + assert_eq!(stm.read_u8().await.unwrap(), b'H'); +} diff --git a/rust/pgrust/Cargo.toml b/rust/pgrust/Cargo.toml index e23839d874e..e65b8413e27 100644 --- a/rust/pgrust/Cargo.toml +++ b/rust/pgrust/Cargo.toml @@ -18,7 +18,7 @@ pyo3.workspace = true tokio.workspace = true tracing.workspace = true db_proto.workspace = true -gel-stream.workspace = true +gel-stream = { workspace = true, features = ["client"] } futures = "0" thiserror = "1" @@ -41,6 +41,7 @@ features = ["full"] [dev-dependencies] tracing-subscriber.workspace = true captive_postgres.workspace = true +gel-stream = { workspace = true, features = ["rustls"] } scopeguard = "1" pretty_assertions = "1.2.0" diff --git a/rust/pgrust/examples/connect.rs b/rust/pgrust/examples/connect.rs index 1a6d05c6796..0b5e9fd881e 100644 --- a/rust/pgrust/examples/connect.rs +++ b/rust/pgrust/examples/connect.rs @@ -4,7 +4,7 @@ use captive_postgres::{ use clap::Parser; use clap_derive::Parser; use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target}; +use gel_stream::{Connector, ResolvedTarget, Target}; use pgrust::{ connection::{ dsn::parse_postgres_dsn_env, Client, Credentials, ExecuteSink, Format, MaxRows, diff --git a/rust/pgrust/src/connection/conn.rs b/rust/pgrust/src/connection/conn.rs index 58c6443d175..0715d439642 100644 --- a/rust/pgrust/src/connection/conn.rs +++ b/rust/pgrust/src/connection/conn.rs @@ -14,7 +14,7 @@ use crate::{ }; use db_proto::StructBuffer; use futures::{future::Either, FutureExt}; -use gel_stream::client::{stream::Stream, Connector}; +use gel_stream::{Connector, Stream}; use std::{ cell::RefCell, future::ready, @@ -52,7 +52,7 @@ pub enum PGConnError { /// /// ``` /// # use pgrust::connection::*; -/// # use gel_stream::client::{Target, Connector}; +/// # use gel_stream::{Target, Connector}; /// # _ = async { /// # let credentials = Credentials::default(); /// # let connector = Connector::new(Target::new_tcp(("localhost", 1234))).unwrap(); diff --git a/rust/pgrust/src/connection/dsn/host.rs b/rust/pgrust/src/connection/dsn/host.rs index e08b28b8510..d290b4bfefe 100644 --- a/rust/pgrust/src/connection/dsn/host.rs +++ b/rust/pgrust/src/connection/dsn/host.rs @@ -1,5 +1,5 @@ use super::ParseError; -use gel_stream::client::{ResolvedTarget, TargetName}; +use gel_stream::{ResolvedTarget, TargetName}; use serde_derive::Serialize; use std::net::{IpAddr, Ipv6Addr}; diff --git a/rust/pgrust/src/connection/mod.rs b/rust/pgrust/src/connection/mod.rs index 8ceb3085dc8..28b4f366f91 100644 --- a/rust/pgrust/src/connection/mod.rs +++ b/rust/pgrust/src/connection/mod.rs @@ -13,7 +13,7 @@ pub use flow::{ CopyDataSink, DataSink, DoneHandling, ExecuteSink, FlowAccumulator, Format, MaxRows, Oid, Param, Pipeline, PipelineBuilder, Portal, QuerySink, Statement, }; -use gel_stream::client::ConnectionError; +use gel_stream::ConnectionError; pub use raw_conn::RawClient; macro_rules! __invalid_state { @@ -89,7 +89,6 @@ pub enum SslError { #[derive(Clone, Default, derive_more::Debug)] pub struct Credentials { pub username: String, - #[debug(skip)] pub password: String, pub database: String, pub server_settings: HashMap, diff --git a/rust/pgrust/src/connection/raw_conn.rs b/rust/pgrust/src/connection/raw_conn.rs index fece126c2b3..688f0dde67a 100644 --- a/rust/pgrust/src/connection/raw_conn.rs +++ b/rust/pgrust/src/connection/raw_conn.rs @@ -10,10 +10,7 @@ use crate::protocol::postgres::{FrontendBuilder, InitialBuilder}; use crate::protocol::{postgres::data::SSLResponse, postgres::meta}; use db_proto::StructBuffer; use gel_auth::AuthType; -use gel_stream::client::{ - stream::{Stream, StreamWithUpgrade, UpgradableStream}, - Connector, -}; +use gel_stream::{ConnectionError, Connector, Stream, StreamUpgrade}; use std::collections::HashMap; use std::pin::Pin; use tokio::io::AsyncWriteExt; @@ -74,16 +71,13 @@ impl ConnectionDriver { } } - async fn drive_bytes( + async fn drive_bytes( &mut self, state: &mut ConnectionState, drive: &[u8], message_buffer: &mut StructBuffer, - stream: &mut UpgradableStream, - ) -> Result<(), PGConnectionError> - where - (B, C): StreamWithUpgrade, - { + stream: &mut S, + ) -> Result<(), PGConnectionError> { message_buffer.push_fallible(drive, |msg| { state.drive(ConnectionDrive::Message(msg), self) })?; @@ -100,7 +94,10 @@ impl ConnectionDriver { } if self.upgrade { self.upgrade = false; - stream.secure_upgrade().await?; + stream + .secure_upgrade() + .await + .map_err(ConnectionError::from)?; state.drive(ConnectionDrive::SslReady, self)?; } else { break; @@ -109,15 +106,12 @@ impl ConnectionDriver { Ok(()) } - async fn drive( + async fn drive( &mut self, state: &mut ConnectionState, drive: ConnectionDrive<'_>, - stream: &mut UpgradableStream, - ) -> Result<(), PGConnectionError> - where - (B, C): StreamWithUpgrade, - { + stream: &mut S, + ) -> Result<(), PGConnectionError> { state.drive(drive, self)?; loop { if !self.send_buffer.is_empty() { @@ -132,7 +126,10 @@ impl ConnectionDriver { } if self.upgrade { self.upgrade = false; - stream.secure_upgrade().await?; + stream + .secure_upgrade() + .await + .map_err(ConnectionError::from)?; state.drive(ConnectionDrive::SslReady, self)?; } else { break; @@ -221,11 +218,11 @@ impl RawClient { } // This should not be possible -- we've fully upgraded the stream by now - let Ok(stream) = stream.into_choice() else { + let Ok(stream) = stream.into_boxed() else { return Err(invalid_state!("Connection was not ready")); }; - Ok(RawClient::new_boxed(stream.into_boxed(), update.params)) + Ok(RawClient::new_boxed(stream, update.params)) } /// Consume the `RawClient` and return the underlying stream and connection parameters. diff --git a/rust/pgrust/src/handshake/edgedb_server.rs b/rust/pgrust/src/handshake/edgedb_server.rs index 6aa2106f8b2..00a4a54fbbe 100644 --- a/rust/pgrust/src/handshake/edgedb_server.rs +++ b/rust/pgrust/src/handshake/edgedb_server.rs @@ -140,8 +140,10 @@ enum ServerStateImpl { Error, } +#[derive(derive_more::Debug, Default)] pub struct ServerState { state: ServerStateImpl, + #[debug(skip)] buffer: StructBuffer, } diff --git a/rust/pgrust/src/handshake/mod.rs b/rust/pgrust/src/handshake/mod.rs index a253e3bbde6..bc3689b5c20 100644 --- a/rust/pgrust/src/handshake/mod.rs +++ b/rust/pgrust/src/handshake/mod.rs @@ -139,7 +139,7 @@ mod tests { username: "user".to_string(), password: "password".to_string(), database: "database".to_string(), - ..Default::default() + server_settings: Default::default(), }, ConnectionSslRequirement::Disable, ); diff --git a/rust/pgrust/src/python.rs b/rust/pgrust/src/python.rs index 0e14393cf78..a31c515fbd4 100644 --- a/rust/pgrust/src/python.rs +++ b/rust/pgrust/src/python.rs @@ -14,7 +14,7 @@ use crate::{ protocol::postgres::{data::SSLResponse, meta, FrontendBuilder, InitialBuilder}, }; use db_proto::StructBuffer; -use gel_stream::client::ResolvedTarget; +use gel_stream::ResolvedTarget; use pyo3::{ buffer::PyBuffer, exceptions::{PyException, PyRuntimeError}, diff --git a/rust/pgrust/tests/query_real_postgres.rs b/rust/pgrust/tests/query_real_postgres.rs index 4f2ba64b39f..22fc622e198 100644 --- a/rust/pgrust/tests/query_real_postgres.rs +++ b/rust/pgrust/tests/query_real_postgres.rs @@ -6,7 +6,7 @@ use std::rc::Rc; // Constants use db_proto::match_message; use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target}; +use gel_stream::{Connector, ResolvedTarget, Target}; use pgrust::connection::{ Client, Credentials, FlowAccumulator, MaxRows, Oid, Param, PipelineBuilder, Portal, Statement, }; diff --git a/rust/pgrust/tests/real_postgres.rs b/rust/pgrust/tests/real_postgres.rs index d0cb92fcf8a..301d97ec390 100644 --- a/rust/pgrust/tests/real_postgres.rs +++ b/rust/pgrust/tests/real_postgres.rs @@ -1,6 +1,6 @@ // Constants use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target, TlsParameters}; +use gel_stream::{Connector, ResolvedTarget, Target, TlsParameters}; use pgrust::connection::{Credentials, PGConnectionError, RawClient}; use pgrust::errors::PgServerError; use pgrust::handshake::ConnectionSslRequirement; diff --git a/tests/certs/ca.cert.pem b/tests/certs/ca.cert.pem index 63e21bcf524..95b20225e32 100644 --- a/tests/certs/ca.cert.pem +++ b/tests/certs/ca.cert.pem @@ -1,40 +1,40 @@ -----BEGIN CERTIFICATE----- -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 -wuuleg3Qo92tkeoX9SqR +CQEWEGhlbGxvQGVkZ2VkYi5jb22CFERoZl6t5a0Aw+udK3fmakODwWozMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAEFPR/3ga+tJenOAlNwykYma +4rz1ryxizrww2TgFKmA7VdPK+NqyoTuK+OhikJ0r2GCk6jEQvru4e7pBxsUoBpTP +d6wv/xNkMnDgS/J9VGziQF3ZarbayyQdLlt+J/kmvxiF9/RUyB0x3f3hfx/yqrRD +b07/0qRgW0pIk/D5Hs+D3FnPpr3i0pg1iauLwnWptagobFEM27eHAuqOmmc8EMUP +hHmwhEI7vQ1NZ7X/+gdVx/CyIiDYBw88/x4aEH/6rVPZU3Ifg5GINGyMyndJ+WtV +21CSFz8SqG+K2pU3k9wjorJcSZr2ChLEi9gyHH4Rk9ADHYxiKg+qb11Mysyx4Qoo +pyfGeJq1qhb2ScJrdTuj2NctQhUVTQoeIWh36zdf6sxRLXcj8M6gQz5joed1/7Y7 +YgOXq3gmI4e9you/F4Vqhdl3ojhstkpW8fWQiXYvWIvOctgjGtZoLP4gZujgGs4h ++fdX5pMmOoSPrriUINo+0W55hhIFIDisUNkxC1PKkjdU4XjckFC9iJeT0VsKLPzK +HMN0LA7BxEjLnV0TG/vXaoaM+rlz11nMTwt7BNSWqhH+6lxwgOSG3Ft7u8svt7x/ +6b706AHItpYRegu+NWzVfrbntZsJSdGSYi8mZwvIjSrA8o/zFpWepINlWph14mxU +bmAtF79u44d/tAoBn/gH -----END CERTIFICATE----- diff --git a/tests/certs/ca.crl.pem b/tests/certs/ca.crl.pem index 5f3b1bac25f..8c956b333ab 100644 --- a/tests/certs/ca.crl.pem +++ b/tests/certs/ca.crl.pem @@ -3,22 +3,22 @@ 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 -----END X509 CRL----- diff --git a/tests/certs/ca.key.pem b/tests/certs/ca.key.pem index 718e4c4fdb4..f49f6fa219f 100644 --- a/tests/certs/ca.key.pem +++ b/tests/certs/ca.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -9SXjVRx6nxQSlO4HYDaa2aw6W0+wdw== +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 +HEQwFKprD1VR7j6l2kChJIMHc5RJxQ== -----END PRIVATE KEY----- diff --git a/tests/certs/client.cert.pem b/tests/certs/client.cert.pem index 14510751712..ee18ce07ccf 100644 --- a/tests/certs/client.cert.pem +++ b/tests/certs/client.cert.pem @@ -1,33 +1,36 @@ -----BEGIN CERTIFICATE----- -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 +vR6+GZsfuWGM8iVlCZPSFrZCngjEZKg= -----END CERTIFICATE----- diff --git a/tests/certs/client.csr.pem b/tests/certs/client.csr.pem index ed38fc1246e..d0ccdd809d4 100644 --- a/tests/certs/client.csr.pem +++ b/tests/certs/client.csr.pem @@ -3,27 +3,27 @@ MIIE4TCCAskCAQAwgZsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh MRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRQwEgYDVQQKDAtFZGdlREIgSW5jLjEV MBMGA1UECwwMRWRnZURCIHRlc3RzMREwDwYDVQQDDAhzc2xfdXNlcjEfMB0GCSqG SIb3DQEJARYQaGVsbG9AZWRnZWRiLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKI4Gq3AsHQ8sWyVk+bKgeYuoN0NdfXaALQNZiSZRYlzeiKadugm -3B5SVPU3ivIM+DzKxWIuZRq082xxflBGQIS3AARfjgUD4oSlq8kqnqZG8Gm6PgsA -pG64Dmr/jeU33U2KCtCHSS7ciCLMz3fBWsilaztdLFH0psDjFVGQTiWm0WDzgZNN -It7mXcvUoyb3/rFXgeE0mg35PqVhSlWyFrT4Vb7j1bK4T+yW4ulfx3TgzkGaRp4+ -NnoHWE1arDfT4XZxiav5t/S110W/UR1xMY0+wdCIu5Gl+JKUpazikEz+kJAC5OGJ -kW2nzMMYJ/MlnZWK84q+hM8QZshCHQdW5z87BFwe2382zOs5Zzj/w7XD2cI7pw+3 -Z3FAL79sx+quZZRJomaJTj/capBxK426oewcA4Ey2wmZa7zLVX8Xs0+vmWhm2/xC -/p+E5reLI/v0y2YIW0KmyBKU5X1Hew9b27jZgoao7dPIb36NNDIh9MhQ/pBU5PE1 -XGz679OnQJDZVNUNhZosZoBeuMTrp+g3n7Cuim0btsf3+SQBRlZftfBHJwTspc6H -GPmPKiLCOMSYzx+fZ1e4bw4X7wfkBf+C8uxt55mD1vtd5bvU41++97VtwkPt/9aA -ySd4cb7V6YJPA250+AvUUD5qkq54Si0+ZVJ4RdhBQdDma/skHuu+xS6tAgMBAAGg -ADANBgkqhkiG9w0BAQsFAAOCAgEAdXiLGvPIm4u2XF8OyCi/2wbwT3Hswg8Z7AG+ -F4z6L3B+mDZNVtk+NQr3eAr9Eg5HsjC81VxSwXQtwjnzinAgpoNqRr70qhKeCjXr -szVHdN40L5J2RA+PeB9qFsUBXymt7qr9Cqb6a3s4sHTy8wMaYOmmkNqfdak674Tl -C7+Z/E9saASlgDDrlLLvzvPgC/y5gIhNYK7LIHI8yOtgd96R5Gs9/hyJ9y05+B9i -rnwok1QBkpy2cGnYoX+4Hn2gRIu6wMWfv5mj/wfn/gGihe8Fi2/89u+XRSZaZivZ -9CQzoLu1bajof8lSDPjORrL/ceiz7nNtKlkBCGtsscGUvuFXSMg7ENIukzGhCFI9 -Yo2ZVNnEjzaaBngVSdufVWkUhS/AfxxWKUDq/tS1zzX76PlZ1Cc847x6s+8+28uu -f9IOxwxVMJqEwtvIpG0ECsBBr+tgYIBaaSyUIHRlagOfeZ23HgJjYxa9Zvuxs+gb -GVheIgz1oZRtYL/MUa9UwptQ666gzcBXLQf5oCKzp73WIPVdp99r3y8P0b2X63Xz -Dhtp5dMfSlitOM7a3/Ddqt/iiSsq2caV5hbSElQsorxypbDv+roL851TRzqfHYSA -dZIgI0aWgVfsXDtByf8R7lfZWgwISsIKAomsSXIFihERKkzxWG1swCIs8WcqLcAM -6wHuhd0= +ADCCAgoCggIBAMUzOWyNYcpd7fCMtrBXA2YI4Uop1A0xfZtAg1Gopcg46WziPtrV +RlVtqyCzUome87CIJ6ggqLblS6SnrpWnw6YsNv3Hc9Zt3OonF6SrMF/ygglxMzXF +6cuoSevQVyWlgQobWd9N0gHzQGj95iF7p3f4+CdCK7R6tThG6rPg/QUlTSOW+ZBO +BjJsbGUMIbNDXm2UBUDqEGqNX+A4WiG3TSlos7uBJnBmDLRRqsuC1MF4FRXnE/Xo +rKsc3CE3k9DVijHQXlkhmAux33I8GtSrQj8yUmDPRwuUMFNlT6lQRj55pObTIz3p +3XvJlG3GB8VMwlW5P/y5GnjDdHKNjWBKKhGvYKUtbtkP3KlRLlbOOTqclwO6oytI +e7voZqKH6bN14vCmlNkUd3kcQGkV2rswtlL/Dmx4c/ZemURHNI8tOMiXtky/aBFt +tAk8EEb4qLGRvY5RK1GA+M3oRuIdwSJOYEkq7D345HJ3xoznCC/JXdfCtULHB08b +36UtDeIdx7WeHM5/xqW3aLavxM3QpsRswfONXeqDeBmXF/JB5br7Ls3TQpPFsELh +BKLBeibuWGBPPVln8RnVZw6I17a9Y9WAXLAYJh1n+fwnMR0qxnmQlptoILeNriCR +syLOtSP+o+5v0S2kxfMys4s3sBMntQawgkFABHn0iymMPwm7p91O85t1AgMBAAGg +ADANBgkqhkiG9w0BAQsFAAOCAgEAXK7EjCpnqgDWCumXkE5fkymVgQ40gtj4OvMz +OVjW+HqNIU9+v12OqENxtPZJLxzU7hsGbUjNY6zuplFnaK86Z8GTMXbvLz2tXtN+ ++BIi6ZGzPrvFub5CLBpxzVBQdDCSDkR8t5D0LRl+N1ep+Ls3FyCOWRe5LF58tbCl +SLImwOFaOLRe3dALB8vvMKi/BP9zZUuxRgNIy4mdMUasr8ma9xkb19/FvOy9BMIJ +ei9g28+xgOJ14uI1zqrKIDpdLcgObYy1DpPatpzgs65JLnVxZH8H3r2DFd7m+XuI +mt0iZr7Cry7aYgdemOCf8jehq+dJkqvefQFUPbelbOZV7yLQS74CQXbLkhmTytP+ +zYqDIU6Gwo65rE59g53Aonqa+gOgGdu9cKfz54Sa4KqtsGZPtsASd4jgp8bcQ5sE +8Reg4fjWETyNVIDf2FHPEL4S3IbLRaRATcPzTvBYxP/CotqnoexXT2Vp6PSwYnVk +Lm1bd41oEhitlrzU7Zx/fOvJuL079Qy+2ixQiusEfRaYNICVHyaC7JieNk6P2G5Y +qyUx4beBOYm+Ux1R4kuyRGI7befJa1QyE0nxFQmJrHzOkrwJ722MMZSkhAyB5wKV +NKVMxMMSFpevo7wDRjlZve5V8R0l2lDc8TGrmRFDCSchvO0yLlnEg7TrdIRXAAuq +MDjdO8g= -----END CERTIFICATE REQUEST----- diff --git a/tests/certs/client.key.pem b/tests/certs/client.key.pem index aa63c1f5237..d6ad1d98b8f 100644 --- a/tests/certs/client.key.pem +++ b/tests/certs/client.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -g1WA14/4g+NcaVuglAM0na4pouro +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDFMzlsjWHKXe3w +jLawVwNmCOFKKdQNMX2bQINRqKXIOOls4j7a1UZVbasgs1KJnvOwiCeoIKi25Uuk +p66Vp8OmLDb9x3PWbdzqJxekqzBf8oIJcTM1xenLqEnr0FclpYEKG1nfTdIB80Bo +/eYhe6d3+PgnQiu0erU4Ruqz4P0FJU0jlvmQTgYybGxlDCGzQ15tlAVA6hBqjV/g +OFoht00paLO7gSZwZgy0UarLgtTBeBUV5xP16KyrHNwhN5PQ1Yox0F5ZIZgLsd9y +PBrUq0I/MlJgz0cLlDBTZU+pUEY+eaTm0yM96d17yZRtxgfFTMJVuT/8uRp4w3Ry +jY1gSioRr2ClLW7ZD9ypUS5Wzjk6nJcDuqMrSHu76Gaih+mzdeLwppTZFHd5HEBp +Fdq7MLZS/w5seHP2XplERzSPLTjIl7ZMv2gRbbQJPBBG+Kixkb2OUStRgPjN6Ebi +HcEiTmBJKuw9+ORyd8aM5wgvyV3XwrVCxwdPG9+lLQ3iHce1nhzOf8alt2i2r8TN +0KbEbMHzjV3qg3gZlxfyQeW6+y7N00KTxbBC4QSiwXom7lhgTz1ZZ/EZ1WcOiNe2 +vWPVgFywGCYdZ/n8JzEdKsZ5kJabaCC3ja4gkbMizrUj/qPub9EtpMXzMrOLN7AT +J7UGsIJBQAR59IspjD8Ju6fdTvObdQIDAQABAoICAAaWkwUO5iT6JWBjexkCFzF5 ++3jcU+LK8/zTV2/LeBpr2FSUbHAoLuzcuJpjk07YuiB8NAL4cFqH55KNLZZ/X9h1 +4rJwzuxriDVkb/RG6dtSwUhqeUEDJy/wI+QWdkriMCDzz/lXYrxA8bZwQRd+R5aJ +AVVibw5dCR/jsqSm0B0zZVPaj+Tjzm4x1B8+HAQerJFxoAlOqJS+u2TEzTISKyhG +gLazdmLL7gG6NsAM02nRRrcQHMka6GXhFXOgpTYVZEQMx5InvqopW6M34deYDyMI +XdsxIZj/7utiV5p6/ZXJv5oclLFVVlpz3hsawhiz20w836fkUT+WnBXVp9L/N0+H +7J/MmbbDgsLIMpPUMC45kEYfFuYjZYvcnhxHfnfG7IQm1HGOq5pAVUiZ022JD9Y8 +VvYJLOUQJEce320ZaJrBnzcH7ApxcrcJdcwargGqPl1QVNWcjqb0tzQgtVvgRpC9 +aynqifAWIx7UHVfECZw33k5kZOz62PgJ1OjYw2QXYiJO7ROICOnJR3YxYNtYyV39 +O01kuVtVYZ680J6VacIYVRe88DoV7BBacoHFaNIeE4eBKvO7RGcG+IdkRSviEZpF +Jzh9m8q8qTt0lUf9pExH8RdmSfTYW2bnoj2GZrMT4XwiPsjELb6Klz3CI51LTcwq +ZUlqx5ehq2KiKl3Y3pHjAoIBAQDn/BfHcadRPS4Yua1y7iSmHFV1O5VGS+lAWH2l +RhsAakuk7MfeyRAe5/t6t9N+oO4L6JTIE5oNHdKOxaL8fpzb58R/6OJI/BSISJq5 +yN7qPvBDDfQVygdITjtNSskq+1FQMMx1lmKhjOyx+DAI6MwDW8YqdkFyfMy2GcZD +Yr/11m26zLF3KCKrYD3Vq08nHhDc0jAXXw+xYf/+iGOvWk26MW59UJp4smJ4PUL8 +S+KNsFQrd7nU+jWGtcXaPCql6qk35nG4rNy3uBnLNSuKA7oPOffN2dvPpKTg8NgU +/kXu+LUdU5aHFXdPGl8mKnOKD+JJd4FDF1tcUwokn2ug/yk3AoIBAQDZnUqrFpUL +Fj1Qu78wnaSFLqj3l0NtYeTCmYbae+1qRV2V1/W4Q5yASypOBey5du5A76n05o8O +2v88jJ++LbqG5y9QJlbl6cQox4xjG2mhHnFPR/1SXU8leikiQCUmndlIAbuPIY76 ++QfUsvGAVxWDTrMS2quXRO1MzzL7v2pfHTL80enU+6x9YLUQMp5pZKg3nV5m3ZPH +UQdu/jyxVipiPOywYSzNyrTqBYChXLJEE6V0Ty2VMT3eOydWfaU2hd0p2ht7WuEQ +L2W53Kb0H/SNh/GwWpiN4XJKd/yQlcJkXitGgZ5xcp2aY7ydHtbbfT+MCmRP0ljT +YFvG2pv6QYazAoIBAQDmx/4r9l/aTL/H7yejF1A0RCmr56t39FrGHYJZYeXIwvYf +y0KG2oUECgo+qhNnfNdz11vzsrRlag6m4+xhvd90URxFlztOGiCe94OdYTyJ0jUY +sA/rgUE/aDxMhyKbdMsOuI0eSY4zYsuxvNKkeltC2BDK+zvellLcscVwEhQfj8M3 +uxytCqt6y9KX9sVWh+2EkEExbutgrrqJz8tDjdWXbkeZuQ8DFYsqTN+PuDpYdFs3 +pvKi8os/SSPcGFDhIBJZvxHRA37L8gUPCAUZVt3I+gUQrzOiXQt9j3uXXuHZe2hK +FXbBSdSYSAbyI/cvGOAn8BAS23CS5zVG+6WJ021/AoIBAQC3ZL6rpvFekZSE+GSt +FP20m9kcJ6dUhH6knXwvnuc7e0/eW00iyCAZYr85V/bjal5p7VCfKrr/ewJFRgHN +5X3f+O8/rb/oLPT6pQkj8NM5TI2TkgjkI+zymZwW2FY20Cpwa71kZ5S2366Ay3mJ +flqL+YQi7JRVfGo8JBZEYVHE7Leupz1YF+2LEDgneXFVQtYdYItRR4UmIZyRJsOB +dCtt9QhHsO1wVVfYLWD1HEjD5Ia4mY3BwOjx44pIcsUMSQ5VGhG1CKbJ3Bfv5gvx +iwivShUeWYtdbtTB+5KnSv6zVUVFOzGLTFuT5F/tTjMmcMxgOdXGC3B+WyOdV1jC +M/zPAoIBAGsuz6FfKGBGL8C8B6vcfjWCsEtzT0l7HzYIhAiSqoacIWuXwlSlvM/Q +GiCd1A09QXNH78KVwmnz0s87qz4D3jV4udhM1TuR7WSZEnw0pUlbV69LV3S/1enF +h3WW2yX/6pA+BHB9YlJc+2Ef1D6skl3NsKQieLcRoqKwAniGK78cTZe66H0tMNIW +9VcGQFJmJkejgxez5MJpXBZJh2lEXjKe3iz1n5g+NL3M/pzzFuqX8YXpUDA07XxZ +rD1+sICtSKUHXJYFxZ7XORP1sEH1dGiWdX1ZzO/mKuj0rAASCm39I6aJg5FfLVT8 +TRkcU50kVlx/0XcGTR0F9Cp2fhO8NHo= -----END PRIVATE KEY----- diff --git a/tests/certs/client.key.protected.pem b/tests/certs/client.key.protected.pem index e2b882cc99b..4fffb1fd88a 100644 --- a/tests/certs/client.key.protected.pem +++ b/tests/certs/client.key.protected.pem @@ -1,54 +1,54 @@ -----BEGIN ENCRYPTED PRIVATE KEY----- -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 -----END ENCRYPTED PRIVATE KEY----- diff --git a/tests/certs/client_ca.cert.pem b/tests/certs/client_ca.cert.pem index becca16bea7..1278c0ec1b0 100644 --- a/tests/certs/client_ca.cert.pem +++ b/tests/certs/client_ca.cert.pem @@ -1,36 +1,36 @@ -----BEGIN CERTIFICATE----- -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 -z1r76p+mCg== +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKybpkWhPpMncwyrbUmPWyjYh0v42XS+ ++Mr+G45OAzt6H+FCnOKLTaHV3dOAAztmYcc/XjBJ51Tv/bRqn8ou2xhCAX5eky2i +8xBq04dYLz1iatT2Gvla0JpxozNxKEQhGN/AaC6BsGomSf05sjgrTI/b5tEZxzv3 +iqdyewPq9bYPiEjU7r7lQBOGUfmItpUQq1NQXhBO6ezovFAZ52iPxfyIdatl9CWY +bZWc/VgEIc3ojjsfspeXvkbDawQlIkJgBFD+O5BPDltF5bZG0MLcSU1fnWpwFlf5 +Cqf+H7F7dk001zD90Uq1evBFmYbQMD2IIeDP05kK5aeWcRX9ibbEydUaRKh6L1Ag +JrfmBoneoMcjxbdiK43b8lsPnkEeuvCwu5VN0upHLGJW7Fy60assL0hCvSMbmKTJ +qIHQd+sINifXq2vAjVZdUJompHrnypJxIrxdl+sTSYP/veZwvxuLdTUXQceiofEc +aR/y7OcLOIgywQkbqkrO/Cx1fcoPopr++dAEWQ2VhoSPuoC9f54dxgeMXj1/Kmxy +u4z89Xz6HfWqNDYbAEwSaWFOOWewUVfnsJ7gcptE2Arn+NlllGQN10DKdwHKUiKG +YfBhd3tdMlMkkNtowUGHhny32eoEnQv3Xqrd4rqe8cE58bKacM+OhhPkfWA2UT9w +bYA2mUVcg+izAgMBAAGjUzBRMB0GA1UdDgQWBBQyJOoeR8Y5TkgQ9vmRjskM3yS1 +qTAfBgNVHSMEGDAWgBQyJOoeR8Y5TkgQ9vmRjskM3yS1qTAPBgNVHRMBAf8EBTAD +AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAmq6ca42dFmuRrIzMTKQgAAD70QC1dgGAh +N8miJlbTfzsqXKtiMezZCQmeBJHVb3ljYtf3HkddqxQG8YGHOYTbxjvpoMhUbQe7 +/r2iBtYtMcempJPpflT3GqNPZcESMQKJP7Cq8uZjSbHAE3kgXxH6/89J9DP2V0mF +fOs3pnenvsEQPnPub/QZ4XGRtUJH1+0ALlBfvULiG8Sm3pMS0wvOeNB7GkXwUl1V +ZvEhCTJUX1lrgYVmw/wnypAffABIXl1PIeXP2GVxANPjFhFgoSKJI1iAvMoCeCAQ +JLuH7Vxk1nA9BaQavwvWJdDlfdtDMTrMegM9U2dSHeqw1Ai8lyxsINnCRtmLSRui +7DztPojiUanBJSPNJPzcAjJvFJRJ/xafHL3uhK31cMo15yUskxPPJvSfVzDvRGBX +GQjN7BIcFVx9CZYwjlVkXjGXCbUs+LAo5ecN6MmQ/BU4AKJ8GHcH2VBQ34W7H1TU +ZlnQxlzus+eMlhAjkoEKQn7SLjHdZT0SqYBPKXDymj2/VtvTqJgwcrf2E0pKBDh3 +TlmL+OuSLjwmhoQo2YASw0wb1NKJuALvYUfULl7en+WQPpfYvcHdShqWe8cid3T9 +BSksp7qKiKm67n4okeOqhUJu68yJ1ffdAnZCoy8DQmTouIWSAf2/5Z4En9rfT8+a +nuI9Lyjq7Q== -----END CERTIFICATE----- diff --git a/tests/certs/client_ca.cert.srl b/tests/certs/client_ca.cert.srl index 5e2fab31bcb..58dc4271789 100644 --- a/tests/certs/client_ca.cert.srl +++ b/tests/certs/client_ca.cert.srl @@ -1 +1 @@ -3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3ABD +3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3ABE diff --git a/tests/certs/client_ca.key.pem b/tests/certs/client_ca.key.pem index ad3a15a3d2f..864e7f15cfb 100644 --- a/tests/certs/client_ca.key.pem +++ b/tests/certs/client_ca.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -JMzZVaMH/iiG4xZmm1vh3roPi8Sq +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 +grZhpKVB22PtQI9T68oHoj4yU7BC -----END PRIVATE KEY----- diff --git a/tests/certs/gen.sh b/tests/certs/gen.sh index ed53e24218a..1ee040f624c 100755 --- a/tests/certs/gen.sh +++ b/tests/certs/gen.sh @@ -35,7 +35,7 @@ openssl req -new -x509 -key client_ca.key.pem -out client_ca.cert.pem -days 7300 # Client cert openssl genrsa -out client.key.pem 4096 openssl req -new -key client.key.pem -out client.csr.pem -subj "/C=US/ST=California/L=San Francisco/O=EdgeDB Inc./OU=EdgeDB tests/CN=ssl_user/emailAddress=hello@edgedb.com" -batch -openssl x509 -req -in client.csr.pem -CA client_ca.cert.pem -CAkey client_ca.key.pem -CAcreateserial -out client.cert.pem -days 7300 +openssl x509 -req -in client.csr.pem -CA client_ca.cert.pem -CAkey client_ca.key.pem -CAcreateserial -out client.cert.pem -days 7300 -extensions v3_req -extfile ca.conf # Password protected client key openssl rsa -aes256 -in client.key.pem -out client.key.protected.pem -passout pass:secret1234 diff --git a/tests/certs/server.cert.pem b/tests/certs/server.cert.pem index 970908a810c..8f7361e4d50 100644 --- a/tests/certs/server.cert.pem +++ b/tests/certs/server.cert.pem @@ -1,36 +1,36 @@ -----BEGIN CERTIFICATE----- -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 -m+hGEYaP23LwDLBwv9//+jNASPYLfA== +c3QwHQYDVR0OBBYEFJfIRd55lBPNoJqNtVl+a7OOsIOvMB8GA1UdIwQYMBaAFBRx +NC1cmmAeggflm7LlZqIIZSTKMA0GCSqGSIb3DQEBCwUAA4ICAQBYe/i6zkxTwJXH +Zhv+0kAgdUIBiTKBImzwPwnwShbKbWNLloKtZ6aF+Spy1uO0w/NnCZ5S8M/E7HZr +ELnLJR+tU//sfmDb/y0UGNyJptj2z78R8k7yZCqA2MpA+t8nf9TT9cYu2wmCORt+ +jNZ0qYiRD4JichkVprkswF8gzZkhy8tM8TzO1HJu5TTZKQqcT4O1BCh9LkSgkhFD +OYqVqwdq/bo8tCnJzICl6ZdRObKUkQ3MrEyGde68suvG5mlfxylgknF9BUDvQKPA +eQISbIy+KuUSgD5q8f12qL6O1gPbnydYaFdS3aY8nTkfZCKUFcqBroyO57vK9rr3 +WdUZoT3eU011JrAXG7w8MBaoghTHor8mx3tjsNmnnJztngvm2nE2f34q261SA/uT +jfp1avecmzRFudUtT4NaAHw2aa6KqTZ4y/nHfoFozJxMtYVyuFGsIeToAAtZIpdb +zp8cDL7kW6MTIwFy7d8RAI+msDB5dUgT45iJUseAGklvnn/kibLzsbgfkeZXLxTg +l7oPm8ybtrM0RU/s3Pkknq5zoYp4PTQukcWWKO6rKBnu4UHDaF7ATtj9/7mQ/7rK +Muqt+iFhb3RMD7lj0ihZokvGZSe1AQxyS48llbLZoXOts20giTZGwVkvR125jF70 +bLtP4MYoBxHJxYGo4r0S6pYJ/nnTEA== -----END CERTIFICATE----- diff --git a/tests/certs/server.key.pem b/tests/certs/server.key.pem index 65bf666b930..c9a8a6abef2 100644 --- a/tests/certs/server.key.pem +++ b/tests/certs/server.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -VOSY1MQIxTgVpg1s9emO9LzO+FedN5k= +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 +OVaGdduWlABHp+A2Q9+iJdYrF5iN -----END PRIVATE KEY----- From 0676b5e3b58ff9d9ae72bdcc6edb731122e95f74 Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Fri, 31 Jan 2025 12:58:43 -0800 Subject: [PATCH 2/7] Make sure config spec-dependent functions are regened when grafting testmode (#8283) When adding remapping machinery in #8275 I forgot that `_testmode` config gets grafted onto bootstrap cache shipped in production builds. Rectify that. --- edb/pgsql/metaschema.py | 20 ++++++++++++++++++++ edb/server/bootstrap.py | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/edb/pgsql/metaschema.py b/edb/pgsql/metaschema.py index 0a696b43072..3152f6a1da8 100644 --- a/edb/pgsql/metaschema.py +++ b/edb/pgsql/metaschema.py @@ -8239,6 +8239,26 @@ async def generate_support_functions( return trampoline_functions(cmds) +async def regenerate_config_support_functions( + conn: PGConnection, + config_spec: edbconfig.Spec, +) -> None: + # Regenerate functions dependent on config spec. + commands = dbops.CommandGroup() + + funcs = [ + ApplySessionConfigFunction(config_spec), + PostgresJsonConfigValueToFrontendConfigValueFunction(config_spec), + ] + + cmds = [dbops.CreateFunction(func, or_replace=True) for func in funcs] + commands.add_commands(cmds) + + block = dbops.PLTopBlock() + commands.generate(block) + await _execute_block(conn, block) + + async def generate_more_support_functions( conn: PGConnection, compiler: edbcompiler.Compiler, diff --git a/edb/server/bootstrap.py b/edb/server/bootstrap.py index e7a526de6f4..7e33d70c66d 100644 --- a/edb/server/bootstrap.py +++ b/edb/server/bootstrap.py @@ -1781,8 +1781,10 @@ async def _init_stdlib( await conn.sql_execute(testmode_sql.encode("utf-8")) trampolines.extend(new_trampolines) # _testmode includes extra config settings, so make sure - # those are picked up. + # those are picked up... config_spec = config.load_spec_from_schema(stdlib.stdschema) + # ...and that config functions dependent on it are regenerated + await metaschema.regenerate_config_support_functions(conn, config_spec) logger.info('Finalizing database setup...') From a8c5ae09d59d79e4fd6edd31e51715bb60375d05 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Sat, 1 Feb 2025 08:50:14 -0800 Subject: [PATCH 3/7] Don't try to use a fixed port in test_server_config_default (#8272) We had a flake regarding this. (At least on my machine?), linux never randomly assigns an even numbered port, so probably the flake collided with something external specifically looking for it? The find_available_port mechanism is fundamentally racy, of course; the port could be allocated by someone else immediately, and in testing I did manage to observe cycle lengths as short as 2 before a reuse. Possibly these tests should just have a big hammer `@retry_failed_test(3)` decorator around them or something, but I am reluctant to introduce this because I fear we will use it instead of writing proper tests. (Most tests don't have as good an excuse for flakiness as needing to allocate a shared resource in a 16-bit namespace). --- edb/testbase/server.py | 21 ++++----------------- tests/test_server_config.py | 4 ++-- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/edb/testbase/server.py b/edb/testbase/server.py index c563684a284..354ca9abc99 100644 --- a/edb/testbase/server.py +++ b/edb/testbase/server.py @@ -3002,23 +3002,10 @@ def get_cases_by_shard(cases, selected_shard, total_shards, verbosity, stats): return _merge_results(cases) -def find_available_port(max_value=None) -> int: - if max_value is None: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(("localhost", 0)) - return sock.getsockname()[1] - elif max_value > 1024: - port = max_value - while port > 1024: - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(("localhost", port)) - return port - except IOError: - port -= 1 - raise RuntimeError("cannot find an available port") - else: - raise ValueError("max_value must be greater than 1024") +def find_available_port() -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(("localhost", 0)) + return sock.getsockname()[1] def _needs_factoring(weakly): diff --git a/tests/test_server_config.py b/tests/test_server_config.py index f59660f8fb9..96558d9016f 100644 --- a/tests/test_server_config.py +++ b/tests/test_server_config.py @@ -2366,7 +2366,7 @@ async def test_server_config_env_03(self): "cannot use CONFIGURE INSTANCE in multi-tenant mode", ) async def test_server_config_default(self): - p1 = tb.find_available_port(max_value=50000) + p1 = tb.find_available_port() async with tb.start_edgedb_server( extra_args=["--port", str(p1)] ) as sd: @@ -2378,7 +2378,7 @@ async def test_server_config_default(self): """), p1, ) - p2 = tb.find_available_port(p1 - 1) + p2 = tb.find_available_port() await conn.execute(f"""\ configure instance set listen_port := {p2} """) From e4a6db4650bd2ef29d47aacc0928fdee7a113da8 Mon Sep 17 00:00:00 2001 From: dnwpark Date: Tue, 4 Feb 2025 10:04:53 -0500 Subject: [PATCH 4/7] Fix inline functions substituting parameters from hidden nodes. (#8288) A function body may be a statement which contains references to a parent statement. Ensure that this parent's parameters are not substituted while inlining the function parameters. --- edb/common/ast/transformer.py | 12 +++++++++ edb/edgeql/compiler/func.py | 4 +++ tests/test_edgeql_functions_inline.py | 39 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/edb/common/ast/transformer.py b/edb/common/ast/transformer.py index 30d11671c79..c3e893d5beb 100644 --- a/edb/common/ast/transformer.py +++ b/edb/common/ast/transformer.py @@ -64,6 +64,12 @@ def generic_visit(self, node): changes = {} for field, old_value in base.iter_fields(node, include_meta=False): + field_spec = node._fields[field] + if self.skip_hidden and field_spec.hidden: + continue + if field in self.extra_skips: + continue + old_value = getattr(node, field, None) if typeutils.is_container(old_value): @@ -79,6 +85,12 @@ def generic_visit(self, node): else: for field, old_value in base.iter_fields(node, include_meta=False): + field_spec = node._fields[field] + if self.skip_hidden and field_spec.hidden: + continue + if field in self.extra_skips: + continue + old_value = getattr(node, field, None) if typeutils.is_container(old_value): diff --git a/edb/edgeql/compiler/func.py b/edb/edgeql/compiler/func.py index 736220333a2..19f46345346 100644 --- a/edb/edgeql/compiler/func.py +++ b/edb/edgeql/compiler/func.py @@ -479,6 +479,10 @@ def compile_FunctionCall( class ArgumentInliner(ast.NodeTransformer): + # Don't look through hidden nodes, they may contain references to nodes + # which should not be modified. For example, irast.Stmt.parent_stmt. + skip_hidden = True + mapped_args: dict[irast.PathId, irast.PathId] inlined_arg_keys: list[int | str] diff --git a/tests/test_edgeql_functions_inline.py b/tests/test_edgeql_functions_inline.py index 14f0bf13241..9487ca4a87f 100644 --- a/tests/test_edgeql_functions_inline.py +++ b/tests/test_edgeql_functions_inline.py @@ -3133,6 +3133,45 @@ async def test_edgeql_functions_inline_nested_basic_20(self): sort=True, ) + async def test_edgeql_functions_inline_nested_basic_21(self): + # Inner function body is a statement with a parent statement + # + # A function body may be a statement which contains references to a + # parent statement. Ensure that this parent's parameters are not + # substituted while inlining the function parameters. + # + # In this case the outer function's `for` contains the parameter `x` + # which is at risk of being substituted when the inner function + # inlines its parameters. + await self.con.execute(''' + create function inner(x: int64) -> int64 { + set is_inlined := true; + using (select x) + }; + create function foo(x: int64) -> set of int64 { + set is_inlined := true; + using (for y in {x, x + 1, x + 2} union (inner(y))); + }; + ''') + await self.assert_query_result( + 'select foo({})', + [], + ) + await self.assert_query_result( + 'select foo(10)', + [10, 11, 12], + ) + await self.assert_query_result( + 'select foo({10, 20, 30})', + [10, 11, 12, 20, 21, 22, 30, 31, 32], + sort=True, + ) + await self.assert_query_result( + 'for x in {10, 20, 30} union (select foo(x))', + [10, 11, 12, 20, 21, 22, 30, 31, 32], + sort=True, + ) + async def test_edgeql_functions_inline_nested_array_01(self): # Return array from inner function await self.con.execute(''' From 7945efe6297baca239c12f56f740f17be1a78f73 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Tue, 4 Feb 2025 10:12:49 -0800 Subject: [PATCH 5/7] Fix broken error messages for type mismatches in a number of schema objects (#8294) Currently, for triggers, access policies, and function argument defaults, if the inferred type is something that doesn't appear in the schema (like a tuple), we a "cannot get item data" error. Fix that by using the schemas generated while compiling the expressions. Fixes #8291. --- edb/schema/functions.py | 7 +++++-- edb/schema/policies.py | 2 +- edb/schema/triggers.py | 4 ++-- tests/test_edgeql_ddl.py | 22 +++++++++++++++++++++- tests/test_edgeql_triggers.py | 16 +++++++++++++++- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/edb/schema/functions.py b/edb/schema/functions.py index b17fb4b95e3..5bcfadc5bdd 100644 --- a/edb/schema/functions.py +++ b/edb/schema/functions.py @@ -1940,13 +1940,16 @@ def _create_begin( if check_default_type: default_type = ir_default.stype - if not default_type.assignment_castable_to(p_type, schema): + if not default_type.assignment_castable_to( + p_type, ir_default.schema + ): raise errors.InvalidFunctionDefinitionError( f'cannot create the `{signature}` function: ' f'invalid declaration of parameter ' f'{p.get_displayname(schema)!r}: ' f'unexpected type of the default expression: ' - f'{default_type.get_displayname(schema)}, expected ' + f'{default_type.get_displayname(ir_default.schema)}, ' + f'expected ' f'{p_type.get_displayname(schema)}', span=self.span) diff --git a/edb/schema/policies.py b/edb/schema/policies.py index 8a38190c40a..797d70c3923 100644 --- a/edb/schema/policies.py +++ b/edb/schema/policies.py @@ -188,7 +188,7 @@ def canonicalize_attributes( span = self.get_attribute_span(field) raise errors.SchemaDefinitionError( f'{vname} expression for {pol_name} is of invalid type: ' - f'{expr_type.get_displayname(schema)}, ' + f'{expr_type.get_displayname(expression.irast.schema)}, ' f'expected {target.get_displayname(schema)}', span=self.span, ) diff --git a/edb/schema/triggers.py b/edb/schema/triggers.py index 496bc5155df..77803ed995e 100644 --- a/edb/schema/triggers.py +++ b/edb/schema/triggers.py @@ -153,8 +153,8 @@ def canonicalize_attributes( raise errors.SchemaDefinitionError( f'{vname} expression for {trig_name} is of invalid ' f'type: ' - f'{expr_type.get_displayname(schema)}, ' - f'expected {target.get_displayname(schema)}', + f'{expr_type.get_displayname(expression.irast.schema)}' + f', expected {target.get_displayname(schema)}', span=span, ) diff --git a/tests/test_edgeql_ddl.py b/tests/test_edgeql_ddl.py index 3d569848ceb..c2565c2e357 100644 --- a/tests/test_edgeql_ddl.py +++ b/tests/test_edgeql_ddl.py @@ -4294,7 +4294,7 @@ async def test_edgeql_ddl_function_07(self): """) async def test_edgeql_ddl_function_08(self): - with self.assertRaisesRegex( + async with self.assertRaisesRegexTx( edgedb.InvalidFunctionDefinitionError, r'invalid declaration.*unexpected type of the default'): @@ -4303,6 +4303,15 @@ async def test_edgeql_ddl_function_08(self): USING EdgeQL $$ SELECT "1" $$; """) + async with self.assertRaisesRegexTx( + edgedb.InvalidFunctionDefinitionError, + r'invalid declaration.*unexpected type of the default'): + + await self.con.execute(""" + CREATE FUNCTION ddlf_08(s: std::str = ()) -> std::str + USING EdgeQL $$ SELECT "1" $$; + """) + async def test_edgeql_ddl_function_09(self): await self.con.execute(""" CREATE FUNCTION ddlf_09( @@ -6865,6 +6874,17 @@ async def test_edgeql_ddl_policies_02(self): }; """) + async with self.assertRaisesRegexTx( + edgedb.SchemaDefinitionError, + r"using expression.* is of invalid type", + ): + await self.con.execute(""" + create type X { + create access policy test + allow all using (()); + }; + """) + async with self.assertRaisesRegexTx( edgedb.SchemaDefinitionError, r"possibly an empty set returned", diff --git a/tests/test_edgeql_triggers.py b/tests/test_edgeql_triggers.py index e0d52826909..b5bfcd65fbf 100644 --- a/tests/test_edgeql_triggers.py +++ b/tests/test_edgeql_triggers.py @@ -1372,7 +1372,7 @@ async def test_edgeql_triggers_when_04(self): ['c'], ) - async def test_edgeql_triggers_when_bad(self): + async def test_edgeql_triggers_when_bad_01(self): async with self.assertRaisesRegexTx( edgedb.SchemaDefinitionError, r"data-modifying statements are not allowed"): @@ -1386,6 +1386,20 @@ async def test_edgeql_triggers_when_bad(self): }; ''') + async def test_edgeql_triggers_when_bad_02(self): + async with self.assertRaisesRegexTx( + edgedb.SchemaDefinitionError, + r"when expression.*is of invalid type"): + await self.con.query(''' + alter type InsertTest { + create trigger log_new after insert, update for each + when (()) + do ( + insert Note { name := "new", note := __new__.name } + ); + }; + ''') + async def test_edgeql_triggers_cached_global_01(self): # Install FOR ALL triggers for everything await self.con.execute(''' From a52ad34be3073da255535e2e160e7be93bc06ab7 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Tue, 4 Feb 2025 13:28:10 -0500 Subject: [PATCH 6/7] Add `pg_show_all_settings` to allowed pg functions (#8298) This is used by pgAdmin4 as of 8.12 and replaces their usage of the table `pg_catalog.pg_settings` with `pg_catalog.pg_show_all_settings()`. Closes #8297 See https://github.com/pgadmin-org/pgadmin4/pull/7870 --- edb/pgsql/resolver/static.py | 1 + tests/test_sql_query.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/edb/pgsql/resolver/static.py b/edb/pgsql/resolver/static.py index 88f40fedfab..b4d3b0d2885 100644 --- a/edb/pgsql/resolver/static.py +++ b/edb/pgsql/resolver/static.py @@ -226,6 +226,7 @@ def eval_TypeCast( 'pg_last_wal_replay_lsn', 'pg_current_wal_flush_lsn', 'pg_relation_is_publishable', + 'pg_show_all_settings', } ) diff --git a/tests/test_sql_query.py b/tests/test_sql_query.py index 1c16454d580..837b4cd1644 100644 --- a/tests/test_sql_query.py +++ b/tests/test_sql_query.py @@ -1968,7 +1968,8 @@ async def test_sql_query_pgadmin_hack(self): await self.scon.execute("SET DateStyle=ISO;") await self.scon.execute("SET client_min_messages=notice;") await self.scon.execute( - "SELECT set_config('bytea_output','hex',false) FROM pg_settings" + "SELECT set_config('bytea_output','hex',false)" + " FROM pg_catalog.pg_show_all_settings()" " WHERE name = 'bytea_output'; " ) await self.scon.execute("SET client_encoding='WIN874';") From 79d6c8662f99b831cfb47d3155127a4e1c6ee82f Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Tue, 4 Feb 2025 11:04:02 -0800 Subject: [PATCH 7/7] Mark the assert_* functions as being Immutable (#8292) This seems basically semantically correct to me. The motivation is that we use `assert_exists({})` as a dummy expression when making schema changes that affect schema expressions, and currently it is possible to get errors due to that expression being `Stable`. --- edb/buildmeta.py | 2 +- edb/lib/std/20-genericfuncs.edgeql | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/edb/buildmeta.py b/edb/buildmeta.py index 6b8f53ab59c..ff4bbf45d6f 100644 --- a/edb/buildmeta.py +++ b/edb/buildmeta.py @@ -60,7 +60,7 @@ # The merge conflict there is a nice reminder that you probably need # to write a patch in edb/pgsql/patches.py, and then you should preserve # the old value. -EDGEDB_CATALOG_VERSION = 2024_01_28_00_00 +EDGEDB_CATALOG_VERSION = 2024_02_03_00_00 EDGEDB_MAJOR_VERSION = 7 diff --git a/edb/lib/std/20-genericfuncs.edgeql b/edb/lib/std/20-genericfuncs.edgeql index 0712796b2f0..bb395dec3fc 100644 --- a/edb/lib/std/20-genericfuncs.edgeql +++ b/edb/lib/std/20-genericfuncs.edgeql @@ -31,7 +31,7 @@ std::assert_single( CREATE ANNOTATION std::description := "Check that the input set contains at most one element, raise CardinalityViolationError otherwise."; - SET volatility := 'Stable'; + SET volatility := 'Immutable'; SET preserves_optionality := true; USING SQL EXPRESSION; }; @@ -49,7 +49,7 @@ std::assert_exists( CREATE ANNOTATION std::description := "Check that the input set contains at least one element, raise CardinalityViolationError otherwise."; - SET volatility := 'Stable'; + SET volatility := 'Immutable'; SET preserves_upper_cardinality := true; USING SQL EXPRESSION; }; @@ -67,7 +67,7 @@ std::assert_distinct( CREATE ANNOTATION std::description := "Check that the input set is a proper set, i.e. all elements are unique"; - SET volatility := 'Stable'; + SET volatility := 'Immutable'; SET preserves_optionality := true; SET preserves_upper_cardinality := true; USING SQL EXPRESSION;