Fix compatbilité de version sur projet neuf

EBO <eric.bouhana@softalys.com> committé le 2026-07-31 19:01

46318ea11d5058d6d99869a702bc4d744cb63eab

1 parent(s)

16 fichiers modifiés +826 -297
M Cargo.lock
+247 -254
@@ -34,7 +34,7 @@ dependencies = [
34 34 "rsa",
35 35 "serde",
36 36 "serde_json",
37 - "sha2",
37 + "sha2 0.10.9",
38 38 "thiserror 2.0.18",
39 39 "tokio",
40 40 "tower",
@@ -64,7 +64,7 @@ version = "0.5.2"
64 64 source = "registry+https://github.com/rust-lang/crates.io-index"
65 65 checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
66 66 dependencies = [
67 - "crypto-common",
67 + "crypto-common 0.1.7",
68 68 "generic-array",
69 69 ]
70 70
@@ -76,7 +76,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
76 76 dependencies = [
77 77 "cfg-if",
78 78 "cipher",
79 - "cpufeatures",
79 + "cpufeatures 0.2.17",
80 80 ]
81 81
82 82 [[package]]
@@ -725,6 +725,15 @@ dependencies = [
725 725 ]
726 726
727 727 [[package]]
728 +name = "block-buffer"
729 +version = "0.12.1"
730 +source = "registry+https://github.com/rust-lang/crates.io-index"
731 +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
732 +dependencies = [
733 + "hybrid-array",
734 +]
735 +
736 +[[package]]
728 737 name = "blowfish"
729 738 version = "0.9.1"
730 739 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -848,6 +857,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
848 857 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
849 858
850 859 [[package]]
860 +name = "chacha20"
861 +version = "0.10.1"
862 +source = "registry+https://github.com/rust-lang/crates.io-index"
863 +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
864 +dependencies = [
865 + "cfg-if",
866 + "cpufeatures 0.3.0",
867 + "rand_core 0.10.1",
868 +]
869 +
870 +[[package]]
851 871 name = "chrono"
852 872 version = "0.4.44"
853 873 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -867,7 +887,7 @@ version = "0.4.4"
867 887 source = "registry+https://github.com/rust-lang/crates.io-index"
868 888 checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
869 889 dependencies = [
870 - "crypto-common",
890 + "crypto-common 0.1.7",
871 891 "inout",
872 892 ]
873 893
@@ -912,6 +932,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
912 932 checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
913 933
914 934 [[package]]
935 +name = "cmov"
936 +version = "0.5.4"
937 +source = "registry+https://github.com/rust-lang/crates.io-index"
938 +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
939 +
940 +[[package]]
915 941 name = "colorchoice"
916 942 version = "1.0.4"
917 943 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1024,6 +1050,15 @@ dependencies = [
1024 1050 ]
1025 1051
1026 1052 [[package]]
1053 +name = "cpufeatures"
1054 +version = "0.3.0"
1055 +source = "registry+https://github.com/rust-lang/crates.io-index"
1056 +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
1057 +dependencies = [
1058 + "libc",
1059 +]
1060 +
1061 +[[package]]
1027 1062 name = "crc"
1028 1063 version = "3.4.0"
1029 1064 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1116,6 +1151,15 @@ dependencies = [
1116 1151 ]
1117 1152
1118 1153 [[package]]
1154 +name = "crypto-common"
1155 +version = "0.2.2"
1156 +source = "registry+https://github.com/rust-lang/crates.io-index"
1157 +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
1158 +dependencies = [
1159 + "hybrid-array",
1160 +]
1161 +
1162 +[[package]]
1119 1163 name = "cssparser"
1120 1164 version = "0.35.0"
1121 1165 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1148,15 +1192,24 @@ dependencies = [
1148 1192 ]
1149 1193
1150 1194 [[package]]
1195 +name = "ctutils"
1196 +version = "0.4.2"
1197 +source = "registry+https://github.com/rust-lang/crates.io-index"
1198 +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
1199 +dependencies = [
1200 + "cmov",
1201 +]
1202 +
1203 +[[package]]
1151 1204 name = "curve25519-dalek"
1152 1205 version = "4.1.3"
1153 1206 source = "registry+https://github.com/rust-lang/crates.io-index"
1154 1207 checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
1155 1208 dependencies = [
1156 1209 "cfg-if",
1157 - "cpufeatures",
1210 + "cpufeatures 0.2.17",
1158 1211 "curve25519-dalek-derive",
1159 - "digest",
1212 + "digest 0.10.7",
1160 1213 "fiat-crypto",
1161 1214 "rustc_version",
1162 1215 "subtle",
@@ -1298,6 +1351,17 @@ dependencies = [
1298 1351 ]
1299 1352
1300 1353 [[package]]
1354 +name = "derive-where"
1355 +version = "1.6.1"
1356 +source = "registry+https://github.com/rust-lang/crates.io-index"
1357 +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
1358 +dependencies = [
1359 + "proc-macro2",
1360 + "quote",
1361 + "syn 2.0.117",
1362 +]
1363 +
1364 +[[package]]
1301 1365 name = "derive_builder"
1302 1366 version = "0.20.2"
1303 1367 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1370,13 +1434,24 @@ version = "0.10.7"
1370 1434 source = "registry+https://github.com/rust-lang/crates.io-index"
1371 1435 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
1372 1436 dependencies = [
1373 - "block-buffer",
1437 + "block-buffer 0.10.4",
1374 1438 "const-oid",
1375 - "crypto-common",
1439 + "crypto-common 0.1.7",
1376 1440 "subtle",
1377 1441 ]
1378 1442
1379 1443 [[package]]
1444 +name = "digest"
1445 +version = "0.11.3"
1446 +source = "registry+https://github.com/rust-lang/crates.io-index"
1447 +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
1448 +dependencies = [
1449 + "block-buffer 0.12.1",
1450 + "crypto-common 0.2.2",
1451 + "ctutils",
1452 +]
1453 +
1454 +[[package]]
1380 1455 name = "displaydoc"
1381 1456 version = "0.2.5"
1382 1457 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1421,7 +1496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1421 1496 checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
1422 1497 dependencies = [
1423 1498 "der",
1424 - "digest",
1499 + "digest 0.10.7",
1425 1500 "elliptic-curve",
1426 1501 "rfc6979",
1427 1502 "signature",
@@ -1447,7 +1522,7 @@ dependencies = [
1447 1522 "curve25519-dalek",
1448 1523 "ed25519",
1449 1524 "serde",
1450 - "sha2",
1525 + "sha2 0.10.9",
1451 1526 "subtle",
1452 1527 "zeroize",
1453 1528 ]
@@ -1469,11 +1544,11 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
1469 1544 dependencies = [
1470 1545 "base16ct",
1471 1546 "crypto-bigint",
1472 - "digest",
1547 + "digest 0.10.7",
1473 1548 "ff",
1474 1549 "generic-array",
1475 1550 "group",
1476 - "hkdf",
1551 + "hkdf 0.12.4",
1477 1552 "pem-rfc7468",
1478 1553 "pkcs8",
1479 1554 "rand_core 0.6.4",
@@ -1555,13 +1630,12 @@ dependencies = [
1555 1630
1556 1631 [[package]]
1557 1632 name = "etcetera"
1558 -version = "0.8.0"
1633 +version = "0.11.0"
1559 1634 source = "registry+https://github.com/rust-lang/crates.io-index"
1560 -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
1635 +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96"
1561 1636 dependencies = [
1562 1637 "cfg-if",
1563 - "home",
1564 - "windows-sys 0.48.0",
1638 + "windows-sys 0.61.2",
1565 1639 ]
1566 1640
1567 1641 [[package]]
@@ -1643,9 +1717,9 @@ dependencies = [
1643 1717
1644 1718 [[package]]
1645 1719 name = "flume"
1646 -version = "0.11.1"
1720 +version = "0.12.0"
1647 1721 source = "registry+https://github.com/rust-lang/crates.io-index"
1648 -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
1722 +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
1649 1723 dependencies = [
1650 1724 "futures-core",
1651 1725 "futures-sink",
@@ -1903,6 +1977,7 @@ dependencies = [
1903 1977 "cfg-if",
1904 1978 "libc",
1905 1979 "r-efi 6.0.0",
1980 + "rand_core 0.10.1",
1906 1981 "wasip2",
1907 1982 "wasip3",
1908 1983 ]
@@ -1986,8 +2061,6 @@ version = "0.15.5"
1986 2061 source = "registry+https://github.com/rust-lang/crates.io-index"
1987 2062 checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
1988 2063 dependencies = [
1989 - "allocator-api2",
1990 - "equivalent",
1991 2064 "foldhash 0.1.5",
1992 2065 ]
1993 2066
@@ -1997,20 +2070,13 @@ version = "0.16.1"
1997 2070 source = "registry+https://github.com/rust-lang/crates.io-index"
1998 2071 checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
1999 2072 dependencies = [
2073 + "allocator-api2",
2074 + "equivalent",
2000 2075 "foldhash 0.2.0",
2001 2076 ]
2002 2077
2003 2078 [[package]]
2004 2079 name = "hashlink"
2005 -version = "0.10.0"
2006 -source = "registry+https://github.com/rust-lang/crates.io-index"
2007 -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
2008 -dependencies = [
2009 - "hashbrown 0.15.5",
2010 -]
2011 -
2012 -[[package]]
2013 -name = "hashlink"
2014 2080 version = "0.11.0"
2015 2081 source = "registry+https://github.com/rust-lang/crates.io-index"
2016 2082 checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230"
@@ -2048,7 +2114,16 @@ version = "0.12.4"
2048 2114 source = "registry+https://github.com/rust-lang/crates.io-index"
2049 2115 checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
2050 2116 dependencies = [
2051 - "hmac",
2117 + "hmac 0.12.1",
2118 +]
2119 +
2120 +[[package]]
2121 +name = "hkdf"
2122 +version = "0.13.0"
2123 +source = "registry+https://github.com/rust-lang/crates.io-index"
2124 +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018"
2125 +dependencies = [
2126 + "hmac 0.13.0",
2052 2127 ]
2053 2128
2054 2129 [[package]]
@@ -2057,16 +2132,16 @@ version = "0.12.1"
2057 2132 source = "registry+https://github.com/rust-lang/crates.io-index"
2058 2133 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
2059 2134 dependencies = [
2060 - "digest",
2135 + "digest 0.10.7",
2061 2136 ]
2062 2137
2063 2138 [[package]]
2064 -name = "home"
2065 -version = "0.5.12"
2139 +name = "hmac"
2140 +version = "0.13.0"
2066 2141 source = "registry+https://github.com/rust-lang/crates.io-index"
2067 -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
2142 +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
2068 2143 dependencies = [
2069 - "windows-sys 0.61.2",
2144 + "digest 0.11.3",
2070 2145 ]
2071 2146
2072 2147 [[package]]
@@ -2151,7 +2226,7 @@ dependencies = [
2151 2226 "httpdate",
2152 2227 "reqwest 0.13.3",
2153 2228 "reqwest-middleware",
2154 - "sha2",
2229 + "sha2 0.10.9",
2155 2230 "tokio",
2156 2231 ]
2157 2232
@@ -2168,6 +2243,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2168 2243 checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
2169 2244
2170 2245 [[package]]
2246 +name = "hybrid-array"
2247 +version = "0.4.14"
2248 +source = "registry+https://github.com/rust-lang/crates.io-index"
2249 +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b"
2250 +dependencies = [
2251 + "typenum",
2252 +]
2253 +
2254 +[[package]]
2171 2255 name = "hyper"
2172 2256 version = "1.8.1"
2173 2257 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2458,17 +2542,6 @@ dependencies = [
2458 2542 ]
2459 2543
2460 2544 [[package]]
2461 -name = "inherent"
2462 -version = "1.0.13"
2463 -source = "registry+https://github.com/rust-lang/crates.io-index"
2464 -checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7"
2465 -dependencies = [
2466 - "proc-macro2",
2467 - "quote",
2468 - "syn 2.0.117",
2469 -]
2470 -
2471 -[[package]]
2472 2545 name = "inout"
2473 2546 version = "0.1.4"
2474 2547 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2542,7 +2615,7 @@ dependencies = [
2542 2615 "base64 0.22.1",
2543 2616 "ed25519-dalek",
2544 2617 "getrandom 0.2.17",
2545 - "hmac",
2618 + "hmac 0.12.1",
2546 2619 "js-sys",
2547 2620 "p256",
2548 2621 "p384",
@@ -2551,7 +2624,7 @@ dependencies = [
2551 2624 "rsa",
2552 2625 "serde",
2553 2626 "serde_json",
2554 - "sha2",
2627 + "sha2 0.10.9",
2555 2628 "signature",
2556 2629 "simple_asn1",
2557 2630 ]
@@ -2681,18 +2754,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2681 2754 checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
2682 2755
2683 2756 [[package]]
2684 -name = "libredox"
2685 -version = "0.1.14"
2686 -source = "registry+https://github.com/rust-lang/crates.io-index"
2687 -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
2688 -dependencies = [
2689 - "bitflags 2.11.0",
2690 - "libc",
2691 - "plain",
2692 - "redox_syscall 0.7.3",
2693 -]
2694 -
2695 -[[package]]
2696 2757 name = "libsqlite3-sys"
2697 2758 version = "0.30.1"
2698 2759 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2798,12 +2859,12 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
2798 2859
2799 2860 [[package]]
2800 2861 name = "md-5"
2801 -version = "0.10.6"
2862 +version = "0.11.0"
2802 2863 source = "registry+https://github.com/rust-lang/crates.io-index"
2803 -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
2864 +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98"
2804 2865 dependencies = [
2805 2866 "cfg-if",
2806 - "digest",
2867 + "digest 0.11.3",
2807 2868 ]
2808 2869
2809 2870 [[package]]
@@ -3075,7 +3136,7 @@ dependencies = [
3075 3136 "serde",
3076 3137 "serde_json",
3077 3138 "serde_path_to_error",
3078 - "sha2",
3139 + "sha2 0.10.9",
3079 3140 "thiserror 1.0.69",
3080 3141 "url",
3081 3142 ]
@@ -3108,7 +3169,7 @@ dependencies = [
3108 3169 "chrono",
3109 3170 "dyn-clone",
3110 3171 "ed25519-dalek",
3111 - "hmac",
3172 + "hmac 0.12.1",
3112 3173 "http",
3113 3174 "itertools 0.10.5",
3114 3175 "log",
@@ -3123,7 +3184,7 @@ dependencies = [
3123 3184 "serde_path_to_error",
3124 3185 "serde_plain",
3125 3186 "serde_with",
3126 - "sha2",
3187 + "sha2 0.10.9",
3127 3188 "subtle",
3128 3189 "thiserror 1.0.69",
3129 3190 "url",
@@ -3224,7 +3285,7 @@ dependencies = [
3224 3285 "ecdsa",
3225 3286 "elliptic-curve",
3226 3287 "primeorder",
3227 - "sha2",
3288 + "sha2 0.10.9",
3228 3289 ]
3229 3290
3230 3291 [[package]]
@@ -3236,7 +3297,7 @@ dependencies = [
3236 3297 "ecdsa",
3237 3298 "elliptic-curve",
3238 3299 "primeorder",
3239 - "sha2",
3300 + "sha2 0.10.9",
3240 3301 ]
3241 3302
3242 3303 [[package]]
@@ -3263,7 +3324,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
3263 3324 dependencies = [
3264 3325 "cfg-if",
3265 3326 "libc",
3266 - "redox_syscall 0.5.18",
3327 + "redox_syscall",
3267 3328 "smallvec",
3268 3329 "windows-link",
3269 3330 ]
@@ -3394,12 +3455,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
3394 3455 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
3395 3456
3396 3457 [[package]]
3397 -name = "plain"
3398 -version = "0.2.3"
3399 -source = "registry+https://github.com/rust-lang/crates.io-index"
3400 -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
3401 -
3402 -[[package]]
3403 3458 name = "pluralizer"
3404 3459 version = "0.5.0"
3405 3460 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3429,7 +3484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
3429 3484 checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
3430 3485 dependencies = [
3431 3486 "cfg-if",
3432 - "cpufeatures",
3487 + "cpufeatures 0.2.17",
3433 3488 "opaque-debug",
3434 3489 "universal-hash",
3435 3490 ]
@@ -3695,6 +3750,17 @@ dependencies = [
3695 3750 ]
3696 3751
3697 3752 [[package]]
3753 +name = "rand"
3754 +version = "0.10.2"
3755 +source = "registry+https://github.com/rust-lang/crates.io-index"
3756 +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
3757 +dependencies = [
3758 + "chacha20",
3759 + "getrandom 0.4.2",
3760 + "rand_core 0.10.1",
3761 +]
3762 +
3763 +[[package]]
3698 3764 name = "rand_chacha"
3699 3765 version = "0.3.1"
3700 3766 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3733,6 +3799,12 @@ dependencies = [
3733 3799 ]
3734 3800
3735 3801 [[package]]
3802 +name = "rand_core"
3803 +version = "0.10.1"
3804 +source = "registry+https://github.com/rust-lang/crates.io-index"
3805 +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
3806 +
3807 +[[package]]
3736 3808 name = "redis-protocol"
3737 3809 version = "5.0.1"
3738 3810 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3756,15 +3828,6 @@ dependencies = [
3756 3828 ]
3757 3829
3758 3830 [[package]]
3759 -name = "redox_syscall"
3760 -version = "0.7.3"
3761 -source = "registry+https://github.com/rust-lang/crates.io-index"
3762 -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16"
3763 -dependencies = [
3764 - "bitflags 2.11.0",
3765 -]
3766 -
3767 -[[package]]
3768 3831 name = "ref-cast"
3769 3832 version = "1.0.25"
3770 3833 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3920,7 +3983,7 @@ version = "0.4.0"
3920 3983 source = "registry+https://github.com/rust-lang/crates.io-index"
3921 3984 checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
3922 3985 dependencies = [
3923 - "hmac",
3986 + "hmac 0.12.1",
3924 3987 "subtle",
3925 3988 ]
3926 3989
@@ -3993,7 +4056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
3993 4056 checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
3994 4057 dependencies = [
3995 4058 "const-oid",
3996 - "digest",
4059 + "digest 0.10.7",
3997 4060 "num-bigint-dig",
3998 4061 "num-integer",
3999 4062 "num-traits",
@@ -4155,7 +4218,7 @@ dependencies = [
4155 4218 "serde",
4156 4219 "serde_json",
4157 4220 "serial_test",
4158 - "sha2",
4221 + "sha2 0.10.9",
4159 4222 "subtle",
4160 4223 "thiserror 2.0.18",
4161 4224 "time",
@@ -4197,7 +4260,7 @@ dependencies = [
4197 4260 "serde",
4198 4261 "serde_json",
4199 4262 "serial_test",
4200 - "sha2",
4263 + "sha2 0.10.9",
4201 4264 "subtle",
4202 4265 "thiserror 2.0.18",
4203 4266 "tokio",
@@ -4358,14 +4421,15 @@ dependencies = [
4358 4421
4359 4422 [[package]]
4360 4423 name = "sea-orm"
4361 -version = "2.0.0-rc.37"
4424 +version = "2.0.0"
4362 4425 source = "registry+https://github.com/rust-lang/crates.io-index"
4363 -checksum = "4b846dc1c7fefbea372c03765ff08307d68894bbad8c73b66176dcd53a3ee131"
4426 +checksum = "549c6d29a2e7a84e35c5dfbc06370a62c4d35f2328c31005267bec586b34f682"
4364 4427 dependencies = [
4365 4428 "async-stream",
4366 4429 "async-trait",
4367 4430 "bigdecimal",
4368 4431 "chrono",
4432 + "derive-where",
4369 4433 "derive_more",
4370 4434 "futures-util",
4371 4435 "itertools 0.14.0",
@@ -4382,12 +4446,14 @@ dependencies = [
4382 4446 "serde",
4383 4447 "serde_json",
4384 4448 "sqlx",
4449 + "sqlx-core",
4385 4450 "strum",
4386 4451 "thiserror 2.0.18",
4387 4452 "time",
4388 4453 "tracing",
4389 4454 "url",
4390 4455 "uuid",
4456 + "web-time",
4391 4457 ]
4392 4458
4393 4459 [[package]]
@@ -4403,9 +4469,9 @@ dependencies = [
4403 4469
4404 4470 [[package]]
4405 4471 name = "sea-orm-cli"
4406 -version = "2.0.0-rc.37"
4472 +version = "2.0.0"
4407 4473 source = "registry+https://github.com/rust-lang/crates.io-index"
4408 -checksum = "cd9b34d4c8e615079c04eb7863a429c2d2a8bf9c934eb9eeb580f51f36367124"
4474 +checksum = "3ec4b7c39c90efa92b8bb0b91ac7159684b9fa0d6371ce39bfab0a9793ce7394"
4409 4475 dependencies = [
4410 4476 "chrono",
4411 4477 "clap",
@@ -4423,9 +4489,9 @@ dependencies = [
4423 4489
4424 4490 [[package]]
4425 4491 name = "sea-orm-macros"
4426 -version = "2.0.0-rc.37"
4492 +version = "2.0.0"
4427 4493 source = "registry+https://github.com/rust-lang/crates.io-index"
4428 -checksum = "b449fe660e4d365f335222025df97ae01e670ef7ad788b3c67db9183b6cb0474"
4494 +checksum = "b4cbb7ae053b9b37c919ea944a3bc52f7830a90c223f8a765c908293bca8f22d"
4429 4495 dependencies = [
4430 4496 "heck 0.5.0",
4431 4497 "itertools 0.14.0",
@@ -4439,9 +4505,9 @@ dependencies = [
4439 4505
4440 4506 [[package]]
4441 4507 name = "sea-orm-migration"
4442 -version = "2.0.0-rc.37"
4508 +version = "2.0.0"
4443 4509 source = "registry+https://github.com/rust-lang/crates.io-index"
4444 -checksum = "b3ceb928aac8be83332d34d1fdbc827d43696135a800723ffeb2e0b33b7b495e"
4510 +checksum = "ef3576c5301b67ea7d2ce4515858d700066e51911c7d228a439c00ff258695c8"
4445 4511 dependencies = [
4446 4512 "async-trait",
4447 4513 "clap",
@@ -4455,12 +4521,11 @@ dependencies = [
4455 4521
4456 4522 [[package]]
4457 4523 name = "sea-query"
4458 -version = "1.0.0-rc.31"
4524 +version = "1.0.1"
4459 4525 source = "registry+https://github.com/rust-lang/crates.io-index"
4460 -checksum = "58decdaaaf2a698170af2fa1b2e8f7b43a970e7768bf18aebaab113bada46354"
4526 +checksum = "8d190cfb3bcceb8a8d7d04dee5a0c77f60c7627979cdcb47fdcb8934f009badf"
4461 4527 dependencies = [
4462 4528 "chrono",
4463 - "inherent",
4464 4529 "ordered-float 4.6.0",
4465 4530 "rust_decimal",
4466 4531 "sea-query-derive",
@@ -4471,9 +4536,9 @@ dependencies = [
4471 4536
4472 4537 [[package]]
4473 4538 name = "sea-query-derive"
4474 -version = "1.0.0-rc.12"
4539 +version = "1.0.0"
4475 4540 source = "registry+https://github.com/rust-lang/crates.io-index"
4476 -checksum = "8d88ad44b6ad9788c8b9476b6b91f94c7461d1e19d39cd8ea37838b1e6ff5aa8"
4541 +checksum = "a0b0f466921cdd3cf4b89d5c3ac2173dba89a873ab395b123a645de181ec7537"
4477 4542 dependencies = [
4478 4543 "darling 0.20.11",
4479 4544 "heck 0.4.1",
@@ -4485,9 +4550,9 @@ dependencies = [
4485 4550
4486 4551 [[package]]
4487 4552 name = "sea-query-sqlx"
4488 -version = "0.8.0-rc.14"
4553 +version = "0.9.1"
4489 4554 source = "registry+https://github.com/rust-lang/crates.io-index"
4490 -checksum = "e4377164b09a11bb692dec6966eb0e6908d63d768defef0be689b39e02cf8544"
4555 +checksum = "4eaa419cdb9157da1361186b1959983eb2ea0dcb9a3c69dc45c449ecb2af8fef"
4491 4556 dependencies = [
4492 4557 "sea-query",
4493 4558 "sqlx",
@@ -4495,9 +4560,9 @@ dependencies = [
4495 4560
4496 4561 [[package]]
4497 4562 name = "sea-schema"
4498 -version = "0.17.0-rc.17"
4563 +version = "0.18.1"
4499 4564 source = "registry+https://github.com/rust-lang/crates.io-index"
4500 -checksum = "b363dd21c20fe4d1488819cb2bc7f8d4696c62dd9f39554f97639f54d57dd0ab"
4565 +checksum = "3553c77dceed56e95bece9ea876c4dd67ca879ef51055a0b97a7bb89a8ae4fed"
4501 4566 dependencies = [
4502 4567 "async-trait",
4503 4568 "sea-query",
@@ -4717,8 +4782,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
4717 4782 checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
4718 4783 dependencies = [
4719 4784 "cfg-if",
4720 - "cpufeatures",
4721 - "digest",
4785 + "cpufeatures 0.2.17",
4786 + "digest 0.10.7",
4787 +]
4788 +
4789 +[[package]]
4790 +name = "sha1"
4791 +version = "0.11.0"
4792 +source = "registry+https://github.com/rust-lang/crates.io-index"
4793 +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214"
4794 +dependencies = [
4795 + "cfg-if",
4796 + "cpufeatures 0.3.0",
4797 + "digest 0.11.3",
4722 4798 ]
4723 4799
4724 4800 [[package]]
@@ -4728,8 +4804,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
4728 4804 checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
4729 4805 dependencies = [
4730 4806 "cfg-if",
4731 - "cpufeatures",
4732 - "digest",
4807 + "cpufeatures 0.2.17",
4808 + "digest 0.10.7",
4809 +]
4810 +
4811 +[[package]]
4812 +name = "sha2"
4813 +version = "0.11.0"
4814 +source = "registry+https://github.com/rust-lang/crates.io-index"
4815 +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
4816 +dependencies = [
4817 + "cfg-if",
4818 + "cpufeatures 0.3.0",
4819 + "digest 0.11.3",
4733 4820 ]
4734 4821
4735 4822 [[package]]
@@ -4769,7 +4856,7 @@ version = "2.2.0"
4769 4856 source = "registry+https://github.com/rust-lang/crates.io-index"
4770 4857 checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
4771 4858 dependencies = [
4772 - "digest",
4859 + "digest 0.10.7",
4773 4860 "rand_core 0.6.4",
4774 4861 ]
4775 4862
@@ -4859,9 +4946,9 @@ dependencies = [
4859 4946
4860 4947 [[package]]
4861 4948 name = "sqlx"
4862 -version = "0.8.6"
4949 +version = "0.9.0"
4863 4950 source = "registry+https://github.com/rust-lang/crates.io-index"
4864 -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
4951 +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71"
4865 4952 dependencies = [
4866 4953 "sqlx-core",
4867 4954 "sqlx-macros",
@@ -4872,12 +4959,13 @@ dependencies = [
4872 4959
4873 4960 [[package]]
4874 4961 name = "sqlx-core"
4875 -version = "0.8.6"
4962 +version = "0.9.0"
4876 4963 source = "registry+https://github.com/rust-lang/crates.io-index"
4877 -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
4964 +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb"
4878 4965 dependencies = [
4879 4966 "base64 0.22.1",
4880 4967 "bytes",
4968 + "cfg-if",
4881 4969 "chrono",
4882 4970 "crc",
4883 4971 "crossbeam-queue",
@@ -4887,18 +4975,17 @@ dependencies = [
4887 4975 "futures-intrusive",
4888 4976 "futures-io",
4889 4977 "futures-util",
4890 - "hashbrown 0.15.5",
4891 - "hashlink 0.10.0",
4978 + "hashbrown 0.16.1",
4979 + "hashlink",
4892 4980 "indexmap 2.13.0",
4893 4981 "log",
4894 4982 "memchr",
4895 4983 "native-tls",
4896 - "once_cell",
4897 4984 "percent-encoding",
4898 4985 "rust_decimal",
4899 4986 "serde",
4900 4987 "serde_json",
4901 - "sha2",
4988 + "sha2 0.10.9",
4902 4989 "smallvec",
4903 4990 "thiserror 2.0.18",
4904 4991 "time",
@@ -4911,9 +4998,9 @@ dependencies = [
4911 4998
4912 4999 [[package]]
4913 5000 name = "sqlx-macros"
4914 -version = "0.8.6"
5001 +version = "0.9.0"
4915 5002 source = "registry+https://github.com/rust-lang/crates.io-index"
4916 -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
5003 +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf"
4917 5004 dependencies = [
4918 5005 "proc-macro2",
4919 5006 "quote",
@@ -4924,20 +5011,20 @@ dependencies = [
4924 5011
4925 5012 [[package]]
4926 5013 name = "sqlx-macros-core"
4927 -version = "0.8.6"
5014 +version = "0.9.0"
4928 5015 source = "registry+https://github.com/rust-lang/crates.io-index"
4929 -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
5016 +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3"
4930 5017 dependencies = [
5018 + "cfg-if",
4931 5019 "dotenvy",
4932 5020 "either",
4933 5021 "heck 0.5.0",
4934 5022 "hex",
4935 - "once_cell",
4936 5023 "proc-macro2",
4937 5024 "quote",
4938 5025 "serde",
4939 5026 "serde_json",
4940 - "sha2",
5027 + "sha2 0.10.9",
4941 5028 "sqlx-core",
4942 5029 "sqlx-mysql",
4943 5030 "sqlx-postgres",
@@ -4949,55 +5036,39 @@ dependencies = [
4949 5036
4950 5037 [[package]]
4951 5038 name = "sqlx-mysql"
4952 -version = "0.8.6"
5039 +version = "0.9.0"
4953 5040 source = "registry+https://github.com/rust-lang/crates.io-index"
4954 -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
5041 +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27"
4955 5042 dependencies = [
4956 - "atoi",
4957 - "base64 0.22.1",
4958 5043 "bitflags 2.11.0",
4959 5044 "byteorder",
4960 5045 "bytes",
4961 5046 "chrono",
4962 5047 "crc",
4963 - "digest",
5048 + "digest 0.11.3",
4964 5049 "dotenvy",
4965 5050 "either",
4966 - "futures-channel",
4967 5051 "futures-core",
4968 - "futures-io",
4969 5052 "futures-util",
4970 5053 "generic-array",
4971 - "hex",
4972 - "hkdf",
4973 - "hmac",
4974 - "itoa",
4975 5054 "log",
4976 - "md-5",
4977 - "memchr",
4978 - "once_cell",
4979 5055 "percent-encoding",
4980 - "rand 0.8.5",
4981 - "rsa",
4982 5056 "rust_decimal",
4983 5057 "serde",
4984 - "sha1",
4985 - "sha2",
4986 - "smallvec",
5058 + "sha1 0.11.0",
5059 + "sha2 0.11.0",
4987 5060 "sqlx-core",
4988 - "stringprep",
4989 5061 "thiserror 2.0.18",
4990 5062 "time",
4991 5063 "tracing",
4992 5064 "uuid",
4993 - "whoami",
4994 5065 ]
4995 5066
4996 5067 [[package]]
4997 5068 name = "sqlx-postgres"
4998 -version = "0.8.6"
5069 +version = "0.9.0"
4999 5070 source = "registry+https://github.com/rust-lang/crates.io-index"
5000 -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
5071 +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e"
5001 5072 dependencies = [
5002 5073 "atoi",
5003 5074 "base64 0.22.1",
@@ -5011,19 +5082,17 @@ dependencies = [
5011 5082 "futures-core",
5012 5083 "futures-util",
5013 5084 "hex",
5014 - "hkdf",
5015 - "hmac",
5016 - "home",
5085 + "hkdf 0.13.0",
5086 + "hmac 0.13.0",
5017 5087 "itoa",
5018 5088 "log",
5019 5089 "md-5",
5020 5090 "memchr",
5021 - "once_cell",
5022 - "rand 0.8.5",
5091 + "rand 0.10.2",
5023 5092 "rust_decimal",
5024 5093 "serde",
5025 5094 "serde_json",
5026 - "sha2",
5095 + "sha2 0.11.0",
5027 5096 "smallvec",
5028 5097 "sqlx-core",
5029 5098 "stringprep",
@@ -5036,13 +5105,14 @@ dependencies = [
5036 5105
5037 5106 [[package]]
5038 5107 name = "sqlx-sqlite"
5039 -version = "0.8.6"
5108 +version = "0.9.0"
5040 5109 source = "registry+https://github.com/rust-lang/crates.io-index"
5041 -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
5110 +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c"
5042 5111 dependencies = [
5043 5112 "atoi",
5044 5113 "chrono",
5045 5114 "flume",
5115 + "form_urlencoded",
5046 5116 "futures-channel",
5047 5117 "futures-core",
5048 5118 "futures-executor",
@@ -5052,7 +5122,6 @@ dependencies = [
5052 5122 "log",
5053 5123 "percent-encoding",
5054 5124 "serde",
5055 - "serde_urlencoded",
5056 5125 "sqlx-core",
5057 5126 "thiserror 2.0.18",
5058 5127 "time",
@@ -5117,9 +5186,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
5117 5186
5118 5187 [[package]]
5119 5188 name = "strum"
5120 -version = "0.27.2"
5189 +version = "0.28.0"
5121 5190 source = "registry+https://github.com/rust-lang/crates.io-index"
5122 -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
5191 +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
5123 5192
5124 5193 [[package]]
5125 5194 name = "subtle"
@@ -5451,11 +5520,11 @@ checksum = "a2b36a9dd327e9f401320a2cb4572cc76ff43742bcfc3291f871691050f140ba"
5451 5520 dependencies = [
5452 5521 "base32",
5453 5522 "constant_time_eq",
5454 - "hmac",
5523 + "hmac 0.12.1",
5455 5524 "qrcodegen-image",
5456 5525 "rand 0.9.2",
5457 - "sha1",
5458 - "sha2",
5526 + "sha1 0.10.6",
5527 + "sha2 0.10.9",
5459 5528 "url",
5460 5529 "urlencoding",
5461 5530 ]
@@ -5688,9 +5757,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
5688 5757
5689 5758 [[package]]
5690 5759 name = "typenum"
5691 -version = "1.19.0"
5760 +version = "1.20.1"
5692 5761 source = "registry+https://github.com/rust-lang/crates.io-index"
5693 -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
5762 +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
5694 5763
5695 5764 [[package]]
5696 5765 name = "unicase"
@@ -5743,7 +5812,7 @@ version = "0.5.1"
5743 5812 source = "registry+https://github.com/rust-lang/crates.io-index"
5744 5813 checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
5745 5814 dependencies = [
5746 - "crypto-common",
5815 + "crypto-common 0.1.7",
5747 5816 "subtle",
5748 5817 ]
5749 5818
@@ -5884,12 +5953,6 @@ dependencies = [
5884 5953 ]
5885 5954
5886 5955 [[package]]
5887 -name = "wasite"
5888 -version = "0.1.0"
5889 -source = "registry+https://github.com/rust-lang/crates.io-index"
5890 -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
5891 -
5892 -[[package]]
5893 5956 name = "wasm-bindgen"
5894 5957 version = "0.2.114"
5895 5958 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6038,13 +6101,9 @@ dependencies = [
6038 6101
6039 6102 [[package]]
6040 6103 name = "whoami"
6041 -version = "1.6.1"
6104 +version = "2.1.2"
6042 6105 source = "registry+https://github.com/rust-lang/crates.io-index"
6043 -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
6044 -dependencies = [
6045 - "libredox",
6046 - "wasite",
6047 -]
6106 +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d"
6048 6107
6049 6108 [[package]]
6050 6109 name = "winapi"
@@ -6140,20 +6199,11 @@ dependencies = [
6140 6199
6141 6200 [[package]]
6142 6201 name = "windows-sys"
6143 -version = "0.48.0"
6144 -source = "registry+https://github.com/rust-lang/crates.io-index"
6145 -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
6146 -dependencies = [
6147 - "windows-targets 0.48.5",
6148 -]
6149 -
6150 -[[package]]
6151 -name = "windows-sys"
6152 6202 version = "0.52.0"
6153 6203 source = "registry+https://github.com/rust-lang/crates.io-index"
6154 6204 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
6155 6205 dependencies = [
6156 - "windows-targets 0.52.6",
6206 + "windows-targets",
6157 6207 ]
6158 6208
6159 6209 [[package]]
@@ -6162,7 +6212,7 @@ version = "0.59.0"
6162 6212 source = "registry+https://github.com/rust-lang/crates.io-index"
6163 6213 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
6164 6214 dependencies = [
6165 - "windows-targets 0.52.6",
6215 + "windows-targets",
6166 6216 ]
6167 6217
6168 6218 [[package]]
@@ -6176,67 +6226,34 @@ dependencies = [
6176 6226
6177 6227 [[package]]
6178 6228 name = "windows-targets"
6179 -version = "0.48.5"
6180 -source = "registry+https://github.com/rust-lang/crates.io-index"
6181 -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
6182 -dependencies = [
6183 - "windows_aarch64_gnullvm 0.48.5",
6184 - "windows_aarch64_msvc 0.48.5",
6185 - "windows_i686_gnu 0.48.5",
6186 - "windows_i686_msvc 0.48.5",
6187 - "windows_x86_64_gnu 0.48.5",
6188 - "windows_x86_64_gnullvm 0.48.5",
6189 - "windows_x86_64_msvc 0.48.5",
6190 -]
6191 -
6192 -[[package]]
6193 -name = "windows-targets"
6194 6229 version = "0.52.6"
6195 6230 source = "registry+https://github.com/rust-lang/crates.io-index"
6196 6231 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
6197 6232 dependencies = [
6198 - "windows_aarch64_gnullvm 0.52.6",
6199 - "windows_aarch64_msvc 0.52.6",
6200 - "windows_i686_gnu 0.52.6",
6233 + "windows_aarch64_gnullvm",
6234 + "windows_aarch64_msvc",
6235 + "windows_i686_gnu",
6201 6236 "windows_i686_gnullvm",
6202 - "windows_i686_msvc 0.52.6",
6203 - "windows_x86_64_gnu 0.52.6",
6204 - "windows_x86_64_gnullvm 0.52.6",
6205 - "windows_x86_64_msvc 0.52.6",
6237 + "windows_i686_msvc",
6238 + "windows_x86_64_gnu",
6239 + "windows_x86_64_gnullvm",
6240 + "windows_x86_64_msvc",
6206 6241 ]
6207 6242
6208 6243 [[package]]
6209 6244 name = "windows_aarch64_gnullvm"
6210 -version = "0.48.5"
6211 -source = "registry+https://github.com/rust-lang/crates.io-index"
6212 -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
6213 -
6214 -[[package]]
6215 -name = "windows_aarch64_gnullvm"
6216 6245 version = "0.52.6"
6217 6246 source = "registry+https://github.com/rust-lang/crates.io-index"
6218 6247 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
6219 6248
6220 6249 [[package]]
6221 6250 name = "windows_aarch64_msvc"
6222 -version = "0.48.5"
6223 -source = "registry+https://github.com/rust-lang/crates.io-index"
6224 -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
6225 -
6226 -[[package]]
6227 -name = "windows_aarch64_msvc"
6228 6251 version = "0.52.6"
6229 6252 source = "registry+https://github.com/rust-lang/crates.io-index"
6230 6253 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
6231 6254
6232 6255 [[package]]
6233 6256 name = "windows_i686_gnu"
6234 -version = "0.48.5"
6235 -source = "registry+https://github.com/rust-lang/crates.io-index"
6236 -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
6237 -
6238 -[[package]]
6239 -name = "windows_i686_gnu"
6240 6257 version = "0.52.6"
6241 6258 source = "registry+https://github.com/rust-lang/crates.io-index"
6242 6259 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -6249,48 +6266,24 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
6249 6266
6250 6267 [[package]]
6251 6268 name = "windows_i686_msvc"
6252 -version = "0.48.5"
6253 -source = "registry+https://github.com/rust-lang/crates.io-index"
6254 -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
6255 -
6256 -[[package]]
6257 -name = "windows_i686_msvc"
6258 6269 version = "0.52.6"
6259 6270 source = "registry+https://github.com/rust-lang/crates.io-index"
6260 6271 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
6261 6272
6262 6273 [[package]]
6263 6274 name = "windows_x86_64_gnu"
6264 -version = "0.48.5"
6265 -source = "registry+https://github.com/rust-lang/crates.io-index"
6266 -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
6267 -
6268 -[[package]]
6269 -name = "windows_x86_64_gnu"
6270 6275 version = "0.52.6"
6271 6276 source = "registry+https://github.com/rust-lang/crates.io-index"
6272 6277 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
6273 6278
6274 6279 [[package]]
6275 6280 name = "windows_x86_64_gnullvm"
6276 -version = "0.48.5"
6277 -source = "registry+https://github.com/rust-lang/crates.io-index"
6278 -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
6279 -
6280 -[[package]]
6281 -name = "windows_x86_64_gnullvm"
6282 6281 version = "0.52.6"
6283 6282 source = "registry+https://github.com/rust-lang/crates.io-index"
6284 6283 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
6285 6284
6286 6285 [[package]]
6287 6286 name = "windows_x86_64_msvc"
6288 -version = "0.48.5"
6289 -source = "registry+https://github.com/rust-lang/crates.io-index"
6290 -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
6291 -
6292 -[[package]]
6293 -name = "windows_x86_64_msvc"
6294 6287 version = "0.52.6"
6295 6288 source = "registry+https://github.com/rust-lang/crates.io-index"
6296 6289 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
@@ -6438,7 +6431,7 @@ checksum = "631a50d867fafb7093e709d75aaee9e0e0d5deb934021fcea25ac2fe09edc51e"
6438 6431 dependencies = [
6439 6432 "arraydeque",
6440 6433 "encoding_rs",
6441 - "hashlink 0.11.0",
6434 + "hashlink",
6442 6435 ]
6443 6436
6444 6437 [[package]]
M app/Cargo.toml
+1 -1
@@ -39,7 +39,7 @@ rustwarden-ui = { path = "../crates/rustwarden-ui" }
39 39 rustwarden-fediverse = { path = "../crates/rustwarden-fediverse", optional = true }
40 40 rustwarden-fediverse-ui = { path = "../crates/rustwarden-fediverse-ui", optional = true }
41 41 rustwarden-fediverse-guard = { path = "../crates/rustwarden-fediverse-guard", optional = true }
42 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
42 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
43 43 axum = { version = "0.8", features = ["macros"] }
44 44 tokio = { version = "1", features = ["full"] }
45 45 tower = { version = "0.5", features = ["limit", "util"] }
M crates/rustwarden-core/Cargo.toml
+3 -3
@@ -25,8 +25,8 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
25 25 # Env
26 26 dotenvy = "0.15"
27 27 # Database ORM
28 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
29 -sea-orm-migration = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
28 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
29 +sea-orm-migration = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
30 30 # Password hashing
31 31 bcrypt = "0.19"
32 32 # Validation
@@ -99,7 +99,7 @@ hyper = { version = "1", features = ["full"] }
99 99 hyper-util = { version = "0.1", features = ["full"] }
100 100 tower = "0.5"
101 101 # Enable SeaORM mock backend for unit tests (RFC 0003+).
102 -sea-orm = { version = "2.0.0-rc.20", features = ["mock"] }
102 +sea-orm = { version = "2.0.0", features = ["mock"] }
103 103 # Fediverse interop tests (RFC 0020): fake-Mastodon HTTP server for
104 104 # round-trip verification of HTTP signatures and outbound delivery.
105 105 wiremock = "0.6"
M crates/rustwarden-core/src/services/oauth/providers/discord.rs
+115 -13
@@ -19,13 +19,54 @@ impl DiscordProvider {
19 19 client_secret,
20 20 }
21 21 }
22 +
23 + /// Build the form body for the token-exchange request.
24 + ///
25 + /// RFC 0035: the PKCE `code_verifier` is appended only when present, so a
26 + /// non-PKCE flow (verifier `None`) behaves exactly as before. Discord applies
27 + /// PKCE whenever a `code_challenge` is sent at the authorization step, so the
28 + /// matching verifier must be replayed here.
29 + fn token_form<'a>(
30 + &'a self,
31 + code: &'a str,
32 + redirect_uri: &'a str,
33 + pkce_verifier: Option<&'a str>,
34 + ) -> Vec<(&'a str, &'a str)> {
35 + let mut form = vec![
36 + ("client_id", self.client_id.as_str()),
37 + ("client_secret", self.client_secret.as_str()),
38 + ("grant_type", "authorization_code"),
39 + ("code", code),
40 + ("redirect_uri", redirect_uri),
41 + ];
42 + if let Some(verifier) = pkce_verifier {
43 + form.push(("code_verifier", verifier));
44 + }
45 + form
46 + }
22 47 }
23 48
24 -#[derive(Deserialize)]
49 +#[derive(Deserialize, Debug)]
25 50 struct DiscordTokenResponse {
26 51 access_token: String,
27 52 }
28 53
54 +/// Parse the Discord token endpoint response.
55 +///
56 +/// RFC 0035 §6: reading the body as text and parsing it here surfaces Discord's
57 +/// structured OAuth error (e.g. `{"error":"invalid_grant",...}`) instead of an
58 +/// opaque "error decoding response body".
59 +fn parse_discord_token(
60 + status: reqwest::StatusCode,
61 + body: &str,
62 +) -> Result<DiscordTokenResponse, AppError> {
63 + serde_json::from_str::<DiscordTokenResponse>(body).map_err(|_| {
64 + AppError::Internal(format!(
65 + "Discord token exchange rejected (HTTP {status}): {body}"
66 + ))
67 + })
68 +}
69 +
29 70 #[derive(Deserialize)]
30 71 struct DiscordUser {
31 72 id: String,
@@ -78,26 +119,24 @@ impl OAuthProvider for DiscordProvider {
78 119 &self,
79 120 code: &str,
80 121 redirect_uri: &str,
81 - _pkce_verifier: Option<&str>,
122 + pkce_verifier: Option<&str>,
82 123 _nonce: Option<&str>,
83 124 ) -> Result<ProviderUserInfo, AppError> {
84 125 let http = reqwest::Client::new();
85 126
86 - let token_resp = http
127 + let response = http
87 128 .post("https://discord.com/api/oauth2/token")
88 - .form(&[
89 - ("client_id", self.client_id.as_str()),
90 - ("client_secret", self.client_secret.as_str()),
91 - ("grant_type", "authorization_code"),
92 - ("code", code),
93 - ("redirect_uri", redirect_uri),
94 - ])
129 + .form(&self.token_form(code, redirect_uri, pkce_verifier))
95 130 .send()
96 131 .await
97 - .map_err(|e| AppError::Internal(format!("Discord token exchange failed: {}", e)))?
98 - .json::<DiscordTokenResponse>()
132 + .map_err(|e| AppError::Internal(format!("Discord token exchange failed: {}", e)))?;
133 +
134 + let status = response.status();
135 + let body = response
136 + .text()
99 137 .await
100 - .map_err(|e| AppError::Internal(format!("Discord token parse failed: {}", e)))?;
138 + .map_err(|e| AppError::Internal(format!("Discord token read failed: {}", e)))?;
139 + let token_resp = parse_discord_token(status, &body)?;
101 140
102 141 let user: DiscordUser = http
103 142 .get("https://discord.com/api/v10/users/@me")
@@ -128,3 +167,66 @@ impl OAuthProvider for DiscordProvider {
128 167 })
129 168 }
130 169 }
170 +
171 +#[cfg(test)]
172 +mod tests {
173 + use super::*;
174 +
175 + fn provider() -> DiscordProvider {
176 + DiscordProvider::new("client-id".to_string(), "client-secret".to_string())
177 + }
178 +
179 + // RFC 0035 §7.1: the verifier must be present in the token form when supplied.
180 + #[test]
181 + fn token_form_includes_code_verifier_when_present() {
182 + let p = provider();
183 + let form = p.token_form("the-code", "https://app.example/cb", Some("the-verifier"));
184 + assert!(
185 + form.contains(&("code_verifier", "the-verifier")),
186 + "code_verifier must be sent to the token endpoint when PKCE is used"
187 + );
188 + assert!(form.contains(&("grant_type", "authorization_code")));
189 + assert!(form.contains(&("redirect_uri", "https://app.example/cb")));
190 + }
191 +
192 + // RFC 0035 §7.1: a non-PKCE flow (verifier None) must not add the parameter.
193 + #[test]
194 + fn token_form_omits_code_verifier_when_absent() {
195 + let p = provider();
196 + let form = p.token_form("the-code", "https://app.example/cb", None);
197 + assert!(form.iter().all(|(k, _)| *k != "code_verifier"));
198 + }
199 +
200 + // RFC 0035 §7.2: a code_challenge is emitted at authorization, so a matching
201 + // verifier must be carried in the session for the exchange.
202 + #[test]
203 + fn authorization_url_emits_challenge_and_keeps_verifier() {
204 + let auth = provider()
205 + .authorization_url("https://app.example/callback")
206 + .expect("authorization_url should succeed");
207 + assert!(auth.url.contains("code_challenge="));
208 + assert!(auth.url.contains("code_challenge_method=S256"));
209 + assert!(
210 + auth.pkce_verifier.is_some(),
211 + "verifier must be retained whenever a challenge is sent"
212 + );
213 + }
214 +
215 + // RFC 0035 §6: a structured OAuth error body must surface instead of an
216 + // opaque deserialization failure.
217 + #[test]
218 + fn parse_discord_token_surfaces_error_body() {
219 + let body = r#"{"error":"invalid_grant","error_description":"Invalid code_verifier"}"#;
220 + let err = parse_discord_token(reqwest::StatusCode::BAD_REQUEST, body)
221 + .expect_err("error body must not parse as success");
222 + assert!(err.to_string().contains("Invalid code_verifier"));
223 + }
224 +
225 + #[test]
226 + fn parse_discord_token_accepts_success_body() {
227 + let body = r#"{"access_token":"discord_token","token_type":"Bearer"}"#;
228 + let token = parse_discord_token(reqwest::StatusCode::OK, body)
229 + .expect("valid token response should parse");
230 + assert_eq!(token.access_token, "discord_token");
231 + }
232 +}
M crates/rustwarden-core/src/services/oauth/providers/github.rs
+112 -11
@@ -18,13 +18,51 @@ impl GitHubProvider {
18 18 client_secret,
19 19 }
20 20 }
21 +
22 + /// Build the form body for the token-exchange request.
23 + ///
24 + /// RFC 0035: the PKCE `code_verifier` is appended only when present, so a
25 + /// non-PKCE flow (verifier `None`) behaves exactly as before. GitHub has
26 + /// enforced PKCE since 2025-07-14, so a `code_challenge` emitted at the
27 + /// authorization step must be matched by the verifier here.
28 + fn token_form<'a>(
29 + &'a self,
30 + code: &'a str,
31 + pkce_verifier: Option<&'a str>,
32 + ) -> Vec<(&'a str, &'a str)> {
33 + let mut form = vec![
34 + ("client_id", self.client_id.as_str()),
35 + ("client_secret", self.client_secret.as_str()),
36 + ("code", code),
37 + ];
38 + if let Some(verifier) = pkce_verifier {
39 + form.push(("code_verifier", verifier));
40 + }
41 + form
42 + }
21 43 }
22 44
23 -#[derive(Deserialize)]
45 +#[derive(Deserialize, Debug)]
24 46 struct GitHubTokenResponse {
25 47 access_token: String,
26 48 }
27 49
50 +/// Parse the GitHub token endpoint response.
51 +///
52 +/// RFC 0035 §6: on failure GitHub returns `{"error":...,"error_description":...}`
53 +/// with an HTTP 200 status. Reading the body as text and parsing it here lets the
54 +/// real provider error surface instead of an opaque "error decoding response body".
55 +fn parse_github_token(
56 + status: reqwest::StatusCode,
57 + body: &str,
58 +) -> Result<GitHubTokenResponse, AppError> {
59 + serde_json::from_str::<GitHubTokenResponse>(body).map_err(|_| {
60 + AppError::Internal(format!(
61 + "GitHub token exchange rejected (HTTP {status}): {body}"
62 + ))
63 + })
64 +}
65 +
28 66 #[derive(Deserialize)]
29 67 struct GitHubUser {
30 68 id: i64,
@@ -82,25 +120,25 @@ impl OAuthProvider for GitHubProvider {
82 120 &self,
83 121 code: &str,
84 122 _redirect_uri: &str,
85 - _pkce_verifier: Option<&str>,
123 + pkce_verifier: Option<&str>,
86 124 _nonce: Option<&str>,
87 125 ) -> Result<ProviderUserInfo, AppError> {
88 126 let http = reqwest::Client::new();
89 127
90 - let token_resp = http
128 + let response = http
91 129 .post("https://github.com/login/oauth/access_token")
92 130 .header("Accept", "application/json")
93 - .form(&[
94 - ("client_id", self.client_id.as_str()),
95 - ("client_secret", self.client_secret.as_str()),
96 - ("code", code),
97 - ])
131 + .form(&self.token_form(code, pkce_verifier))
98 132 .send()
99 133 .await
100 - .map_err(|e| AppError::Internal(format!("GitHub token exchange failed: {}", e)))?
101 - .json::<GitHubTokenResponse>()
134 + .map_err(|e| AppError::Internal(format!("GitHub token exchange failed: {}", e)))?;
135 +
136 + let status = response.status();
137 + let body = response
138 + .text()
102 139 .await
103 - .map_err(|e| AppError::Internal(format!("GitHub token parse failed: {}", e)))?;
140 + .map_err(|e| AppError::Internal(format!("GitHub token read failed: {}", e)))?;
141 + let token_resp = parse_github_token(status, &body)?;
104 142
105 143 let user: GitHubUser = http
106 144 .get("https://api.github.com/user")
@@ -149,3 +187,66 @@ impl OAuthProvider for GitHubProvider {
149 187 })
150 188 }
151 189 }
190 +
191 +#[cfg(test)]
192 +mod tests {
193 + use super::*;
194 +
195 + fn provider() -> GitHubProvider {
196 + GitHubProvider::new("client-id".to_string(), "client-secret".to_string())
197 + }
198 +
199 + // RFC 0035 §7.1: the verifier must be present in the token form when supplied.
200 + #[test]
201 + fn token_form_includes_code_verifier_when_present() {
202 + let p = provider();
203 + let form = p.token_form("the-code", Some("the-verifier"));
204 + assert!(
205 + form.contains(&("code_verifier", "the-verifier")),
206 + "code_verifier must be sent to the token endpoint when PKCE is used"
207 + );
208 + assert!(form.contains(&("code", "the-code")));
209 + }
210 +
211 + // RFC 0035 §7.1: a non-PKCE flow (verifier None) must not add the parameter.
212 + #[test]
213 + fn token_form_omits_code_verifier_when_absent() {
214 + let p = provider();
215 + let form = p.token_form("the-code", None);
216 + assert!(form.iter().all(|(k, _)| *k != "code_verifier"));
217 + }
218 +
219 + // RFC 0035 §7.2: a code_challenge is emitted at authorization, so a matching
220 + // verifier must be carried in the session for the exchange.
221 + #[test]
222 + fn authorization_url_emits_challenge_and_keeps_verifier() {
223 + let auth = provider()
224 + .authorization_url("https://app.example/callback")
225 + .expect("authorization_url should succeed");
226 + assert!(auth.url.contains("code_challenge="));
227 + assert!(auth.url.contains("code_challenge_method=S256"));
228 + assert!(
229 + auth.pkce_verifier.is_some(),
230 + "verifier must be retained whenever a challenge is sent"
231 + );
232 + }
233 +
234 + // RFC 0035 §6: an error body returned with HTTP 200 must surface the raw
235 + // provider message instead of an opaque deserialization error.
236 + #[test]
237 + fn parse_github_token_surfaces_error_body() {
238 + let body = r#"{"error":"bad_verifier","error_description":"code_verifier mismatch"}"#;
239 + let err = parse_github_token(reqwest::StatusCode::OK, body)
240 + .expect_err("error body must not parse as success");
241 + let msg = err.to_string();
242 + assert!(msg.contains("code_verifier mismatch"), "got: {msg}");
243 + }
244 +
245 + #[test]
246 + fn parse_github_token_accepts_success_body() {
247 + let body = r#"{"access_token":"gho_token","token_type":"bearer"}"#;
248 + let token = parse_github_token(reqwest::StatusCode::OK, body)
249 + .expect("valid token response should parse");
250 + assert_eq!(token.access_token, "gho_token");
251 + }
252 +}
M crates/rustwarden-core/src/services/oauth/providers/google.rs
+18 -0
@@ -142,3 +142,21 @@ impl OAuthProvider for GoogleProvider {
142 142 })
143 143 }
144 144 }
145 +
146 +#[cfg(test)]
147 +mod tests {
148 + use super::*;
149 +
150 + // RFC 0035 §7.2: a code_challenge is emitted at authorization, so a matching
151 + // verifier must be retained for the exchange (delegated to `openidconnect`).
152 + #[test]
153 + fn authorization_url_emits_challenge_and_keeps_verifier() {
154 + let provider = GoogleProvider::new("client-id".to_string(), "client-secret".to_string());
155 + let auth = provider
156 + .authorization_url("https://app.example/callback")
157 + .expect("authorization_url should succeed");
158 + assert!(auth.url.contains("code_challenge="));
159 + assert!(auth.url.contains("code_challenge_method=S256"));
160 + assert!(auth.pkce_verifier.is_some());
161 + }
162 +}
M crates/rustwarden-core/src/services/oauth/providers/microsoft.rs
+19 -0
@@ -148,3 +148,22 @@ impl OAuthProvider for MicrosoftProvider {
148 148 })
149 149 }
150 150 }
151 +
152 +#[cfg(test)]
153 +mod tests {
154 + use super::*;
155 +
156 + // RFC 0035 §7.2: a code_challenge is emitted at authorization, so a matching
157 + // verifier must be retained for the exchange (delegated to `openidconnect`).
158 + #[test]
159 + fn authorization_url_emits_challenge_and_keeps_verifier() {
160 + let provider =
161 + MicrosoftProvider::new("client-id".to_string(), "client-secret".to_string(), None);
162 + let auth = provider
163 + .authorization_url("https://app.example/callback")
164 + .expect("authorization_url should succeed");
165 + assert!(auth.url.contains("code_challenge="));
166 + assert!(auth.url.contains("code_challenge_method=S256"));
167 + assert!(auth.pkce_verifier.is_some());
168 + }
169 +}
M crates/rustwarden-core/src/services/resource_service.rs
+1 -1
@@ -471,7 +471,7 @@ impl ResourceService {
471 471 .await?;
472 472
473 473 let mut all = owned;
474 - for r in shared.into_iter().chain(public.into_iter()) {
474 + for r in shared.into_iter().chain(public) {
475 475 if !all.iter().any(|existing| existing.id == r.id) {
476 476 all.push(r);
477 477 }
M crates/rustwarden-fediverse-guard/Cargo.toml
+3 -3
@@ -24,8 +24,8 @@ rustwarden-fediverse = { path = "../rustwarden-fediverse" }
24 24 tokio = { version = "1", features = ["sync", "time", "rt", "macros"] }
25 25 async-trait = "0.1"
26 26 # ORM + migrations
27 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
28 -sea-orm-migration = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
27 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
28 +sea-orm-migration = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
29 29 # Concurrent hot-path
30 30 dashmap = "6"
31 31 # Serialization
@@ -47,7 +47,7 @@ tower-sessions = { version = "0.14", optional = true }
47 47 workspace = true
48 48
49 49 [dev-dependencies]
50 -sea-orm = { version = "2.0.0-rc.20", features = ["mock"] }
50 +sea-orm = { version = "2.0.0", features = ["mock"] }
51 51 tokio = { version = "1", features = ["full", "test-util"] }
52 52
53 53 [[bin]]
M crates/rustwarden-fediverse-ui/Cargo.toml
+2 -2
@@ -17,7 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
17 17 serde_json = "1.0"
18 18 askama = "0.15"
19 19 tracing = "0.1"
20 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
20 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
21 21 uuid = { version = "1.0", features = ["v4", "serde"] }
22 22 chrono = { version = "0.4", features = ["serde"] }
23 23 tower = { version = "0.5", features = ["limit"] }
@@ -32,7 +32,7 @@ time = { version = "0.3", features = ["macros", "serde"] }
32 32 # hit); `tower/util` provides `ServiceExt::oneshot`; `serial_test` serialises
33 33 # the process-global env mutations needed to load `FediverseConfig` /
34 34 # `AuthConfig`.
35 -sea-orm = { version = "2.0.0-rc.20", features = ["mock"] }
35 +sea-orm = { version = "2.0.0", features = ["mock"] }
36 36 tower = { version = "0.5", features = ["limit", "util"] }
37 37 serial_test = "3"
38 38
M crates/rustwarden-fediverse/Cargo.toml
+3 -3
@@ -21,8 +21,8 @@ serde_json = "1.0"
21 21 # Tracing
22 22 tracing = "0.1"
23 23 # ORM
24 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
25 -sea-orm-migration = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
24 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
25 +sea-orm-migration = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
26 26 # Time & identifiers
27 27 chrono = { version = "0.4", features = ["serde"] }
28 28 uuid = { version = "1.0", features = ["v4", "serde"] }
@@ -54,7 +54,7 @@ validator = { version = "0.20", features = ["derive"] }
54 54 workspace = true
55 55
56 56 [dev-dependencies]
57 -sea-orm = { version = "2.0.0-rc.20", features = ["mock"] }
57 +sea-orm = { version = "2.0.0", features = ["mock"] }
58 58 wiremock = "0.6"
59 59 # Serialise tests that mutate process-wide environment variables
60 60 # (ENCRYPTION_KEY, OAUTH_ENCRYPTION_KEY) so async tests on `MockDatabase`
M crates/rustwarden-ui/Cargo.toml
+1 -1
@@ -22,7 +22,7 @@ askama = "0.15"
22 22 # Logging
23 23 tracing = "0.1"
24 24 # Database ORM
25 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
25 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
26 26 # UUID & Datetime
27 27 uuid = { version = "1.0", features = ["v4", "serde"] }
28 28 chrono = { version = "0.4", features = ["serde"] }
M docs/SERVICES_REFERENCE.md
+21 -2
@@ -771,11 +771,30 @@ Interface que chaque provider implemente (Google, GitHub, Discord, Microsoft).
771 771 |---------|-----------|-------------|
772 772 | `name` | `(&self) → &str` | Identifiant (`"google"`, `"github"`, `"discord"`, `"microsoft"`). |
773 773 | `display_name` | `(&self) → &str` | Nom affichable (`"Google"`, `"GitHub"`, etc.). |
774 -| `authorization_url` | `(&self, redirect_uri: &str) → Result<AuthorizationUrl>` | Genere l'URL d'autorisation avec state/nonce/PKCE. |
775 -| `exchange_code` | `(&self, code, redirect_uri, pkce_verifier, nonce) → Result<ProviderUserInfo>` | Echange le code d'autorisation contre les infos utilisateur. |
774 +| `authorization_url` | `(&self, redirect_uri: &str) → Result<AuthorizationUrl>` | Genere l'URL d'autorisation avec state CSRF, nonce (OIDC) et challenge PKCE `S256`. Le `pkce_verifier` correspondant est conserve en session. |
775 +| `exchange_code` | `(&self, code, redirect_uri, pkce_verifier, nonce) → Result<ProviderUserInfo>` | Echange le code d'autorisation contre les infos utilisateur. Le `pkce_verifier` issu de la session est **transmis au endpoint token** (obligatoire depuis que GitHub impose PKCE, cf. RFC 0035). |
776 776
777 777 **Providers implementes** : Google (OIDC complet), GitHub (OAuth2 + REST API), Discord (OAuth2 + REST API), Microsoft (Azure AD avec support tenant).
778 778
779 +#### PKCE (RFC 7636) — invariant sur les 4 providers
780 +
781 +Tous les providers emettent un `code_challenge=…&code_challenge_method=S256` a
782 +l'autorisation et **rejouent le `code_verifier` a l'echange** :
783 +
784 +- **Google** et **Microsoft** (OIDC) delèguent au crate `openidconnect` via
785 + `set_pkce_verifier(...)`.
786 +- **GitHub** et **Discord** (OAuth2 + POST `reqwest` manuel) ajoutent le champ
787 + `code_verifier` au formulaire d'echange, **uniquement s'il est present**
788 + (rétro-compatible avec un flux sans PKCE). Cf. RFC 0035 : avant ce correctif
789 + le verifier etait ignore, ce qui cassait la connexion GitHub depuis que GitHub
790 + impose PKCE (14 juillet 2025).
791 +
792 +> **Diagnostic** : GitHub/Discord renvoient leurs erreurs sous forme de corps
793 +> JSON (`{"error":…,"error_description":…}`, parfois en HTTP 200 pour GitHub).
794 +> `exchange_code` lit le corps en texte avant de le parser et remonte le message
795 +> brut du provider (`… token exchange rejected (HTTP …): …`) au lieu d'une erreur
796 +> de desserialisation opaque.
797 +
779 798 ---
780 799
781 800 ## 15. Rate limiting
A docs/rfcs/0035-oauth-pkce-code-verifier.md
+277 -0
@@ -0,0 +1,277 @@
1 +# RFC — OAuth : `code_verifier` PKCE manquant à l'échange (providers GitHub & Discord)
2 +
3 +| | |
4 +|---|---|
5 +| **Statut** | Implémenté (2026-06-18) |
6 +| **Date** | 2026-06-18 |
7 +| **Composant** | `rustwarden-core` — `src/services/oauth/providers/` |
8 +| **Auteur** | Intégrateur PasterMan (remonté depuis une instance en production) |
9 +| **Destinataires** | Mainteneurs du framework Rustwarden |
10 +| **Gravité** | Élevée — connexion OAuth GitHub **totalement cassée** en production |
11 +
12 +---
13 +
14 +## 1. Résumé (TL;DR)
15 +
16 +Les providers OAuth **GitHub** et **Discord** envoient un `code_challenge` PKCE
17 +(méthode `S256`) à l'étape d'autorisation, mais **n'envoient jamais le
18 +`code_verifier` correspondant** à l'étape d'échange du code contre un token. Le
19 +paramètre `pkce_verifier`, pourtant transmis par le handler de callback, est
20 +ignoré (`_pkce_verifier`).
21 +
22 +Depuis que **GitHub impose PKCE (14 juillet 2025)**, un `code_challenge` envoyé
23 +sans `code_verifier` est rejeté : le endpoint token renvoie un corps JSON
24 +d'erreur (sans `access_token`). Résultat côté Rustwarden :
25 +
26 +```
27 +ERROR rustwarden_core::error: Internal error: GitHub token parse failed: error decoding response body
28 +```
29 +
30 +et l'utilisateur reçoit un `500 {"error":"Internal server error"}`.
31 +
32 +Les providers **Google** et **Microsoft** ne sont **pas** affectés : ils passent
33 +par le crate `openidconnect` et appellent `set_pkce_verifier(...)` correctement.
34 +
35 +**Demande** : inclure `code_verifier` dans l'échange des providers GitHub et
36 +Discord. Correctif minime, sans changement d'API publique.
37 +
38 +---
39 +
40 +## 2. Symptôme observé en production
41 +
42 +- L'utilisateur clique « Se connecter avec GitHub ».
43 +- Redirection vers `https://github.com/login/oauth/authorize?...&code_challenge=...&code_challenge_method=S256` — OK.
44 +- Retour sur `https://<domaine>/api/v1/auth/oauth/github/callback?code=...&state=...`.
45 +- Validation du `state` CSRF : **OK** (aucune erreur « state mismatch » dans les logs).
46 +- Échange du `code` → **échec** :
47 +
48 +```
49 +DEBUG reqwest::connect: starting new connection: https://github.com/
50 +DEBUG hyper_util...: connected to 140.82.121.4:443
51 +ERROR rustwarden_core::error: Internal error: GitHub token parse failed: error decoding response body
52 +```
53 +
54 +Le message est trompeur : GitHub répond `200 OK` avec un corps du type
55 +`{"error":"...","error_description":"..."}`. Comme le code désérialise
56 +directement dans la struct de succès (`GitHubTokenResponse { access_token }`),
57 +le champ manquant produit une erreur « error decoding response body » qui
58 +**masque le vrai message d'erreur de GitHub** (voir §6).
59 +
60 +---
61 +
62 +## 3. Cause racine
63 +
64 +### 3.1. Étape d'autorisation — un `code_challenge` est émis
65 +
66 +`src/services/oauth/providers/github.rs` (`authorization_url`) :
67 +
68 +```rust
69 +// ~ligne 57
70 +let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
71 +
72 +let url = format!(
73 + "https://github.com/login/oauth/authorize?\
74 + client_id={}&redirect_uri={}&scope=user:email&state={}&\
75 + code_challenge={}&\ // ← challenge envoyé
76 + code_challenge_method=S256", // ← méthode S256
77 + ...
78 +);
79 +
80 +Ok(AuthorizationUrl {
81 + url,
82 + csrf_state: state.secret().to_string(),
83 + nonce: None,
84 + pkce_verifier: Some(pkce_verifier.secret().to_string()), // ← verifier conservé en session
85 +})
86 +```
87 +
88 +### 3.2. Le handler transmet bien le verifier
89 +
90 +`src/auth/oauth_handlers.rs` (`oauth_callback`) :
91 +
92 +```rust
93 +// ~ligne 170 : récupéré depuis la session
94 +let pkce_verifier: Option<String> = session.get(OAUTH_PKCE_KEY).await.unwrap_or(None);
95 +
96 +// ~ligne 186 : passé à l'échange
97 +let user_info = provider
98 + .exchange_code(code, &redirect_uri, pkce_verifier.as_deref(), nonce.as_deref())
99 + .await?;
100 +```
101 +
102 +### 3.3. L'échange ignore le verifier — le bug
103 +
104 +`src/services/oauth/providers/github.rs` (`exchange_code`) :
105 +
106 +```rust
107 +async fn exchange_code(
108 + &self,
109 + code: &str,
110 + _redirect_uri: &str,
111 + _pkce_verifier: Option<&str>, // ← reçu mais IGNORÉ (préfixe _)
112 + _nonce: Option<&str>,
113 +) -> Result<ProviderUserInfo, AppError> {
114 + let http = reqwest::Client::new();
115 +
116 + let token_resp = http
117 + .post("https://github.com/login/oauth/access_token")
118 + .header("Accept", "application/json")
119 + .form(&[
120 + ("client_id", self.client_id.as_str()),
121 + ("client_secret", self.client_secret.as_str()),
122 + ("code", code),
123 + // ← MANQUE: ("code_verifier", verifier)
124 + ])
125 + .send().await?
126 + .json::<GitHubTokenResponse>().await?; // ← échoue ici quand GitHub renvoie une erreur
127 + ...
128 +}
129 +```
130 +
131 +### 3.4. Pourquoi maintenant
132 +
133 +GitHub a généralisé la prise en charge de PKCE le **14 juillet 2025**
134 +(cf. §9). Auparavant, un `code_challenge` envoyé était ignoré, et l'échange
135 +sans `code_verifier` réussissait. Désormais, le code d'autorisation est lié au
136 +challenge et l'échange **exige** le verifier ; son absence provoque le rejet.
137 +C'est une **régression côté serveur GitHub** qui révèle un défaut latent du
138 +provider.
139 +
140 +---
141 +
142 +## 4. Périmètre — providers concernés
143 +
144 +| Provider | Fichier | `code_challenge` à l'autorisation | `code_verifier` à l'échange | État |
145 +|---|---|:--:|:--:|:--:|
146 +| **GitHub** | `providers/github.rs` | oui (`~l.65`) | **non** (`_pkce_verifier`, `~l.85`) | ❌ |
147 +| **Discord** | `providers/discord.rs` | oui (`~l.61`) | **non** (`_pkce_verifier`, `~l.81`) | ❌ |
148 +| Google | `providers/google.rs` | oui (`~l.48`) | oui (`set_pkce_verifier`, `~l.100`) | ✅ |
149 +| Microsoft | `providers/microsoft.rs` | oui (`~l.50`) | oui (`set_pkce_verifier`, `~l.106`) | ✅ |
150 +
151 +**Différence structurelle** : Google et Microsoft sont des providers OIDC qui
152 +délèguent l'échange au crate `openidconnect`
153 +(`token_request.set_pkce_verifier(PkceCodeVerifier::new(verifier))`). GitHub et
154 +Discord construisent **manuellement** un POST `reqwest` et ont omis le paramètre.
155 +
156 +Discord applique également PKCE lorsqu'un challenge est fourni ; le provider
157 +Discord est donc cassé de la même manière (ou le deviendra), même si ce RFC est
158 +motivé par GitHub.
159 +
160 +---
161 +
162 +## 5. Correctif proposé
163 +
164 +Ajouter `code_verifier` au formulaire d'échange, **uniquement s'il est présent**
165 +(rétro-compatible avec un flux sans PKCE), pour `github.rs` et `discord.rs`.
166 +
167 +### 5.1. `providers/github.rs`
168 +
169 +```rust
170 +async fn exchange_code(
171 + &self,
172 + code: &str,
173 + _redirect_uri: &str,
174 + pkce_verifier: Option<&str>, // était: _pkce_verifier
175 + _nonce: Option<&str>,
176 +) -> Result<ProviderUserInfo, AppError> {
177 + let http = reqwest::Client::new();
178 +
179 + let mut form = vec![
180 + ("client_id", self.client_id.as_str()),
181 + ("client_secret", self.client_secret.as_str()),
182 + ("code", code),
183 + ];
184 + if let Some(verifier) = pkce_verifier {
185 + form.push(("code_verifier", verifier)); // ← pièce manquante
186 + }
187 +
188 + let token_resp = http
189 + .post("https://github.com/login/oauth/access_token")
190 + .header("Accept", "application/json")
191 + .form(&form)
192 + .send().await
193 + .map_err(|e| AppError::Internal(format!("GitHub token exchange failed: {}", e)))?
194 + .json::<GitHubTokenResponse>().await
195 + .map_err(|e| AppError::Internal(format!("GitHub token parse failed: {}", e)))?;
196 + // ... reste inchangé
197 +}
198 +```
199 +
200 +### 5.2. `providers/discord.rs`
201 +
202 +Même correction : dé-préfixer `_pkce_verifier` → `pkce_verifier` et l'ajouter au
203 +formulaire de la requête `POST https://discord.com/api/oauth2/token` sous la clé
204 +`code_verifier` quand il est présent.
205 +
206 +---
207 +
208 +## 6. Amélioration secondaire recommandée (qualité de diagnostic)
209 +
210 +Indépendamment du PKCE, l'échange désérialise **directement** la réponse dans la
211 +struct de succès, ce qui **efface le message d'erreur du provider** et rend tout
212 +incident illisible (« error decoding response body »). Recommandation : lire le
213 +corps en texte d'abord, et remonter l'erreur OAuth structurée.
214 +
215 +```rust
216 +let status = resp.status();
217 +let body = resp.text().await
218 + .map_err(|e| AppError::Internal(format!("GitHub token read failed: {e}")))?;
219 +
220 +match serde_json::from_str::<GitHubTokenResponse>(&body) {
221 + Ok(t) => t,
222 + Err(_) => {
223 + // GitHub renvoie {"error":"...","error_description":"..."} en HTTP 200
224 + return Err(AppError::Internal(format!(
225 + "GitHub token exchange rejected (HTTP {status}): {body}"
226 + )));
227 + }
228 +}
229 +```
230 +
231 +Cela aurait fait apparaître directement dans les logs, par exemple,
232 +`{"error":"...","error_description":"... code_verifier ..."}` au lieu d'un
233 +message générique — divisant par dix le temps de diagnostic.
234 +
235 +---
236 +
237 +## 7. Tests recommandés
238 +
239 +1. **Test unitaire d'échange** : vérifier que le formulaire POST contient
240 + `code_verifier` lorsque `exchange_code` reçoit `Some(verifier)`, et qu'il ne
241 + le contient pas pour `None` (mock du endpoint token via `wiremock`).
242 +2. **Test de non-régression PKCE** : pour les 4 providers, garantir qu'un
243 + `code_challenge` émis à l'autorisation est toujours accompagné d'un
244 + `code_verifier` à l'échange (invariant testé directement).
245 +3. **Test d'intégration GitHub** (manuel/CI gated) : flux complet sur une OAuth
246 + App de test → obtention d'un `access_token`.
247 +
248 +---
249 +
250 +## 8. Compatibilité et risques
251 +
252 +- **API publique** : inchangée. La signature du trait `OAuthProvider` n'est pas
253 + modifiée ; seul le corps de `exchange_code` change (un `_pkce_verifier`
254 + jusque-là ignoré devient utilisé).
255 +- **Rétro-compatibilité** : l'ajout est conditionné par `if let Some(verifier)`,
256 + donc un déploiement sans PKCE (verifier `None`) se comporte comme avant.
257 +- **Sécurité** : envoyer le `code_verifier` est précisément le comportement PKCE
258 + attendu (RFC 7636) ; cela **renforce** la sécurité du flux (protection contre
259 + l'interception du code d'autorisation).
260 +- **Risque de ne rien faire** : connexion GitHub définitivement cassée pour tous
261 + les intégrateurs à jour des changements GitHub ; Discord cassé de même.
262 +
263 +---
264 +
265 +## 9. Références
266 +
267 +- GitHub Changelog — *PKCE support for OAuth and GitHub App authentication*
268 + (14 juillet 2025) :
269 + https://github.blog/changelog/2025-07-14-pkce-support-for-oauth-and-github-app-authentication/
270 +- RFC 7636 — *Proof Key for Code Exchange by OAuth Public Clients* :
271 + https://www.rfc-editor.org/rfc/rfc7636
272 +- Fichiers concernés (chemins relatifs au crate `rustwarden-core`) :
273 + - `src/services/oauth/providers/github.rs` — `authorization_url`, `exchange_code`
274 + - `src/services/oauth/providers/discord.rs` — `authorization_url`, `exchange_code`
275 + - `src/services/oauth/providers/google.rs` — référence d'implémentation correcte
276 + - `src/services/oauth/providers/microsoft.rs` — référence d'implémentation correcte
277 + - `src/auth/oauth_handlers.rs` — `oauth_callback` (transmet `pkce_verifier`)
M template/Cargo.toml
+1 -1
@@ -13,7 +13,7 @@ rustwarden-core = { git = "https://github.com/OWNER/rustwarden.git", path = "cra
13 13 rustwarden-ui = { git = "https://github.com/OWNER/rustwarden.git", path = "crates/rustwarden-ui" }
14 14 axum = { version = "0.8", features = ["macros"] }
15 15 tokio = { version = "1", features = ["full"] }
16 -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
16 +sea-orm = { version = "2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
17 17 tracing = "0.1"
18 18 anyhow = "1.0"
19 19 async-trait = "0.1"
M tools/rustwarden-cli/src/templates.rs
+2 -2
@@ -160,7 +160,7 @@ resolver = "2"
160 160
161 161 [workspace.package]
162 162 edition = "2024"
163 -rust-version = "1.85"
163 +rust-version = "1.94"
164 164
165 165 [workspace.lints.clippy]
166 166 empty_line_after_doc_comments = "allow"
@@ -182,7 +182,7 @@ path = "src/main.rs"
182 182 rustwarden-core = {{ path = "crates/rustwarden-core" }}{ui_dep}{fediverse_dep}{fediverse_ui_dep}
183 183 axum = {{ version = "0.8", features = ["macros"] }}
184 184 tokio = {{ version = "1", features = ["full"] }}
185 -sea-orm = {{ version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }}
185 +sea-orm = {{ version = "=2.0.0", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"] }}
186 186 tracing = "0.1"
187 187 anyhow = "1.0"
188 188 async-trait = "0.1"