diff options
Diffstat (limited to 'rs')
| -rw-r--r-- | rs/.gitignore | 1 | ||||
| -rw-r--r-- | rs/Cargo.lock | 2364 | ||||
| -rw-r--r-- | rs/Cargo.toml | 8 | ||||
| -rw-r--r-- | rs/common/Cargo.toml | 10 | ||||
| -rw-r--r-- | rs/common/src/lib.rs | 368 | ||||
| -rw-r--r-- | rs/git-lfs-authenticate/Cargo.toml | 8 | ||||
| -rw-r--r-- | rs/git-lfs-authenticate/src/main.rs | 236 | ||||
| -rw-r--r-- | rs/server/Cargo.toml | 19 | ||||
| -rw-r--r-- | rs/server/src/main.rs | 1028 | ||||
| -rw-r--r-- | rs/shell/Cargo.toml | 6 | ||||
| -rw-r--r-- | rs/shell/src/main.rs | 143 |
11 files changed, 0 insertions, 4191 deletions
diff --git a/rs/.gitignore b/rs/.gitignore deleted file mode 100644 index b83d222..0000000 --- a/rs/.gitignore +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | /target/ | ||
diff --git a/rs/Cargo.lock b/rs/Cargo.lock deleted file mode 100644 index f3beb9e..0000000 --- a/rs/Cargo.lock +++ /dev/null | |||
| @@ -1,2364 +0,0 @@ | |||
| 1 | # This file is automatically @generated by Cargo. | ||
| 2 | # It is not intended for manual editing. | ||
| 3 | version = 3 | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "addr2line" | ||
| 7 | version = "0.21.0" | ||
| 8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" | ||
| 10 | dependencies = [ | ||
| 11 | "gimli", | ||
| 12 | ] | ||
| 13 | |||
| 14 | [[package]] | ||
| 15 | name = "adler" | ||
| 16 | version = "1.0.2" | ||
| 17 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | ||
| 19 | |||
| 20 | [[package]] | ||
| 21 | name = "aho-corasick" | ||
| 22 | version = "1.1.2" | ||
| 23 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 24 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" | ||
| 25 | dependencies = [ | ||
| 26 | "memchr", | ||
| 27 | ] | ||
| 28 | |||
| 29 | [[package]] | ||
| 30 | name = "android-tzdata" | ||
| 31 | version = "0.1.1" | ||
| 32 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 33 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" | ||
| 34 | |||
| 35 | [[package]] | ||
| 36 | name = "android_system_properties" | ||
| 37 | version = "0.1.5" | ||
| 38 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 39 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | ||
| 40 | dependencies = [ | ||
| 41 | "libc", | ||
| 42 | ] | ||
| 43 | |||
| 44 | [[package]] | ||
| 45 | name = "async-trait" | ||
| 46 | version = "0.1.77" | ||
| 47 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 48 | checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" | ||
| 49 | dependencies = [ | ||
| 50 | "proc-macro2", | ||
| 51 | "quote", | ||
| 52 | "syn", | ||
| 53 | ] | ||
| 54 | |||
| 55 | [[package]] | ||
| 56 | name = "autocfg" | ||
| 57 | version = "1.1.0" | ||
| 58 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 59 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" | ||
| 60 | |||
| 61 | [[package]] | ||
| 62 | name = "aws-config" | ||
| 63 | version = "1.1.2" | ||
| 64 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 65 | checksum = "7e64b72d4bdbb41a73d27709c65a25b6e4bfc8321bf70fa3a8b19ce7d4eb81b0" | ||
| 66 | dependencies = [ | ||
| 67 | "aws-credential-types", | ||
| 68 | "aws-http", | ||
| 69 | "aws-runtime", | ||
| 70 | "aws-sdk-sso", | ||
| 71 | "aws-sdk-ssooidc", | ||
| 72 | "aws-sdk-sts", | ||
| 73 | "aws-smithy-async", | ||
| 74 | "aws-smithy-http", | ||
| 75 | "aws-smithy-json", | ||
| 76 | "aws-smithy-runtime", | ||
| 77 | "aws-smithy-runtime-api", | ||
| 78 | "aws-smithy-types", | ||
| 79 | "aws-types", | ||
| 80 | "bytes", | ||
| 81 | "fastrand", | ||
| 82 | "hex", | ||
| 83 | "http 0.2.11", | ||
| 84 | "hyper 0.14.28", | ||
| 85 | "ring", | ||
| 86 | "time", | ||
| 87 | "tokio", | ||
| 88 | "tracing", | ||
| 89 | "zeroize", | ||
| 90 | ] | ||
| 91 | |||
| 92 | [[package]] | ||
| 93 | name = "aws-credential-types" | ||
| 94 | version = "1.1.2" | ||
| 95 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 96 | checksum = "4a7cb3510b95492bd9014b60e2e3bee3e48bc516e220316f8e6b60df18b47331" | ||
| 97 | dependencies = [ | ||
| 98 | "aws-smithy-async", | ||
| 99 | "aws-smithy-runtime-api", | ||
| 100 | "aws-smithy-types", | ||
| 101 | "zeroize", | ||
| 102 | ] | ||
| 103 | |||
| 104 | [[package]] | ||
| 105 | name = "aws-http" | ||
| 106 | version = "0.60.2" | ||
| 107 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 108 | checksum = "a95d41abe4e941399fdb4bc2f54713eac3c839d98151875948bb24e66ab658f2" | ||
| 109 | dependencies = [ | ||
| 110 | "aws-smithy-runtime-api", | ||
| 111 | "aws-smithy-types", | ||
| 112 | "aws-types", | ||
| 113 | "bytes", | ||
| 114 | "http 0.2.11", | ||
| 115 | "http-body 0.4.6", | ||
| 116 | "pin-project-lite", | ||
| 117 | "tracing", | ||
| 118 | ] | ||
| 119 | |||
| 120 | [[package]] | ||
| 121 | name = "aws-runtime" | ||
| 122 | version = "1.1.2" | ||
| 123 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 124 | checksum = "233cca219c6705d525ace011d6f9bc51aaf32fce5b4c41661d2d7ff22d9b4d49" | ||
| 125 | dependencies = [ | ||
| 126 | "aws-credential-types", | ||
| 127 | "aws-http", | ||
| 128 | "aws-sigv4", | ||
| 129 | "aws-smithy-async", | ||
| 130 | "aws-smithy-eventstream", | ||
| 131 | "aws-smithy-http", | ||
| 132 | "aws-smithy-runtime-api", | ||
| 133 | "aws-smithy-types", | ||
| 134 | "aws-types", | ||
| 135 | "fastrand", | ||
| 136 | "http 0.2.11", | ||
| 137 | "percent-encoding", | ||
| 138 | "tracing", | ||
| 139 | "uuid", | ||
| 140 | ] | ||
| 141 | |||
| 142 | [[package]] | ||
| 143 | name = "aws-sdk-s3" | ||
| 144 | version = "1.12.0" | ||
| 145 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 146 | checksum = "634fbe5b6591ee2e281cd2ba8641e9bd752dbf5bf338924d6ad4bd5a3304fe31" | ||
| 147 | dependencies = [ | ||
| 148 | "aws-credential-types", | ||
| 149 | "aws-http", | ||
| 150 | "aws-runtime", | ||
| 151 | "aws-sigv4", | ||
| 152 | "aws-smithy-async", | ||
| 153 | "aws-smithy-checksums", | ||
| 154 | "aws-smithy-eventstream", | ||
| 155 | "aws-smithy-http", | ||
| 156 | "aws-smithy-json", | ||
| 157 | "aws-smithy-runtime", | ||
| 158 | "aws-smithy-runtime-api", | ||
| 159 | "aws-smithy-types", | ||
| 160 | "aws-smithy-xml", | ||
| 161 | "aws-types", | ||
| 162 | "bytes", | ||
| 163 | "http 0.2.11", | ||
| 164 | "http-body 0.4.6", | ||
| 165 | "once_cell", | ||
| 166 | "percent-encoding", | ||
| 167 | "regex-lite", | ||
| 168 | "tracing", | ||
| 169 | "url", | ||
| 170 | ] | ||
| 171 | |||
| 172 | [[package]] | ||
| 173 | name = "aws-sdk-sso" | ||
| 174 | version = "1.10.0" | ||
| 175 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 176 | checksum = "ee41005e0f3a19ae749c7953d9e1f1ef8d2183f76f64966e346fa41c1ba0ed44" | ||
| 177 | dependencies = [ | ||
| 178 | "aws-credential-types", | ||
| 179 | "aws-http", | ||
| 180 | "aws-runtime", | ||
| 181 | "aws-smithy-async", | ||
| 182 | "aws-smithy-http", | ||
| 183 | "aws-smithy-json", | ||
| 184 | "aws-smithy-runtime", | ||
| 185 | "aws-smithy-runtime-api", | ||
| 186 | "aws-smithy-types", | ||
| 187 | "aws-types", | ||
| 188 | "bytes", | ||
| 189 | "http 0.2.11", | ||
| 190 | "once_cell", | ||
| 191 | "regex-lite", | ||
| 192 | "tracing", | ||
| 193 | ] | ||
| 194 | |||
| 195 | [[package]] | ||
| 196 | name = "aws-sdk-ssooidc" | ||
| 197 | version = "1.10.0" | ||
| 198 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 199 | checksum = "fa08168f8a27505e7b90f922c32a489feb1f2133878981a15138bebc849ac09c" | ||
| 200 | dependencies = [ | ||
| 201 | "aws-credential-types", | ||
| 202 | "aws-http", | ||
| 203 | "aws-runtime", | ||
| 204 | "aws-smithy-async", | ||
| 205 | "aws-smithy-http", | ||
| 206 | "aws-smithy-json", | ||
| 207 | "aws-smithy-runtime", | ||
| 208 | "aws-smithy-runtime-api", | ||
| 209 | "aws-smithy-types", | ||
| 210 | "aws-types", | ||
| 211 | "bytes", | ||
| 212 | "http 0.2.11", | ||
| 213 | "once_cell", | ||
| 214 | "regex-lite", | ||
| 215 | "tracing", | ||
| 216 | ] | ||
| 217 | |||
| 218 | [[package]] | ||
| 219 | name = "aws-sdk-sts" | ||
| 220 | version = "1.10.0" | ||
| 221 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 222 | checksum = "29102eff04d50ef70f11a48823db33e33c6cc5f027bfb6ff4864efbd5f1f66f3" | ||
| 223 | dependencies = [ | ||
| 224 | "aws-credential-types", | ||
| 225 | "aws-http", | ||
| 226 | "aws-runtime", | ||
| 227 | "aws-smithy-async", | ||
| 228 | "aws-smithy-http", | ||
| 229 | "aws-smithy-json", | ||
| 230 | "aws-smithy-query", | ||
| 231 | "aws-smithy-runtime", | ||
| 232 | "aws-smithy-runtime-api", | ||
| 233 | "aws-smithy-types", | ||
| 234 | "aws-smithy-xml", | ||
| 235 | "aws-types", | ||
| 236 | "http 0.2.11", | ||
| 237 | "once_cell", | ||
| 238 | "regex-lite", | ||
| 239 | "tracing", | ||
| 240 | ] | ||
| 241 | |||
| 242 | [[package]] | ||
| 243 | name = "aws-sigv4" | ||
| 244 | version = "1.1.2" | ||
| 245 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 246 | checksum = "b92384b39aedb258aa734fe0e7b2ffcd13f33e68227251a72cd2635e0acc8f1a" | ||
| 247 | dependencies = [ | ||
| 248 | "aws-credential-types", | ||
| 249 | "aws-smithy-eventstream", | ||
| 250 | "aws-smithy-http", | ||
| 251 | "aws-smithy-runtime-api", | ||
| 252 | "aws-smithy-types", | ||
| 253 | "bytes", | ||
| 254 | "crypto-bigint 0.5.5", | ||
| 255 | "form_urlencoded", | ||
| 256 | "hex", | ||
| 257 | "hmac", | ||
| 258 | "http 0.2.11", | ||
| 259 | "once_cell", | ||
| 260 | "p256", | ||
| 261 | "percent-encoding", | ||
| 262 | "ring", | ||
| 263 | "sha2", | ||
| 264 | "subtle", | ||
| 265 | "time", | ||
| 266 | "tracing", | ||
| 267 | "zeroize", | ||
| 268 | ] | ||
| 269 | |||
| 270 | [[package]] | ||
| 271 | name = "aws-smithy-async" | ||
| 272 | version = "1.1.3" | ||
| 273 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 274 | checksum = "2eac0bb78e9e2765699999a02d7bfb4e6ad8f13e0962ebb9f5202b1d8cd76006" | ||
| 275 | dependencies = [ | ||
| 276 | "futures-util", | ||
| 277 | "pin-project-lite", | ||
| 278 | "tokio", | ||
| 279 | ] | ||
| 280 | |||
| 281 | [[package]] | ||
| 282 | name = "aws-smithy-checksums" | ||
| 283 | version = "0.60.3" | ||
| 284 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 285 | checksum = "535a2d5f1e459bc7709580a77152c8d493982db083236c2b1d1c51dc6217e8a3" | ||
| 286 | dependencies = [ | ||
| 287 | "aws-smithy-http", | ||
| 288 | "aws-smithy-types", | ||
| 289 | "bytes", | ||
| 290 | "crc32c", | ||
| 291 | "crc32fast", | ||
| 292 | "hex", | ||
| 293 | "http 0.2.11", | ||
| 294 | "http-body 0.4.6", | ||
| 295 | "md-5", | ||
| 296 | "pin-project-lite", | ||
| 297 | "sha1", | ||
| 298 | "sha2", | ||
| 299 | "tracing", | ||
| 300 | ] | ||
| 301 | |||
| 302 | [[package]] | ||
| 303 | name = "aws-smithy-eventstream" | ||
| 304 | version = "0.60.3" | ||
| 305 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 306 | checksum = "682371561562d08ab437766903c6bc28f4f95d7ab2ecfb389bda7849dd98aefe" | ||
| 307 | dependencies = [ | ||
| 308 | "aws-smithy-types", | ||
| 309 | "bytes", | ||
| 310 | "crc32fast", | ||
| 311 | ] | ||
| 312 | |||
| 313 | [[package]] | ||
| 314 | name = "aws-smithy-http" | ||
| 315 | version = "0.60.3" | ||
| 316 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 317 | checksum = "365ca49744b2bda2f1e2dc03b856da3fa5a28ca5b0a41e41d7ff5305a8fae190" | ||
| 318 | dependencies = [ | ||
| 319 | "aws-smithy-eventstream", | ||
| 320 | "aws-smithy-runtime-api", | ||
| 321 | "aws-smithy-types", | ||
| 322 | "bytes", | ||
| 323 | "bytes-utils", | ||
| 324 | "futures-core", | ||
| 325 | "http 0.2.11", | ||
| 326 | "http-body 0.4.6", | ||
| 327 | "once_cell", | ||
| 328 | "percent-encoding", | ||
| 329 | "pin-project-lite", | ||
| 330 | "pin-utils", | ||
| 331 | "tracing", | ||
| 332 | ] | ||
| 333 | |||
| 334 | [[package]] | ||
| 335 | name = "aws-smithy-json" | ||
| 336 | version = "0.60.3" | ||
| 337 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 338 | checksum = "733ccdb727ac63370836aa3b3c483d75ad2ef7bc6507db3efe1d01e8d2e50367" | ||
| 339 | dependencies = [ | ||
| 340 | "aws-smithy-types", | ||
| 341 | ] | ||
| 342 | |||
| 343 | [[package]] | ||
| 344 | name = "aws-smithy-query" | ||
| 345 | version = "0.60.3" | ||
| 346 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 347 | checksum = "aff02ae2ee7968bbce2983ffb5ce529d24f4848532300f398347bde8c2196974" | ||
| 348 | dependencies = [ | ||
| 349 | "aws-smithy-types", | ||
| 350 | "urlencoding", | ||
| 351 | ] | ||
| 352 | |||
| 353 | [[package]] | ||
| 354 | name = "aws-smithy-runtime" | ||
| 355 | version = "1.1.3" | ||
| 356 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 357 | checksum = "6ab9cb6fee50680af8ceaa293ae79eba32095ca117161cb323f9ee30dd87d139" | ||
| 358 | dependencies = [ | ||
| 359 | "aws-smithy-async", | ||
| 360 | "aws-smithy-http", | ||
| 361 | "aws-smithy-runtime-api", | ||
| 362 | "aws-smithy-types", | ||
| 363 | "bytes", | ||
| 364 | "fastrand", | ||
| 365 | "h2 0.3.24", | ||
| 366 | "http 0.2.11", | ||
| 367 | "http-body 0.4.6", | ||
| 368 | "hyper 0.14.28", | ||
| 369 | "hyper-rustls", | ||
| 370 | "once_cell", | ||
| 371 | "pin-project-lite", | ||
| 372 | "pin-utils", | ||
| 373 | "rustls", | ||
| 374 | "tokio", | ||
| 375 | "tracing", | ||
| 376 | ] | ||
| 377 | |||
| 378 | [[package]] | ||
| 379 | name = "aws-smithy-runtime-api" | ||
| 380 | version = "1.1.3" | ||
| 381 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 382 | checksum = "02ca2da7619517310bfead6d18abcdde90f1439224d887d608503cfacff46dff" | ||
| 383 | dependencies = [ | ||
| 384 | "aws-smithy-async", | ||
| 385 | "aws-smithy-types", | ||
| 386 | "bytes", | ||
| 387 | "http 0.2.11", | ||
| 388 | "pin-project-lite", | ||
| 389 | "tokio", | ||
| 390 | "tracing", | ||
| 391 | "zeroize", | ||
| 392 | ] | ||
| 393 | |||
| 394 | [[package]] | ||
| 395 | name = "aws-smithy-types" | ||
| 396 | version = "1.1.3" | ||
| 397 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 398 | checksum = "5d4bb944488536cd2fef43212d829bc7e9a8bfc4afa079d21170441e7be8d2d0" | ||
| 399 | dependencies = [ | ||
| 400 | "base64-simd", | ||
| 401 | "bytes", | ||
| 402 | "bytes-utils", | ||
| 403 | "futures-core", | ||
| 404 | "http 0.2.11", | ||
| 405 | "http-body 0.4.6", | ||
| 406 | "itoa", | ||
| 407 | "num-integer", | ||
| 408 | "pin-project-lite", | ||
| 409 | "pin-utils", | ||
| 410 | "ryu", | ||
| 411 | "serde", | ||
| 412 | "time", | ||
| 413 | "tokio", | ||
| 414 | "tokio-util", | ||
| 415 | ] | ||
| 416 | |||
| 417 | [[package]] | ||
| 418 | name = "aws-smithy-xml" | ||
| 419 | version = "0.60.3" | ||
| 420 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 421 | checksum = "ef796feaf894d7fd03869235237aeffe73ed1b29a3927cceeee2eecadf876eba" | ||
| 422 | dependencies = [ | ||
| 423 | "xmlparser", | ||
| 424 | ] | ||
| 425 | |||
| 426 | [[package]] | ||
| 427 | name = "aws-types" | ||
| 428 | version = "1.1.2" | ||
| 429 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 430 | checksum = "8549aa62c5b7db5c57ab915200ee214b4f5d8f19b29a4a8fa0b3ad3bca1380e3" | ||
| 431 | dependencies = [ | ||
| 432 | "aws-credential-types", | ||
| 433 | "aws-smithy-async", | ||
| 434 | "aws-smithy-runtime-api", | ||
| 435 | "aws-smithy-types", | ||
| 436 | "http 0.2.11", | ||
| 437 | "rustc_version", | ||
| 438 | "tracing", | ||
| 439 | ] | ||
| 440 | |||
| 441 | [[package]] | ||
| 442 | name = "axum" | ||
| 443 | version = "0.7.4" | ||
| 444 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 445 | checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" | ||
| 446 | dependencies = [ | ||
| 447 | "async-trait", | ||
| 448 | "axum-core", | ||
| 449 | "bytes", | ||
| 450 | "futures-util", | ||
| 451 | "http 1.0.0", | ||
| 452 | "http-body 1.0.0", | ||
| 453 | "http-body-util", | ||
| 454 | "hyper 1.1.0", | ||
| 455 | "hyper-util", | ||
| 456 | "itoa", | ||
| 457 | "matchit", | ||
| 458 | "memchr", | ||
| 459 | "mime", | ||
| 460 | "percent-encoding", | ||
| 461 | "pin-project-lite", | ||
| 462 | "rustversion", | ||
| 463 | "serde", | ||
| 464 | "serde_json", | ||
| 465 | "serde_path_to_error", | ||
| 466 | "serde_urlencoded", | ||
| 467 | "sync_wrapper", | ||
| 468 | "tokio", | ||
| 469 | "tower", | ||
| 470 | "tower-layer", | ||
| 471 | "tower-service", | ||
| 472 | "tracing", | ||
| 473 | ] | ||
| 474 | |||
| 475 | [[package]] | ||
| 476 | name = "axum-core" | ||
| 477 | version = "0.4.3" | ||
| 478 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 479 | checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" | ||
| 480 | dependencies = [ | ||
| 481 | "async-trait", | ||
| 482 | "bytes", | ||
| 483 | "futures-util", | ||
| 484 | "http 1.0.0", | ||
| 485 | "http-body 1.0.0", | ||
| 486 | "http-body-util", | ||
| 487 | "mime", | ||
| 488 | "pin-project-lite", | ||
| 489 | "rustversion", | ||
| 490 | "sync_wrapper", | ||
| 491 | "tower-layer", | ||
| 492 | "tower-service", | ||
| 493 | "tracing", | ||
| 494 | ] | ||
| 495 | |||
| 496 | [[package]] | ||
| 497 | name = "backtrace" | ||
| 498 | version = "0.3.69" | ||
| 499 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 500 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" | ||
| 501 | dependencies = [ | ||
| 502 | "addr2line", | ||
| 503 | "cc", | ||
| 504 | "cfg-if", | ||
| 505 | "libc", | ||
| 506 | "miniz_oxide", | ||
| 507 | "object", | ||
| 508 | "rustc-demangle", | ||
| 509 | ] | ||
| 510 | |||
| 511 | [[package]] | ||
| 512 | name = "base16ct" | ||
| 513 | version = "0.1.1" | ||
| 514 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 515 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" | ||
| 516 | |||
| 517 | [[package]] | ||
| 518 | name = "base64" | ||
| 519 | version = "0.21.7" | ||
| 520 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 521 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" | ||
| 522 | |||
| 523 | [[package]] | ||
| 524 | name = "base64-simd" | ||
| 525 | version = "0.8.0" | ||
| 526 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 527 | checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" | ||
| 528 | dependencies = [ | ||
| 529 | "outref", | ||
| 530 | "vsimd", | ||
| 531 | ] | ||
| 532 | |||
| 533 | [[package]] | ||
| 534 | name = "base64ct" | ||
| 535 | version = "1.6.0" | ||
| 536 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 537 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" | ||
| 538 | |||
| 539 | [[package]] | ||
| 540 | name = "bitflags" | ||
| 541 | version = "1.3.2" | ||
| 542 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 543 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||
| 544 | |||
| 545 | [[package]] | ||
| 546 | name = "block-buffer" | ||
| 547 | version = "0.10.4" | ||
| 548 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 549 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" | ||
| 550 | dependencies = [ | ||
| 551 | "generic-array", | ||
| 552 | ] | ||
| 553 | |||
| 554 | [[package]] | ||
| 555 | name = "bumpalo" | ||
| 556 | version = "3.14.0" | ||
| 557 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 558 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" | ||
| 559 | |||
| 560 | [[package]] | ||
| 561 | name = "bytes" | ||
| 562 | version = "1.5.0" | ||
| 563 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 564 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" | ||
| 565 | |||
| 566 | [[package]] | ||
| 567 | name = "bytes-utils" | ||
| 568 | version = "0.1.4" | ||
| 569 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 570 | checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" | ||
| 571 | dependencies = [ | ||
| 572 | "bytes", | ||
| 573 | "either", | ||
| 574 | ] | ||
| 575 | |||
| 576 | [[package]] | ||
| 577 | name = "cc" | ||
| 578 | version = "1.0.83" | ||
| 579 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 580 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" | ||
| 581 | dependencies = [ | ||
| 582 | "libc", | ||
| 583 | ] | ||
| 584 | |||
| 585 | [[package]] | ||
| 586 | name = "cfg-if" | ||
| 587 | version = "1.0.0" | ||
| 588 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 589 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||
| 590 | |||
| 591 | [[package]] | ||
| 592 | name = "chrono" | ||
| 593 | version = "0.4.31" | ||
| 594 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 595 | checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" | ||
| 596 | dependencies = [ | ||
| 597 | "android-tzdata", | ||
| 598 | "iana-time-zone", | ||
| 599 | "js-sys", | ||
| 600 | "num-traits", | ||
| 601 | "serde", | ||
| 602 | "wasm-bindgen", | ||
| 603 | "windows-targets 0.48.5", | ||
| 604 | ] | ||
| 605 | |||
| 606 | [[package]] | ||
| 607 | name = "common" | ||
| 608 | version = "0.1.0" | ||
| 609 | dependencies = [ | ||
| 610 | "chrono", | ||
| 611 | "hmac-sha256", | ||
| 612 | "serde", | ||
| 613 | "subtle", | ||
| 614 | ] | ||
| 615 | |||
| 616 | [[package]] | ||
| 617 | name = "const-oid" | ||
| 618 | version = "0.9.6" | ||
| 619 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 620 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" | ||
| 621 | |||
| 622 | [[package]] | ||
| 623 | name = "core-foundation" | ||
| 624 | version = "0.9.4" | ||
| 625 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 626 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" | ||
| 627 | dependencies = [ | ||
| 628 | "core-foundation-sys", | ||
| 629 | "libc", | ||
| 630 | ] | ||
| 631 | |||
| 632 | [[package]] | ||
| 633 | name = "core-foundation-sys" | ||
| 634 | version = "0.8.6" | ||
| 635 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 636 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" | ||
| 637 | |||
| 638 | [[package]] | ||
| 639 | name = "cpufeatures" | ||
| 640 | version = "0.2.12" | ||
| 641 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 642 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" | ||
| 643 | dependencies = [ | ||
| 644 | "libc", | ||
| 645 | ] | ||
| 646 | |||
| 647 | [[package]] | ||
| 648 | name = "crc32c" | ||
| 649 | version = "0.6.4" | ||
| 650 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 651 | checksum = "d8f48d60e5b4d2c53d5c2b1d8a58c849a70ae5e5509b08a48d047e3b65714a74" | ||
| 652 | dependencies = [ | ||
| 653 | "rustc_version", | ||
| 654 | ] | ||
| 655 | |||
| 656 | [[package]] | ||
| 657 | name = "crc32fast" | ||
| 658 | version = "1.3.2" | ||
| 659 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 660 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" | ||
| 661 | dependencies = [ | ||
| 662 | "cfg-if", | ||
| 663 | ] | ||
| 664 | |||
| 665 | [[package]] | ||
| 666 | name = "crypto-bigint" | ||
| 667 | version = "0.4.9" | ||
| 668 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 669 | checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" | ||
| 670 | dependencies = [ | ||
| 671 | "generic-array", | ||
| 672 | "rand_core", | ||
| 673 | "subtle", | ||
| 674 | "zeroize", | ||
| 675 | ] | ||
| 676 | |||
| 677 | [[package]] | ||
| 678 | name = "crypto-bigint" | ||
| 679 | version = "0.5.5" | ||
| 680 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 681 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" | ||
| 682 | dependencies = [ | ||
| 683 | "rand_core", | ||
| 684 | "subtle", | ||
| 685 | ] | ||
| 686 | |||
| 687 | [[package]] | ||
| 688 | name = "crypto-common" | ||
| 689 | version = "0.1.6" | ||
| 690 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 691 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" | ||
| 692 | dependencies = [ | ||
| 693 | "generic-array", | ||
| 694 | "typenum", | ||
| 695 | ] | ||
| 696 | |||
| 697 | [[package]] | ||
| 698 | name = "der" | ||
| 699 | version = "0.6.1" | ||
| 700 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 701 | checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" | ||
| 702 | dependencies = [ | ||
| 703 | "const-oid", | ||
| 704 | "zeroize", | ||
| 705 | ] | ||
| 706 | |||
| 707 | [[package]] | ||
| 708 | name = "deranged" | ||
| 709 | version = "0.3.11" | ||
| 710 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 711 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" | ||
| 712 | dependencies = [ | ||
| 713 | "powerfmt", | ||
| 714 | ] | ||
| 715 | |||
| 716 | [[package]] | ||
| 717 | name = "digest" | ||
| 718 | version = "0.10.7" | ||
| 719 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 720 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" | ||
| 721 | dependencies = [ | ||
| 722 | "block-buffer", | ||
| 723 | "crypto-common", | ||
| 724 | "subtle", | ||
| 725 | ] | ||
| 726 | |||
| 727 | [[package]] | ||
| 728 | name = "ecdsa" | ||
| 729 | version = "0.14.8" | ||
| 730 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 731 | checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" | ||
| 732 | dependencies = [ | ||
| 733 | "der", | ||
| 734 | "elliptic-curve", | ||
| 735 | "rfc6979", | ||
| 736 | "signature", | ||
| 737 | ] | ||
| 738 | |||
| 739 | [[package]] | ||
| 740 | name = "either" | ||
| 741 | version = "1.9.0" | ||
| 742 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 743 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" | ||
| 744 | |||
| 745 | [[package]] | ||
| 746 | name = "elliptic-curve" | ||
| 747 | version = "0.12.3" | ||
| 748 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 749 | checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" | ||
| 750 | dependencies = [ | ||
| 751 | "base16ct", | ||
| 752 | "crypto-bigint 0.4.9", | ||
| 753 | "der", | ||
| 754 | "digest", | ||
| 755 | "ff", | ||
| 756 | "generic-array", | ||
| 757 | "group", | ||
| 758 | "pkcs8", | ||
| 759 | "rand_core", | ||
| 760 | "sec1", | ||
| 761 | "subtle", | ||
| 762 | "zeroize", | ||
| 763 | ] | ||
| 764 | |||
| 765 | [[package]] | ||
| 766 | name = "equivalent" | ||
| 767 | version = "1.0.1" | ||
| 768 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 769 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" | ||
| 770 | |||
| 771 | [[package]] | ||
| 772 | name = "fastrand" | ||
| 773 | version = "2.0.1" | ||
| 774 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 775 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" | ||
| 776 | |||
| 777 | [[package]] | ||
| 778 | name = "ff" | ||
| 779 | version = "0.12.1" | ||
| 780 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 781 | checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" | ||
| 782 | dependencies = [ | ||
| 783 | "rand_core", | ||
| 784 | "subtle", | ||
| 785 | ] | ||
| 786 | |||
| 787 | [[package]] | ||
| 788 | name = "fnv" | ||
| 789 | version = "1.0.7" | ||
| 790 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 791 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" | ||
| 792 | |||
| 793 | [[package]] | ||
| 794 | name = "form_urlencoded" | ||
| 795 | version = "1.2.1" | ||
| 796 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 797 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" | ||
| 798 | dependencies = [ | ||
| 799 | "percent-encoding", | ||
| 800 | ] | ||
| 801 | |||
| 802 | [[package]] | ||
| 803 | name = "futures-channel" | ||
| 804 | version = "0.3.30" | ||
| 805 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 806 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" | ||
| 807 | dependencies = [ | ||
| 808 | "futures-core", | ||
| 809 | ] | ||
| 810 | |||
| 811 | [[package]] | ||
| 812 | name = "futures-core" | ||
| 813 | version = "0.3.30" | ||
| 814 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 815 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" | ||
| 816 | |||
| 817 | [[package]] | ||
| 818 | name = "futures-sink" | ||
| 819 | version = "0.3.30" | ||
| 820 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 821 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" | ||
| 822 | |||
| 823 | [[package]] | ||
| 824 | name = "futures-task" | ||
| 825 | version = "0.3.30" | ||
| 826 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 827 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" | ||
| 828 | |||
| 829 | [[package]] | ||
| 830 | name = "futures-util" | ||
| 831 | version = "0.3.30" | ||
| 832 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 833 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" | ||
| 834 | dependencies = [ | ||
| 835 | "futures-core", | ||
| 836 | "futures-task", | ||
| 837 | "pin-project-lite", | ||
| 838 | "pin-utils", | ||
| 839 | ] | ||
| 840 | |||
| 841 | [[package]] | ||
| 842 | name = "generic-array" | ||
| 843 | version = "0.14.7" | ||
| 844 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 845 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" | ||
| 846 | dependencies = [ | ||
| 847 | "typenum", | ||
| 848 | "version_check", | ||
| 849 | ] | ||
| 850 | |||
| 851 | [[package]] | ||
| 852 | name = "getrandom" | ||
| 853 | version = "0.2.12" | ||
| 854 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 855 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" | ||
| 856 | dependencies = [ | ||
| 857 | "cfg-if", | ||
| 858 | "libc", | ||
| 859 | "wasi", | ||
| 860 | ] | ||
| 861 | |||
| 862 | [[package]] | ||
| 863 | name = "gimli" | ||
| 864 | version = "0.28.1" | ||
| 865 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 866 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" | ||
| 867 | |||
| 868 | [[package]] | ||
| 869 | name = "git-lfs-authenticate" | ||
| 870 | version = "0.1.0" | ||
| 871 | dependencies = [ | ||
| 872 | "chrono", | ||
| 873 | "common", | ||
| 874 | ] | ||
| 875 | |||
| 876 | [[package]] | ||
| 877 | name = "group" | ||
| 878 | version = "0.12.1" | ||
| 879 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 880 | checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" | ||
| 881 | dependencies = [ | ||
| 882 | "ff", | ||
| 883 | "rand_core", | ||
| 884 | "subtle", | ||
| 885 | ] | ||
| 886 | |||
| 887 | [[package]] | ||
| 888 | name = "h2" | ||
| 889 | version = "0.3.24" | ||
| 890 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 891 | checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" | ||
| 892 | dependencies = [ | ||
| 893 | "bytes", | ||
| 894 | "fnv", | ||
| 895 | "futures-core", | ||
| 896 | "futures-sink", | ||
| 897 | "futures-util", | ||
| 898 | "http 0.2.11", | ||
| 899 | "indexmap", | ||
| 900 | "slab", | ||
| 901 | "tokio", | ||
| 902 | "tokio-util", | ||
| 903 | "tracing", | ||
| 904 | ] | ||
| 905 | |||
| 906 | [[package]] | ||
| 907 | name = "h2" | ||
| 908 | version = "0.4.2" | ||
| 909 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 910 | checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" | ||
| 911 | dependencies = [ | ||
| 912 | "bytes", | ||
| 913 | "fnv", | ||
| 914 | "futures-core", | ||
| 915 | "futures-sink", | ||
| 916 | "futures-util", | ||
| 917 | "http 1.0.0", | ||
| 918 | "indexmap", | ||
| 919 | "slab", | ||
| 920 | "tokio", | ||
| 921 | "tokio-util", | ||
| 922 | "tracing", | ||
| 923 | ] | ||
| 924 | |||
| 925 | [[package]] | ||
| 926 | name = "hashbrown" | ||
| 927 | version = "0.14.3" | ||
| 928 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 929 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" | ||
| 930 | |||
| 931 | [[package]] | ||
| 932 | name = "hermit-abi" | ||
| 933 | version = "0.3.3" | ||
| 934 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 935 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" | ||
| 936 | |||
| 937 | [[package]] | ||
| 938 | name = "hex" | ||
| 939 | version = "0.4.3" | ||
| 940 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 941 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" | ||
| 942 | |||
| 943 | [[package]] | ||
| 944 | name = "hmac" | ||
| 945 | version = "0.12.1" | ||
| 946 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 947 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" | ||
| 948 | dependencies = [ | ||
| 949 | "digest", | ||
| 950 | ] | ||
| 951 | |||
| 952 | [[package]] | ||
| 953 | name = "hmac-sha256" | ||
| 954 | version = "1.1.7" | ||
| 955 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 956 | checksum = "3688e69b38018fec1557254f64c8dc2cc8ec502890182f395dbb0aa997aa5735" | ||
| 957 | |||
| 958 | [[package]] | ||
| 959 | name = "http" | ||
| 960 | version = "0.2.11" | ||
| 961 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 962 | checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" | ||
| 963 | dependencies = [ | ||
| 964 | "bytes", | ||
| 965 | "fnv", | ||
| 966 | "itoa", | ||
| 967 | ] | ||
| 968 | |||
| 969 | [[package]] | ||
| 970 | name = "http" | ||
| 971 | version = "1.0.0" | ||
| 972 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 973 | checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" | ||
| 974 | dependencies = [ | ||
| 975 | "bytes", | ||
| 976 | "fnv", | ||
| 977 | "itoa", | ||
| 978 | ] | ||
| 979 | |||
| 980 | [[package]] | ||
| 981 | name = "http-body" | ||
| 982 | version = "0.4.6" | ||
| 983 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 984 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" | ||
| 985 | dependencies = [ | ||
| 986 | "bytes", | ||
| 987 | "http 0.2.11", | ||
| 988 | "pin-project-lite", | ||
| 989 | ] | ||
| 990 | |||
| 991 | [[package]] | ||
| 992 | name = "http-body" | ||
| 993 | version = "1.0.0" | ||
| 994 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 995 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" | ||
| 996 | dependencies = [ | ||
| 997 | "bytes", | ||
| 998 | "http 1.0.0", | ||
| 999 | ] | ||
| 1000 | |||
| 1001 | [[package]] | ||
| 1002 | name = "http-body-util" | ||
| 1003 | version = "0.1.0" | ||
| 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1005 | checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" | ||
| 1006 | dependencies = [ | ||
| 1007 | "bytes", | ||
| 1008 | "futures-util", | ||
| 1009 | "http 1.0.0", | ||
| 1010 | "http-body 1.0.0", | ||
| 1011 | "pin-project-lite", | ||
| 1012 | ] | ||
| 1013 | |||
| 1014 | [[package]] | ||
| 1015 | name = "httparse" | ||
| 1016 | version = "1.8.0" | ||
| 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1018 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" | ||
| 1019 | |||
| 1020 | [[package]] | ||
| 1021 | name = "httpdate" | ||
| 1022 | version = "1.0.3" | ||
| 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1024 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" | ||
| 1025 | |||
| 1026 | [[package]] | ||
| 1027 | name = "hyper" | ||
| 1028 | version = "0.14.28" | ||
| 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1030 | checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" | ||
| 1031 | dependencies = [ | ||
| 1032 | "bytes", | ||
| 1033 | "futures-channel", | ||
| 1034 | "futures-core", | ||
| 1035 | "futures-util", | ||
| 1036 | "h2 0.3.24", | ||
| 1037 | "http 0.2.11", | ||
| 1038 | "http-body 0.4.6", | ||
| 1039 | "httparse", | ||
| 1040 | "httpdate", | ||
| 1041 | "itoa", | ||
| 1042 | "pin-project-lite", | ||
| 1043 | "socket2", | ||
| 1044 | "tokio", | ||
| 1045 | "tower-service", | ||
| 1046 | "tracing", | ||
| 1047 | "want", | ||
| 1048 | ] | ||
| 1049 | |||
| 1050 | [[package]] | ||
| 1051 | name = "hyper" | ||
| 1052 | version = "1.1.0" | ||
| 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1054 | checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" | ||
| 1055 | dependencies = [ | ||
| 1056 | "bytes", | ||
| 1057 | "futures-channel", | ||
| 1058 | "futures-util", | ||
| 1059 | "h2 0.4.2", | ||
| 1060 | "http 1.0.0", | ||
| 1061 | "http-body 1.0.0", | ||
| 1062 | "httparse", | ||
| 1063 | "httpdate", | ||
| 1064 | "itoa", | ||
| 1065 | "pin-project-lite", | ||
| 1066 | "tokio", | ||
| 1067 | ] | ||
| 1068 | |||
| 1069 | [[package]] | ||
| 1070 | name = "hyper-rustls" | ||
| 1071 | version = "0.24.2" | ||
| 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1073 | checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" | ||
| 1074 | dependencies = [ | ||
| 1075 | "futures-util", | ||
| 1076 | "http 0.2.11", | ||
| 1077 | "hyper 0.14.28", | ||
| 1078 | "log", | ||
| 1079 | "rustls", | ||
| 1080 | "rustls-native-certs", | ||
| 1081 | "tokio", | ||
| 1082 | "tokio-rustls", | ||
| 1083 | ] | ||
| 1084 | |||
| 1085 | [[package]] | ||
| 1086 | name = "hyper-util" | ||
| 1087 | version = "0.1.2" | ||
| 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1089 | checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" | ||
| 1090 | dependencies = [ | ||
| 1091 | "bytes", | ||
| 1092 | "futures-channel", | ||
| 1093 | "futures-util", | ||
| 1094 | "http 1.0.0", | ||
| 1095 | "http-body 1.0.0", | ||
| 1096 | "hyper 1.1.0", | ||
| 1097 | "pin-project-lite", | ||
| 1098 | "socket2", | ||
| 1099 | "tokio", | ||
| 1100 | "tracing", | ||
| 1101 | ] | ||
| 1102 | |||
| 1103 | [[package]] | ||
| 1104 | name = "iana-time-zone" | ||
| 1105 | version = "0.1.59" | ||
| 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1107 | checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" | ||
| 1108 | dependencies = [ | ||
| 1109 | "android_system_properties", | ||
| 1110 | "core-foundation-sys", | ||
| 1111 | "iana-time-zone-haiku", | ||
| 1112 | "js-sys", | ||
| 1113 | "wasm-bindgen", | ||
| 1114 | "windows-core", | ||
| 1115 | ] | ||
| 1116 | |||
| 1117 | [[package]] | ||
| 1118 | name = "iana-time-zone-haiku" | ||
| 1119 | version = "0.1.2" | ||
| 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1121 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" | ||
| 1122 | dependencies = [ | ||
| 1123 | "cc", | ||
| 1124 | ] | ||
| 1125 | |||
| 1126 | [[package]] | ||
| 1127 | name = "idna" | ||
| 1128 | version = "0.5.0" | ||
| 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1130 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" | ||
| 1131 | dependencies = [ | ||
| 1132 | "unicode-bidi", | ||
| 1133 | "unicode-normalization", | ||
| 1134 | ] | ||
| 1135 | |||
| 1136 | [[package]] | ||
| 1137 | name = "indexmap" | ||
| 1138 | version = "2.1.0" | ||
| 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1140 | checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" | ||
| 1141 | dependencies = [ | ||
| 1142 | "equivalent", | ||
| 1143 | "hashbrown", | ||
| 1144 | ] | ||
| 1145 | |||
| 1146 | [[package]] | ||
| 1147 | name = "itoa" | ||
| 1148 | version = "1.0.10" | ||
| 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1150 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" | ||
| 1151 | |||
| 1152 | [[package]] | ||
| 1153 | name = "js-sys" | ||
| 1154 | version = "0.3.67" | ||
| 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1156 | checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" | ||
| 1157 | dependencies = [ | ||
| 1158 | "wasm-bindgen", | ||
| 1159 | ] | ||
| 1160 | |||
| 1161 | [[package]] | ||
| 1162 | name = "lazy_static" | ||
| 1163 | version = "1.4.0" | ||
| 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1165 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||
| 1166 | |||
| 1167 | [[package]] | ||
| 1168 | name = "libc" | ||
| 1169 | version = "0.2.152" | ||
| 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1171 | checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" | ||
| 1172 | |||
| 1173 | [[package]] | ||
| 1174 | name = "lock_api" | ||
| 1175 | version = "0.4.11" | ||
| 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1177 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" | ||
| 1178 | dependencies = [ | ||
| 1179 | "autocfg", | ||
| 1180 | "scopeguard", | ||
| 1181 | ] | ||
| 1182 | |||
| 1183 | [[package]] | ||
| 1184 | name = "log" | ||
| 1185 | version = "0.4.20" | ||
| 1186 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1187 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" | ||
| 1188 | |||
| 1189 | [[package]] | ||
| 1190 | name = "matchers" | ||
| 1191 | version = "0.1.0" | ||
| 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1193 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" | ||
| 1194 | dependencies = [ | ||
| 1195 | "regex-automata 0.1.10", | ||
| 1196 | ] | ||
| 1197 | |||
| 1198 | [[package]] | ||
| 1199 | name = "matchit" | ||
| 1200 | version = "0.7.3" | ||
| 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1202 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" | ||
| 1203 | |||
| 1204 | [[package]] | ||
| 1205 | name = "md-5" | ||
| 1206 | version = "0.10.6" | ||
| 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1208 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" | ||
| 1209 | dependencies = [ | ||
| 1210 | "cfg-if", | ||
| 1211 | "digest", | ||
| 1212 | ] | ||
| 1213 | |||
| 1214 | [[package]] | ||
| 1215 | name = "memchr" | ||
| 1216 | version = "2.7.1" | ||
| 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1218 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" | ||
| 1219 | |||
| 1220 | [[package]] | ||
| 1221 | name = "mime" | ||
| 1222 | version = "0.3.17" | ||
| 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1224 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" | ||
| 1225 | |||
| 1226 | [[package]] | ||
| 1227 | name = "miniz_oxide" | ||
| 1228 | version = "0.7.1" | ||
| 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1230 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" | ||
| 1231 | dependencies = [ | ||
| 1232 | "adler", | ||
| 1233 | ] | ||
| 1234 | |||
| 1235 | [[package]] | ||
| 1236 | name = "mio" | ||
| 1237 | version = "0.8.10" | ||
| 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1239 | checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" | ||
| 1240 | dependencies = [ | ||
| 1241 | "libc", | ||
| 1242 | "wasi", | ||
| 1243 | "windows-sys 0.48.0", | ||
| 1244 | ] | ||
| 1245 | |||
| 1246 | [[package]] | ||
| 1247 | name = "nu-ansi-term" | ||
| 1248 | version = "0.46.0" | ||
| 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1250 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" | ||
| 1251 | dependencies = [ | ||
| 1252 | "overload", | ||
| 1253 | "winapi", | ||
| 1254 | ] | ||
| 1255 | |||
| 1256 | [[package]] | ||
| 1257 | name = "num-integer" | ||
| 1258 | version = "0.1.45" | ||
| 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1260 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" | ||
| 1261 | dependencies = [ | ||
| 1262 | "autocfg", | ||
| 1263 | "num-traits", | ||
| 1264 | ] | ||
| 1265 | |||
| 1266 | [[package]] | ||
| 1267 | name = "num-traits" | ||
| 1268 | version = "0.2.17" | ||
| 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1270 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" | ||
| 1271 | dependencies = [ | ||
| 1272 | "autocfg", | ||
| 1273 | ] | ||
| 1274 | |||
| 1275 | [[package]] | ||
| 1276 | name = "num_cpus" | ||
| 1277 | version = "1.16.0" | ||
| 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1279 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" | ||
| 1280 | dependencies = [ | ||
| 1281 | "hermit-abi", | ||
| 1282 | "libc", | ||
| 1283 | ] | ||
| 1284 | |||
| 1285 | [[package]] | ||
| 1286 | name = "object" | ||
| 1287 | version = "0.32.2" | ||
| 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1289 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" | ||
| 1290 | dependencies = [ | ||
| 1291 | "memchr", | ||
| 1292 | ] | ||
| 1293 | |||
| 1294 | [[package]] | ||
| 1295 | name = "once_cell" | ||
| 1296 | version = "1.19.0" | ||
| 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1298 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" | ||
| 1299 | |||
| 1300 | [[package]] | ||
| 1301 | name = "openssl-probe" | ||
| 1302 | version = "0.1.5" | ||
| 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1304 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" | ||
| 1305 | |||
| 1306 | [[package]] | ||
| 1307 | name = "outref" | ||
| 1308 | version = "0.5.1" | ||
| 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1310 | checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" | ||
| 1311 | |||
| 1312 | [[package]] | ||
| 1313 | name = "overload" | ||
| 1314 | version = "0.1.1" | ||
| 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1316 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" | ||
| 1317 | |||
| 1318 | [[package]] | ||
| 1319 | name = "p256" | ||
| 1320 | version = "0.11.1" | ||
| 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1322 | checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" | ||
| 1323 | dependencies = [ | ||
| 1324 | "ecdsa", | ||
| 1325 | "elliptic-curve", | ||
| 1326 | "sha2", | ||
| 1327 | ] | ||
| 1328 | |||
| 1329 | [[package]] | ||
| 1330 | name = "parking_lot" | ||
| 1331 | version = "0.12.1" | ||
| 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1333 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" | ||
| 1334 | dependencies = [ | ||
| 1335 | "lock_api", | ||
| 1336 | "parking_lot_core", | ||
| 1337 | ] | ||
| 1338 | |||
| 1339 | [[package]] | ||
| 1340 | name = "parking_lot_core" | ||
| 1341 | version = "0.9.9" | ||
| 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1343 | checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" | ||
| 1344 | dependencies = [ | ||
| 1345 | "cfg-if", | ||
| 1346 | "libc", | ||
| 1347 | "redox_syscall", | ||
| 1348 | "smallvec", | ||
| 1349 | "windows-targets 0.48.5", | ||
| 1350 | ] | ||
| 1351 | |||
| 1352 | [[package]] | ||
| 1353 | name = "percent-encoding" | ||
| 1354 | version = "2.3.1" | ||
| 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1356 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" | ||
| 1357 | |||
| 1358 | [[package]] | ||
| 1359 | name = "pin-project" | ||
| 1360 | version = "1.1.3" | ||
| 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1362 | checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" | ||
| 1363 | dependencies = [ | ||
| 1364 | "pin-project-internal", | ||
| 1365 | ] | ||
| 1366 | |||
| 1367 | [[package]] | ||
| 1368 | name = "pin-project-internal" | ||
| 1369 | version = "1.1.3" | ||
| 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1371 | checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" | ||
| 1372 | dependencies = [ | ||
| 1373 | "proc-macro2", | ||
| 1374 | "quote", | ||
| 1375 | "syn", | ||
| 1376 | ] | ||
| 1377 | |||
| 1378 | [[package]] | ||
| 1379 | name = "pin-project-lite" | ||
| 1380 | version = "0.2.13" | ||
| 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1382 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" | ||
| 1383 | |||
| 1384 | [[package]] | ||
| 1385 | name = "pin-utils" | ||
| 1386 | version = "0.1.0" | ||
| 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1388 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" | ||
| 1389 | |||
| 1390 | [[package]] | ||
| 1391 | name = "pkcs8" | ||
| 1392 | version = "0.9.0" | ||
| 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1394 | checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" | ||
| 1395 | dependencies = [ | ||
| 1396 | "der", | ||
| 1397 | "spki", | ||
| 1398 | ] | ||
| 1399 | |||
| 1400 | [[package]] | ||
| 1401 | name = "powerfmt" | ||
| 1402 | version = "0.2.0" | ||
| 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1404 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" | ||
| 1405 | |||
| 1406 | [[package]] | ||
| 1407 | name = "proc-macro2" | ||
| 1408 | version = "1.0.76" | ||
| 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1410 | checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" | ||
| 1411 | dependencies = [ | ||
| 1412 | "unicode-ident", | ||
| 1413 | ] | ||
| 1414 | |||
| 1415 | [[package]] | ||
| 1416 | name = "quote" | ||
| 1417 | version = "1.0.35" | ||
| 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1419 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" | ||
| 1420 | dependencies = [ | ||
| 1421 | "proc-macro2", | ||
| 1422 | ] | ||
| 1423 | |||
| 1424 | [[package]] | ||
| 1425 | name = "rand_core" | ||
| 1426 | version = "0.6.4" | ||
| 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1428 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" | ||
| 1429 | dependencies = [ | ||
| 1430 | "getrandom", | ||
| 1431 | ] | ||
| 1432 | |||
| 1433 | [[package]] | ||
| 1434 | name = "redox_syscall" | ||
| 1435 | version = "0.4.1" | ||
| 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1437 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" | ||
| 1438 | dependencies = [ | ||
| 1439 | "bitflags", | ||
| 1440 | ] | ||
| 1441 | |||
| 1442 | [[package]] | ||
| 1443 | name = "regex" | ||
| 1444 | version = "1.10.3" | ||
| 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1446 | checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" | ||
| 1447 | dependencies = [ | ||
| 1448 | "aho-corasick", | ||
| 1449 | "memchr", | ||
| 1450 | "regex-automata 0.4.4", | ||
| 1451 | "regex-syntax 0.8.2", | ||
| 1452 | ] | ||
| 1453 | |||
| 1454 | [[package]] | ||
| 1455 | name = "regex-automata" | ||
| 1456 | version = "0.1.10" | ||
| 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1458 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" | ||
| 1459 | dependencies = [ | ||
| 1460 | "regex-syntax 0.6.29", | ||
| 1461 | ] | ||
| 1462 | |||
| 1463 | [[package]] | ||
| 1464 | name = "regex-automata" | ||
| 1465 | version = "0.4.4" | ||
| 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1467 | checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" | ||
| 1468 | dependencies = [ | ||
| 1469 | "aho-corasick", | ||
| 1470 | "memchr", | ||
| 1471 | "regex-syntax 0.8.2", | ||
| 1472 | ] | ||
| 1473 | |||
| 1474 | [[package]] | ||
| 1475 | name = "regex-lite" | ||
| 1476 | version = "0.1.5" | ||
| 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1478 | checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" | ||
| 1479 | |||
| 1480 | [[package]] | ||
| 1481 | name = "regex-syntax" | ||
| 1482 | version = "0.6.29" | ||
| 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1484 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" | ||
| 1485 | |||
| 1486 | [[package]] | ||
| 1487 | name = "regex-syntax" | ||
| 1488 | version = "0.8.2" | ||
| 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1490 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" | ||
| 1491 | |||
| 1492 | [[package]] | ||
| 1493 | name = "rfc6979" | ||
| 1494 | version = "0.3.1" | ||
| 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1496 | checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" | ||
| 1497 | dependencies = [ | ||
| 1498 | "crypto-bigint 0.4.9", | ||
| 1499 | "hmac", | ||
| 1500 | "zeroize", | ||
| 1501 | ] | ||
| 1502 | |||
| 1503 | [[package]] | ||
| 1504 | name = "ring" | ||
| 1505 | version = "0.17.7" | ||
| 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1507 | checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" | ||
| 1508 | dependencies = [ | ||
| 1509 | "cc", | ||
| 1510 | "getrandom", | ||
| 1511 | "libc", | ||
| 1512 | "spin", | ||
| 1513 | "untrusted", | ||
| 1514 | "windows-sys 0.48.0", | ||
| 1515 | ] | ||
| 1516 | |||
| 1517 | [[package]] | ||
| 1518 | name = "rustc-demangle" | ||
| 1519 | version = "0.1.23" | ||
| 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1521 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" | ||
| 1522 | |||
| 1523 | [[package]] | ||
| 1524 | name = "rustc_version" | ||
| 1525 | version = "0.4.0" | ||
| 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1527 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" | ||
| 1528 | dependencies = [ | ||
| 1529 | "semver", | ||
| 1530 | ] | ||
| 1531 | |||
| 1532 | [[package]] | ||
| 1533 | name = "rustls" | ||
| 1534 | version = "0.21.10" | ||
| 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1536 | checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" | ||
| 1537 | dependencies = [ | ||
| 1538 | "log", | ||
| 1539 | "ring", | ||
| 1540 | "rustls-webpki", | ||
| 1541 | "sct", | ||
| 1542 | ] | ||
| 1543 | |||
| 1544 | [[package]] | ||
| 1545 | name = "rustls-native-certs" | ||
| 1546 | version = "0.6.3" | ||
| 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1548 | checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" | ||
| 1549 | dependencies = [ | ||
| 1550 | "openssl-probe", | ||
| 1551 | "rustls-pemfile", | ||
| 1552 | "schannel", | ||
| 1553 | "security-framework", | ||
| 1554 | ] | ||
| 1555 | |||
| 1556 | [[package]] | ||
| 1557 | name = "rustls-pemfile" | ||
| 1558 | version = "1.0.4" | ||
| 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1560 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" | ||
| 1561 | dependencies = [ | ||
| 1562 | "base64", | ||
| 1563 | ] | ||
| 1564 | |||
| 1565 | [[package]] | ||
| 1566 | name = "rustls-webpki" | ||
| 1567 | version = "0.101.7" | ||
| 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1569 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" | ||
| 1570 | dependencies = [ | ||
| 1571 | "ring", | ||
| 1572 | "untrusted", | ||
| 1573 | ] | ||
| 1574 | |||
| 1575 | [[package]] | ||
| 1576 | name = "rustversion" | ||
| 1577 | version = "1.0.14" | ||
| 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1579 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" | ||
| 1580 | |||
| 1581 | [[package]] | ||
| 1582 | name = "ryu" | ||
| 1583 | version = "1.0.16" | ||
| 1584 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1585 | checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" | ||
| 1586 | |||
| 1587 | [[package]] | ||
| 1588 | name = "schannel" | ||
| 1589 | version = "0.1.23" | ||
| 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1591 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" | ||
| 1592 | dependencies = [ | ||
| 1593 | "windows-sys 0.52.0", | ||
| 1594 | ] | ||
| 1595 | |||
| 1596 | [[package]] | ||
| 1597 | name = "scopeguard" | ||
| 1598 | version = "1.2.0" | ||
| 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1600 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" | ||
| 1601 | |||
| 1602 | [[package]] | ||
| 1603 | name = "sct" | ||
| 1604 | version = "0.7.1" | ||
| 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1606 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" | ||
| 1607 | dependencies = [ | ||
| 1608 | "ring", | ||
| 1609 | "untrusted", | ||
| 1610 | ] | ||
| 1611 | |||
| 1612 | [[package]] | ||
| 1613 | name = "sec1" | ||
| 1614 | version = "0.3.0" | ||
| 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1616 | checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" | ||
| 1617 | dependencies = [ | ||
| 1618 | "base16ct", | ||
| 1619 | "der", | ||
| 1620 | "generic-array", | ||
| 1621 | "pkcs8", | ||
| 1622 | "subtle", | ||
| 1623 | "zeroize", | ||
| 1624 | ] | ||
| 1625 | |||
| 1626 | [[package]] | ||
| 1627 | name = "security-framework" | ||
| 1628 | version = "2.9.2" | ||
| 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1630 | checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" | ||
| 1631 | dependencies = [ | ||
| 1632 | "bitflags", | ||
| 1633 | "core-foundation", | ||
| 1634 | "core-foundation-sys", | ||
| 1635 | "libc", | ||
| 1636 | "security-framework-sys", | ||
| 1637 | ] | ||
| 1638 | |||
| 1639 | [[package]] | ||
| 1640 | name = "security-framework-sys" | ||
| 1641 | version = "2.9.1" | ||
| 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1643 | checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" | ||
| 1644 | dependencies = [ | ||
| 1645 | "core-foundation-sys", | ||
| 1646 | "libc", | ||
| 1647 | ] | ||
| 1648 | |||
| 1649 | [[package]] | ||
| 1650 | name = "semver" | ||
| 1651 | version = "1.0.21" | ||
| 1652 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1653 | checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" | ||
| 1654 | |||
| 1655 | [[package]] | ||
| 1656 | name = "serde" | ||
| 1657 | version = "1.0.195" | ||
| 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1659 | checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" | ||
| 1660 | dependencies = [ | ||
| 1661 | "serde_derive", | ||
| 1662 | ] | ||
| 1663 | |||
| 1664 | [[package]] | ||
| 1665 | name = "serde_derive" | ||
| 1666 | version = "1.0.195" | ||
| 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1668 | checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" | ||
| 1669 | dependencies = [ | ||
| 1670 | "proc-macro2", | ||
| 1671 | "quote", | ||
| 1672 | "syn", | ||
| 1673 | ] | ||
| 1674 | |||
| 1675 | [[package]] | ||
| 1676 | name = "serde_json" | ||
| 1677 | version = "1.0.111" | ||
| 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1679 | checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" | ||
| 1680 | dependencies = [ | ||
| 1681 | "itoa", | ||
| 1682 | "ryu", | ||
| 1683 | "serde", | ||
| 1684 | ] | ||
| 1685 | |||
| 1686 | [[package]] | ||
| 1687 | name = "serde_path_to_error" | ||
| 1688 | version = "0.1.15" | ||
| 1689 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1690 | checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" | ||
| 1691 | dependencies = [ | ||
| 1692 | "itoa", | ||
| 1693 | "serde", | ||
| 1694 | ] | ||
| 1695 | |||
| 1696 | [[package]] | ||
| 1697 | name = "serde_urlencoded" | ||
| 1698 | version = "0.7.1" | ||
| 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1700 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" | ||
| 1701 | dependencies = [ | ||
| 1702 | "form_urlencoded", | ||
| 1703 | "itoa", | ||
| 1704 | "ryu", | ||
| 1705 | "serde", | ||
| 1706 | ] | ||
| 1707 | |||
| 1708 | [[package]] | ||
| 1709 | name = "server" | ||
| 1710 | version = "0.1.0" | ||
| 1711 | dependencies = [ | ||
| 1712 | "aws-config", | ||
| 1713 | "aws-sdk-s3", | ||
| 1714 | "axum", | ||
| 1715 | "base64", | ||
| 1716 | "chrono", | ||
| 1717 | "common", | ||
| 1718 | "mime", | ||
| 1719 | "serde", | ||
| 1720 | "serde_json", | ||
| 1721 | "tokio", | ||
| 1722 | "tokio-util", | ||
| 1723 | "tower", | ||
| 1724 | "tracing-subscriber", | ||
| 1725 | ] | ||
| 1726 | |||
| 1727 | [[package]] | ||
| 1728 | name = "sha1" | ||
| 1729 | version = "0.10.6" | ||
| 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1731 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" | ||
| 1732 | dependencies = [ | ||
| 1733 | "cfg-if", | ||
| 1734 | "cpufeatures", | ||
| 1735 | "digest", | ||
| 1736 | ] | ||
| 1737 | |||
| 1738 | [[package]] | ||
| 1739 | name = "sha2" | ||
| 1740 | version = "0.10.8" | ||
| 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1742 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" | ||
| 1743 | dependencies = [ | ||
| 1744 | "cfg-if", | ||
| 1745 | "cpufeatures", | ||
| 1746 | "digest", | ||
| 1747 | ] | ||
| 1748 | |||
| 1749 | [[package]] | ||
| 1750 | name = "sharded-slab" | ||
| 1751 | version = "0.1.7" | ||
| 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1753 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" | ||
| 1754 | dependencies = [ | ||
| 1755 | "lazy_static", | ||
| 1756 | ] | ||
| 1757 | |||
| 1758 | [[package]] | ||
| 1759 | name = "shell" | ||
| 1760 | version = "0.1.0" | ||
| 1761 | |||
| 1762 | [[package]] | ||
| 1763 | name = "signal-hook-registry" | ||
| 1764 | version = "1.4.1" | ||
| 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1766 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" | ||
| 1767 | dependencies = [ | ||
| 1768 | "libc", | ||
| 1769 | ] | ||
| 1770 | |||
| 1771 | [[package]] | ||
| 1772 | name = "signature" | ||
| 1773 | version = "1.6.4" | ||
| 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1775 | checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" | ||
| 1776 | dependencies = [ | ||
| 1777 | "digest", | ||
| 1778 | "rand_core", | ||
| 1779 | ] | ||
| 1780 | |||
| 1781 | [[package]] | ||
| 1782 | name = "slab" | ||
| 1783 | version = "0.4.9" | ||
| 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1785 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" | ||
| 1786 | dependencies = [ | ||
| 1787 | "autocfg", | ||
| 1788 | ] | ||
| 1789 | |||
| 1790 | [[package]] | ||
| 1791 | name = "smallvec" | ||
| 1792 | version = "1.11.2" | ||
| 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1794 | checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" | ||
| 1795 | |||
| 1796 | [[package]] | ||
| 1797 | name = "socket2" | ||
| 1798 | version = "0.5.5" | ||
| 1799 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1800 | checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" | ||
| 1801 | dependencies = [ | ||
| 1802 | "libc", | ||
| 1803 | "windows-sys 0.48.0", | ||
| 1804 | ] | ||
| 1805 | |||
| 1806 | [[package]] | ||
| 1807 | name = "spin" | ||
| 1808 | version = "0.9.8" | ||
| 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1810 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" | ||
| 1811 | |||
| 1812 | [[package]] | ||
| 1813 | name = "spki" | ||
| 1814 | version = "0.6.0" | ||
| 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1816 | checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" | ||
| 1817 | dependencies = [ | ||
| 1818 | "base64ct", | ||
| 1819 | "der", | ||
| 1820 | ] | ||
| 1821 | |||
| 1822 | [[package]] | ||
| 1823 | name = "subtle" | ||
| 1824 | version = "2.5.0" | ||
| 1825 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1826 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" | ||
| 1827 | |||
| 1828 | [[package]] | ||
| 1829 | name = "syn" | ||
| 1830 | version = "2.0.48" | ||
| 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1832 | checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" | ||
| 1833 | dependencies = [ | ||
| 1834 | "proc-macro2", | ||
| 1835 | "quote", | ||
| 1836 | "unicode-ident", | ||
| 1837 | ] | ||
| 1838 | |||
| 1839 | [[package]] | ||
| 1840 | name = "sync_wrapper" | ||
| 1841 | version = "0.1.2" | ||
| 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1843 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" | ||
| 1844 | |||
| 1845 | [[package]] | ||
| 1846 | name = "thread_local" | ||
| 1847 | version = "1.1.7" | ||
| 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1849 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" | ||
| 1850 | dependencies = [ | ||
| 1851 | "cfg-if", | ||
| 1852 | "once_cell", | ||
| 1853 | ] | ||
| 1854 | |||
| 1855 | [[package]] | ||
| 1856 | name = "time" | ||
| 1857 | version = "0.3.31" | ||
| 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1859 | checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" | ||
| 1860 | dependencies = [ | ||
| 1861 | "deranged", | ||
| 1862 | "powerfmt", | ||
| 1863 | "serde", | ||
| 1864 | "time-core", | ||
| 1865 | "time-macros", | ||
| 1866 | ] | ||
| 1867 | |||
| 1868 | [[package]] | ||
| 1869 | name = "time-core" | ||
| 1870 | version = "0.1.2" | ||
| 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1872 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" | ||
| 1873 | |||
| 1874 | [[package]] | ||
| 1875 | name = "time-macros" | ||
| 1876 | version = "0.2.16" | ||
| 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1878 | checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" | ||
| 1879 | dependencies = [ | ||
| 1880 | "time-core", | ||
| 1881 | ] | ||
| 1882 | |||
| 1883 | [[package]] | ||
| 1884 | name = "tinyvec" | ||
| 1885 | version = "1.6.0" | ||
| 1886 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1887 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" | ||
| 1888 | dependencies = [ | ||
| 1889 | "tinyvec_macros", | ||
| 1890 | ] | ||
| 1891 | |||
| 1892 | [[package]] | ||
| 1893 | name = "tinyvec_macros" | ||
| 1894 | version = "0.1.1" | ||
| 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1896 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" | ||
| 1897 | |||
| 1898 | [[package]] | ||
| 1899 | name = "tokio" | ||
| 1900 | version = "1.35.1" | ||
| 1901 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1902 | checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" | ||
| 1903 | dependencies = [ | ||
| 1904 | "backtrace", | ||
| 1905 | "bytes", | ||
| 1906 | "libc", | ||
| 1907 | "mio", | ||
| 1908 | "num_cpus", | ||
| 1909 | "parking_lot", | ||
| 1910 | "pin-project-lite", | ||
| 1911 | "signal-hook-registry", | ||
| 1912 | "socket2", | ||
| 1913 | "tokio-macros", | ||
| 1914 | "windows-sys 0.48.0", | ||
| 1915 | ] | ||
| 1916 | |||
| 1917 | [[package]] | ||
| 1918 | name = "tokio-macros" | ||
| 1919 | version = "2.2.0" | ||
| 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1921 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" | ||
| 1922 | dependencies = [ | ||
| 1923 | "proc-macro2", | ||
| 1924 | "quote", | ||
| 1925 | "syn", | ||
| 1926 | ] | ||
| 1927 | |||
| 1928 | [[package]] | ||
| 1929 | name = "tokio-rustls" | ||
| 1930 | version = "0.24.1" | ||
| 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1932 | checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" | ||
| 1933 | dependencies = [ | ||
| 1934 | "rustls", | ||
| 1935 | "tokio", | ||
| 1936 | ] | ||
| 1937 | |||
| 1938 | [[package]] | ||
| 1939 | name = "tokio-util" | ||
| 1940 | version = "0.7.10" | ||
| 1941 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1942 | checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" | ||
| 1943 | dependencies = [ | ||
| 1944 | "bytes", | ||
| 1945 | "futures-core", | ||
| 1946 | "futures-sink", | ||
| 1947 | "pin-project-lite", | ||
| 1948 | "tokio", | ||
| 1949 | "tracing", | ||
| 1950 | ] | ||
| 1951 | |||
| 1952 | [[package]] | ||
| 1953 | name = "tower" | ||
| 1954 | version = "0.4.13" | ||
| 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1956 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" | ||
| 1957 | dependencies = [ | ||
| 1958 | "futures-core", | ||
| 1959 | "futures-util", | ||
| 1960 | "pin-project", | ||
| 1961 | "pin-project-lite", | ||
| 1962 | "tokio", | ||
| 1963 | "tower-layer", | ||
| 1964 | "tower-service", | ||
| 1965 | "tracing", | ||
| 1966 | ] | ||
| 1967 | |||
| 1968 | [[package]] | ||
| 1969 | name = "tower-layer" | ||
| 1970 | version = "0.3.2" | ||
| 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1972 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" | ||
| 1973 | |||
| 1974 | [[package]] | ||
| 1975 | name = "tower-service" | ||
| 1976 | version = "0.3.2" | ||
| 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1978 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" | ||
| 1979 | |||
| 1980 | [[package]] | ||
| 1981 | name = "tracing" | ||
| 1982 | version = "0.1.40" | ||
| 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1984 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" | ||
| 1985 | dependencies = [ | ||
| 1986 | "log", | ||
| 1987 | "pin-project-lite", | ||
| 1988 | "tracing-attributes", | ||
| 1989 | "tracing-core", | ||
| 1990 | ] | ||
| 1991 | |||
| 1992 | [[package]] | ||
| 1993 | name = "tracing-attributes" | ||
| 1994 | version = "0.1.27" | ||
| 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1996 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" | ||
| 1997 | dependencies = [ | ||
| 1998 | "proc-macro2", | ||
| 1999 | "quote", | ||
| 2000 | "syn", | ||
| 2001 | ] | ||
| 2002 | |||
| 2003 | [[package]] | ||
| 2004 | name = "tracing-core" | ||
| 2005 | version = "0.1.32" | ||
| 2006 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2007 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" | ||
| 2008 | dependencies = [ | ||
| 2009 | "once_cell", | ||
| 2010 | "valuable", | ||
| 2011 | ] | ||
| 2012 | |||
| 2013 | [[package]] | ||
| 2014 | name = "tracing-log" | ||
| 2015 | version = "0.2.0" | ||
| 2016 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2017 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" | ||
| 2018 | dependencies = [ | ||
| 2019 | "log", | ||
| 2020 | "once_cell", | ||
| 2021 | "tracing-core", | ||
| 2022 | ] | ||
| 2023 | |||
| 2024 | [[package]] | ||
| 2025 | name = "tracing-subscriber" | ||
| 2026 | version = "0.3.18" | ||
| 2027 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2028 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" | ||
| 2029 | dependencies = [ | ||
| 2030 | "matchers", | ||
| 2031 | "nu-ansi-term", | ||
| 2032 | "once_cell", | ||
| 2033 | "regex", | ||
| 2034 | "sharded-slab", | ||
| 2035 | "smallvec", | ||
| 2036 | "thread_local", | ||
| 2037 | "tracing", | ||
| 2038 | "tracing-core", | ||
| 2039 | "tracing-log", | ||
| 2040 | ] | ||
| 2041 | |||
| 2042 | [[package]] | ||
| 2043 | name = "try-lock" | ||
| 2044 | version = "0.2.5" | ||
| 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2046 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" | ||
| 2047 | |||
| 2048 | [[package]] | ||
| 2049 | name = "typenum" | ||
| 2050 | version = "1.17.0" | ||
| 2051 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2052 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" | ||
| 2053 | |||
| 2054 | [[package]] | ||
| 2055 | name = "unicode-bidi" | ||
| 2056 | version = "0.3.15" | ||
| 2057 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2058 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" | ||
| 2059 | |||
| 2060 | [[package]] | ||
| 2061 | name = "unicode-ident" | ||
| 2062 | version = "1.0.12" | ||
| 2063 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2064 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" | ||
| 2065 | |||
| 2066 | [[package]] | ||
| 2067 | name = "unicode-normalization" | ||
| 2068 | version = "0.1.22" | ||
| 2069 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2070 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" | ||
| 2071 | dependencies = [ | ||
| 2072 | "tinyvec", | ||
| 2073 | ] | ||
| 2074 | |||
| 2075 | [[package]] | ||
| 2076 | name = "untrusted" | ||
| 2077 | version = "0.9.0" | ||
| 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2079 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" | ||
| 2080 | |||
| 2081 | [[package]] | ||
| 2082 | name = "url" | ||
| 2083 | version = "2.5.0" | ||
| 2084 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2085 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" | ||
| 2086 | dependencies = [ | ||
| 2087 | "form_urlencoded", | ||
| 2088 | "idna", | ||
| 2089 | "percent-encoding", | ||
| 2090 | ] | ||
| 2091 | |||
| 2092 | [[package]] | ||
| 2093 | name = "urlencoding" | ||
| 2094 | version = "2.1.3" | ||
| 2095 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2096 | checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" | ||
| 2097 | |||
| 2098 | [[package]] | ||
| 2099 | name = "uuid" | ||
| 2100 | version = "1.6.1" | ||
| 2101 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2102 | checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" | ||
| 2103 | |||
| 2104 | [[package]] | ||
| 2105 | name = "valuable" | ||
| 2106 | version = "0.1.0" | ||
| 2107 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2108 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" | ||
| 2109 | |||
| 2110 | [[package]] | ||
| 2111 | name = "version_check" | ||
| 2112 | version = "0.9.4" | ||
| 2113 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2114 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" | ||
| 2115 | |||
| 2116 | [[package]] | ||
| 2117 | name = "vsimd" | ||
| 2118 | version = "0.8.0" | ||
| 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2120 | checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" | ||
| 2121 | |||
| 2122 | [[package]] | ||
| 2123 | name = "want" | ||
| 2124 | version = "0.3.1" | ||
| 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2126 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" | ||
| 2127 | dependencies = [ | ||
| 2128 | "try-lock", | ||
| 2129 | ] | ||
| 2130 | |||
| 2131 | [[package]] | ||
| 2132 | name = "wasi" | ||
| 2133 | version = "0.11.0+wasi-snapshot-preview1" | ||
| 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2135 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" | ||
| 2136 | |||
| 2137 | [[package]] | ||
| 2138 | name = "wasm-bindgen" | ||
| 2139 | version = "0.2.90" | ||
| 2140 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2141 | checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" | ||
| 2142 | dependencies = [ | ||
| 2143 | "cfg-if", | ||
| 2144 | "wasm-bindgen-macro", | ||
| 2145 | ] | ||
| 2146 | |||
| 2147 | [[package]] | ||
| 2148 | name = "wasm-bindgen-backend" | ||
| 2149 | version = "0.2.90" | ||
| 2150 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2151 | checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" | ||
| 2152 | dependencies = [ | ||
| 2153 | "bumpalo", | ||
| 2154 | "log", | ||
| 2155 | "once_cell", | ||
| 2156 | "proc-macro2", | ||
| 2157 | "quote", | ||
| 2158 | "syn", | ||
| 2159 | "wasm-bindgen-shared", | ||
| 2160 | ] | ||
| 2161 | |||
| 2162 | [[package]] | ||
| 2163 | name = "wasm-bindgen-macro" | ||
| 2164 | version = "0.2.90" | ||
| 2165 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2166 | checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" | ||
| 2167 | dependencies = [ | ||
| 2168 | "quote", | ||
| 2169 | "wasm-bindgen-macro-support", | ||
| 2170 | ] | ||
| 2171 | |||
| 2172 | [[package]] | ||
| 2173 | name = "wasm-bindgen-macro-support" | ||
| 2174 | version = "0.2.90" | ||
| 2175 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2176 | checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" | ||
| 2177 | dependencies = [ | ||
| 2178 | "proc-macro2", | ||
| 2179 | "quote", | ||
| 2180 | "syn", | ||
| 2181 | "wasm-bindgen-backend", | ||
| 2182 | "wasm-bindgen-shared", | ||
| 2183 | ] | ||
| 2184 | |||
| 2185 | [[package]] | ||
| 2186 | name = "wasm-bindgen-shared" | ||
| 2187 | version = "0.2.90" | ||
| 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2189 | checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" | ||
| 2190 | |||
| 2191 | [[package]] | ||
| 2192 | name = "winapi" | ||
| 2193 | version = "0.3.9" | ||
| 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2195 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" | ||
| 2196 | dependencies = [ | ||
| 2197 | "winapi-i686-pc-windows-gnu", | ||
| 2198 | "winapi-x86_64-pc-windows-gnu", | ||
| 2199 | ] | ||
| 2200 | |||
| 2201 | [[package]] | ||
| 2202 | name = "winapi-i686-pc-windows-gnu" | ||
| 2203 | version = "0.4.0" | ||
| 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2205 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||
| 2206 | |||
| 2207 | [[package]] | ||
| 2208 | name = "winapi-x86_64-pc-windows-gnu" | ||
| 2209 | version = "0.4.0" | ||
| 2210 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2211 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||
| 2212 | |||
| 2213 | [[package]] | ||
| 2214 | name = "windows-core" | ||
| 2215 | version = "0.52.0" | ||
| 2216 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2217 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" | ||
| 2218 | dependencies = [ | ||
| 2219 | "windows-targets 0.52.0", | ||
| 2220 | ] | ||
| 2221 | |||
| 2222 | [[package]] | ||
| 2223 | name = "windows-sys" | ||
| 2224 | version = "0.48.0" | ||
| 2225 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2226 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" | ||
| 2227 | dependencies = [ | ||
| 2228 | "windows-targets 0.48.5", | ||
| 2229 | ] | ||
| 2230 | |||
| 2231 | [[package]] | ||
| 2232 | name = "windows-sys" | ||
| 2233 | version = "0.52.0" | ||
| 2234 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2235 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" | ||
| 2236 | dependencies = [ | ||
| 2237 | "windows-targets 0.52.0", | ||
| 2238 | ] | ||
| 2239 | |||
| 2240 | [[package]] | ||
| 2241 | name = "windows-targets" | ||
| 2242 | version = "0.48.5" | ||
| 2243 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2244 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" | ||
| 2245 | dependencies = [ | ||
| 2246 | "windows_aarch64_gnullvm 0.48.5", | ||
| 2247 | "windows_aarch64_msvc 0.48.5", | ||
| 2248 | "windows_i686_gnu 0.48.5", | ||
| 2249 | "windows_i686_msvc 0.48.5", | ||
| 2250 | "windows_x86_64_gnu 0.48.5", | ||
| 2251 | "windows_x86_64_gnullvm 0.48.5", | ||
| 2252 | "windows_x86_64_msvc 0.48.5", | ||
| 2253 | ] | ||
| 2254 | |||
| 2255 | [[package]] | ||
| 2256 | name = "windows-targets" | ||
| 2257 | version = "0.52.0" | ||
| 2258 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2259 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" | ||
| 2260 | dependencies = [ | ||
| 2261 | "windows_aarch64_gnullvm 0.52.0", | ||
| 2262 | "windows_aarch64_msvc 0.52.0", | ||
| 2263 | "windows_i686_gnu 0.52.0", | ||
| 2264 | "windows_i686_msvc 0.52.0", | ||
| 2265 | "windows_x86_64_gnu 0.52.0", | ||
| 2266 | "windows_x86_64_gnullvm 0.52.0", | ||
| 2267 | "windows_x86_64_msvc 0.52.0", | ||
| 2268 | ] | ||
| 2269 | |||
| 2270 | [[package]] | ||
| 2271 | name = "windows_aarch64_gnullvm" | ||
| 2272 | version = "0.48.5" | ||
| 2273 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2274 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" | ||
| 2275 | |||
| 2276 | [[package]] | ||
| 2277 | name = "windows_aarch64_gnullvm" | ||
| 2278 | version = "0.52.0" | ||
| 2279 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2280 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" | ||
| 2281 | |||
| 2282 | [[package]] | ||
| 2283 | name = "windows_aarch64_msvc" | ||
| 2284 | version = "0.48.5" | ||
| 2285 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2286 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" | ||
| 2287 | |||
| 2288 | [[package]] | ||
| 2289 | name = "windows_aarch64_msvc" | ||
| 2290 | version = "0.52.0" | ||
| 2291 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2292 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" | ||
| 2293 | |||
| 2294 | [[package]] | ||
| 2295 | name = "windows_i686_gnu" | ||
| 2296 | version = "0.48.5" | ||
| 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2298 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" | ||
| 2299 | |||
| 2300 | [[package]] | ||
| 2301 | name = "windows_i686_gnu" | ||
| 2302 | version = "0.52.0" | ||
| 2303 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2304 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" | ||
| 2305 | |||
| 2306 | [[package]] | ||
| 2307 | name = "windows_i686_msvc" | ||
| 2308 | version = "0.48.5" | ||
| 2309 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2310 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" | ||
| 2311 | |||
| 2312 | [[package]] | ||
| 2313 | name = "windows_i686_msvc" | ||
| 2314 | version = "0.52.0" | ||
| 2315 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2316 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" | ||
| 2317 | |||
| 2318 | [[package]] | ||
| 2319 | name = "windows_x86_64_gnu" | ||
| 2320 | version = "0.48.5" | ||
| 2321 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2322 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" | ||
| 2323 | |||
| 2324 | [[package]] | ||
| 2325 | name = "windows_x86_64_gnu" | ||
| 2326 | version = "0.52.0" | ||
| 2327 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2328 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" | ||
| 2329 | |||
| 2330 | [[package]] | ||
| 2331 | name = "windows_x86_64_gnullvm" | ||
| 2332 | version = "0.48.5" | ||
| 2333 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2334 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" | ||
| 2335 | |||
| 2336 | [[package]] | ||
| 2337 | name = "windows_x86_64_gnullvm" | ||
| 2338 | version = "0.52.0" | ||
| 2339 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2340 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" | ||
| 2341 | |||
| 2342 | [[package]] | ||
| 2343 | name = "windows_x86_64_msvc" | ||
| 2344 | version = "0.48.5" | ||
| 2345 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2346 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" | ||
| 2347 | |||
| 2348 | [[package]] | ||
| 2349 | name = "windows_x86_64_msvc" | ||
| 2350 | version = "0.52.0" | ||
| 2351 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2352 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" | ||
| 2353 | |||
| 2354 | [[package]] | ||
| 2355 | name = "xmlparser" | ||
| 2356 | version = "0.13.6" | ||
| 2357 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2358 | checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" | ||
| 2359 | |||
| 2360 | [[package]] | ||
| 2361 | name = "zeroize" | ||
| 2362 | version = "1.7.0" | ||
| 2363 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2364 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" | ||
diff --git a/rs/Cargo.toml b/rs/Cargo.toml deleted file mode 100644 index 6439e6b..0000000 --- a/rs/Cargo.toml +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | [workspace] | ||
| 2 | resolver = "2" | ||
| 3 | members = [ | ||
| 4 | "common", | ||
| 5 | "git-lfs-authenticate", | ||
| 6 | "server", | ||
| 7 | "shell", | ||
| 8 | ] | ||
diff --git a/rs/common/Cargo.toml b/rs/common/Cargo.toml deleted file mode 100644 index 20d9bdd..0000000 --- a/rs/common/Cargo.toml +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "common" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | chrono = "0.4" | ||
| 8 | hmac-sha256 = "1.1" | ||
| 9 | subtle = "2.5" | ||
| 10 | serde = { version = "1", features = ["derive"] } | ||
diff --git a/rs/common/src/lib.rs b/rs/common/src/lib.rs deleted file mode 100644 index 995352d..0000000 --- a/rs/common/src/lib.rs +++ /dev/null | |||
| @@ -1,368 +0,0 @@ | |||
| 1 | use chrono::{DateTime, Utc}; | ||
| 2 | use serde::de; | ||
| 3 | use serde::{Deserialize, Serialize}; | ||
| 4 | use std::fmt::Write; | ||
| 5 | use std::ops; | ||
| 6 | use std::{fmt, str::FromStr}; | ||
| 7 | use subtle::ConstantTimeEq; | ||
| 8 | |||
| 9 | #[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] | ||
| 10 | #[repr(u8)] | ||
| 11 | pub enum Operation { | ||
| 12 | #[serde(rename = "download")] | ||
| 13 | Download = 1, | ||
| 14 | #[serde(rename = "upload")] | ||
| 15 | Upload = 2, | ||
| 16 | } | ||
| 17 | |||
| 18 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
| 19 | pub struct ParseOperationError; | ||
| 20 | |||
| 21 | impl fmt::Display for ParseOperationError { | ||
| 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 23 | write!(f, "operation should be 'download' or 'upload'") | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | impl FromStr for Operation { | ||
| 28 | type Err = ParseOperationError; | ||
| 29 | |||
| 30 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| 31 | match s { | ||
| 32 | "upload" => Ok(Self::Upload), | ||
| 33 | "download" => Ok(Self::Download), | ||
| 34 | _ => Err(ParseOperationError), | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | #[repr(u8)] | ||
| 40 | enum AuthType { | ||
| 41 | BatchApi = 1, | ||
| 42 | Download = 2, | ||
| 43 | } | ||
| 44 | |||
| 45 | /// None means out of range. | ||
| 46 | fn decode_nibble(c: u8) -> Option<u8> { | ||
| 47 | if c.is_ascii_digit() { | ||
| 48 | Some(c - b'0') | ||
| 49 | } else if (b'a'..=b'f').contains(&c) { | ||
| 50 | Some(c - b'a' + 10) | ||
| 51 | } else if (b'A'..=b'F').contains(&c) { | ||
| 52 | Some(c - b'A' + 10) | ||
| 53 | } else { | ||
| 54 | None | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||
| 59 | pub struct HexByte(pub u8); | ||
| 60 | |||
| 61 | impl<'de> Deserialize<'de> for HexByte { | ||
| 62 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
| 63 | where | ||
| 64 | D: serde::Deserializer<'de>, | ||
| 65 | { | ||
| 66 | let str = <&str>::deserialize(deserializer)?; | ||
| 67 | let &[b1, b2] = str.as_bytes() else { | ||
| 68 | return Err(de::Error::invalid_length( | ||
| 69 | str.len(), | ||
| 70 | &"two hexadecimal characters", | ||
| 71 | )); | ||
| 72 | }; | ||
| 73 | let (Some(b1), Some(b2)) = (decode_nibble(b1), decode_nibble(b2)) else { | ||
| 74 | return Err(de::Error::invalid_value( | ||
| 75 | de::Unexpected::Str(str), | ||
| 76 | &"two hexadecimal characters", | ||
| 77 | )); | ||
| 78 | }; | ||
| 79 | Ok(HexByte((b1 << 4) | b2)) | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | impl fmt::Display for HexByte { | ||
| 84 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 85 | let &HexByte(b) = self; | ||
| 86 | HexFmt(&[b]).fmt(f) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
| 91 | pub enum ParseHexError { | ||
| 92 | UnevenNibbles, | ||
| 93 | InvalidCharacter, | ||
| 94 | TooShort, | ||
| 95 | TooLong, | ||
| 96 | } | ||
| 97 | |||
| 98 | impl fmt::Display for ParseHexError { | ||
| 99 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 100 | match self { | ||
| 101 | Self::UnevenNibbles => { | ||
| 102 | write!(f, "uneven amount of nibbles (chars in range [a-zA-Z0-9])") | ||
| 103 | } | ||
| 104 | Self::InvalidCharacter => write!(f, "non-hex character encountered"), | ||
| 105 | Self::TooShort => write!(f, "unexpected end of hex sequence"), | ||
| 106 | Self::TooLong => write!(f, "longer hex sequence than expected"), | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | #[derive(Debug)] | ||
| 112 | pub enum ReadHexError { | ||
| 113 | Io(std::io::Error), | ||
| 114 | Format(ParseHexError), | ||
| 115 | } | ||
| 116 | |||
| 117 | impl fmt::Display for ReadHexError { | ||
| 118 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 119 | match self { | ||
| 120 | Self::Io(e) => e.fmt(f), | ||
| 121 | Self::Format(e) => e.fmt(f), | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | fn parse_hex_exact(value: &str, buf: &mut [u8]) -> Result<(), ParseHexError> { | ||
| 127 | if value.bytes().len() % 2 == 1 { | ||
| 128 | return Err(ParseHexError::UnevenNibbles); | ||
| 129 | } | ||
| 130 | if value.bytes().len() < 2 * buf.len() { | ||
| 131 | return Err(ParseHexError::TooShort); | ||
| 132 | } | ||
| 133 | if value.bytes().len() > 2 * buf.len() { | ||
| 134 | return Err(ParseHexError::TooLong); | ||
| 135 | } | ||
| 136 | for (i, c) in value.bytes().enumerate() { | ||
| 137 | if let Some(b) = decode_nibble(c) { | ||
| 138 | if i % 2 == 0 { | ||
| 139 | buf[i / 2] = b << 4; | ||
| 140 | } else { | ||
| 141 | buf[i / 2] |= b; | ||
| 142 | } | ||
| 143 | } else { | ||
| 144 | return Err(ParseHexError::InvalidCharacter); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | Ok(()) | ||
| 148 | } | ||
| 149 | |||
| 150 | pub struct SafeByteArray<const N: usize> { | ||
| 151 | inner: [u8; N], | ||
| 152 | } | ||
| 153 | |||
| 154 | impl<const N: usize> SafeByteArray<N> { | ||
| 155 | pub fn new() -> Self { | ||
| 156 | Self { inner: [0; N] } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | impl<const N: usize> Default for SafeByteArray<N> { | ||
| 161 | fn default() -> Self { | ||
| 162 | Self::new() | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | impl<const N: usize> AsRef<[u8]> for SafeByteArray<N> { | ||
| 167 | fn as_ref(&self) -> &[u8] { | ||
| 168 | &self.inner | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | impl<const N: usize> AsMut<[u8]> for SafeByteArray<N> { | ||
| 173 | fn as_mut(&mut self) -> &mut [u8] { | ||
| 174 | &mut self.inner | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | impl<const N: usize> Drop for SafeByteArray<N> { | ||
| 179 | fn drop(&mut self) { | ||
| 180 | self.inner.fill(0) | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | impl<const N: usize> FromStr for SafeByteArray<N> { | ||
| 185 | type Err = ParseHexError; | ||
| 186 | |||
| 187 | fn from_str(value: &str) -> Result<Self, Self::Err> { | ||
| 188 | let mut sba = Self { inner: [0u8; N] }; | ||
| 189 | parse_hex_exact(value, &mut sba.inner)?; | ||
| 190 | Ok(sba) | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | pub type Oid = Digest<32>; | ||
| 195 | |||
| 196 | #[derive(Debug, Copy, Clone)] | ||
| 197 | pub enum SpecificClaims { | ||
| 198 | BatchApi(Operation), | ||
| 199 | Download(Oid), | ||
| 200 | } | ||
| 201 | |||
| 202 | #[derive(Debug, Copy, Clone)] | ||
| 203 | pub struct Claims<'a> { | ||
| 204 | pub specific_claims: SpecificClaims, | ||
| 205 | pub repo_path: &'a str, | ||
| 206 | pub expires_at: DateTime<Utc>, | ||
| 207 | } | ||
| 208 | |||
| 209 | /// Returns None if the claims are invalid. Repo path length may be no more than 100 bytes. | ||
| 210 | pub fn generate_tag(claims: Claims, key: impl AsRef<[u8]>) -> Option<Digest<32>> { | ||
| 211 | if claims.repo_path.len() > 100 { | ||
| 212 | return None; | ||
| 213 | } | ||
| 214 | |||
| 215 | let mut hmac = hmac_sha256::HMAC::new(key); | ||
| 216 | match claims.specific_claims { | ||
| 217 | SpecificClaims::BatchApi(operation) => { | ||
| 218 | hmac.update([AuthType::BatchApi as u8]); | ||
| 219 | hmac.update([operation as u8]); | ||
| 220 | } | ||
| 221 | SpecificClaims::Download(oid) => { | ||
| 222 | hmac.update([AuthType::Download as u8]); | ||
| 223 | hmac.update(oid.as_bytes()); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | hmac.update([claims.repo_path.len() as u8]); | ||
| 227 | hmac.update(claims.repo_path.as_bytes()); | ||
| 228 | hmac.update(claims.expires_at.timestamp().to_be_bytes()); | ||
| 229 | Some(hmac.finalize().into()) | ||
| 230 | } | ||
| 231 | |||
| 232 | pub struct HexFmt<B: AsRef<[u8]>>(pub B); | ||
| 233 | |||
| 234 | impl<B: AsRef<[u8]>> fmt::Display for HexFmt<B> { | ||
| 235 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 236 | let HexFmt(buf) = self; | ||
| 237 | for b in buf.as_ref() { | ||
| 238 | let (high, low) = (b >> 4, b & 0xF); | ||
| 239 | let highc = if high < 10 { | ||
| 240 | high + b'0' | ||
| 241 | } else { | ||
| 242 | high - 10 + b'a' | ||
| 243 | }; | ||
| 244 | let lowc = if low < 10 { | ||
| 245 | low + b'0' | ||
| 246 | } else { | ||
| 247 | low - 10 + b'a' | ||
| 248 | }; | ||
| 249 | f.write_char(highc as char)?; | ||
| 250 | f.write_char(lowc as char)?; | ||
| 251 | } | ||
| 252 | Ok(()) | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | pub struct EscJsonFmt<'a>(pub &'a str); | ||
| 257 | |||
| 258 | impl<'a> fmt::Display for EscJsonFmt<'a> { | ||
| 259 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 260 | let EscJsonFmt(buf) = self; | ||
| 261 | for c in buf.chars() { | ||
| 262 | match c { | ||
| 263 | '"' => f.write_str("\\\"")?, // quote | ||
| 264 | '\\' => f.write_str("\\\\")?, // backslash | ||
| 265 | '\x08' => f.write_str("\\b")?, // backspace | ||
| 266 | '\x0C' => f.write_str("\\f")?, // form feed | ||
| 267 | '\n' => f.write_str("\\n")?, // line feed | ||
| 268 | '\r' => f.write_str("\\r")?, // carriage return | ||
| 269 | '\t' => f.write_str("\\t")?, // horizontal tab | ||
| 270 | _ => f.write_char(c)?, | ||
| 271 | }; | ||
| 272 | } | ||
| 273 | Ok(()) | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | #[derive(Debug, Copy, Clone)] | ||
| 278 | pub struct Digest<const N: usize> { | ||
| 279 | inner: [u8; N], | ||
| 280 | } | ||
| 281 | |||
| 282 | impl<const N: usize> ops::Index<usize> for Digest<N> { | ||
| 283 | type Output = u8; | ||
| 284 | |||
| 285 | fn index(&self, index: usize) -> &Self::Output { | ||
| 286 | &self.inner[index] | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | impl<const N: usize> Digest<N> { | ||
| 291 | pub fn as_bytes(&self) -> &[u8; N] { | ||
| 292 | &self.inner | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | impl<const N: usize> fmt::Display for Digest<N> { | ||
| 297 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 298 | HexFmt(&self.inner).fmt(f) | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | impl<const N: usize> Digest<N> { | ||
| 303 | pub fn new(data: [u8; N]) -> Self { | ||
| 304 | Self { inner: data } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | impl<const N: usize> From<[u8; N]> for Digest<N> { | ||
| 309 | fn from(value: [u8; N]) -> Self { | ||
| 310 | Self::new(value) | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | impl<const N: usize> From<Digest<N>> for [u8; N] { | ||
| 315 | fn from(val: Digest<N>) -> Self { | ||
| 316 | val.inner | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | impl<const N: usize> FromStr for Digest<N> { | ||
| 321 | type Err = ParseHexError; | ||
| 322 | |||
| 323 | fn from_str(value: &str) -> Result<Self, Self::Err> { | ||
| 324 | let mut buf = [0u8; N]; | ||
| 325 | parse_hex_exact(value, &mut buf)?; | ||
| 326 | Ok(buf.into()) | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | impl<const N: usize> ConstantTimeEq for Digest<N> { | ||
| 331 | fn ct_eq(&self, other: &Self) -> subtle::Choice { | ||
| 332 | self.inner.ct_eq(&other.inner) | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<const N: usize> PartialEq for Digest<N> { | ||
| 337 | fn eq(&self, other: &Self) -> bool { | ||
| 338 | self.ct_eq(other).into() | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | impl<const N: usize> Eq for Digest<N> {} | ||
| 343 | |||
| 344 | impl<'de, const N: usize> Deserialize<'de> for Digest<N> { | ||
| 345 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
| 346 | where | ||
| 347 | D: serde::Deserializer<'de>, | ||
| 348 | { | ||
| 349 | let hex = <&str>::deserialize(deserializer)?; | ||
| 350 | Digest::from_str(hex).map_err(de::Error::custom) | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | impl<const N: usize> Serialize for Digest<N> { | ||
| 355 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
| 356 | where | ||
| 357 | S: serde::Serializer, | ||
| 358 | { | ||
| 359 | serializer.serialize_str(&format!("{self}")) | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | pub type Key = SafeByteArray<64>; | ||
| 364 | |||
| 365 | pub fn load_key(path: &str) -> Result<Key, ReadHexError> { | ||
| 366 | let key_str = std::fs::read_to_string(path).map_err(ReadHexError::Io)?; | ||
| 367 | key_str.trim().parse().map_err(ReadHexError::Format) | ||
| 368 | } | ||
diff --git a/rs/git-lfs-authenticate/Cargo.toml b/rs/git-lfs-authenticate/Cargo.toml deleted file mode 100644 index 217250f..0000000 --- a/rs/git-lfs-authenticate/Cargo.toml +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "git-lfs-authenticate" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | chrono = "0.4" | ||
| 8 | common = { path = "../common" } | ||
diff --git a/rs/git-lfs-authenticate/src/main.rs b/rs/git-lfs-authenticate/src/main.rs deleted file mode 100644 index 36d7818..0000000 --- a/rs/git-lfs-authenticate/src/main.rs +++ /dev/null | |||
| @@ -1,236 +0,0 @@ | |||
| 1 | use std::{fmt, process::ExitCode, time::Duration}; | ||
| 2 | |||
| 3 | use chrono::Utc; | ||
| 4 | use common::{Operation, ParseOperationError}; | ||
| 5 | |||
| 6 | fn help() { | ||
| 7 | eprintln!("Usage: git-lfs-authenticate <REPO> upload/download"); | ||
| 8 | } | ||
| 9 | |||
| 10 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 11 | enum RepoNameError { | ||
| 12 | TooLong, | ||
| 13 | UnresolvedPath, | ||
| 14 | AbsolutePath, | ||
| 15 | MissingGitSuffix, | ||
| 16 | } | ||
| 17 | |||
| 18 | impl fmt::Display for RepoNameError { | ||
| 19 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 20 | match self { | ||
| 21 | Self::TooLong => write!(f, "too long (more than 100 characters)"), | ||
| 22 | Self::UnresolvedPath => { | ||
| 23 | write!(f, "contains path one or more path elements '.' and '..'") | ||
| 24 | } | ||
| 25 | Self::AbsolutePath => { | ||
| 26 | write!(f, "starts with '/', which is not allowed") | ||
| 27 | } | ||
| 28 | Self::MissingGitSuffix => write!(f, "misses '.git' suffix"), | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | // Using `Result<(), E>` here instead of `Option<E>` because `None` typically signifies some error | ||
| 34 | // state with no further details provided. If we were to return an `Option` type, the user would | ||
| 35 | // have to first transform it into a `Result` type in order to use the `?` operator, meaning that | ||
| 36 | // they would have to the following operation to get the type into the right shape: | ||
| 37 | // `validate_repo_path(path).map_or(Ok(()), Err)`. That would not be very ergonomic. | ||
| 38 | fn validate_repo_path(path: &str) -> Result<(), RepoNameError> { | ||
| 39 | if path.len() > 100 { | ||
| 40 | return Err(RepoNameError::TooLong); | ||
| 41 | } | ||
| 42 | if path.contains("//") | ||
| 43 | || path.contains("/./") | ||
| 44 | || path.contains("/../") | ||
| 45 | || path.starts_with("./") | ||
| 46 | || path.starts_with("../") | ||
| 47 | { | ||
| 48 | return Err(RepoNameError::UnresolvedPath); | ||
| 49 | } | ||
| 50 | if path.starts_with('/') { | ||
| 51 | return Err(RepoNameError::AbsolutePath); | ||
| 52 | } | ||
| 53 | if !path.ends_with(".git") { | ||
| 54 | return Err(RepoNameError::MissingGitSuffix); | ||
| 55 | } | ||
| 56 | Ok(()) | ||
| 57 | } | ||
| 58 | |||
| 59 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 60 | enum ParseCmdlineError { | ||
| 61 | UnknownOperation(ParseOperationError), | ||
| 62 | InvalidRepoName(RepoNameError), | ||
| 63 | UnexpectedArgCount(ArgCountError), | ||
| 64 | } | ||
| 65 | |||
| 66 | impl From<RepoNameError> for ParseCmdlineError { | ||
| 67 | fn from(value: RepoNameError) -> Self { | ||
| 68 | Self::InvalidRepoName(value) | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | impl From<ParseOperationError> for ParseCmdlineError { | ||
| 73 | fn from(value: ParseOperationError) -> Self { | ||
| 74 | Self::UnknownOperation(value) | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | impl From<ArgCountError> for ParseCmdlineError { | ||
| 79 | fn from(value: ArgCountError) -> Self { | ||
| 80 | Self::UnexpectedArgCount(value) | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | impl fmt::Display for ParseCmdlineError { | ||
| 85 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 86 | match self { | ||
| 87 | Self::UnknownOperation(e) => write!(f, "unknown operation: {e}"), | ||
| 88 | Self::InvalidRepoName(e) => write!(f, "invalid repository name: {e}"), | ||
| 89 | Self::UnexpectedArgCount(e) => e.fmt(f), | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 95 | struct ArgCountError { | ||
| 96 | provided: usize, | ||
| 97 | expected: usize, | ||
| 98 | } | ||
| 99 | |||
| 100 | impl fmt::Display for ArgCountError { | ||
| 101 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 102 | write!( | ||
| 103 | f, | ||
| 104 | "got {} argument(s), expected {}", | ||
| 105 | self.provided, self.expected | ||
| 106 | ) | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | fn get_cmdline_args<const N: usize>() -> Result<[String; N], ArgCountError> { | ||
| 111 | let args = std::env::args(); | ||
| 112 | if args.len() - 1 != N { | ||
| 113 | return Err(ArgCountError { | ||
| 114 | provided: args.len() - 1, | ||
| 115 | expected: N, | ||
| 116 | }); | ||
| 117 | } | ||
| 118 | |||
| 119 | // Does not allocate. | ||
| 120 | const EMPTY_STRING: String = String::new(); | ||
| 121 | let mut values = [EMPTY_STRING; N]; | ||
| 122 | |||
| 123 | // Skip the first element; we do not care about the program name. | ||
| 124 | for (i, arg) in args.skip(1).enumerate() { | ||
| 125 | values[i] = arg | ||
| 126 | } | ||
| 127 | Ok(values) | ||
| 128 | } | ||
| 129 | |||
| 130 | fn parse_cmdline() -> Result<(String, Operation), ParseCmdlineError> { | ||
| 131 | let [repo_path, op_str] = get_cmdline_args::<2>()?; | ||
| 132 | let op: Operation = op_str.parse()?; | ||
| 133 | validate_repo_path(&repo_path)?; | ||
| 134 | Ok((repo_path.to_string(), op)) | ||
| 135 | } | ||
| 136 | |||
| 137 | fn repo_exists(name: &str) -> bool { | ||
| 138 | match std::fs::metadata(name) { | ||
| 139 | Ok(metadata) => metadata.is_dir(), | ||
| 140 | _ => false, | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | struct Config { | ||
| 145 | href_base: String, | ||
| 146 | key_path: String, | ||
| 147 | } | ||
| 148 | |||
| 149 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 150 | enum LoadConfigError { | ||
| 151 | BaseUrlNotProvided, | ||
| 152 | BaseUrlSlashSuffixMissing, | ||
| 153 | KeyPathNotProvided, | ||
| 154 | } | ||
| 155 | |||
| 156 | impl fmt::Display for LoadConfigError { | ||
| 157 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 158 | match self { | ||
| 159 | Self::BaseUrlNotProvided => write!(f, "base URL not provided"), | ||
| 160 | Self::BaseUrlSlashSuffixMissing => write!(f, "base URL does not end with slash"), | ||
| 161 | Self::KeyPathNotProvided => write!(f, "key path not provided"), | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | fn load_config() -> Result<Config, LoadConfigError> { | ||
| 167 | let Ok(href_base) = std::env::var("GITOLFS3_HREF_BASE") else { | ||
| 168 | return Err(LoadConfigError::BaseUrlNotProvided); | ||
| 169 | }; | ||
| 170 | if !href_base.ends_with('/') { | ||
| 171 | return Err(LoadConfigError::BaseUrlSlashSuffixMissing); | ||
| 172 | } | ||
| 173 | let Ok(key_path) = std::env::var("GITOLFS3_KEY_PATH") else { | ||
| 174 | return Err(LoadConfigError::KeyPathNotProvided); | ||
| 175 | }; | ||
| 176 | Ok(Config { | ||
| 177 | href_base, | ||
| 178 | key_path, | ||
| 179 | }) | ||
| 180 | } | ||
| 181 | |||
| 182 | fn main() -> ExitCode { | ||
| 183 | let config = match load_config() { | ||
| 184 | Ok(config) => config, | ||
| 185 | Err(e) => { | ||
| 186 | eprintln!("Failed to load config: {e}"); | ||
| 187 | return ExitCode::FAILURE; | ||
| 188 | } | ||
| 189 | }; | ||
| 190 | let key = match common::load_key(&config.key_path) { | ||
| 191 | Ok(key) => key, | ||
| 192 | Err(e) => { | ||
| 193 | eprintln!("Failed to load key: {e}"); | ||
| 194 | return ExitCode::FAILURE; | ||
| 195 | } | ||
| 196 | }; | ||
| 197 | |||
| 198 | let (repo_name, operation) = match parse_cmdline() { | ||
| 199 | Ok(args) => args, | ||
| 200 | Err(e) => { | ||
| 201 | eprintln!("Error: {e}\n"); | ||
| 202 | help(); | ||
| 203 | // Exit code 2 signifies bad usage of CLI. | ||
| 204 | return ExitCode::from(2); | ||
| 205 | } | ||
| 206 | }; | ||
| 207 | |||
| 208 | if !repo_exists(&repo_name) { | ||
| 209 | eprintln!("Error: repository does not exist"); | ||
| 210 | return ExitCode::FAILURE; | ||
| 211 | } | ||
| 212 | |||
| 213 | let expires_at = Utc::now() + Duration::from_secs(5 * 60); | ||
| 214 | let Some(tag) = common::generate_tag( | ||
| 215 | common::Claims { | ||
| 216 | specific_claims: common::SpecificClaims::BatchApi(operation), | ||
| 217 | repo_path: &repo_name, | ||
| 218 | expires_at, | ||
| 219 | }, | ||
| 220 | key, | ||
| 221 | ) else { | ||
| 222 | eprintln!("Failed to generate validation tag"); | ||
| 223 | return ExitCode::FAILURE; | ||
| 224 | }; | ||
| 225 | |||
| 226 | println!( | ||
| 227 | "{{\"header\":{{\"Authorization\":\"Gitolfs3-Hmac-Sha256 {tag} {}\"}},\ | ||
| 228 | \"expires_at\":\"{}\",\"href\":\"{}{}/info/lfs\"}}", | ||
| 229 | expires_at.timestamp(), | ||
| 230 | common::EscJsonFmt(&expires_at.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)), | ||
| 231 | common::EscJsonFmt(&config.href_base), | ||
| 232 | common::EscJsonFmt(&repo_name), | ||
| 233 | ); | ||
| 234 | |||
| 235 | ExitCode::SUCCESS | ||
| 236 | } | ||
diff --git a/rs/server/Cargo.toml b/rs/server/Cargo.toml deleted file mode 100644 index edb76d8..0000000 --- a/rs/server/Cargo.toml +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "server" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | aws-config = { version = "1.1.2" } | ||
| 8 | aws-sdk-s3 = "1.12.0" | ||
| 9 | axum = "0.7" | ||
| 10 | base64 = "0.21" | ||
| 11 | chrono = { version = "0.4", features = ["serde"] } | ||
| 12 | common = { path = "../common" } | ||
| 13 | mime = "0.3" | ||
| 14 | serde = { version = "1", features = ["derive"] } | ||
| 15 | serde_json = "1" | ||
| 16 | tokio = { version = "1.35", features = ["full"] } | ||
| 17 | tokio-util = "0.7" | ||
| 18 | tower = "0.4" | ||
| 19 | tracing-subscriber = { version = "0.3", features = ["env-filter"] } | ||
diff --git a/rs/server/src/main.rs b/rs/server/src/main.rs deleted file mode 100644 index 8baa0d6..0000000 --- a/rs/server/src/main.rs +++ /dev/null | |||
| @@ -1,1028 +0,0 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 2 | use std::collections::HashSet; | ||
| 3 | use std::process::ExitCode; | ||
| 4 | use std::sync::Arc; | ||
| 5 | |||
| 6 | use aws_sdk_s3::error::SdkError; | ||
| 7 | use aws_sdk_s3::operation::head_object::HeadObjectOutput; | ||
| 8 | use axum::extract::rejection; | ||
| 9 | use axum::extract::FromRequest; | ||
| 10 | use axum::extract::Path; | ||
| 11 | use axum::extract::State; | ||
| 12 | use axum::http::header; | ||
| 13 | use axum::http::HeaderMap; | ||
| 14 | use axum::http::HeaderValue; | ||
| 15 | use axum::response::Response; | ||
| 16 | use axum::Json; | ||
| 17 | use axum::ServiceExt; | ||
| 18 | use base64::prelude::*; | ||
| 19 | use chrono::DateTime; | ||
| 20 | use chrono::Utc; | ||
| 21 | use common::HexByte; | ||
| 22 | use serde::de; | ||
| 23 | use serde::de::DeserializeOwned; | ||
| 24 | use serde::Deserialize; | ||
| 25 | use serde::Serialize; | ||
| 26 | use tower::Layer; | ||
| 27 | |||
| 28 | use axum::{ | ||
| 29 | async_trait, | ||
| 30 | extract::{FromRequestParts, OriginalUri, Request}, | ||
| 31 | http::{request::Parts, StatusCode, Uri}, | ||
| 32 | response::IntoResponse, | ||
| 33 | routing::{get, post}, | ||
| 34 | Extension, Router, | ||
| 35 | }; | ||
| 36 | |||
| 37 | #[derive(Clone)] | ||
| 38 | struct RepositoryName(String); | ||
| 39 | |||
| 40 | struct RepositoryNameRejection; | ||
| 41 | |||
| 42 | impl IntoResponse for RepositoryNameRejection { | ||
| 43 | fn into_response(self) -> Response { | ||
| 44 | (StatusCode::INTERNAL_SERVER_ERROR, "Missing repository name").into_response() | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | #[async_trait] | ||
| 49 | impl<S: Send + Sync> FromRequestParts<S> for RepositoryName { | ||
| 50 | type Rejection = RepositoryNameRejection; | ||
| 51 | |||
| 52 | async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { | ||
| 53 | let Ok(Extension(repo_name)) = Extension::<Self>::from_request_parts(parts, state).await | ||
| 54 | else { | ||
| 55 | return Err(RepositoryNameRejection); | ||
| 56 | }; | ||
| 57 | Ok(repo_name) | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | async fn rewrite_url<B>( | ||
| 62 | mut req: axum::http::Request<B>, | ||
| 63 | ) -> Result<axum::http::Request<B>, StatusCode> { | ||
| 64 | let uri = req.uri(); | ||
| 65 | let original_uri = OriginalUri(uri.clone()); | ||
| 66 | |||
| 67 | let Some(path_and_query) = uri.path_and_query() else { | ||
| 68 | // L @ no path & query | ||
| 69 | return Err(StatusCode::BAD_REQUEST); | ||
| 70 | }; | ||
| 71 | let Some((repo, path)) = path_and_query.path().split_once("/info/lfs/objects") else { | ||
| 72 | return Err(StatusCode::NOT_FOUND); | ||
| 73 | }; | ||
| 74 | let repo = repo | ||
| 75 | .trim_start_matches('/') | ||
| 76 | .trim_end_matches('/') | ||
| 77 | .to_string(); | ||
| 78 | if !path.starts_with('/') || !repo.ends_with(".git") { | ||
| 79 | return Err(StatusCode::NOT_FOUND); | ||
| 80 | } | ||
| 81 | |||
| 82 | let mut parts = uri.clone().into_parts(); | ||
| 83 | parts.path_and_query = match path_and_query.query() { | ||
| 84 | None => path.try_into().ok(), | ||
| 85 | Some(q) => format!("{path}?{q}").try_into().ok(), | ||
| 86 | }; | ||
| 87 | let Ok(new_uri) = Uri::from_parts(parts) else { | ||
| 88 | return Err(StatusCode::INTERNAL_SERVER_ERROR); | ||
| 89 | }; | ||
| 90 | |||
| 91 | *req.uri_mut() = new_uri; | ||
| 92 | req.extensions_mut().insert(original_uri); | ||
| 93 | req.extensions_mut().insert(RepositoryName(repo)); | ||
| 94 | |||
| 95 | Ok(req) | ||
| 96 | } | ||
| 97 | |||
| 98 | struct AppState { | ||
| 99 | s3_client: aws_sdk_s3::Client, | ||
| 100 | s3_bucket: String, | ||
| 101 | authz_conf: AuthorizationConfig, | ||
| 102 | // Should not end with a slash. | ||
| 103 | base_url: String, | ||
| 104 | } | ||
| 105 | |||
| 106 | struct Env { | ||
| 107 | s3_access_key_id: String, | ||
| 108 | s3_secret_access_key: String, | ||
| 109 | s3_bucket: String, | ||
| 110 | s3_region: String, | ||
| 111 | s3_endpoint: String, | ||
| 112 | base_url: String, | ||
| 113 | key_path: String, | ||
| 114 | listen_host: String, | ||
| 115 | listen_port: String, | ||
| 116 | trusted_forwarded_hosts: String, | ||
| 117 | } | ||
| 118 | |||
| 119 | fn require_env(name: &str) -> Result<String, String> { | ||
| 120 | std::env::var(name) | ||
| 121 | .map_err(|_| format!("environment variable {name} should be defined and valid")) | ||
| 122 | } | ||
| 123 | |||
| 124 | impl Env { | ||
| 125 | fn load() -> Result<Env, String> { | ||
| 126 | Ok(Env { | ||
| 127 | s3_secret_access_key: require_env("GITOLFS3_S3_SECRET_ACCESS_KEY_FILE")?, | ||
| 128 | s3_access_key_id: require_env("GITOLFS3_S3_ACCESS_KEY_ID_FILE")?, | ||
| 129 | s3_region: require_env("GITOLFS3_S3_REGION")?, | ||
| 130 | s3_endpoint: require_env("GITOLFS3_S3_ENDPOINT")?, | ||
| 131 | s3_bucket: require_env("GITOLFS3_S3_BUCKET")?, | ||
| 132 | base_url: require_env("GITOLFS3_BASE_URL")?, | ||
| 133 | key_path: require_env("GITOLFS3_KEY_PATH")?, | ||
| 134 | listen_host: require_env("GITOLFS3_LISTEN_HOST")?, | ||
| 135 | listen_port: require_env("GITOLFS3_LISTEN_PORT")?, | ||
| 136 | trusted_forwarded_hosts: std::env::var("GITOLFS3_TRUSTED_FORWARDED_HOSTS") | ||
| 137 | .unwrap_or_default(), | ||
| 138 | }) | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | fn get_s3_client(env: &Env) -> Result<aws_sdk_s3::Client, std::io::Error> { | ||
| 143 | let access_key_id = std::fs::read_to_string(&env.s3_access_key_id)?; | ||
| 144 | let secret_access_key = std::fs::read_to_string(&env.s3_secret_access_key)?; | ||
| 145 | |||
| 146 | let credentials = aws_sdk_s3::config::Credentials::new( | ||
| 147 | access_key_id, | ||
| 148 | secret_access_key, | ||
| 149 | None, | ||
| 150 | None, | ||
| 151 | "gitolfs3-env", | ||
| 152 | ); | ||
| 153 | let config = aws_config::SdkConfig::builder() | ||
| 154 | .behavior_version(aws_config::BehaviorVersion::latest()) | ||
| 155 | .region(aws_config::Region::new(env.s3_region.clone())) | ||
| 156 | .endpoint_url(&env.s3_endpoint) | ||
| 157 | .credentials_provider(aws_sdk_s3::config::SharedCredentialsProvider::new( | ||
| 158 | credentials, | ||
| 159 | )) | ||
| 160 | .build(); | ||
| 161 | Ok(aws_sdk_s3::Client::new(&config)) | ||
| 162 | } | ||
| 163 | |||
| 164 | #[tokio::main] | ||
| 165 | async fn main() -> ExitCode { | ||
| 166 | tracing_subscriber::fmt::init(); | ||
| 167 | |||
| 168 | let env = match Env::load() { | ||
| 169 | Ok(env) => env, | ||
| 170 | Err(e) => { | ||
| 171 | println!("Failed to load configuration: {e}"); | ||
| 172 | return ExitCode::from(2); | ||
| 173 | } | ||
| 174 | }; | ||
| 175 | |||
| 176 | let s3_client = match get_s3_client(&env) { | ||
| 177 | Ok(s3_client) => s3_client, | ||
| 178 | Err(e) => { | ||
| 179 | println!("Failed to create S3 client: {e}"); | ||
| 180 | return ExitCode::FAILURE; | ||
| 181 | } | ||
| 182 | }; | ||
| 183 | let key = match common::load_key(&env.key_path) { | ||
| 184 | Ok(key) => key, | ||
| 185 | Err(e) => { | ||
| 186 | println!("Failed to load Gitolfs3 key: {e}"); | ||
| 187 | return ExitCode::FAILURE; | ||
| 188 | } | ||
| 189 | }; | ||
| 190 | |||
| 191 | let trusted_forwarded_hosts: HashSet<String> = env | ||
| 192 | .trusted_forwarded_hosts | ||
| 193 | .split(',') | ||
| 194 | .map(|s| s.to_owned()) | ||
| 195 | .filter(|s| !s.is_empty()) | ||
| 196 | .collect(); | ||
| 197 | let base_url = env.base_url.trim_end_matches('/').to_string(); | ||
| 198 | |||
| 199 | let authz_conf = AuthorizationConfig { | ||
| 200 | key, | ||
| 201 | trusted_forwarded_hosts, | ||
| 202 | }; | ||
| 203 | |||
| 204 | let shared_state = Arc::new(AppState { | ||
| 205 | s3_client, | ||
| 206 | s3_bucket: env.s3_bucket, | ||
| 207 | authz_conf, | ||
| 208 | base_url, | ||
| 209 | }); | ||
| 210 | let app = Router::new() | ||
| 211 | .route("/batch", post(batch)) | ||
| 212 | .route("/:oid0/:oid1/:oid", get(obj_download)) | ||
| 213 | .with_state(shared_state); | ||
| 214 | |||
| 215 | let middleware = axum::middleware::map_request(rewrite_url); | ||
| 216 | let app_with_middleware = middleware.layer(app); | ||
| 217 | |||
| 218 | let Ok(listen_port): Result<u16, _> = env.listen_port.parse() else { | ||
| 219 | println!("Configured LISTEN_PORT should be an unsigned integer no higher than 65535"); | ||
| 220 | return ExitCode::from(2); | ||
| 221 | }; | ||
| 222 | let addr: (String, u16) = (env.listen_host, listen_port); | ||
| 223 | let listener = match tokio::net::TcpListener::bind(addr).await { | ||
| 224 | Ok(listener) => listener, | ||
| 225 | Err(e) => { | ||
| 226 | println!("Failed to listen: {e}"); | ||
| 227 | return ExitCode::FAILURE; | ||
| 228 | } | ||
| 229 | }; | ||
| 230 | |||
| 231 | match axum::serve(listener, app_with_middleware.into_make_service()).await { | ||
| 232 | Ok(_) => ExitCode::SUCCESS, | ||
| 233 | Err(e) => { | ||
| 234 | println!("Error serving: {e}"); | ||
| 235 | ExitCode::FAILURE | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)] | ||
| 241 | enum TransferAdapter { | ||
| 242 | #[serde(rename = "basic")] | ||
| 243 | Basic, | ||
| 244 | #[serde(other)] | ||
| 245 | Unknown, | ||
| 246 | } | ||
| 247 | |||
| 248 | #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)] | ||
| 249 | enum HashAlgo { | ||
| 250 | #[serde(rename = "sha256")] | ||
| 251 | Sha256, | ||
| 252 | #[serde(other)] | ||
| 253 | Unknown, | ||
| 254 | } | ||
| 255 | |||
| 256 | impl Default for HashAlgo { | ||
| 257 | fn default() -> Self { | ||
| 258 | Self::Sha256 | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] | ||
| 263 | struct BatchRequestObject { | ||
| 264 | oid: common::Oid, | ||
| 265 | size: i64, | ||
| 266 | } | ||
| 267 | |||
| 268 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
| 269 | struct BatchRef { | ||
| 270 | name: String, | ||
| 271 | } | ||
| 272 | |||
| 273 | fn default_transfers() -> Vec<TransferAdapter> { | ||
| 274 | vec![TransferAdapter::Basic] | ||
| 275 | } | ||
| 276 | |||
| 277 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] | ||
| 278 | struct BatchRequest { | ||
| 279 | operation: common::Operation, | ||
| 280 | #[serde(default = "default_transfers")] | ||
| 281 | transfers: Vec<TransferAdapter>, | ||
| 282 | objects: Vec<BatchRequestObject>, | ||
| 283 | #[serde(default)] | ||
| 284 | hash_algo: HashAlgo, | ||
| 285 | } | ||
| 286 | |||
| 287 | #[derive(Debug, Clone)] | ||
| 288 | struct GitLfsJson<T>(Json<T>); | ||
| 289 | |||
| 290 | const LFS_MIME: &str = "application/vnd.git-lfs+json"; | ||
| 291 | |||
| 292 | enum GitLfsJsonRejection { | ||
| 293 | Json(rejection::JsonRejection), | ||
| 294 | MissingGitLfsJsonContentType, | ||
| 295 | } | ||
| 296 | |||
| 297 | impl IntoResponse for GitLfsJsonRejection { | ||
| 298 | fn into_response(self) -> Response { | ||
| 299 | match self { | ||
| 300 | Self::Json(rej) => rej.into_response(), | ||
| 301 | Self::MissingGitLfsJsonContentType => make_error_resp( | ||
| 302 | StatusCode::UNSUPPORTED_MEDIA_TYPE, | ||
| 303 | &format!("Expected request with `Content-Type: {LFS_MIME}`"), | ||
| 304 | ) | ||
| 305 | .into_response(), | ||
| 306 | } | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | fn is_git_lfs_json_mimetype(mimetype: &str) -> bool { | ||
| 311 | let Ok(mime) = mimetype.parse::<mime::Mime>() else { | ||
| 312 | return false; | ||
| 313 | }; | ||
| 314 | if mime.type_() != mime::APPLICATION | ||
| 315 | || mime.subtype() != "vnd.git-lfs" | ||
| 316 | || mime.suffix() != Some(mime::JSON) | ||
| 317 | { | ||
| 318 | return false; | ||
| 319 | } | ||
| 320 | match mime.get_param(mime::CHARSET) { | ||
| 321 | Some(mime::UTF_8) | None => true, | ||
| 322 | Some(_) => false, | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | fn has_git_lfs_json_content_type(req: &Request) -> bool { | ||
| 327 | let Some(content_type) = req.headers().get(header::CONTENT_TYPE) else { | ||
| 328 | return false; | ||
| 329 | }; | ||
| 330 | let Ok(content_type) = content_type.to_str() else { | ||
| 331 | return false; | ||
| 332 | }; | ||
| 333 | is_git_lfs_json_mimetype(content_type) | ||
| 334 | } | ||
| 335 | |||
| 336 | #[async_trait] | ||
| 337 | impl<T, S> FromRequest<S> for GitLfsJson<T> | ||
| 338 | where | ||
| 339 | T: DeserializeOwned, | ||
| 340 | S: Send + Sync, | ||
| 341 | { | ||
| 342 | type Rejection = GitLfsJsonRejection; | ||
| 343 | |||
| 344 | async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> { | ||
| 345 | if !has_git_lfs_json_content_type(&req) { | ||
| 346 | return Err(GitLfsJsonRejection::MissingGitLfsJsonContentType); | ||
| 347 | } | ||
| 348 | Json::<T>::from_request(req, state) | ||
| 349 | .await | ||
| 350 | .map(GitLfsJson) | ||
| 351 | .map_err(GitLfsJsonRejection::Json) | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | impl<T: Serialize> IntoResponse for GitLfsJson<T> { | ||
| 356 | fn into_response(self) -> Response { | ||
| 357 | let GitLfsJson(json) = self; | ||
| 358 | let mut resp = json.into_response(); | ||
| 359 | resp.headers_mut().insert( | ||
| 360 | header::CONTENT_TYPE, | ||
| 361 | HeaderValue::from_static("application/vnd.git-lfs+json; charset=utf-8"), | ||
| 362 | ); | ||
| 363 | resp | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | #[derive(Debug, Serialize)] | ||
| 368 | struct GitLfsErrorData<'a> { | ||
| 369 | message: &'a str, | ||
| 370 | } | ||
| 371 | |||
| 372 | type GitLfsErrorResponse<'a> = (StatusCode, GitLfsJson<GitLfsErrorData<'a>>); | ||
| 373 | |||
| 374 | const fn make_error_resp(code: StatusCode, message: &str) -> GitLfsErrorResponse { | ||
| 375 | (code, GitLfsJson(Json(GitLfsErrorData { message }))) | ||
| 376 | } | ||
| 377 | |||
| 378 | #[derive(Debug, Serialize, Clone)] | ||
| 379 | struct BatchResponseObjectAction { | ||
| 380 | href: String, | ||
| 381 | #[serde(skip_serializing_if = "HashMap::is_empty")] | ||
| 382 | header: HashMap<String, String>, | ||
| 383 | expires_at: DateTime<Utc>, | ||
| 384 | } | ||
| 385 | |||
| 386 | #[derive(Default, Debug, Serialize, Clone)] | ||
| 387 | struct BatchResponseObjectActions { | ||
| 388 | #[serde(skip_serializing_if = "Option::is_none")] | ||
| 389 | upload: Option<BatchResponseObjectAction>, | ||
| 390 | #[serde(skip_serializing_if = "Option::is_none")] | ||
| 391 | download: Option<BatchResponseObjectAction>, | ||
| 392 | #[serde(skip_serializing_if = "Option::is_none")] | ||
| 393 | verify: Option<BatchResponseObjectAction>, | ||
| 394 | } | ||
| 395 | |||
| 396 | #[derive(Debug, Clone, Serialize)] | ||
| 397 | struct BatchResponseObjectError { | ||
| 398 | code: u16, | ||
| 399 | message: String, | ||
| 400 | } | ||
| 401 | |||
| 402 | #[derive(Debug, Serialize, Clone)] | ||
| 403 | struct BatchResponseObject { | ||
| 404 | oid: common::Oid, | ||
| 405 | size: i64, | ||
| 406 | #[serde(skip_serializing_if = "Option::is_none")] | ||
| 407 | authenticated: Option<bool>, | ||
| 408 | actions: BatchResponseObjectActions, | ||
| 409 | #[serde(skip_serializing_if = "Option::is_none")] | ||
| 410 | error: Option<BatchResponseObjectError>, | ||
| 411 | } | ||
| 412 | |||
| 413 | impl BatchResponseObject { | ||
| 414 | fn error(obj: &BatchRequestObject, code: StatusCode, message: String) -> BatchResponseObject { | ||
| 415 | BatchResponseObject { | ||
| 416 | oid: obj.oid, | ||
| 417 | size: obj.size, | ||
| 418 | authenticated: None, | ||
| 419 | actions: Default::default(), | ||
| 420 | error: Some(BatchResponseObjectError { | ||
| 421 | code: code.as_u16(), | ||
| 422 | message, | ||
| 423 | }), | ||
| 424 | } | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | #[derive(Debug, Serialize, Clone)] | ||
| 429 | struct BatchResponse { | ||
| 430 | transfer: TransferAdapter, | ||
| 431 | objects: Vec<BatchResponseObject>, | ||
| 432 | hash_algo: HashAlgo, | ||
| 433 | } | ||
| 434 | |||
| 435 | fn validate_checksum(oid: common::Oid, obj: &HeadObjectOutput) -> bool { | ||
| 436 | if let Some(checksum) = obj.checksum_sha256() { | ||
| 437 | if let Ok(checksum) = BASE64_STANDARD.decode(checksum) { | ||
| 438 | if let Ok(checksum32b) = TryInto::<[u8; 32]>::try_into(checksum) { | ||
| 439 | return common::Oid::from(checksum32b) == oid; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | } | ||
| 443 | true | ||
| 444 | } | ||
| 445 | |||
| 446 | fn validate_size(expected: i64, obj: &HeadObjectOutput) -> bool { | ||
| 447 | if let Some(length) = obj.content_length() { | ||
| 448 | return length == expected; | ||
| 449 | } | ||
| 450 | true | ||
| 451 | } | ||
| 452 | |||
| 453 | async fn handle_upload_object( | ||
| 454 | state: &AppState, | ||
| 455 | repo: &str, | ||
| 456 | obj: &BatchRequestObject, | ||
| 457 | ) -> Option<BatchResponseObject> { | ||
| 458 | let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); | ||
| 459 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); | ||
| 460 | |||
| 461 | match state | ||
| 462 | .s3_client | ||
| 463 | .head_object() | ||
| 464 | .bucket(&state.s3_bucket) | ||
| 465 | .key(full_path.clone()) | ||
| 466 | .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) | ||
| 467 | .send() | ||
| 468 | .await | ||
| 469 | { | ||
| 470 | Ok(result) => { | ||
| 471 | if validate_size(obj.size, &result) && validate_checksum(obj.oid, &result) { | ||
| 472 | return None; | ||
| 473 | } | ||
| 474 | } | ||
| 475 | Err(SdkError::ServiceError(e)) if e.err().is_not_found() => {} | ||
| 476 | Err(e) => { | ||
| 477 | println!("Failed to HeadObject (repo {repo}, OID {}): {e}", obj.oid); | ||
| 478 | return Some(BatchResponseObject::error( | ||
| 479 | obj, | ||
| 480 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 481 | "Failed to query object information".to_string(), | ||
| 482 | )); | ||
| 483 | } | ||
| 484 | }; | ||
| 485 | |||
| 486 | let expires_in = std::time::Duration::from_secs(5 * 60); | ||
| 487 | let expires_at = Utc::now() + expires_in; | ||
| 488 | |||
| 489 | let Ok(config) = aws_sdk_s3::presigning::PresigningConfig::expires_in(expires_in) else { | ||
| 490 | return Some(BatchResponseObject::error( | ||
| 491 | obj, | ||
| 492 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 493 | "Failed to generate upload URL".to_string(), | ||
| 494 | )); | ||
| 495 | }; | ||
| 496 | let Ok(presigned) = state | ||
| 497 | .s3_client | ||
| 498 | .put_object() | ||
| 499 | .bucket(&state.s3_bucket) | ||
| 500 | .key(full_path) | ||
| 501 | .checksum_sha256(obj.oid.to_string()) | ||
| 502 | .content_length(obj.size) | ||
| 503 | .presigned(config) | ||
| 504 | .await | ||
| 505 | else { | ||
| 506 | return Some(BatchResponseObject::error( | ||
| 507 | obj, | ||
| 508 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 509 | "Failed to generate upload URL".to_string(), | ||
| 510 | )); | ||
| 511 | }; | ||
| 512 | Some(BatchResponseObject { | ||
| 513 | oid: obj.oid, | ||
| 514 | size: obj.size, | ||
| 515 | authenticated: Some(true), | ||
| 516 | actions: BatchResponseObjectActions { | ||
| 517 | upload: Some(BatchResponseObjectAction { | ||
| 518 | header: presigned | ||
| 519 | .headers() | ||
| 520 | .map(|(k, v)| (k.to_owned(), v.to_owned())) | ||
| 521 | .collect(), | ||
| 522 | expires_at, | ||
| 523 | href: presigned.uri().to_string(), | ||
| 524 | }), | ||
| 525 | ..Default::default() | ||
| 526 | }, | ||
| 527 | error: None, | ||
| 528 | }) | ||
| 529 | } | ||
| 530 | |||
| 531 | async fn handle_download_object( | ||
| 532 | state: &AppState, | ||
| 533 | repo: &str, | ||
| 534 | obj: &BatchRequestObject, | ||
| 535 | trusted: bool, | ||
| 536 | ) -> BatchResponseObject { | ||
| 537 | let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); | ||
| 538 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); | ||
| 539 | |||
| 540 | let result = match state | ||
| 541 | .s3_client | ||
| 542 | .head_object() | ||
| 543 | .bucket(&state.s3_bucket) | ||
| 544 | .key(&full_path) | ||
| 545 | .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) | ||
| 546 | .send() | ||
| 547 | .await | ||
| 548 | { | ||
| 549 | Ok(result) => result, | ||
| 550 | Err(e) => { | ||
| 551 | println!("Failed to HeadObject (repo {repo}, OID {}): {e}", obj.oid); | ||
| 552 | return BatchResponseObject::error( | ||
| 553 | obj, | ||
| 554 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 555 | "Failed to query object information".to_string(), | ||
| 556 | ); | ||
| 557 | } | ||
| 558 | }; | ||
| 559 | |||
| 560 | // Scaleway actually doesn't provide SHA256 suport, but maybe in the future :) | ||
| 561 | if !validate_checksum(obj.oid, &result) { | ||
| 562 | return BatchResponseObject::error( | ||
| 563 | obj, | ||
| 564 | StatusCode::UNPROCESSABLE_ENTITY, | ||
| 565 | "Object corrupted".to_string(), | ||
| 566 | ); | ||
| 567 | } | ||
| 568 | if !validate_size(obj.size, &result) { | ||
| 569 | return BatchResponseObject::error( | ||
| 570 | obj, | ||
| 571 | StatusCode::UNPROCESSABLE_ENTITY, | ||
| 572 | "Incorrect size specified (or object corrupted)".to_string(), | ||
| 573 | ); | ||
| 574 | } | ||
| 575 | |||
| 576 | let expires_in = std::time::Duration::from_secs(5 * 60); | ||
| 577 | let expires_at = Utc::now() + expires_in; | ||
| 578 | |||
| 579 | if trusted { | ||
| 580 | let Ok(config) = aws_sdk_s3::presigning::PresigningConfig::expires_in(expires_in) else { | ||
| 581 | return BatchResponseObject::error( | ||
| 582 | obj, | ||
| 583 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 584 | "Failed to generate upload URL".to_string(), | ||
| 585 | ); | ||
| 586 | }; | ||
| 587 | let Ok(presigned) = state | ||
| 588 | .s3_client | ||
| 589 | .get_object() | ||
| 590 | .bucket(&state.s3_bucket) | ||
| 591 | .key(full_path) | ||
| 592 | .presigned(config) | ||
| 593 | .await | ||
| 594 | else { | ||
| 595 | return BatchResponseObject::error( | ||
| 596 | obj, | ||
| 597 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 598 | "Failed to generate upload URL".to_string(), | ||
| 599 | ); | ||
| 600 | }; | ||
| 601 | return BatchResponseObject { | ||
| 602 | oid: obj.oid, | ||
| 603 | size: obj.size, | ||
| 604 | authenticated: Some(true), | ||
| 605 | actions: BatchResponseObjectActions { | ||
| 606 | download: Some(BatchResponseObjectAction { | ||
| 607 | header: presigned | ||
| 608 | .headers() | ||
| 609 | .map(|(k, v)| (k.to_owned(), v.to_owned())) | ||
| 610 | .collect(), | ||
| 611 | expires_at, | ||
| 612 | href: presigned.uri().to_string(), | ||
| 613 | }), | ||
| 614 | ..Default::default() | ||
| 615 | }, | ||
| 616 | error: None, | ||
| 617 | }; | ||
| 618 | } | ||
| 619 | |||
| 620 | let Some(tag) = common::generate_tag( | ||
| 621 | common::Claims { | ||
| 622 | specific_claims: common::SpecificClaims::Download(obj.oid), | ||
| 623 | repo_path: repo, | ||
| 624 | expires_at, | ||
| 625 | }, | ||
| 626 | &state.authz_conf.key, | ||
| 627 | ) else { | ||
| 628 | return BatchResponseObject::error( | ||
| 629 | obj, | ||
| 630 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 631 | "Internal server error".to_string(), | ||
| 632 | ); | ||
| 633 | }; | ||
| 634 | |||
| 635 | let upload_path = format!( | ||
| 636 | "{repo}/info/lfs/objects/{}/{}/{}", | ||
| 637 | HexByte(obj.oid[0]), | ||
| 638 | HexByte(obj.oid[1]), | ||
| 639 | obj.oid, | ||
| 640 | ); | ||
| 641 | |||
| 642 | BatchResponseObject { | ||
| 643 | oid: obj.oid, | ||
| 644 | size: obj.size, | ||
| 645 | authenticated: Some(true), | ||
| 646 | actions: BatchResponseObjectActions { | ||
| 647 | download: Some(BatchResponseObjectAction { | ||
| 648 | header: { | ||
| 649 | let mut map = HashMap::new(); | ||
| 650 | map.insert( | ||
| 651 | "Authorization".to_string(), | ||
| 652 | format!("Gitolfs3-Hmac-Sha256 {tag} {}", expires_at.timestamp()), | ||
| 653 | ); | ||
| 654 | map | ||
| 655 | }, | ||
| 656 | expires_at, | ||
| 657 | href: format!("{}/{upload_path}", state.base_url), | ||
| 658 | }), | ||
| 659 | ..Default::default() | ||
| 660 | }, | ||
| 661 | error: None, | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | struct AuthorizationConfig { | ||
| 666 | trusted_forwarded_hosts: HashSet<String>, | ||
| 667 | key: common::Key, | ||
| 668 | } | ||
| 669 | |||
| 670 | struct Trusted(bool); | ||
| 671 | |||
| 672 | fn forwarded_for_trusted_host( | ||
| 673 | headers: &HeaderMap, | ||
| 674 | trusted: &HashSet<String>, | ||
| 675 | ) -> Result<bool, GitLfsErrorResponse<'static>> { | ||
| 676 | if let Some(forwarded_for) = headers.get("X-Forwarded-For") { | ||
| 677 | if let Ok(forwarded_for) = forwarded_for.to_str() { | ||
| 678 | if trusted.contains(forwarded_for) { | ||
| 679 | return Ok(true); | ||
| 680 | } | ||
| 681 | } else { | ||
| 682 | return Err(make_error_resp( | ||
| 683 | StatusCode::NOT_FOUND, | ||
| 684 | "Invalid X-Forwarded-For header", | ||
| 685 | )); | ||
| 686 | } | ||
| 687 | } | ||
| 688 | Ok(false) | ||
| 689 | } | ||
| 690 | const REPO_NOT_FOUND: GitLfsErrorResponse = | ||
| 691 | make_error_resp(StatusCode::NOT_FOUND, "Repository not found"); | ||
| 692 | |||
| 693 | fn authorize_batch( | ||
| 694 | conf: &AuthorizationConfig, | ||
| 695 | repo_path: &str, | ||
| 696 | public: bool, | ||
| 697 | operation: common::Operation, | ||
| 698 | headers: &HeaderMap, | ||
| 699 | ) -> Result<Trusted, GitLfsErrorResponse<'static>> { | ||
| 700 | // - No authentication required for downloading exported repos | ||
| 701 | // - When authenticated: | ||
| 702 | // - Download / upload over presigned URLs | ||
| 703 | // - When accessing over Tailscale: | ||
| 704 | // - No authentication required for downloading from any repo | ||
| 705 | |||
| 706 | let claims = VerifyClaimsInput { | ||
| 707 | specific_claims: common::SpecificClaims::BatchApi(operation), | ||
| 708 | repo_path, | ||
| 709 | }; | ||
| 710 | if verify_claims(conf, &claims, headers)? { | ||
| 711 | return Ok(Trusted(true)); | ||
| 712 | } | ||
| 713 | |||
| 714 | let trusted = forwarded_for_trusted_host(headers, &conf.trusted_forwarded_hosts)?; | ||
| 715 | if operation != common::Operation::Download { | ||
| 716 | if trusted { | ||
| 717 | return Err(make_error_resp( | ||
| 718 | StatusCode::FORBIDDEN, | ||
| 719 | "Authentication required to upload", | ||
| 720 | )); | ||
| 721 | } | ||
| 722 | return Err(REPO_NOT_FOUND); | ||
| 723 | } | ||
| 724 | if trusted { | ||
| 725 | return Ok(Trusted(true)); | ||
| 726 | } | ||
| 727 | |||
| 728 | if public { | ||
| 729 | Ok(Trusted(false)) | ||
| 730 | } else { | ||
| 731 | Err(REPO_NOT_FOUND) | ||
| 732 | } | ||
| 733 | } | ||
| 734 | |||
| 735 | fn repo_exists(name: &str) -> bool { | ||
| 736 | let Ok(metadata) = std::fs::metadata(name) else { | ||
| 737 | return false; | ||
| 738 | }; | ||
| 739 | metadata.is_dir() | ||
| 740 | } | ||
| 741 | |||
| 742 | fn is_repo_public(name: &str) -> Option<bool> { | ||
| 743 | if !repo_exists(name) { | ||
| 744 | return None; | ||
| 745 | } | ||
| 746 | std::fs::metadata(format!("{name}/git-daemon-export-ok")) | ||
| 747 | .ok()? | ||
| 748 | .is_file() | ||
| 749 | .into() | ||
| 750 | } | ||
| 751 | |||
| 752 | async fn batch( | ||
| 753 | State(state): State<Arc<AppState>>, | ||
| 754 | headers: HeaderMap, | ||
| 755 | RepositoryName(repo): RepositoryName, | ||
| 756 | GitLfsJson(Json(payload)): GitLfsJson<BatchRequest>, | ||
| 757 | ) -> Response { | ||
| 758 | let Some(public) = is_repo_public(&repo) else { | ||
| 759 | return REPO_NOT_FOUND.into_response(); | ||
| 760 | }; | ||
| 761 | let Trusted(trusted) = match authorize_batch( | ||
| 762 | &state.authz_conf, | ||
| 763 | &repo, | ||
| 764 | public, | ||
| 765 | payload.operation, | ||
| 766 | &headers, | ||
| 767 | ) { | ||
| 768 | Ok(authn) => authn, | ||
| 769 | Err(e) => return e.into_response(), | ||
| 770 | }; | ||
| 771 | |||
| 772 | if !headers | ||
| 773 | .get_all("Accept") | ||
| 774 | .iter() | ||
| 775 | .filter_map(|v| v.to_str().ok()) | ||
| 776 | .any(is_git_lfs_json_mimetype) | ||
| 777 | { | ||
| 778 | let message = format!("Expected `{LFS_MIME}` in list of acceptable response media types"); | ||
| 779 | return make_error_resp(StatusCode::NOT_ACCEPTABLE, &message).into_response(); | ||
| 780 | } | ||
| 781 | |||
| 782 | if payload.hash_algo != HashAlgo::Sha256 { | ||
| 783 | let message = "Unsupported hashing algorithm specified"; | ||
| 784 | return make_error_resp(StatusCode::CONFLICT, message).into_response(); | ||
| 785 | } | ||
| 786 | if !payload.transfers.is_empty() && !payload.transfers.contains(&TransferAdapter::Basic) { | ||
| 787 | let message = "Unsupported transfer adapter specified (supported: basic)"; | ||
| 788 | return make_error_resp(StatusCode::CONFLICT, message).into_response(); | ||
| 789 | } | ||
| 790 | |||
| 791 | let mut resp = BatchResponse { | ||
| 792 | transfer: TransferAdapter::Basic, | ||
| 793 | objects: vec![], | ||
| 794 | hash_algo: HashAlgo::Sha256, | ||
| 795 | }; | ||
| 796 | for obj in payload.objects { | ||
| 797 | match payload.operation { | ||
| 798 | common::Operation::Download => resp | ||
| 799 | .objects | ||
| 800 | .push(handle_download_object(&state, &repo, &obj, trusted).await), | ||
| 801 | common::Operation::Upload => { | ||
| 802 | if let Some(obj_resp) = handle_upload_object(&state, &repo, &obj).await { | ||
| 803 | resp.objects.push(obj_resp); | ||
| 804 | } | ||
| 805 | } | ||
| 806 | }; | ||
| 807 | } | ||
| 808 | GitLfsJson(Json(resp)).into_response() | ||
| 809 | } | ||
| 810 | |||
| 811 | #[derive(Deserialize, Copy, Clone)] | ||
| 812 | #[serde(remote = "Self")] | ||
| 813 | struct FileParams { | ||
| 814 | oid0: HexByte, | ||
| 815 | oid1: HexByte, | ||
| 816 | oid: common::Oid, | ||
| 817 | } | ||
| 818 | |||
| 819 | impl<'de> Deserialize<'de> for FileParams { | ||
| 820 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
| 821 | where | ||
| 822 | D: serde::Deserializer<'de>, | ||
| 823 | { | ||
| 824 | let unchecked @ FileParams { | ||
| 825 | oid0: HexByte(oid0), | ||
| 826 | oid1: HexByte(oid1), | ||
| 827 | oid, | ||
| 828 | } = FileParams::deserialize(deserializer)?; | ||
| 829 | if oid0 != oid.as_bytes()[0] { | ||
| 830 | return Err(de::Error::custom( | ||
| 831 | "first OID path part does not match first byte of full OID", | ||
| 832 | )); | ||
| 833 | } | ||
| 834 | if oid1 != oid.as_bytes()[1] { | ||
| 835 | return Err(de::Error::custom( | ||
| 836 | "second OID path part does not match first byte of full OID", | ||
| 837 | )); | ||
| 838 | } | ||
| 839 | Ok(unchecked) | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | pub struct VerifyClaimsInput<'a> { | ||
| 844 | pub specific_claims: common::SpecificClaims, | ||
| 845 | pub repo_path: &'a str, | ||
| 846 | } | ||
| 847 | |||
| 848 | fn verify_claims( | ||
| 849 | conf: &AuthorizationConfig, | ||
| 850 | claims: &VerifyClaimsInput, | ||
| 851 | headers: &HeaderMap, | ||
| 852 | ) -> Result<bool, GitLfsErrorResponse<'static>> { | ||
| 853 | const INVALID_AUTHZ_HEADER: GitLfsErrorResponse = | ||
| 854 | make_error_resp(StatusCode::BAD_REQUEST, "Invalid authorization header"); | ||
| 855 | |||
| 856 | if let Some(authz) = headers.get(header::AUTHORIZATION) { | ||
| 857 | if let Ok(authz) = authz.to_str() { | ||
| 858 | if let Some(val) = authz.strip_prefix("Gitolfs3-Hmac-Sha256 ") { | ||
| 859 | let (tag, expires_at) = val.split_once(' ').ok_or(INVALID_AUTHZ_HEADER)?; | ||
| 860 | let tag: common::Digest<32> = tag.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; | ||
| 861 | let expires_at: i64 = expires_at.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; | ||
| 862 | let expires_at = | ||
| 863 | DateTime::<Utc>::from_timestamp(expires_at, 0).ok_or(INVALID_AUTHZ_HEADER)?; | ||
| 864 | let Some(expected_tag) = common::generate_tag( | ||
| 865 | common::Claims { | ||
| 866 | specific_claims: claims.specific_claims, | ||
| 867 | repo_path: claims.repo_path, | ||
| 868 | expires_at, | ||
| 869 | }, | ||
| 870 | &conf.key, | ||
| 871 | ) else { | ||
| 872 | return Err(make_error_resp( | ||
| 873 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 874 | "Internal server error", | ||
| 875 | )); | ||
| 876 | }; | ||
| 877 | if tag == expected_tag { | ||
| 878 | return Ok(true); | ||
| 879 | } | ||
| 880 | } | ||
| 881 | } | ||
| 882 | return Err(INVALID_AUTHZ_HEADER); | ||
| 883 | } | ||
| 884 | Ok(false) | ||
| 885 | } | ||
| 886 | |||
| 887 | fn authorize_get( | ||
| 888 | conf: &AuthorizationConfig, | ||
| 889 | repo_path: &str, | ||
| 890 | oid: common::Oid, | ||
| 891 | headers: &HeaderMap, | ||
| 892 | ) -> Result<(), GitLfsErrorResponse<'static>> { | ||
| 893 | let claims = VerifyClaimsInput { | ||
| 894 | specific_claims: common::SpecificClaims::Download(oid), | ||
| 895 | repo_path, | ||
| 896 | }; | ||
| 897 | if !verify_claims(conf, &claims, headers)? { | ||
| 898 | return Err(make_error_resp( | ||
| 899 | StatusCode::UNAUTHORIZED, | ||
| 900 | "Repository not found", | ||
| 901 | )); | ||
| 902 | } | ||
| 903 | Ok(()) | ||
| 904 | } | ||
| 905 | |||
| 906 | async fn obj_download( | ||
| 907 | State(state): State<Arc<AppState>>, | ||
| 908 | headers: HeaderMap, | ||
| 909 | RepositoryName(repo): RepositoryName, | ||
| 910 | Path(FileParams { oid0, oid1, oid }): Path<FileParams>, | ||
| 911 | ) -> Response { | ||
| 912 | if let Err(e) = authorize_get(&state.authz_conf, &repo, oid, &headers) { | ||
| 913 | return e.into_response(); | ||
| 914 | } | ||
| 915 | |||
| 916 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, oid); | ||
| 917 | let result = match state | ||
| 918 | .s3_client | ||
| 919 | .get_object() | ||
| 920 | .bucket(&state.s3_bucket) | ||
| 921 | .key(full_path) | ||
| 922 | .checksum_mode(aws_sdk_s3::types::ChecksumMode::Enabled) | ||
| 923 | .send() | ||
| 924 | .await | ||
| 925 | { | ||
| 926 | Ok(result) => result, | ||
| 927 | Err(e) => { | ||
| 928 | println!("Failed to GetObject (repo {repo}, OID {oid}): {e}"); | ||
| 929 | return ( | ||
| 930 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 931 | "Failed to query object information", | ||
| 932 | ) | ||
| 933 | .into_response(); | ||
| 934 | } | ||
| 935 | }; | ||
| 936 | |||
| 937 | let mut headers = header::HeaderMap::new(); | ||
| 938 | if let Some(content_type) = result.content_type { | ||
| 939 | let Ok(header_value) = content_type.try_into() else { | ||
| 940 | return ( | ||
| 941 | StatusCode::INTERNAL_SERVER_ERROR, | ||
| 942 | "Object has invalid content type", | ||
| 943 | ) | ||
| 944 | .into_response(); | ||
| 945 | }; | ||
| 946 | headers.insert(header::CONTENT_TYPE, header_value); | ||
| 947 | } | ||
| 948 | if let Some(content_length) = result.content_length { | ||
| 949 | headers.insert(header::CONTENT_LENGTH, content_length.into()); | ||
| 950 | } | ||
| 951 | |||
| 952 | let async_read = result.body.into_async_read(); | ||
| 953 | let stream = tokio_util::io::ReaderStream::new(async_read); | ||
| 954 | let body = axum::body::Body::from_stream(stream); | ||
| 955 | |||
| 956 | (headers, body).into_response() | ||
| 957 | } | ||
| 958 | |||
| 959 | #[test] | ||
| 960 | fn test_mimetype() { | ||
| 961 | assert!(is_git_lfs_json_mimetype("application/vnd.git-lfs+json")); | ||
| 962 | assert!(!is_git_lfs_json_mimetype("application/vnd.git-lfs")); | ||
| 963 | assert!(!is_git_lfs_json_mimetype("application/json")); | ||
| 964 | assert!(is_git_lfs_json_mimetype( | ||
| 965 | "application/vnd.git-lfs+json; charset=utf-8" | ||
| 966 | )); | ||
| 967 | assert!(is_git_lfs_json_mimetype( | ||
| 968 | "application/vnd.git-lfs+json; charset=UTF-8" | ||
| 969 | )); | ||
| 970 | assert!(!is_git_lfs_json_mimetype( | ||
| 971 | "application/vnd.git-lfs+json; charset=ISO-8859-1" | ||
| 972 | )); | ||
| 973 | } | ||
| 974 | |||
| 975 | #[test] | ||
| 976 | fn test_deserialize() { | ||
| 977 | let json = r#"{"operation":"upload","objects":[{"oid":"8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c","size":170904}], | ||
| 978 | "transfers":["lfs-standalone-file","basic","ssh"],"ref":{"name":"refs/heads/main"},"hash_algo":"sha256"}"#; | ||
| 979 | let expected = BatchRequest { | ||
| 980 | operation: common::Operation::Upload, | ||
| 981 | objects: vec![BatchRequestObject { | ||
| 982 | oid: "8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c" | ||
| 983 | .parse() | ||
| 984 | .unwrap(), | ||
| 985 | size: 170904, | ||
| 986 | }], | ||
| 987 | transfers: vec![ | ||
| 988 | TransferAdapter::Unknown, | ||
| 989 | TransferAdapter::Basic, | ||
| 990 | TransferAdapter::Unknown, | ||
| 991 | ], | ||
| 992 | hash_algo: HashAlgo::Sha256, | ||
| 993 | }; | ||
| 994 | assert_eq!( | ||
| 995 | serde_json::from_str::<BatchRequest>(json).unwrap(), | ||
| 996 | expected | ||
| 997 | ); | ||
| 998 | } | ||
| 999 | |||
| 1000 | #[test] | ||
| 1001 | fn test_validate_claims() { | ||
| 1002 | let key = "00232f7a019bd34e3921ee6c5f04caf48a4489d1be5d1999038950a7054e0bfea369ce2becc0f13fd3c69f8af2384a25b7ac2d52eb52c33722f3c00c50d4c9c2"; | ||
| 1003 | let key: common::Key = key.parse().unwrap(); | ||
| 1004 | |||
| 1005 | let claims = common::Claims { | ||
| 1006 | expires_at: Utc::now() + std::time::Duration::from_secs(5 * 60), | ||
| 1007 | repo_path: "lfs-test.git", | ||
| 1008 | specific_claims: common::SpecificClaims::BatchApi(common::Operation::Download), | ||
| 1009 | }; | ||
| 1010 | let tag = common::generate_tag(claims, &key).unwrap(); | ||
| 1011 | let header_value = format!( | ||
| 1012 | "Gitolfs3-Hmac-Sha256 {tag} {}", | ||
| 1013 | claims.expires_at.timestamp() | ||
| 1014 | ); | ||
| 1015 | |||
| 1016 | let conf = AuthorizationConfig { | ||
| 1017 | key, | ||
| 1018 | trusted_forwarded_hosts: HashSet::new(), | ||
| 1019 | }; | ||
| 1020 | let verification_claims = VerifyClaimsInput { | ||
| 1021 | repo_path: claims.repo_path, | ||
| 1022 | specific_claims: claims.specific_claims, | ||
| 1023 | }; | ||
| 1024 | let mut headers = HeaderMap::new(); | ||
| 1025 | headers.insert(header::AUTHORIZATION, header_value.try_into().unwrap()); | ||
| 1026 | |||
| 1027 | assert!(verify_claims(&conf, &verification_claims, &headers).unwrap()); | ||
| 1028 | } | ||
diff --git a/rs/shell/Cargo.toml b/rs/shell/Cargo.toml deleted file mode 100644 index 0dcb6d6..0000000 --- a/rs/shell/Cargo.toml +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "shell" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
diff --git a/rs/shell/src/main.rs b/rs/shell/src/main.rs deleted file mode 100644 index ef0ef48..0000000 --- a/rs/shell/src/main.rs +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | use std::{os::unix::process::CommandExt, process::ExitCode}; | ||
| 2 | |||
| 3 | fn parse_sq(s: &str) -> Option<(String, &str)> { | ||
| 4 | #[derive(PartialEq, Eq)] | ||
| 5 | enum SqState { | ||
| 6 | Quoted, | ||
| 7 | Unquoted { may_escape: bool }, | ||
| 8 | UnquotedEscaped, | ||
| 9 | } | ||
| 10 | |||
| 11 | let mut result = String::new(); | ||
| 12 | let mut state = SqState::Unquoted { may_escape: false }; | ||
| 13 | let mut remaining = ""; | ||
| 14 | for (i, c) in s.char_indices() { | ||
| 15 | match state { | ||
| 16 | SqState::Unquoted { may_escape: false } => { | ||
| 17 | if c != '\'' { | ||
| 18 | return None; | ||
| 19 | } | ||
| 20 | state = SqState::Quoted | ||
| 21 | } | ||
| 22 | SqState::Quoted => { | ||
| 23 | if c == '\'' { | ||
| 24 | state = SqState::Unquoted { may_escape: true }; | ||
| 25 | continue; | ||
| 26 | } | ||
| 27 | result.push(c); | ||
| 28 | } | ||
| 29 | SqState::Unquoted { may_escape: true } => { | ||
| 30 | if is_posix_space(c) { | ||
| 31 | remaining = &s[i..]; | ||
| 32 | break; | ||
| 33 | } | ||
| 34 | if c != '\\' { | ||
| 35 | return None; | ||
| 36 | } | ||
| 37 | state = SqState::UnquotedEscaped; | ||
| 38 | } | ||
| 39 | SqState::UnquotedEscaped => { | ||
| 40 | if c != '\\' && c != '!' { | ||
| 41 | return None; | ||
| 42 | } | ||
| 43 | result.push(c); | ||
| 44 | state = SqState::Unquoted { may_escape: false }; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | if state != (SqState::Unquoted { may_escape: true }) { | ||
| 50 | return None; | ||
| 51 | } | ||
| 52 | Some((result, remaining)) | ||
| 53 | } | ||
| 54 | |||
| 55 | fn parse_cmd(mut cmd: &str) -> Option<Vec<String>> { | ||
| 56 | let mut args = Vec::<String>::new(); | ||
| 57 | |||
| 58 | cmd = cmd.trim_matches(is_posix_space); | ||
| 59 | while cmd != "" { | ||
| 60 | if cmd.starts_with('\'') { | ||
| 61 | let (arg, remaining) = parse_sq(cmd)?; | ||
| 62 | args.push(arg); | ||
| 63 | cmd = remaining.trim_start_matches(is_posix_space); | ||
| 64 | } else if let Some((arg, remaining)) = cmd.split_once(is_posix_space) { | ||
| 65 | args.push(arg.to_owned()); | ||
| 66 | cmd = remaining.trim_start_matches(is_posix_space); | ||
| 67 | } else { | ||
| 68 | args.push(cmd.to_owned()); | ||
| 69 | cmd = ""; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | Some(args) | ||
| 74 | } | ||
| 75 | |||
| 76 | fn is_posix_space(c: char) -> bool { | ||
| 77 | // Form feed: 0x0c | ||
| 78 | // Vertical tab: 0x0b | ||
| 79 | c == ' ' || c == '\x0c' || c == '\n' || c == '\r' || c == '\t' || c == '\x0b' | ||
| 80 | } | ||
| 81 | |||
| 82 | fn main() -> ExitCode { | ||
| 83 | let bad_usage = ExitCode::from(2); | ||
| 84 | |||
| 85 | let mut args = std::env::args().skip(1); | ||
| 86 | if args.next() != Some("-c".to_string()) { | ||
| 87 | eprintln!("Expected usage: shell -c <argument>"); | ||
| 88 | return bad_usage; | ||
| 89 | } | ||
| 90 | let Some(cmd) = args.next() else { | ||
| 91 | eprintln!("Missing argument for argument '-c'"); | ||
| 92 | return bad_usage; | ||
| 93 | }; | ||
| 94 | if args.next() != None { | ||
| 95 | eprintln!("Too many arguments passed"); | ||
| 96 | return bad_usage; | ||
| 97 | } | ||
| 98 | |||
| 99 | let Some(mut cmd) = parse_cmd(&cmd) else { | ||
| 100 | eprintln!("Bad command"); | ||
| 101 | return bad_usage; | ||
| 102 | }; | ||
| 103 | |||
| 104 | let Some(mut program) = cmd.drain(0..1).next() else { | ||
| 105 | eprintln!("Bad command"); | ||
| 106 | return bad_usage; | ||
| 107 | }; | ||
| 108 | if program == "git" { | ||
| 109 | let Some(subcommand) = cmd.drain(0..1).next() else { | ||
| 110 | eprintln!("Bad command"); | ||
| 111 | return bad_usage; | ||
| 112 | }; | ||
| 113 | program.push('-'); | ||
| 114 | program.push_str(&subcommand); | ||
| 115 | } | ||
| 116 | |||
| 117 | let mut args = Vec::new(); | ||
| 118 | |||
| 119 | let git_cmds = ["git-receive-pack", "git-upload-archive", "git-upload-pack"]; | ||
| 120 | if git_cmds.contains(&program.as_str()) { | ||
| 121 | if cmd.len() != 1 { | ||
| 122 | eprintln!("Bad command"); | ||
| 123 | return bad_usage; | ||
| 124 | } | ||
| 125 | let repository = cmd[0].trim_start_matches('/'); | ||
| 126 | args.push(repository); | ||
| 127 | } else if program == "git-lfs-authenticate" { | ||
| 128 | if cmd.len() != 2 { | ||
| 129 | eprintln!("Bad command"); | ||
| 130 | return bad_usage; | ||
| 131 | } | ||
| 132 | let repository = cmd[0].trim_start_matches('/'); | ||
| 133 | args.push(repository); | ||
| 134 | args.push(&cmd[1]); | ||
| 135 | } else { | ||
| 136 | eprintln!("Unknown command"); | ||
| 137 | return bad_usage; | ||
| 138 | } | ||
| 139 | |||
| 140 | let e = std::process::Command::new(program).args(args).exec(); | ||
| 141 | eprintln!("Error: {e}"); | ||
| 142 | ExitCode::FAILURE | ||
| 143 | } | ||