From 5e2eea0d979c7ad8eb48204b22e516b2504b1690 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Tue, 22 Mar 2022 20:45:59 +0100 Subject: [PATCH] sqlx: update dependency and protect against injections --- Cargo.lock | 457 ++++++++++++++--------- Cargo.toml | 9 + app/Cargo.toml | 3 + auth/Cargo.toml | 2 +- server/Cargo.toml | 12 +- server/src/domain/sql_backend_handler.rs | 195 ++++++---- server/src/domain/sql_opaque_handler.rs | 38 +- server/src/domain/sql_tables.rs | 8 +- server/src/infra/jwt_sql_tables.rs | 12 +- server/src/infra/sql_backend_handler.rs | 69 ++-- 10 files changed, 496 insertions(+), 309 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6fd2ab..95c3f2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "ahash 0.7.4", + "ahash", "base64", "bitflags", "brotli2", @@ -89,7 +89,7 @@ dependencies = [ "h2", "http", "httparse", - "itoa", + "itoa 0.4.8", "language-tags", "local-channel", "log", @@ -212,7 +212,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.7.4", + "ahash", "bytes", "cfg-if 1.0.0", "cookie", @@ -221,7 +221,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "itoa", + "itoa 0.4.8", "language-tags", "log", "mime", @@ -306,26 +306,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.4.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" - -[[package]] -name = "ahash" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" -dependencies = [ - "getrandom 0.2.3", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom 0.2.3", "once_cell", @@ -465,6 +448,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" + [[package]] name = "bincode" version = "1.3.3" @@ -555,12 +544,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.7.0" @@ -693,6 +676,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "const-oid" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" + [[package]] name = "const_fn" version = "0.4.8" @@ -749,13 +738,19 @@ dependencies = [ [[package]] name = "crc" -version = "1.8.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" dependencies = [ - "build_const", + "crc-catalog", ] +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + [[package]] name = "crc32fast" version = "1.2.1" @@ -831,6 +826,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-bigint" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "crypto-mac" version = "0.10.1" @@ -906,6 +912,16 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +dependencies = [ + "const-oid", + "crypto-bigint", +] + [[package]] name = "derive_builder" version = "0.10.2" @@ -976,6 +992,26 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "discard" version = "1.0.4" @@ -1086,6 +1122,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "flume" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project", + "spin 0.9.2", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1146,9 +1194,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -1156,9 +1204,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-enum" @@ -1173,9 +1221,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -1183,19 +1231,28 @@ dependencies = [ ] [[package]] -name = "futures-io" -version = "0.3.17" +name = "futures-intrusive" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -1203,23 +1260,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1229,8 +1285,6 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -1430,23 +1484,23 @@ name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.7", -] [[package]] name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] [[package]] name = "hashlink" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown 0.9.1", + "hashbrown 0.11.2", ] [[package]] @@ -1528,7 +1582,7 @@ checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 0.4.8", ] [[package]] @@ -1575,7 +1629,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.8", "pin-project-lite", "socket2", "tokio", @@ -1622,12 +1676,12 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "indexmap" -version = "1.7.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.11.2", + "hashbrown 0.9.1", "serde", ] @@ -1667,6 +1721,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "jobserver" version = "0.1.24" @@ -1765,7 +1825,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin", + "spin 0.5.2", ] [[package]] @@ -1856,9 +1916,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.101" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libm" @@ -1868,9 +1928,9 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libsqlite3-sys" -version = "0.20.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" +checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58" dependencies = [ "cc", "pkg-config", @@ -1923,6 +1983,7 @@ dependencies = [ "orion", "rand 0.8.4", "sea-query", + "sea-query-binder", "secstr", "serde", "serde_json", @@ -1949,6 +2010,7 @@ dependencies = [ "chrono", "graphql_client", "http", + "indexmap", "jwt", "lldap_auth", "rand 0.8.4", @@ -2232,17 +2294,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg 1.0.1", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.3.3" @@ -2256,9 +2307,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" dependencies = [ "autocfg 0.1.7", "byteorder", @@ -2267,8 +2318,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.7.3", - "serde", + "rand 0.8.4", "smallvec", "zeroize", ] @@ -2301,6 +2351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg 1.0.1", + "libm", ] [[package]] @@ -2324,9 +2375,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "opaque-debug" @@ -2443,9 +2494,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "pear" @@ -2471,14 +2522,12 @@ dependencies = [ ] [[package]] -name = "pem" -version = "0.8.3" +name = "pem-rfc7468" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +checksum = "84e93a3b1cc0510b03020f33f21e62acdde3dcaef432edc95bea377fbd4c2cd4" dependencies = [ - "base64", - "once_cell", - "regex", + "base64ct", ] [[package]] @@ -2528,6 +2577,30 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c" +dependencies = [ + "der", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" +dependencies = [ + "der", + "pem-rfc7468", + "pkcs1", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -2599,17 +2672,11 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -2629,9 +2696,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.9" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" dependencies = [ "proc-macro2", ] @@ -2742,13 +2809,24 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7776223e2696f1aa4c6b0170e83212f47296a00424305117d013dfe86fb0fe55" +dependencies = [ + "getrandom 0.2.3", + "redox_syscall", + "thiserror", +] + [[package]] name = "regex" version = "1.5.4" @@ -2835,9 +2913,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" +checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" dependencies = [ "byteorder", "digest", @@ -2846,12 +2924,10 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "pem", - "rand 0.7.3", - "sha2", - "simple_asn1", + "pkcs1", + "pkcs8", + "rand 0.8.4", "subtle", - "thiserror", "zeroize", ] @@ -2924,21 +3000,40 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sea-query" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3266fa53846a5ac9eaf85709979acde05d9ba54a5fa4a0b35d897074f1569a2" +version = "0.25.0" +source = "git+https://github.com/SeaQL/sea-query/?rev=f2b74b2875a1a5a5550a7c8658d3fcd385134925#f2b74b2875a1a5a5550a7c8658d3fcd385134925" dependencies = [ "chrono", "sea-query-derive", + "sea-query-driver", +] + +[[package]] +name = "sea-query-binder" +version = "0.1.0" +source = "git+https://github.com/SeaQL/sea-query/?rev=f2b74b2875a1a5a5550a7c8658d3fcd385134925#f2b74b2875a1a5a5550a7c8658d3fcd385134925" +dependencies = [ + "sea-query", + "sqlx", ] [[package]] name = "sea-query-derive" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f30d6681c05300d4d92aa3dce08585b52c775735d632bb1f16f9f68f29c832d" +version = "0.2.0" +source = "git+https://github.com/SeaQL/sea-query/?rev=f2b74b2875a1a5a5550a7c8658d3fcd385134925#f2b74b2875a1a5a5550a7c8658d3fcd385134925" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote", + "syn", + "thiserror", +] + +[[package]] +name = "sea-query-driver" +version = "0.1.1" +source = "git+https://github.com/SeaQL/sea-query/?rev=f2b74b2875a1a5a5550a7c8658d3fcd385134925#f2b74b2875a1a5a5550a7c8658d3fcd385134925" dependencies = [ - "heck 0.3.3", "proc-macro2", "quote", "syn", @@ -3012,18 +3107,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -3032,12 +3127,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.67" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "indexmap", - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -3049,7 +3144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -3075,9 +3170,9 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.9.6" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9204c41a1597a8c5af23c82d1c921cb01ec0a4c59e07a9c7306062829a3903f3" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer", "cfg-if 1.0.0", @@ -3125,17 +3220,6 @@ dependencies = [ "libc", ] -[[package]] -name = "simple_asn1" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" -dependencies = [ - "chrono", - "num-bigint 0.2.6", - "num-traits", -] - [[package]] name = "slab" version = "0.4.4" @@ -3144,9 +3228,9 @@ checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smartstring" @@ -3180,23 +3264,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "sqlformat" -version = "0.1.7" +name = "spin" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684001e7985ec1a9a66963b77ed151ef22a7876b3fdd7e37a57ec774f54b7d96" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" dependencies = [ - "lazy_static", - "maplit", + "lock_api", +] + +[[package]] +name = "spki" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +dependencies = [ + "der", +] + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools", "nom 7.0.0", - "regex", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.5.1" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2739d54a2ae9fdd0f545cb4e4b5574efb95e2ec71b7f921678e246fb20dcaaf" +checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3204,11 +3304,11 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.1" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cad9cae4ca8947eba1a90e8ec7d3c59e7a768e2f120dc9013b669c34a90711" +checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" dependencies = [ - "ahash 0.6.3", + "ahash", "atoi", "base64", "bitflags", @@ -3216,29 +3316,32 @@ dependencies = [ "bytes", "chrono", "crc", - "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils", "digest", + "dirs", "either", + "flume", "futures-channel", "futures-core", + "futures-executor", + "futures-intrusive", "futures-util", "generic-array", "hashlink", "hex", - "hmac 0.10.1", - "itoa", + "hmac 0.11.0", + "indexmap", + "itoa 1.0.1", "libc", "libsqlite3-sys", "log", "md-5", "memchr", - "num-bigint 0.3.3", + "num-bigint", "once_cell", - "parking_lot", + "paste", "percent-encoding", - "rand 0.7.3", + "rand 0.8.4", "rsa", "serde", "serde_json", @@ -3256,14 +3359,14 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.5.1" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01caee2b3935b4efe152f3262afbe51546ce3b1fc27ad61014e1b3cf5f55366e" +checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" dependencies = [ "dotenv", "either", - "futures", "heck 0.3.3", + "once_cell", "proc-macro2", "quote", "sha2", @@ -3275,9 +3378,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.3.0" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ce2e16b6774c671cc183e1d202386fdf9cde1e8468c1894a7f2a63eb671c4f4" +checksum = "b555e70fbbf84e269ec3858b7a6515bcfe7a166a7cc9c636dd6efd20431678b6" dependencies = [ "actix-rt", "native-tls", @@ -3374,9 +3477,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.75" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", @@ -3443,18 +3546,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -3576,9 +3679,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite", @@ -3976,9 +4079,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7741161a40200a867c96dfa5574544efa4178cf4c8f770b62dd1cc0362d7ae1" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" dependencies = [ "wasm-bindgen", "web-sys", diff --git a/Cargo.toml b/Cargo.toml index ed466dc..66d8c75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,12 @@ rev = '67050812695b7a8a90b81b0637e347fc6629daed' [patch.crates-io.yew_form_derive] git = 'https://github.com/sassman/yew_form/' rev = '67050812695b7a8a90b81b0637e347fc6629daed' + +# TODO: remove after https://github.com/SeaQL/sea-query has a release >0.25 +[patch.crates-io.sea-query] +git = 'https://github.com/SeaQL/sea-query/' +rev = 'f2b74b2875a1a5a5550a7c8658d3fcd385134925' + +[patch.crates-io.sea-query-binder] +git = 'https://github.com/SeaQL/sea-query/' +rev = 'f2b74b2875a1a5a5550a7c8658d3fcd385134925' diff --git a/app/Cargo.toml b/app/Cargo.toml index 6dd3ddd..dd5db10 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -21,6 +21,9 @@ yew-router = "0.15" yew_form = "0.1.8" yew_form_derive = "*" +# Needed because of https://github.com/tkaitchuck/aHash/issues/95 +indexmap = "=1.6.2" + [dependencies.web-sys] version = "0.3" features = [ diff --git a/auth/Cargo.toml b/auth/Cargo.toml index 63a2608..8940df6 100644 --- a/auth/Cargo.toml +++ b/auth/Cargo.toml @@ -13,7 +13,7 @@ js = [] [dependencies] rust-argon2 = "0.8" curve25519-dalek = "3" -digest = "*" +digest = "0.9" generic-array = "*" rand = "0.8" serde = "*" diff --git a/server/Cargo.toml b/server/Cargo.toml index ccdf738..8069268 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -34,7 +34,7 @@ native-tls = "0.2.10" serde = "*" serde_json = "1" sha2 = "0.9" -sqlx-core = "=0.5.1" +sqlx-core = "0.5.11" thiserror = "*" time = "0.2" tokio = { version = "1.13.1", features = ["full"] } @@ -64,7 +64,7 @@ features = [ ] [dependencies.sqlx] -version = "0.5.1" +version = "0.5.11" features = [ "any", "chrono", @@ -76,8 +76,12 @@ features = [ ] [dependencies.sea-query] -version = "0.9.4" -features = ["with-chrono"] +version = "^0.25" +features = ["with-chrono", "sqlx-sqlite"] + +[dependencies.sea-query-binder] +version = "*" +features = ["with-chrono", "sqlx-sqlite", "sqlx-any"] [dependencies.figment] features = ["env", "toml"] diff --git a/server/src/domain/sql_backend_handler.rs b/server/src/domain/sql_backend_handler.rs index 1b2c739..46c21af 100644 --- a/server/src/domain/sql_backend_handler.rs +++ b/server/src/domain/sql_backend_handler.rs @@ -2,8 +2,9 @@ use super::{error::*, handler::*, sql_tables::*}; use crate::infra::configuration::Configuration; use async_trait::async_trait; use futures_util::StreamExt; -use sea_query::{Expr, Iden, Order, Query, SimpleExpr}; -use sqlx::{FromRow, Row}; +use sea_query::{Cond, Expr, Iden, Order, Query, SimpleExpr}; +use sea_query_binder::SqlxBinder; +use sqlx::{query_as_with, query_with, FromRow, Row}; use std::collections::HashSet; #[derive(Debug, Clone)] @@ -101,7 +102,7 @@ fn get_group_filter_expr(filter: GroupRequestFilter) -> SimpleExpr { Query::select() .column(Memberships::GroupId) .from(Memberships::Table) - .and_where(Expr::col(Memberships::UserId).eq(user)) + .cond_where(Expr::col(Memberships::UserId).eq(user)) .take(), ), } @@ -114,7 +115,7 @@ impl BackendHandler for SqlBackendHandler { filters: Option, get_groups: bool, ) -> Result> { - let query = { + let (query, values) = { let mut query_builder = Query::select() .column((Users::Table, Users::UserId)) .column(Users::Email) @@ -154,14 +155,24 @@ impl BackendHandler for SqlBackendHandler { && filter != UserRequestFilter::Or(Vec::new()) { let (RequiresGroup(requires_group), condition) = get_user_filter_expr(filter); - query_builder.and_where(condition); - if requires_group && !get_groups { - add_join_group_tables(&mut query_builder); + query_builder.cond_where(condition); + if requires_group { + query_builder + .left_join( + Memberships::Table, + Expr::tbl(Users::Table, Users::UserId) + .equals(Memberships::Table, Memberships::UserId), + ) + .left_join( + Groups::Table, + Expr::tbl(Memberships::Table, Memberships::GroupId) + .equals(Groups::Table, Groups::GroupId), + ); } } } - query_builder.to_string(DbQueryBuilder {}) + query_builder.build_sqlx(DbQueryBuilder {}) }; log::error!("query: {}", &query); @@ -170,7 +181,7 @@ impl BackendHandler for SqlBackendHandler { let mut users = Vec::new(); // The rows are returned sorted by user_id. We group them by // this key which gives us one element (`rows`) per group. - for (_, rows) in &sqlx::query(&query) + for (_, rows) in &query_with(&query, values) .fetch_all(&self.sql_pool) .await? .into_iter() @@ -200,7 +211,7 @@ impl BackendHandler for SqlBackendHandler { } async fn list_groups(&self, filters: Option) -> Result> { - let query: String = { + let (query, values) = { let mut query_builder = Query::select() .column((Groups::Table, Groups::GroupId)) .column(Groups::DisplayName) @@ -223,11 +234,11 @@ impl BackendHandler for SqlBackendHandler { if filter != GroupRequestFilter::And(Vec::new()) && filter != GroupRequestFilter::Or(Vec::new()) { - query_builder.and_where(get_group_filter_expr(filter)); + query_builder.cond_where(get_group_filter_expr(filter)); } } - query_builder.to_string(DbQueryBuilder {}) + query_builder.build_sqlx(DbQueryBuilder {}) }; // For group_by. @@ -235,7 +246,7 @@ impl BackendHandler for SqlBackendHandler { let mut groups = Vec::new(); // The rows are returned sorted by display_name, equivalent to group_id. We group them by // this key which gives us one element (`rows`) per group. - for ((group_id, display_name), rows) in &sqlx::query(&query) + for ((group_id, display_name), rows) in &query_with(query.as_str(), values) .fetch_all(&self.sql_pool) .await? .into_iter() @@ -261,7 +272,7 @@ impl BackendHandler for SqlBackendHandler { } async fn get_user_details(&self, user_id: &UserId) -> Result { - let query = Query::select() + let (query, values) = Query::select() .column(Users::UserId) .column(Users::Email) .column(Users::DisplayName) @@ -270,25 +281,27 @@ impl BackendHandler for SqlBackendHandler { .column(Users::Avatar) .column(Users::CreationDate) .from(Users::Table) - .and_where(Expr::col(Users::UserId).eq(user_id)) - .to_string(DbQueryBuilder {}); + .cond_where(Expr::col(Users::UserId).eq(user_id)) + .build_sqlx(DbQueryBuilder {}); - Ok(sqlx::query_as::<_, User>(&query) + Ok(query_as_with::<_, User, _>(query.as_str(), values) .fetch_one(&self.sql_pool) .await?) } async fn get_group_details(&self, group_id: GroupId) -> Result { - let query = Query::select() + let (query, values) = Query::select() .column(Groups::GroupId) .column(Groups::DisplayName) .from(Groups::Table) - .and_where(Expr::col(Groups::GroupId).eq(group_id)) - .to_string(DbQueryBuilder {}); + .cond_where(Expr::col(Groups::GroupId).eq(group_id)) + .build_sqlx(DbQueryBuilder {}); - Ok(sqlx::query_as::<_, GroupIdAndName>(&query) - .fetch_one(&self.sql_pool) - .await?) + Ok( + query_as_with::<_, GroupIdAndName, _>(query.as_str(), values) + .fetch_one(&self.sql_pool) + .await?, + ) } async fn get_user_groups(&self, user_id: &UserId) -> Result> { @@ -297,7 +310,7 @@ impl BackendHandler for SqlBackendHandler { groups.insert(GroupIdAndName(GroupId(1), "lldap_admin".to_string())); return Ok(groups); } - let query: String = Query::select() + let (query, values) = Query::select() .column((Groups::Table, Groups::GroupId)) .column(Groups::DisplayName) .from(Groups::Table) @@ -306,10 +319,10 @@ impl BackendHandler for SqlBackendHandler { Expr::tbl(Groups::Table, Groups::GroupId) .equals(Memberships::Table, Memberships::GroupId), ) - .and_where(Expr::col(Memberships::UserId).eq(user_id)) - .to_string(DbQueryBuilder {}); + .cond_where(Expr::col(Memberships::UserId).eq(user_id)) + .build_sqlx(DbQueryBuilder {}); - sqlx::query(&query) + query_with(query.as_str(), values) // Extract the group id from the row. .map(|row: DbRow| { GroupIdAndName( @@ -338,20 +351,21 @@ impl BackendHandler for SqlBackendHandler { Users::LastName, Users::CreationDate, ]; - let values = vec![ - request.user_id.into(), - request.email.into(), - request.display_name.unwrap_or_default().into(), - request.first_name.unwrap_or_default().into(), - request.last_name.unwrap_or_default().into(), - chrono::Utc::now().naive_utc().into(), - ]; - let query = Query::insert() + let (query, values) = Query::insert() .into_table(Users::Table) .columns(columns) - .values_panic(values) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .values_panic(vec![ + request.user_id.into(), + request.email.into(), + request.display_name.unwrap_or_default().into(), + request.first_name.unwrap_or_default().into(), + request.last_name.unwrap_or_default().into(), + chrono::Utc::now().naive_utc().into(), + ]) + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } @@ -372,12 +386,14 @@ impl BackendHandler for SqlBackendHandler { if values.is_empty() { return Ok(()); } - let query = Query::update() + let (query, values) = Query::update() .table(Users::Table) .values(values) - .and_where(Expr::col(Users::UserId).eq(request.user_id)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .cond_where(Expr::col(Users::UserId).eq(request.user_id)) + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } @@ -389,66 +405,83 @@ impl BackendHandler for SqlBackendHandler { if values.is_empty() { return Ok(()); } - let query = Query::update() + let (query, values) = Query::update() .table(Groups::Table) .values(values) - .and_where(Expr::col(Groups::GroupId).eq(request.group_id)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .cond_where(Expr::col(Groups::GroupId).eq(request.group_id)) + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } async fn delete_user(&self, user_id: &UserId) -> Result<()> { - let delete_query = Query::delete() + let (delete_query, values) = Query::delete() .from_table(Users::Table) - .and_where(Expr::col(Users::UserId).eq(user_id)) - .to_string(DbQueryBuilder {}); - sqlx::query(&delete_query).execute(&self.sql_pool).await?; + .cond_where(Expr::col(Users::UserId).eq(user_id)) + .build_sqlx(DbQueryBuilder {}); + query_with(delete_query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } async fn create_group(&self, group_name: &str) -> Result { - let query = Query::insert() + let (query, values) = Query::insert() .into_table(Groups::Table) .columns(vec![Groups::DisplayName]) .values_panic(vec![group_name.into()]) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; - let query = Query::select() + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; + let (query, values) = Query::select() .column(Groups::GroupId) .from(Groups::Table) - .and_where(Expr::col(Groups::DisplayName).eq(group_name)) - .to_string(DbQueryBuilder {}); - let row = sqlx::query(&query).fetch_one(&self.sql_pool).await?; + .cond_where(Expr::col(Groups::DisplayName).eq(group_name)) + .build_sqlx(DbQueryBuilder {}); + let row = query_with(query.as_str(), values) + .fetch_one(&self.sql_pool) + .await?; Ok(GroupId(row.get::(&*Groups::GroupId.to_string()))) } async fn delete_group(&self, group_id: GroupId) -> Result<()> { - let delete_query = Query::delete() + let (delete_query, values) = Query::delete() .from_table(Groups::Table) - .and_where(Expr::col(Groups::GroupId).eq(group_id)) - .to_string(DbQueryBuilder {}); - sqlx::query(&delete_query).execute(&self.sql_pool).await?; + .cond_where(Expr::col(Groups::GroupId).eq(group_id)) + .build_sqlx(DbQueryBuilder {}); + query_with(delete_query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } async fn add_user_to_group(&self, user_id: &UserId, group_id: GroupId) -> Result<()> { - let query = Query::insert() + let (query, values) = Query::insert() .into_table(Memberships::Table) .columns(vec![Memberships::UserId, Memberships::GroupId]) .values_panic(vec![user_id.into(), group_id.into()]) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } async fn remove_user_from_group(&self, user_id: &UserId, group_id: GroupId) -> Result<()> { - let query = Query::delete() + let (query, values) = Query::delete() .from_table(Memberships::Table) - .and_where(Expr::col(Memberships::GroupId).eq(group_id)) - .and_where(Expr::col(Memberships::UserId).eq(user_id)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .cond_where( + Cond::all() + .add(Expr::col(Memberships::GroupId).eq(group_id)) + .add(Expr::col(Memberships::UserId).eq(user_id)), + ) + .build_sqlx(DbQueryBuilder {}); + query_with(query.as_str(), values) + .execute(&self.sql_pool) + .await?; Ok(()) } } @@ -846,4 +879,26 @@ mod tests { assert_eq!(get_user_names(&handler, None).await, vec!["val"]); } + + #[tokio::test] + async fn test_sql_injection() { + let sql_pool = get_initialized_db().await; + let config = get_default_config(); + let handler = SqlBackendHandler::new(config, sql_pool); + let user_name = UserId::new(r#"bob"e"i'o;aĆ¼"#); + insert_user(&handler, user_name.as_str(), "bob00").await; + { + let users = handler + .list_users(None, false) + .await + .unwrap() + .into_iter() + .map(|u| u.user.user_id) + .collect::>(); + + assert_eq!(users, vec![user_name.clone()]); + let user = handler.get_user_details(&user_name).await.unwrap(); + assert_eq!(user.user_id, user_name); + } + } } diff --git a/server/src/domain/sql_opaque_handler.rs b/server/src/domain/sql_opaque_handler.rs index 6208601..9c48eca 100644 --- a/server/src/domain/sql_opaque_handler.rs +++ b/server/src/domain/sql_opaque_handler.rs @@ -9,6 +9,7 @@ use async_trait::async_trait; use lldap_auth::opaque; use log::*; use sea_query::{Expr, Iden, Query}; +use sea_query_binder::SqlxBinder; use secstr::SecUtf8; use sqlx::Row; @@ -53,12 +54,15 @@ impl SqlBackendHandler { ) -> Result> { // Fetch the previously registered password file from the DB. let password_file_bytes = { - let query = Query::select() + let (query, values) = Query::select() .column(Users::PasswordHash) .from(Users::Table) - .and_where(Expr::col(Users::UserId).eq(username)) - .to_string(DbQueryBuilder {}); - if let Some(row) = sqlx::query(&query).fetch_optional(&self.sql_pool).await? { + .cond_where(Expr::col(Users::UserId).eq(username)) + .build_sqlx(DbQueryBuilder {}); + if let Some(row) = sqlx::query_with(query.as_str(), values) + .fetch_optional(&self.sql_pool) + .await? + { if let Some(bytes) = row.get::>, _>(&*Users::PasswordHash.to_string()) { @@ -94,12 +98,15 @@ impl LoginHandler for SqlBackendHandler { ))); } } - let query = Query::select() + let (query, values) = Query::select() .column(Users::PasswordHash) .from(Users::Table) - .and_where(Expr::col(Users::UserId).eq(&request.name)) - .to_string(DbQueryBuilder {}); - if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await { + .cond_where(Expr::col(Users::UserId).eq(&request.name)) + .build_sqlx(DbQueryBuilder {}); + if let Ok(row) = sqlx::query_with(&query, values) + .fetch_one(&self.sql_pool) + .await + { if let Some(password_hash) = row.get::>, _>(&*Users::PasswordHash.to_string()) { @@ -209,15 +216,14 @@ impl OpaqueHandler for SqlOpaqueHandler { opaque::server::registration::get_password_file(request.registration_upload); { // Set the user password to the new password. - let update_query = Query::update() + let (update_query, values) = Query::update() .table(Users::Table) - .values(vec![( - Users::PasswordHash, - password_file.serialize().into(), - )]) - .and_where(Expr::col(Users::UserId).eq(username)) - .to_string(DbQueryBuilder {}); - sqlx::query(&update_query).execute(&self.sql_pool).await?; + .value(Users::PasswordHash, password_file.serialize().into()) + .cond_where(Expr::col(Users::UserId).eq(username)) + .build_sqlx(DbQueryBuilder {}); + sqlx::query_with(update_query.as_str(), values) + .execute(&self.sql_pool) + .await?; } Ok(()) } diff --git a/server/src/domain/sql_tables.rs b/server/src/domain/sql_tables.rs index a48fad0..ae644ef 100644 --- a/server/src/domain/sql_tables.rs +++ b/server/src/domain/sql_tables.rs @@ -169,16 +169,16 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> { .foreign_key( ForeignKey::create() .name("MembershipUserForeignKey") - .table(Memberships::Table, Users::Table) - .col(Memberships::UserId, Users::UserId) + .from(Memberships::Table, Memberships::UserId) + .to(Users::Table, Users::UserId) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) .foreign_key( ForeignKey::create() .name("MembershipGroupForeignKey") - .table(Memberships::Table, Groups::Table) - .col(Memberships::GroupId, Groups::GroupId) + .from(Memberships::Table, Memberships::GroupId) + .to(Groups::Table, Groups::GroupId) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) diff --git a/server/src/infra/jwt_sql_tables.rs b/server/src/infra/jwt_sql_tables.rs index a937510..737b91e 100644 --- a/server/src/infra/jwt_sql_tables.rs +++ b/server/src/infra/jwt_sql_tables.rs @@ -55,8 +55,8 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> { .foreign_key( ForeignKey::create() .name("JwtRefreshStorageUserForeignKey") - .table(JwtRefreshStorage::Table, Users::Table) - .col(JwtRefreshStorage::UserId, Users::UserId) + .from(JwtRefreshStorage::Table, JwtRefreshStorage::UserId) + .to(Users::Table, Users::UserId) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) @@ -94,8 +94,8 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> { .foreign_key( ForeignKey::create() .name("JwtStorageUserForeignKey") - .table(JwtStorage::Table, Users::Table) - .col(JwtStorage::UserId, Users::UserId) + .from(JwtStorage::Table, JwtStorage::UserId) + .to(Users::Table, Users::UserId) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) @@ -127,8 +127,8 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> { .foreign_key( ForeignKey::create() .name("PasswordResetTokensUserForeignKey") - .table(PasswordResetTokens::Table, Users::Table) - .col(PasswordResetTokens::UserId, Users::UserId) + .from(PasswordResetTokens::Table, PasswordResetTokens::UserId) + .to(Users::Table, Users::UserId) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) diff --git a/server/src/infra/sql_backend_handler.rs b/server/src/infra/sql_backend_handler.rs index 3a76467..29e52f3 100644 --- a/server/src/infra/sql_backend_handler.rs +++ b/server/src/infra/sql_backend_handler.rs @@ -3,7 +3,8 @@ use crate::domain::{error::*, handler::UserId, sql_backend_handler::SqlBackendHa use async_trait::async_trait; use futures_util::StreamExt; use sea_query::{Expr, Iden, Query, SimpleExpr}; -use sqlx::Row; +use sea_query_binder::SqlxBinder; +use sqlx::{query_as_with, query_with, Row}; use std::collections::HashSet; fn gen_random_string(len: usize) -> String { @@ -19,12 +20,12 @@ fn gen_random_string(len: usize) -> String { #[async_trait] impl TcpBackendHandler for SqlBackendHandler { async fn get_jwt_blacklist(&self) -> anyhow::Result> { - let query = Query::select() + let (query, values) = Query::select() .column(JwtStorage::JwtHash) .from(JwtStorage::Table) - .to_string(DbQueryBuilder {}); + .build_sqlx(DbQueryBuilder {}); - sqlx::query(&query) + query_with(&query, values) .map(|row: DbRow| row.get::(&*JwtStorage::JwtHash.to_string()) as u64) .fetch(&self.sql_pool) .collect::>>() @@ -45,7 +46,7 @@ impl TcpBackendHandler for SqlBackendHandler { s.finish() }; let duration = chrono::Duration::days(30); - let query = Query::insert() + let (query, values) = Query::insert() .into_table(JwtRefreshStorage::Table) .columns(vec![ JwtRefreshStorage::RefreshTokenHash, @@ -57,71 +58,75 @@ impl TcpBackendHandler for SqlBackendHandler { user.into(), (chrono::Utc::now() + duration).naive_utc().into(), ]) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(&query, values).execute(&self.sql_pool).await?; Ok((refresh_token, duration)) } async fn check_token(&self, refresh_token_hash: u64, user: &UserId) -> Result { - let query = Query::select() + let (query, values) = Query::select() .expr(SimpleExpr::Value(1.into())) .from(JwtRefreshStorage::Table) .and_where(Expr::col(JwtRefreshStorage::RefreshTokenHash).eq(refresh_token_hash as i64)) .and_where(Expr::col(JwtRefreshStorage::UserId).eq(user)) - .to_string(DbQueryBuilder {}); - Ok(sqlx::query(&query) + .build_sqlx(DbQueryBuilder {}); + Ok(query_with(&query, values) .fetch_optional(&self.sql_pool) .await? .is_some()) } async fn blacklist_jwts(&self, user: &UserId) -> Result> { use sqlx::Result; - let query = Query::select() + let (query, values) = Query::select() .column(JwtStorage::JwtHash) .from(JwtStorage::Table) .and_where(Expr::col(JwtStorage::UserId).eq(user)) .and_where(Expr::col(JwtStorage::Blacklisted).eq(true)) - .to_string(DbQueryBuilder {}); - let result = sqlx::query(&query) + .build_sqlx(DbQueryBuilder {}); + let result = query_with(&query, values) .map(|row: DbRow| row.get::(&*JwtStorage::JwtHash.to_string()) as u64) .fetch(&self.sql_pool) .collect::>>() .await .into_iter() .collect::>>(); - let query = Query::update() + let (query, values) = Query::update() .table(JwtStorage::Table) .values(vec![(JwtStorage::Blacklisted, true.into())]) .and_where(Expr::col(JwtStorage::UserId).eq(user)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(&query, values).execute(&self.sql_pool).await?; Ok(result?) } async fn delete_refresh_token(&self, refresh_token_hash: u64) -> Result<()> { - let query = Query::delete() + let (query, values) = Query::delete() .from_table(JwtRefreshStorage::Table) .and_where(Expr::col(JwtRefreshStorage::RefreshTokenHash).eq(refresh_token_hash)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(&query, values).execute(&self.sql_pool).await?; Ok(()) } async fn start_password_reset(&self, user: &UserId) -> Result> { - let query = Query::select() + let (query, values) = Query::select() .column(Users::UserId) .from(Users::Table) .and_where(Expr::col(Users::UserId).eq(user)) - .to_string(DbQueryBuilder {}); + .build_sqlx(DbQueryBuilder {}); // Check that the user exists. - if sqlx::query(&query).fetch_one(&self.sql_pool).await.is_err() { + if query_with(&query, values) + .fetch_one(&self.sql_pool) + .await + .is_err() + { return Ok(None); } let token = gen_random_string(100); let duration = chrono::Duration::minutes(10); - let query = Query::insert() + let (query, values) = Query::insert() .into_table(PasswordResetTokens::Table) .columns(vec![ PasswordResetTokens::Token, @@ -133,31 +138,33 @@ impl TcpBackendHandler for SqlBackendHandler { user.into(), (chrono::Utc::now() + duration).naive_utc().into(), ]) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(&query, values).execute(&self.sql_pool).await?; Ok(Some(token)) } async fn get_user_id_for_password_reset_token(&self, token: &str) -> Result { - let query = Query::select() + let (query, values) = Query::select() .column(PasswordResetTokens::UserId) .from(PasswordResetTokens::Table) .and_where(Expr::col(PasswordResetTokens::Token).eq(token)) .and_where( Expr::col(PasswordResetTokens::ExpiryDate).gt(chrono::Utc::now().naive_utc()), ) - .to_string(DbQueryBuilder {}); + .build_sqlx(DbQueryBuilder {}); - let (user_id,) = sqlx::query_as(&query).fetch_one(&self.sql_pool).await?; + let (user_id,) = query_as_with(&query, values) + .fetch_one(&self.sql_pool) + .await?; Ok(user_id) } async fn delete_password_reset_token(&self, token: &str) -> Result<()> { - let query = Query::delete() + let (query, values) = Query::delete() .from_table(PasswordResetTokens::Table) .and_where(Expr::col(PasswordResetTokens::Token).eq(token)) - .to_string(DbQueryBuilder {}); - sqlx::query(&query).execute(&self.sql_pool).await?; + .build_sqlx(DbQueryBuilder {}); + query_with(&query, values).execute(&self.sql_pool).await?; Ok(()) } }