├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── README.md ├── config ├── default.json ├── production.json └── test.json ├── openapi.yaml ├── rustfmt.toml └── src ├── app.rs ├── database.rs ├── errors.rs ├── logger.rs ├── main.rs ├── models ├── cat.rs ├── mod.rs └── user.rs ├── routes ├── cat.rs ├── mod.rs ├── status.rs └── user.rs ├── settings.rs ├── tests ├── mod.rs ├── routes │ ├── cat.rs │ ├── mod.rs │ ├── status.rs │ └── user.rs ├── setup.rs └── utils.rs └── utils ├── authenticate_request.rs ├── custom_response.rs ├── date.rs ├── mod.rs ├── models.rs ├── pagination.rs ├── to_object_id.rs └── token.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v2 15 | 16 | - name: Install toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: stable 20 | override: true 21 | components: rustfmt, clippy 22 | 23 | - name: Start MongoDB 24 | uses: supercharge/mongodb-github-action@1.7.0 25 | with: 26 | mongodb-version: 5.0 27 | 28 | - uses: actions/cache@v2 29 | with: 30 | path: | 31 | ~/.cargo/registry 32 | ~/.cargo/git 33 | target 34 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 35 | 36 | - name: Run cargo fmt 37 | uses: actions-rs/cargo@v1 38 | with: 39 | command: fmt 40 | args: --all -- --check 41 | 42 | - name: Run cargo check 43 | uses: actions-rs/cargo@v1 44 | with: 45 | command: check 46 | 47 | - name: Run cargo clippy 48 | uses: actions-rs/cargo@v1 49 | with: 50 | command: clippy 51 | args: -- -D warnings 52 | 53 | - name: Run cargo test 54 | uses: actions-rs/cargo@v1 55 | with: 56 | command: test 57 | args: -- --test-threads=1 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | # MacOS related files 9 | .DS_Store 10 | 11 | # Environment variables 12 | .env 13 | config/local.json 14 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Inflector" 7 | version = "0.11.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" 10 | dependencies = [ 11 | "lazy_static", 12 | "regex", 13 | ] 14 | 15 | [[package]] 16 | name = "addr2line" 17 | version = "0.20.0" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 20 | dependencies = [ 21 | "gimli", 22 | ] 23 | 24 | [[package]] 25 | name = "adler" 26 | version = "1.0.2" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 29 | 30 | [[package]] 31 | name = "ahash" 32 | version = "0.8.3" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" 35 | dependencies = [ 36 | "cfg-if", 37 | "getrandom", 38 | "once_cell", 39 | "version_check", 40 | ] 41 | 42 | [[package]] 43 | name = "aho-corasick" 44 | version = "1.0.2" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" 47 | dependencies = [ 48 | "memchr", 49 | ] 50 | 51 | [[package]] 52 | name = "alloc-no-stdlib" 53 | version = "2.0.4" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" 56 | 57 | [[package]] 58 | name = "alloc-stdlib" 59 | version = "0.2.2" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" 62 | dependencies = [ 63 | "alloc-no-stdlib", 64 | ] 65 | 66 | [[package]] 67 | name = "android-tzdata" 68 | version = "0.1.1" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 71 | 72 | [[package]] 73 | name = "android_system_properties" 74 | version = "0.1.5" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 77 | dependencies = [ 78 | "libc", 79 | ] 80 | 81 | [[package]] 82 | name = "assert-json-diff" 83 | version = "2.0.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" 86 | dependencies = [ 87 | "serde", 88 | "serde_json", 89 | ] 90 | 91 | [[package]] 92 | name = "async-compression" 93 | version = "0.4.1" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "62b74f44609f0f91493e3082d3734d98497e094777144380ea4db9f9905dd5b6" 96 | dependencies = [ 97 | "brotli", 98 | "futures-core", 99 | "memchr", 100 | "pin-project-lite", 101 | "tokio", 102 | ] 103 | 104 | [[package]] 105 | name = "async-trait" 106 | version = "0.1.79" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" 109 | dependencies = [ 110 | "proc-macro2", 111 | "quote", 112 | "syn 2.0.48", 113 | ] 114 | 115 | [[package]] 116 | name = "autocfg" 117 | version = "1.1.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 120 | 121 | [[package]] 122 | name = "axum" 123 | version = "0.6.20" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" 126 | dependencies = [ 127 | "async-trait", 128 | "axum-core", 129 | "bitflags 1.3.2", 130 | "bytes", 131 | "futures-util", 132 | "headers", 133 | "http 0.2.9", 134 | "http-body 0.4.5", 135 | "hyper 0.14.27", 136 | "itoa", 137 | "matchit", 138 | "memchr", 139 | "mime", 140 | "percent-encoding", 141 | "pin-project-lite", 142 | "rustversion", 143 | "serde", 144 | "serde_json", 145 | "serde_path_to_error", 146 | "serde_urlencoded", 147 | "sync_wrapper", 148 | "tokio", 149 | "tower", 150 | "tower-layer", 151 | "tower-service", 152 | ] 153 | 154 | [[package]] 155 | name = "axum-core" 156 | version = "0.3.4" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" 159 | dependencies = [ 160 | "async-trait", 161 | "bytes", 162 | "futures-util", 163 | "http 0.2.9", 164 | "http-body 0.4.5", 165 | "mime", 166 | "rustversion", 167 | "tower-layer", 168 | "tower-service", 169 | ] 170 | 171 | [[package]] 172 | name = "backtrace" 173 | version = "0.3.68" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 176 | dependencies = [ 177 | "addr2line", 178 | "cc", 179 | "cfg-if", 180 | "libc", 181 | "miniz_oxide", 182 | "object", 183 | "rustc-demangle", 184 | ] 185 | 186 | [[package]] 187 | name = "base64" 188 | version = "0.13.1" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 191 | 192 | [[package]] 193 | name = "base64" 194 | version = "0.21.2" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" 197 | 198 | [[package]] 199 | name = "bcrypt" 200 | version = "0.15.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "28d1c9c15093eb224f0baa400f38fcd713fc1391a6f1c389d886beef146d60a3" 203 | dependencies = [ 204 | "base64 0.21.2", 205 | "blowfish", 206 | "getrandom", 207 | "subtle", 208 | "zeroize", 209 | ] 210 | 211 | [[package]] 212 | name = "bitflags" 213 | version = "1.3.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 216 | 217 | [[package]] 218 | name = "bitflags" 219 | version = "2.3.3" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" 222 | dependencies = [ 223 | "serde", 224 | ] 225 | 226 | [[package]] 227 | name = "bitvec" 228 | version = "1.0.1" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 231 | dependencies = [ 232 | "funty", 233 | "radium", 234 | "tap", 235 | "wyz", 236 | ] 237 | 238 | [[package]] 239 | name = "block-buffer" 240 | version = "0.10.4" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 243 | dependencies = [ 244 | "generic-array", 245 | ] 246 | 247 | [[package]] 248 | name = "blowfish" 249 | version = "0.9.1" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" 252 | dependencies = [ 253 | "byteorder", 254 | "cipher", 255 | ] 256 | 257 | [[package]] 258 | name = "brotli" 259 | version = "3.3.4" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" 262 | dependencies = [ 263 | "alloc-no-stdlib", 264 | "alloc-stdlib", 265 | "brotli-decompressor", 266 | ] 267 | 268 | [[package]] 269 | name = "brotli-decompressor" 270 | version = "2.3.4" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" 273 | dependencies = [ 274 | "alloc-no-stdlib", 275 | "alloc-stdlib", 276 | ] 277 | 278 | [[package]] 279 | name = "bson" 280 | version = "2.7.0" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "58da0ae1e701ea752cc46c1bb9f39d5ecefc7395c3ecd526261a566d4f16e0c2" 283 | dependencies = [ 284 | "ahash", 285 | "base64 0.13.1", 286 | "bitvec", 287 | "chrono", 288 | "hex", 289 | "indexmap 1.9.3", 290 | "js-sys", 291 | "once_cell", 292 | "rand", 293 | "serde", 294 | "serde_bytes", 295 | "serde_json", 296 | "serde_with", 297 | "time", 298 | "uuid", 299 | ] 300 | 301 | [[package]] 302 | name = "bumpalo" 303 | version = "3.13.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" 306 | 307 | [[package]] 308 | name = "byteorder" 309 | version = "1.4.3" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 312 | 313 | [[package]] 314 | name = "bytes" 315 | version = "1.5.0" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 318 | 319 | [[package]] 320 | name = "cc" 321 | version = "1.0.90" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" 324 | 325 | [[package]] 326 | name = "cfg-if" 327 | version = "1.0.0" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 330 | 331 | [[package]] 332 | name = "chrono" 333 | version = "0.4.31" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" 336 | dependencies = [ 337 | "android-tzdata", 338 | "iana-time-zone", 339 | "js-sys", 340 | "num-traits", 341 | "wasm-bindgen", 342 | "windows-targets 0.48.1", 343 | ] 344 | 345 | [[package]] 346 | name = "cipher" 347 | version = "0.4.4" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 350 | dependencies = [ 351 | "crypto-common", 352 | "inout", 353 | ] 354 | 355 | [[package]] 356 | name = "config" 357 | version = "0.14.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" 360 | dependencies = [ 361 | "async-trait", 362 | "convert_case 0.6.0", 363 | "json5", 364 | "lazy_static", 365 | "nom", 366 | "pathdiff", 367 | "ron", 368 | "rust-ini", 369 | "serde", 370 | "serde_json", 371 | "toml", 372 | "yaml-rust", 373 | ] 374 | 375 | [[package]] 376 | name = "const-random" 377 | version = "0.1.17" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" 380 | dependencies = [ 381 | "const-random-macro", 382 | ] 383 | 384 | [[package]] 385 | name = "const-random-macro" 386 | version = "0.1.16" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" 389 | dependencies = [ 390 | "getrandom", 391 | "once_cell", 392 | "tiny-keccak", 393 | ] 394 | 395 | [[package]] 396 | name = "convert_case" 397 | version = "0.4.0" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 400 | 401 | [[package]] 402 | name = "convert_case" 403 | version = "0.6.0" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 406 | dependencies = [ 407 | "unicode-segmentation", 408 | ] 409 | 410 | [[package]] 411 | name = "core-foundation" 412 | version = "0.9.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 415 | dependencies = [ 416 | "core-foundation-sys", 417 | "libc", 418 | ] 419 | 420 | [[package]] 421 | name = "core-foundation-sys" 422 | version = "0.8.4" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" 425 | 426 | [[package]] 427 | name = "cpufeatures" 428 | version = "0.2.9" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 431 | dependencies = [ 432 | "libc", 433 | ] 434 | 435 | [[package]] 436 | name = "crunchy" 437 | version = "0.2.2" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 440 | 441 | [[package]] 442 | name = "crypto-common" 443 | version = "0.1.6" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 446 | dependencies = [ 447 | "generic-array", 448 | "typenum", 449 | ] 450 | 451 | [[package]] 452 | name = "darling" 453 | version = "0.10.2" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" 456 | dependencies = [ 457 | "darling_core 0.10.2", 458 | "darling_macro 0.10.2", 459 | ] 460 | 461 | [[package]] 462 | name = "darling" 463 | version = "0.13.4" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" 466 | dependencies = [ 467 | "darling_core 0.13.4", 468 | "darling_macro 0.13.4", 469 | ] 470 | 471 | [[package]] 472 | name = "darling_core" 473 | version = "0.10.2" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" 476 | dependencies = [ 477 | "fnv", 478 | "ident_case", 479 | "proc-macro2", 480 | "quote", 481 | "strsim 0.9.3", 482 | "syn 1.0.109", 483 | ] 484 | 485 | [[package]] 486 | name = "darling_core" 487 | version = "0.13.4" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" 490 | dependencies = [ 491 | "fnv", 492 | "ident_case", 493 | "proc-macro2", 494 | "quote", 495 | "strsim 0.10.0", 496 | "syn 1.0.109", 497 | ] 498 | 499 | [[package]] 500 | name = "darling_macro" 501 | version = "0.10.2" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" 504 | dependencies = [ 505 | "darling_core 0.10.2", 506 | "quote", 507 | "syn 1.0.109", 508 | ] 509 | 510 | [[package]] 511 | name = "darling_macro" 512 | version = "0.13.4" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" 515 | dependencies = [ 516 | "darling_core 0.13.4", 517 | "quote", 518 | "syn 1.0.109", 519 | ] 520 | 521 | [[package]] 522 | name = "data-encoding" 523 | version = "2.4.0" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" 526 | 527 | [[package]] 528 | name = "derivative" 529 | version = "2.2.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 532 | dependencies = [ 533 | "proc-macro2", 534 | "quote", 535 | "syn 1.0.109", 536 | ] 537 | 538 | [[package]] 539 | name = "derive_more" 540 | version = "0.99.17" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 543 | dependencies = [ 544 | "convert_case 0.4.0", 545 | "proc-macro2", 546 | "quote", 547 | "rustc_version 0.4.0", 548 | "syn 1.0.109", 549 | ] 550 | 551 | [[package]] 552 | name = "diff" 553 | version = "0.1.13" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" 556 | 557 | [[package]] 558 | name = "digest" 559 | version = "0.10.7" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 562 | dependencies = [ 563 | "block-buffer", 564 | "crypto-common", 565 | "subtle", 566 | ] 567 | 568 | [[package]] 569 | name = "dlv-list" 570 | version = "0.5.2" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" 573 | dependencies = [ 574 | "const-random", 575 | ] 576 | 577 | [[package]] 578 | name = "encoding_rs" 579 | version = "0.8.32" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" 582 | dependencies = [ 583 | "cfg-if", 584 | ] 585 | 586 | [[package]] 587 | name = "enum-as-inner" 588 | version = "0.4.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" 591 | dependencies = [ 592 | "heck", 593 | "proc-macro2", 594 | "quote", 595 | "syn 1.0.109", 596 | ] 597 | 598 | [[package]] 599 | name = "equivalent" 600 | version = "1.0.1" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 603 | 604 | [[package]] 605 | name = "errno" 606 | version = "0.3.1" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" 609 | dependencies = [ 610 | "errno-dragonfly", 611 | "libc", 612 | "windows-sys 0.48.0", 613 | ] 614 | 615 | [[package]] 616 | name = "errno-dragonfly" 617 | version = "0.1.2" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 620 | dependencies = [ 621 | "cc", 622 | "libc", 623 | ] 624 | 625 | [[package]] 626 | name = "fastrand" 627 | version = "1.9.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" 630 | dependencies = [ 631 | "instant", 632 | ] 633 | 634 | [[package]] 635 | name = "fnv" 636 | version = "1.0.7" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 639 | 640 | [[package]] 641 | name = "foreign-types" 642 | version = "0.3.2" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 645 | dependencies = [ 646 | "foreign-types-shared", 647 | ] 648 | 649 | [[package]] 650 | name = "foreign-types-shared" 651 | version = "0.1.1" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 654 | 655 | [[package]] 656 | name = "form_urlencoded" 657 | version = "1.2.0" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 660 | dependencies = [ 661 | "percent-encoding", 662 | ] 663 | 664 | [[package]] 665 | name = "funty" 666 | version = "2.0.0" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 669 | 670 | [[package]] 671 | name = "futures" 672 | version = "0.3.28" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 675 | dependencies = [ 676 | "futures-channel", 677 | "futures-core", 678 | "futures-executor", 679 | "futures-io", 680 | "futures-sink", 681 | "futures-task", 682 | "futures-util", 683 | ] 684 | 685 | [[package]] 686 | name = "futures-channel" 687 | version = "0.3.28" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 690 | dependencies = [ 691 | "futures-core", 692 | "futures-sink", 693 | ] 694 | 695 | [[package]] 696 | name = "futures-core" 697 | version = "0.3.28" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 700 | 701 | [[package]] 702 | name = "futures-executor" 703 | version = "0.3.28" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 706 | dependencies = [ 707 | "futures-core", 708 | "futures-task", 709 | "futures-util", 710 | ] 711 | 712 | [[package]] 713 | name = "futures-io" 714 | version = "0.3.28" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 717 | 718 | [[package]] 719 | name = "futures-macro" 720 | version = "0.3.28" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 723 | dependencies = [ 724 | "proc-macro2", 725 | "quote", 726 | "syn 2.0.48", 727 | ] 728 | 729 | [[package]] 730 | name = "futures-sink" 731 | version = "0.3.28" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 734 | 735 | [[package]] 736 | name = "futures-task" 737 | version = "0.3.28" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 740 | 741 | [[package]] 742 | name = "futures-util" 743 | version = "0.3.28" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 746 | dependencies = [ 747 | "futures-channel", 748 | "futures-core", 749 | "futures-io", 750 | "futures-macro", 751 | "futures-sink", 752 | "futures-task", 753 | "memchr", 754 | "pin-project-lite", 755 | "pin-utils", 756 | "slab", 757 | ] 758 | 759 | [[package]] 760 | name = "generic-array" 761 | version = "0.14.7" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 764 | dependencies = [ 765 | "typenum", 766 | "version_check", 767 | ] 768 | 769 | [[package]] 770 | name = "getrandom" 771 | version = "0.2.10" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 774 | dependencies = [ 775 | "cfg-if", 776 | "js-sys", 777 | "libc", 778 | "wasi", 779 | "wasm-bindgen", 780 | ] 781 | 782 | [[package]] 783 | name = "gimli" 784 | version = "0.27.3" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 787 | 788 | [[package]] 789 | name = "h2" 790 | version = "0.4.3" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" 793 | dependencies = [ 794 | "bytes", 795 | "fnv", 796 | "futures-core", 797 | "futures-sink", 798 | "futures-util", 799 | "http 1.1.0", 800 | "indexmap 2.2.1", 801 | "slab", 802 | "tokio", 803 | "tokio-util", 804 | "tracing", 805 | ] 806 | 807 | [[package]] 808 | name = "hashbrown" 809 | version = "0.12.3" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 812 | 813 | [[package]] 814 | name = "hashbrown" 815 | version = "0.13.2" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 818 | 819 | [[package]] 820 | name = "hashbrown" 821 | version = "0.14.3" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 824 | 825 | [[package]] 826 | name = "headers" 827 | version = "0.3.8" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" 830 | dependencies = [ 831 | "base64 0.13.1", 832 | "bitflags 1.3.2", 833 | "bytes", 834 | "headers-core", 835 | "http 0.2.9", 836 | "httpdate", 837 | "mime", 838 | "sha1", 839 | ] 840 | 841 | [[package]] 842 | name = "headers-core" 843 | version = "0.2.0" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 846 | dependencies = [ 847 | "http 0.2.9", 848 | ] 849 | 850 | [[package]] 851 | name = "heck" 852 | version = "0.4.1" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 855 | 856 | [[package]] 857 | name = "hermit-abi" 858 | version = "0.3.2" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 861 | 862 | [[package]] 863 | name = "hex" 864 | version = "0.4.3" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 867 | 868 | [[package]] 869 | name = "hmac" 870 | version = "0.12.1" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 873 | dependencies = [ 874 | "digest", 875 | ] 876 | 877 | [[package]] 878 | name = "hostname" 879 | version = "0.3.1" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" 882 | dependencies = [ 883 | "libc", 884 | "match_cfg", 885 | "winapi", 886 | ] 887 | 888 | [[package]] 889 | name = "http" 890 | version = "0.2.9" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 893 | dependencies = [ 894 | "bytes", 895 | "fnv", 896 | "itoa", 897 | ] 898 | 899 | [[package]] 900 | name = "http" 901 | version = "1.1.0" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 904 | dependencies = [ 905 | "bytes", 906 | "fnv", 907 | "itoa", 908 | ] 909 | 910 | [[package]] 911 | name = "http-body" 912 | version = "0.4.5" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 915 | dependencies = [ 916 | "bytes", 917 | "http 0.2.9", 918 | "pin-project-lite", 919 | ] 920 | 921 | [[package]] 922 | name = "http-body" 923 | version = "1.0.0" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 926 | dependencies = [ 927 | "bytes", 928 | "http 1.1.0", 929 | ] 930 | 931 | [[package]] 932 | name = "http-body-util" 933 | version = "0.1.1" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" 936 | dependencies = [ 937 | "bytes", 938 | "futures-core", 939 | "http 1.1.0", 940 | "http-body 1.0.0", 941 | "pin-project-lite", 942 | ] 943 | 944 | [[package]] 945 | name = "http-range-header" 946 | version = "0.3.0" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" 949 | 950 | [[package]] 951 | name = "httparse" 952 | version = "1.8.0" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 955 | 956 | [[package]] 957 | name = "httpdate" 958 | version = "1.0.2" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 961 | 962 | [[package]] 963 | name = "hyper" 964 | version = "0.14.27" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 967 | dependencies = [ 968 | "bytes", 969 | "futures-channel", 970 | "futures-core", 971 | "futures-util", 972 | "http 0.2.9", 973 | "http-body 0.4.5", 974 | "httparse", 975 | "httpdate", 976 | "itoa", 977 | "pin-project-lite", 978 | "socket2 0.4.9", 979 | "tokio", 980 | "tower-service", 981 | "tracing", 982 | "want", 983 | ] 984 | 985 | [[package]] 986 | name = "hyper" 987 | version = "1.2.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" 990 | dependencies = [ 991 | "bytes", 992 | "futures-channel", 993 | "futures-util", 994 | "h2", 995 | "http 1.1.0", 996 | "http-body 1.0.0", 997 | "httparse", 998 | "itoa", 999 | "pin-project-lite", 1000 | "smallvec", 1001 | "tokio", 1002 | "want", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "hyper-tls" 1007 | version = "0.6.0" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 1010 | dependencies = [ 1011 | "bytes", 1012 | "http-body-util", 1013 | "hyper 1.2.0", 1014 | "hyper-util", 1015 | "native-tls", 1016 | "tokio", 1017 | "tokio-native-tls", 1018 | "tower-service", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "hyper-util" 1023 | version = "0.1.3" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" 1026 | dependencies = [ 1027 | "bytes", 1028 | "futures-channel", 1029 | "futures-util", 1030 | "http 1.1.0", 1031 | "http-body 1.0.0", 1032 | "hyper 1.2.0", 1033 | "pin-project-lite", 1034 | "socket2 0.5.5", 1035 | "tokio", 1036 | "tower", 1037 | "tower-service", 1038 | "tracing", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "iana-time-zone" 1043 | version = "0.1.57" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" 1046 | dependencies = [ 1047 | "android_system_properties", 1048 | "core-foundation-sys", 1049 | "iana-time-zone-haiku", 1050 | "js-sys", 1051 | "wasm-bindgen", 1052 | "windows", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "iana-time-zone-haiku" 1057 | version = "0.1.2" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1060 | dependencies = [ 1061 | "cc", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "ident_case" 1066 | version = "1.0.1" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1069 | 1070 | [[package]] 1071 | name = "idna" 1072 | version = "0.2.3" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 1075 | dependencies = [ 1076 | "matches", 1077 | "unicode-bidi", 1078 | "unicode-normalization", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "idna" 1083 | version = "0.4.0" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 1086 | dependencies = [ 1087 | "unicode-bidi", 1088 | "unicode-normalization", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "if_chain" 1093 | version = "1.0.2" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" 1096 | 1097 | [[package]] 1098 | name = "indexmap" 1099 | version = "1.9.3" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 1102 | dependencies = [ 1103 | "autocfg", 1104 | "hashbrown 0.12.3", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "indexmap" 1109 | version = "2.2.1" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" 1112 | dependencies = [ 1113 | "equivalent", 1114 | "hashbrown 0.14.3", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "inout" 1119 | version = "0.1.3" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 1122 | dependencies = [ 1123 | "generic-array", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "instant" 1128 | version = "0.1.12" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1131 | dependencies = [ 1132 | "cfg-if", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "io-lifetimes" 1137 | version = "1.0.11" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 1140 | dependencies = [ 1141 | "hermit-abi", 1142 | "libc", 1143 | "windows-sys 0.48.0", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "ipconfig" 1148 | version = "0.3.2" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" 1151 | dependencies = [ 1152 | "socket2 0.5.5", 1153 | "widestring", 1154 | "windows-sys 0.48.0", 1155 | "winreg", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "ipnet" 1160 | version = "2.8.0" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" 1163 | 1164 | [[package]] 1165 | name = "itoa" 1166 | version = "1.0.9" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 1169 | 1170 | [[package]] 1171 | name = "js-sys" 1172 | version = "0.3.64" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 1175 | dependencies = [ 1176 | "wasm-bindgen", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "json5" 1181 | version = "0.4.1" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" 1184 | dependencies = [ 1185 | "pest", 1186 | "pest_derive", 1187 | "serde", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "jsonwebtoken" 1192 | version = "9.3.0" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" 1195 | dependencies = [ 1196 | "base64 0.21.2", 1197 | "js-sys", 1198 | "pem", 1199 | "ring 0.17.8", 1200 | "serde", 1201 | "serde_json", 1202 | "simple_asn1", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "lazy_static" 1207 | version = "1.4.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1210 | 1211 | [[package]] 1212 | name = "libc" 1213 | version = "0.2.151" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 1216 | 1217 | [[package]] 1218 | name = "linked-hash-map" 1219 | version = "0.5.6" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 1222 | 1223 | [[package]] 1224 | name = "linux-raw-sys" 1225 | version = "0.3.8" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 1228 | 1229 | [[package]] 1230 | name = "lock_api" 1231 | version = "0.4.10" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 1234 | dependencies = [ 1235 | "autocfg", 1236 | "scopeguard", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "log" 1241 | version = "0.4.19" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 1244 | 1245 | [[package]] 1246 | name = "lru-cache" 1247 | version = "0.1.2" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 1250 | dependencies = [ 1251 | "linked-hash-map", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "match_cfg" 1256 | version = "0.1.0" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" 1259 | 1260 | [[package]] 1261 | name = "matches" 1262 | version = "0.1.10" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 1265 | 1266 | [[package]] 1267 | name = "matchit" 1268 | version = "0.7.0" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" 1271 | 1272 | [[package]] 1273 | name = "md-5" 1274 | version = "0.10.5" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" 1277 | dependencies = [ 1278 | "digest", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "memchr" 1283 | version = "2.5.0" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 1286 | 1287 | [[package]] 1288 | name = "mime" 1289 | version = "0.3.17" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1292 | 1293 | [[package]] 1294 | name = "minimal-lexical" 1295 | version = "0.2.1" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1298 | 1299 | [[package]] 1300 | name = "miniz_oxide" 1301 | version = "0.7.1" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 1304 | dependencies = [ 1305 | "adler", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "mio" 1310 | version = "0.8.10" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" 1313 | dependencies = [ 1314 | "libc", 1315 | "wasi", 1316 | "windows-sys 0.48.0", 1317 | ] 1318 | 1319 | [[package]] 1320 | name = "mongodb" 1321 | version = "2.6.0" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "ebcd85ec209a5b84fd9f54b9e381f6fa17462bc74160d018fc94fd8b9f61faa8" 1324 | dependencies = [ 1325 | "async-trait", 1326 | "base64 0.13.1", 1327 | "bitflags 1.3.2", 1328 | "bson", 1329 | "chrono", 1330 | "derivative", 1331 | "derive_more", 1332 | "futures-core", 1333 | "futures-executor", 1334 | "futures-io", 1335 | "futures-util", 1336 | "hex", 1337 | "hmac", 1338 | "lazy_static", 1339 | "md-5", 1340 | "pbkdf2", 1341 | "percent-encoding", 1342 | "rand", 1343 | "rustc_version_runtime", 1344 | "rustls", 1345 | "rustls-pemfile", 1346 | "serde", 1347 | "serde_bytes", 1348 | "serde_with", 1349 | "sha-1", 1350 | "sha2", 1351 | "socket2 0.4.9", 1352 | "stringprep", 1353 | "strsim 0.10.0", 1354 | "take_mut", 1355 | "thiserror", 1356 | "tokio", 1357 | "tokio-rustls", 1358 | "tokio-util", 1359 | "trust-dns-proto", 1360 | "trust-dns-resolver", 1361 | "typed-builder", 1362 | "uuid", 1363 | "webpki-roots", 1364 | ] 1365 | 1366 | [[package]] 1367 | name = "native-tls" 1368 | version = "0.2.11" 1369 | source = "registry+https://github.com/rust-lang/crates.io-index" 1370 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 1371 | dependencies = [ 1372 | "lazy_static", 1373 | "libc", 1374 | "log", 1375 | "openssl", 1376 | "openssl-probe", 1377 | "openssl-sys", 1378 | "schannel", 1379 | "security-framework", 1380 | "security-framework-sys", 1381 | "tempfile", 1382 | ] 1383 | 1384 | [[package]] 1385 | name = "nom" 1386 | version = "7.1.3" 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" 1388 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1389 | dependencies = [ 1390 | "memchr", 1391 | "minimal-lexical", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "nu-ansi-term" 1396 | version = "0.46.0" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1399 | dependencies = [ 1400 | "overload", 1401 | "winapi", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "num-bigint" 1406 | version = "0.4.3" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 1409 | dependencies = [ 1410 | "autocfg", 1411 | "num-integer", 1412 | "num-traits", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "num-integer" 1417 | version = "0.1.45" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 1420 | dependencies = [ 1421 | "autocfg", 1422 | "num-traits", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "num-traits" 1427 | version = "0.2.15" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 1430 | dependencies = [ 1431 | "autocfg", 1432 | ] 1433 | 1434 | [[package]] 1435 | name = "num_cpus" 1436 | version = "1.16.0" 1437 | source = "registry+https://github.com/rust-lang/crates.io-index" 1438 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1439 | dependencies = [ 1440 | "hermit-abi", 1441 | "libc", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "object" 1446 | version = "0.31.1" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 1449 | dependencies = [ 1450 | "memchr", 1451 | ] 1452 | 1453 | [[package]] 1454 | name = "once_cell" 1455 | version = "1.18.0" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 1458 | 1459 | [[package]] 1460 | name = "openssl" 1461 | version = "0.10.55" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" 1464 | dependencies = [ 1465 | "bitflags 1.3.2", 1466 | "cfg-if", 1467 | "foreign-types", 1468 | "libc", 1469 | "once_cell", 1470 | "openssl-macros", 1471 | "openssl-sys", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "openssl-macros" 1476 | version = "0.1.1" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1479 | dependencies = [ 1480 | "proc-macro2", 1481 | "quote", 1482 | "syn 2.0.48", 1483 | ] 1484 | 1485 | [[package]] 1486 | name = "openssl-probe" 1487 | version = "0.1.5" 1488 | source = "registry+https://github.com/rust-lang/crates.io-index" 1489 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1490 | 1491 | [[package]] 1492 | name = "openssl-sys" 1493 | version = "0.9.90" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" 1496 | dependencies = [ 1497 | "cc", 1498 | "libc", 1499 | "pkg-config", 1500 | "vcpkg", 1501 | ] 1502 | 1503 | [[package]] 1504 | name = "ordered-multimap" 1505 | version = "0.6.0" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" 1508 | dependencies = [ 1509 | "dlv-list", 1510 | "hashbrown 0.13.2", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "overload" 1515 | version = "0.1.1" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1518 | 1519 | [[package]] 1520 | name = "parking_lot" 1521 | version = "0.12.1" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1524 | dependencies = [ 1525 | "lock_api", 1526 | "parking_lot_core", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "parking_lot_core" 1531 | version = "0.9.8" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 1534 | dependencies = [ 1535 | "cfg-if", 1536 | "libc", 1537 | "redox_syscall", 1538 | "smallvec", 1539 | "windows-targets 0.48.1", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "pathdiff" 1544 | version = "0.2.1" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" 1547 | 1548 | [[package]] 1549 | name = "pbkdf2" 1550 | version = "0.11.0" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" 1553 | dependencies = [ 1554 | "digest", 1555 | ] 1556 | 1557 | [[package]] 1558 | name = "pem" 1559 | version = "3.0.3" 1560 | source = "registry+https://github.com/rust-lang/crates.io-index" 1561 | checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" 1562 | dependencies = [ 1563 | "base64 0.21.2", 1564 | "serde", 1565 | ] 1566 | 1567 | [[package]] 1568 | name = "percent-encoding" 1569 | version = "2.3.0" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 1572 | 1573 | [[package]] 1574 | name = "pest" 1575 | version = "2.7.0" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" 1578 | dependencies = [ 1579 | "thiserror", 1580 | "ucd-trie", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "pest_derive" 1585 | version = "2.7.0" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" 1588 | dependencies = [ 1589 | "pest", 1590 | "pest_generator", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "pest_generator" 1595 | version = "2.7.0" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" 1598 | dependencies = [ 1599 | "pest", 1600 | "pest_meta", 1601 | "proc-macro2", 1602 | "quote", 1603 | "syn 2.0.48", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "pest_meta" 1608 | version = "2.7.0" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" 1611 | dependencies = [ 1612 | "once_cell", 1613 | "pest", 1614 | "sha2", 1615 | ] 1616 | 1617 | [[package]] 1618 | name = "pin-project" 1619 | version = "1.1.2" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" 1622 | dependencies = [ 1623 | "pin-project-internal", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "pin-project-internal" 1628 | version = "1.1.2" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" 1631 | dependencies = [ 1632 | "proc-macro2", 1633 | "quote", 1634 | "syn 2.0.48", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "pin-project-lite" 1639 | version = "0.2.12" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" 1642 | 1643 | [[package]] 1644 | name = "pin-utils" 1645 | version = "0.1.0" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1648 | 1649 | [[package]] 1650 | name = "pkg-config" 1651 | version = "0.3.27" 1652 | source = "registry+https://github.com/rust-lang/crates.io-index" 1653 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 1654 | 1655 | [[package]] 1656 | name = "ppv-lite86" 1657 | version = "0.2.17" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1660 | 1661 | [[package]] 1662 | name = "pretty_assertions" 1663 | version = "1.4.0" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" 1666 | dependencies = [ 1667 | "diff", 1668 | "yansi", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "proc-macro-error" 1673 | version = "1.0.4" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1676 | dependencies = [ 1677 | "proc-macro-error-attr", 1678 | "proc-macro2", 1679 | "quote", 1680 | "syn 1.0.109", 1681 | "version_check", 1682 | ] 1683 | 1684 | [[package]] 1685 | name = "proc-macro-error-attr" 1686 | version = "1.0.4" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1689 | dependencies = [ 1690 | "proc-macro2", 1691 | "quote", 1692 | "version_check", 1693 | ] 1694 | 1695 | [[package]] 1696 | name = "proc-macro2" 1697 | version = "1.0.78" 1698 | source = "registry+https://github.com/rust-lang/crates.io-index" 1699 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 1700 | dependencies = [ 1701 | "unicode-ident", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "quick-error" 1706 | version = "1.2.3" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1709 | 1710 | [[package]] 1711 | name = "quote" 1712 | version = "1.0.35" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 1715 | dependencies = [ 1716 | "proc-macro2", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "radium" 1721 | version = "0.7.0" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 1724 | 1725 | [[package]] 1726 | name = "rand" 1727 | version = "0.8.5" 1728 | source = "registry+https://github.com/rust-lang/crates.io-index" 1729 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1730 | dependencies = [ 1731 | "libc", 1732 | "rand_chacha", 1733 | "rand_core", 1734 | ] 1735 | 1736 | [[package]] 1737 | name = "rand_chacha" 1738 | version = "0.3.1" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1741 | dependencies = [ 1742 | "ppv-lite86", 1743 | "rand_core", 1744 | ] 1745 | 1746 | [[package]] 1747 | name = "rand_core" 1748 | version = "0.6.4" 1749 | source = "registry+https://github.com/rust-lang/crates.io-index" 1750 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1751 | dependencies = [ 1752 | "getrandom", 1753 | ] 1754 | 1755 | [[package]] 1756 | name = "redox_syscall" 1757 | version = "0.3.5" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1760 | dependencies = [ 1761 | "bitflags 1.3.2", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "regex" 1766 | version = "1.9.1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" 1769 | dependencies = [ 1770 | "aho-corasick", 1771 | "memchr", 1772 | "regex-automata", 1773 | "regex-syntax", 1774 | ] 1775 | 1776 | [[package]] 1777 | name = "regex-automata" 1778 | version = "0.3.3" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" 1781 | dependencies = [ 1782 | "aho-corasick", 1783 | "memchr", 1784 | "regex-syntax", 1785 | ] 1786 | 1787 | [[package]] 1788 | name = "regex-syntax" 1789 | version = "0.7.4" 1790 | source = "registry+https://github.com/rust-lang/crates.io-index" 1791 | checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 1792 | 1793 | [[package]] 1794 | name = "reqwest" 1795 | version = "0.12.2" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" 1798 | dependencies = [ 1799 | "base64 0.21.2", 1800 | "bytes", 1801 | "encoding_rs", 1802 | "futures-core", 1803 | "futures-util", 1804 | "h2", 1805 | "http 1.1.0", 1806 | "http-body 1.0.0", 1807 | "http-body-util", 1808 | "hyper 1.2.0", 1809 | "hyper-tls", 1810 | "hyper-util", 1811 | "ipnet", 1812 | "js-sys", 1813 | "log", 1814 | "mime", 1815 | "native-tls", 1816 | "once_cell", 1817 | "percent-encoding", 1818 | "pin-project-lite", 1819 | "rustls-pemfile", 1820 | "serde", 1821 | "serde_json", 1822 | "serde_urlencoded", 1823 | "sync_wrapper", 1824 | "system-configuration", 1825 | "tokio", 1826 | "tokio-native-tls", 1827 | "tower-service", 1828 | "url", 1829 | "wasm-bindgen", 1830 | "wasm-bindgen-futures", 1831 | "web-sys", 1832 | "winreg", 1833 | ] 1834 | 1835 | [[package]] 1836 | name = "resolv-conf" 1837 | version = "0.7.0" 1838 | source = "registry+https://github.com/rust-lang/crates.io-index" 1839 | checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" 1840 | dependencies = [ 1841 | "hostname", 1842 | "quick-error", 1843 | ] 1844 | 1845 | [[package]] 1846 | name = "ring" 1847 | version = "0.16.20" 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" 1849 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1850 | dependencies = [ 1851 | "cc", 1852 | "libc", 1853 | "once_cell", 1854 | "spin 0.5.2", 1855 | "untrusted 0.7.1", 1856 | "web-sys", 1857 | "winapi", 1858 | ] 1859 | 1860 | [[package]] 1861 | name = "ring" 1862 | version = "0.17.8" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1865 | dependencies = [ 1866 | "cc", 1867 | "cfg-if", 1868 | "getrandom", 1869 | "libc", 1870 | "spin 0.9.8", 1871 | "untrusted 0.9.0", 1872 | "windows-sys 0.52.0", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "ron" 1877 | version = "0.8.1" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" 1880 | dependencies = [ 1881 | "base64 0.21.2", 1882 | "bitflags 2.3.3", 1883 | "serde", 1884 | "serde_derive", 1885 | ] 1886 | 1887 | [[package]] 1888 | name = "rust-ini" 1889 | version = "0.19.0" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" 1892 | dependencies = [ 1893 | "cfg-if", 1894 | "ordered-multimap", 1895 | ] 1896 | 1897 | [[package]] 1898 | name = "rustapi" 1899 | version = "0.1.0" 1900 | dependencies = [ 1901 | "assert-json-diff", 1902 | "async-trait", 1903 | "axum", 1904 | "bcrypt", 1905 | "bson", 1906 | "bytes", 1907 | "chrono", 1908 | "config", 1909 | "futures", 1910 | "http 0.2.9", 1911 | "jsonwebtoken", 1912 | "lazy_static", 1913 | "mime", 1914 | "once_cell", 1915 | "pretty_assertions", 1916 | "reqwest", 1917 | "serde", 1918 | "serde_derive", 1919 | "serde_json", 1920 | "thiserror", 1921 | "tokio", 1922 | "tower-http", 1923 | "tracing", 1924 | "tracing-subscriber", 1925 | "validator", 1926 | "wither", 1927 | ] 1928 | 1929 | [[package]] 1930 | name = "rustc-demangle" 1931 | version = "0.1.23" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1934 | 1935 | [[package]] 1936 | name = "rustc_version" 1937 | version = "0.2.3" 1938 | source = "registry+https://github.com/rust-lang/crates.io-index" 1939 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1940 | dependencies = [ 1941 | "semver 0.9.0", 1942 | ] 1943 | 1944 | [[package]] 1945 | name = "rustc_version" 1946 | version = "0.4.0" 1947 | source = "registry+https://github.com/rust-lang/crates.io-index" 1948 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1949 | dependencies = [ 1950 | "semver 1.0.18", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "rustc_version_runtime" 1955 | version = "0.2.1" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" 1958 | dependencies = [ 1959 | "rustc_version 0.2.3", 1960 | "semver 0.9.0", 1961 | ] 1962 | 1963 | [[package]] 1964 | name = "rustix" 1965 | version = "0.37.23" 1966 | source = "registry+https://github.com/rust-lang/crates.io-index" 1967 | checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" 1968 | dependencies = [ 1969 | "bitflags 1.3.2", 1970 | "errno", 1971 | "io-lifetimes", 1972 | "libc", 1973 | "linux-raw-sys", 1974 | "windows-sys 0.48.0", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "rustls" 1979 | version = "0.20.8" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" 1982 | dependencies = [ 1983 | "log", 1984 | "ring 0.16.20", 1985 | "sct", 1986 | "webpki", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "rustls-pemfile" 1991 | version = "1.0.3" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" 1994 | dependencies = [ 1995 | "base64 0.21.2", 1996 | ] 1997 | 1998 | [[package]] 1999 | name = "rustversion" 2000 | version = "1.0.14" 2001 | source = "registry+https://github.com/rust-lang/crates.io-index" 2002 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 2003 | 2004 | [[package]] 2005 | name = "ryu" 2006 | version = "1.0.15" 2007 | source = "registry+https://github.com/rust-lang/crates.io-index" 2008 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 2009 | 2010 | [[package]] 2011 | name = "schannel" 2012 | version = "0.1.22" 2013 | source = "registry+https://github.com/rust-lang/crates.io-index" 2014 | checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" 2015 | dependencies = [ 2016 | "windows-sys 0.48.0", 2017 | ] 2018 | 2019 | [[package]] 2020 | name = "scopeguard" 2021 | version = "1.1.0" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 2024 | 2025 | [[package]] 2026 | name = "sct" 2027 | version = "0.7.0" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 2030 | dependencies = [ 2031 | "ring 0.16.20", 2032 | "untrusted 0.7.1", 2033 | ] 2034 | 2035 | [[package]] 2036 | name = "security-framework" 2037 | version = "2.9.1" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" 2040 | dependencies = [ 2041 | "bitflags 1.3.2", 2042 | "core-foundation", 2043 | "core-foundation-sys", 2044 | "libc", 2045 | "security-framework-sys", 2046 | ] 2047 | 2048 | [[package]] 2049 | name = "security-framework-sys" 2050 | version = "2.9.0" 2051 | source = "registry+https://github.com/rust-lang/crates.io-index" 2052 | checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" 2053 | dependencies = [ 2054 | "core-foundation-sys", 2055 | "libc", 2056 | ] 2057 | 2058 | [[package]] 2059 | name = "semver" 2060 | version = "0.9.0" 2061 | source = "registry+https://github.com/rust-lang/crates.io-index" 2062 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 2063 | dependencies = [ 2064 | "semver-parser", 2065 | ] 2066 | 2067 | [[package]] 2068 | name = "semver" 2069 | version = "1.0.18" 2070 | source = "registry+https://github.com/rust-lang/crates.io-index" 2071 | checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" 2072 | 2073 | [[package]] 2074 | name = "semver-parser" 2075 | version = "0.7.0" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 2078 | 2079 | [[package]] 2080 | name = "serde" 2081 | version = "1.0.196" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" 2084 | dependencies = [ 2085 | "serde_derive", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "serde_bytes" 2090 | version = "0.11.12" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" 2093 | dependencies = [ 2094 | "serde", 2095 | ] 2096 | 2097 | [[package]] 2098 | name = "serde_derive" 2099 | version = "1.0.196" 2100 | source = "registry+https://github.com/rust-lang/crates.io-index" 2101 | checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" 2102 | dependencies = [ 2103 | "proc-macro2", 2104 | "quote", 2105 | "syn 2.0.48", 2106 | ] 2107 | 2108 | [[package]] 2109 | name = "serde_json" 2110 | version = "1.0.113" 2111 | source = "registry+https://github.com/rust-lang/crates.io-index" 2112 | checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" 2113 | dependencies = [ 2114 | "indexmap 2.2.1", 2115 | "itoa", 2116 | "ryu", 2117 | "serde", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "serde_path_to_error" 2122 | version = "0.1.14" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" 2125 | dependencies = [ 2126 | "itoa", 2127 | "serde", 2128 | ] 2129 | 2130 | [[package]] 2131 | name = "serde_spanned" 2132 | version = "0.6.5" 2133 | source = "registry+https://github.com/rust-lang/crates.io-index" 2134 | checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" 2135 | dependencies = [ 2136 | "serde", 2137 | ] 2138 | 2139 | [[package]] 2140 | name = "serde_urlencoded" 2141 | version = "0.7.1" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2144 | dependencies = [ 2145 | "form_urlencoded", 2146 | "itoa", 2147 | "ryu", 2148 | "serde", 2149 | ] 2150 | 2151 | [[package]] 2152 | name = "serde_with" 2153 | version = "1.14.0" 2154 | source = "registry+https://github.com/rust-lang/crates.io-index" 2155 | checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" 2156 | dependencies = [ 2157 | "serde", 2158 | "serde_with_macros", 2159 | ] 2160 | 2161 | [[package]] 2162 | name = "serde_with_macros" 2163 | version = "1.5.2" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" 2166 | dependencies = [ 2167 | "darling 0.13.4", 2168 | "proc-macro2", 2169 | "quote", 2170 | "syn 1.0.109", 2171 | ] 2172 | 2173 | [[package]] 2174 | name = "sha-1" 2175 | version = "0.10.1" 2176 | source = "registry+https://github.com/rust-lang/crates.io-index" 2177 | checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" 2178 | dependencies = [ 2179 | "cfg-if", 2180 | "cpufeatures", 2181 | "digest", 2182 | ] 2183 | 2184 | [[package]] 2185 | name = "sha1" 2186 | version = "0.10.5" 2187 | source = "registry+https://github.com/rust-lang/crates.io-index" 2188 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 2189 | dependencies = [ 2190 | "cfg-if", 2191 | "cpufeatures", 2192 | "digest", 2193 | ] 2194 | 2195 | [[package]] 2196 | name = "sha2" 2197 | version = "0.10.7" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 2200 | dependencies = [ 2201 | "cfg-if", 2202 | "cpufeatures", 2203 | "digest", 2204 | ] 2205 | 2206 | [[package]] 2207 | name = "sharded-slab" 2208 | version = "0.1.4" 2209 | source = "registry+https://github.com/rust-lang/crates.io-index" 2210 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 2211 | dependencies = [ 2212 | "lazy_static", 2213 | ] 2214 | 2215 | [[package]] 2216 | name = "signal-hook-registry" 2217 | version = "1.4.1" 2218 | source = "registry+https://github.com/rust-lang/crates.io-index" 2219 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 2220 | dependencies = [ 2221 | "libc", 2222 | ] 2223 | 2224 | [[package]] 2225 | name = "simple_asn1" 2226 | version = "0.6.2" 2227 | source = "registry+https://github.com/rust-lang/crates.io-index" 2228 | checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" 2229 | dependencies = [ 2230 | "num-bigint", 2231 | "num-traits", 2232 | "thiserror", 2233 | "time", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "slab" 2238 | version = "0.4.8" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 2241 | dependencies = [ 2242 | "autocfg", 2243 | ] 2244 | 2245 | [[package]] 2246 | name = "smallvec" 2247 | version = "1.13.2" 2248 | source = "registry+https://github.com/rust-lang/crates.io-index" 2249 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2250 | 2251 | [[package]] 2252 | name = "socket2" 2253 | version = "0.4.9" 2254 | source = "registry+https://github.com/rust-lang/crates.io-index" 2255 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 2256 | dependencies = [ 2257 | "libc", 2258 | "winapi", 2259 | ] 2260 | 2261 | [[package]] 2262 | name = "socket2" 2263 | version = "0.5.5" 2264 | source = "registry+https://github.com/rust-lang/crates.io-index" 2265 | checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" 2266 | dependencies = [ 2267 | "libc", 2268 | "windows-sys 0.48.0", 2269 | ] 2270 | 2271 | [[package]] 2272 | name = "spin" 2273 | version = "0.5.2" 2274 | source = "registry+https://github.com/rust-lang/crates.io-index" 2275 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 2276 | 2277 | [[package]] 2278 | name = "spin" 2279 | version = "0.9.8" 2280 | source = "registry+https://github.com/rust-lang/crates.io-index" 2281 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 2282 | 2283 | [[package]] 2284 | name = "stringprep" 2285 | version = "0.1.3" 2286 | source = "registry+https://github.com/rust-lang/crates.io-index" 2287 | checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" 2288 | dependencies = [ 2289 | "unicode-bidi", 2290 | "unicode-normalization", 2291 | ] 2292 | 2293 | [[package]] 2294 | name = "strsim" 2295 | version = "0.9.3" 2296 | source = "registry+https://github.com/rust-lang/crates.io-index" 2297 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 2298 | 2299 | [[package]] 2300 | name = "strsim" 2301 | version = "0.10.0" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 2304 | 2305 | [[package]] 2306 | name = "subtle" 2307 | version = "2.5.0" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 2310 | 2311 | [[package]] 2312 | name = "syn" 2313 | version = "1.0.109" 2314 | source = "registry+https://github.com/rust-lang/crates.io-index" 2315 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2316 | dependencies = [ 2317 | "proc-macro2", 2318 | "quote", 2319 | "unicode-ident", 2320 | ] 2321 | 2322 | [[package]] 2323 | name = "syn" 2324 | version = "2.0.48" 2325 | source = "registry+https://github.com/rust-lang/crates.io-index" 2326 | checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" 2327 | dependencies = [ 2328 | "proc-macro2", 2329 | "quote", 2330 | "unicode-ident", 2331 | ] 2332 | 2333 | [[package]] 2334 | name = "sync_wrapper" 2335 | version = "0.1.2" 2336 | source = "registry+https://github.com/rust-lang/crates.io-index" 2337 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2338 | 2339 | [[package]] 2340 | name = "system-configuration" 2341 | version = "0.5.1" 2342 | source = "registry+https://github.com/rust-lang/crates.io-index" 2343 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 2344 | dependencies = [ 2345 | "bitflags 1.3.2", 2346 | "core-foundation", 2347 | "system-configuration-sys", 2348 | ] 2349 | 2350 | [[package]] 2351 | name = "system-configuration-sys" 2352 | version = "0.5.0" 2353 | source = "registry+https://github.com/rust-lang/crates.io-index" 2354 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 2355 | dependencies = [ 2356 | "core-foundation-sys", 2357 | "libc", 2358 | ] 2359 | 2360 | [[package]] 2361 | name = "take_mut" 2362 | version = "0.2.2" 2363 | source = "registry+https://github.com/rust-lang/crates.io-index" 2364 | checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" 2365 | 2366 | [[package]] 2367 | name = "tap" 2368 | version = "1.0.1" 2369 | source = "registry+https://github.com/rust-lang/crates.io-index" 2370 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 2371 | 2372 | [[package]] 2373 | name = "tempfile" 2374 | version = "3.6.0" 2375 | source = "registry+https://github.com/rust-lang/crates.io-index" 2376 | checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" 2377 | dependencies = [ 2378 | "autocfg", 2379 | "cfg-if", 2380 | "fastrand", 2381 | "redox_syscall", 2382 | "rustix", 2383 | "windows-sys 0.48.0", 2384 | ] 2385 | 2386 | [[package]] 2387 | name = "thiserror" 2388 | version = "1.0.55" 2389 | source = "registry+https://github.com/rust-lang/crates.io-index" 2390 | checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" 2391 | dependencies = [ 2392 | "thiserror-impl", 2393 | ] 2394 | 2395 | [[package]] 2396 | name = "thiserror-impl" 2397 | version = "1.0.55" 2398 | source = "registry+https://github.com/rust-lang/crates.io-index" 2399 | checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" 2400 | dependencies = [ 2401 | "proc-macro2", 2402 | "quote", 2403 | "syn 2.0.48", 2404 | ] 2405 | 2406 | [[package]] 2407 | name = "thread_local" 2408 | version = "1.1.7" 2409 | source = "registry+https://github.com/rust-lang/crates.io-index" 2410 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" 2411 | dependencies = [ 2412 | "cfg-if", 2413 | "once_cell", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "time" 2418 | version = "0.3.23" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" 2421 | dependencies = [ 2422 | "itoa", 2423 | "serde", 2424 | "time-core", 2425 | "time-macros", 2426 | ] 2427 | 2428 | [[package]] 2429 | name = "time-core" 2430 | version = "0.1.1" 2431 | source = "registry+https://github.com/rust-lang/crates.io-index" 2432 | checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" 2433 | 2434 | [[package]] 2435 | name = "time-macros" 2436 | version = "0.2.10" 2437 | source = "registry+https://github.com/rust-lang/crates.io-index" 2438 | checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" 2439 | dependencies = [ 2440 | "time-core", 2441 | ] 2442 | 2443 | [[package]] 2444 | name = "tiny-keccak" 2445 | version = "2.0.2" 2446 | source = "registry+https://github.com/rust-lang/crates.io-index" 2447 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 2448 | dependencies = [ 2449 | "crunchy", 2450 | ] 2451 | 2452 | [[package]] 2453 | name = "tinyvec" 2454 | version = "1.6.0" 2455 | source = "registry+https://github.com/rust-lang/crates.io-index" 2456 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 2457 | dependencies = [ 2458 | "tinyvec_macros", 2459 | ] 2460 | 2461 | [[package]] 2462 | name = "tinyvec_macros" 2463 | version = "0.1.1" 2464 | source = "registry+https://github.com/rust-lang/crates.io-index" 2465 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2466 | 2467 | [[package]] 2468 | name = "tokio" 2469 | version = "1.35.0" 2470 | source = "registry+https://github.com/rust-lang/crates.io-index" 2471 | checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" 2472 | dependencies = [ 2473 | "backtrace", 2474 | "bytes", 2475 | "libc", 2476 | "mio", 2477 | "num_cpus", 2478 | "parking_lot", 2479 | "pin-project-lite", 2480 | "signal-hook-registry", 2481 | "socket2 0.5.5", 2482 | "tokio-macros", 2483 | "windows-sys 0.48.0", 2484 | ] 2485 | 2486 | [[package]] 2487 | name = "tokio-macros" 2488 | version = "2.2.0" 2489 | source = "registry+https://github.com/rust-lang/crates.io-index" 2490 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 2491 | dependencies = [ 2492 | "proc-macro2", 2493 | "quote", 2494 | "syn 2.0.48", 2495 | ] 2496 | 2497 | [[package]] 2498 | name = "tokio-native-tls" 2499 | version = "0.3.1" 2500 | source = "registry+https://github.com/rust-lang/crates.io-index" 2501 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2502 | dependencies = [ 2503 | "native-tls", 2504 | "tokio", 2505 | ] 2506 | 2507 | [[package]] 2508 | name = "tokio-rustls" 2509 | version = "0.23.4" 2510 | source = "registry+https://github.com/rust-lang/crates.io-index" 2511 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" 2512 | dependencies = [ 2513 | "rustls", 2514 | "tokio", 2515 | "webpki", 2516 | ] 2517 | 2518 | [[package]] 2519 | name = "tokio-util" 2520 | version = "0.7.8" 2521 | source = "registry+https://github.com/rust-lang/crates.io-index" 2522 | checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" 2523 | dependencies = [ 2524 | "bytes", 2525 | "futures-core", 2526 | "futures-io", 2527 | "futures-sink", 2528 | "pin-project-lite", 2529 | "tokio", 2530 | "tracing", 2531 | ] 2532 | 2533 | [[package]] 2534 | name = "toml" 2535 | version = "0.8.9" 2536 | source = "registry+https://github.com/rust-lang/crates.io-index" 2537 | checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" 2538 | dependencies = [ 2539 | "serde", 2540 | "serde_spanned", 2541 | "toml_datetime", 2542 | "toml_edit", 2543 | ] 2544 | 2545 | [[package]] 2546 | name = "toml_datetime" 2547 | version = "0.6.5" 2548 | source = "registry+https://github.com/rust-lang/crates.io-index" 2549 | checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" 2550 | dependencies = [ 2551 | "serde", 2552 | ] 2553 | 2554 | [[package]] 2555 | name = "toml_edit" 2556 | version = "0.21.1" 2557 | source = "registry+https://github.com/rust-lang/crates.io-index" 2558 | checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" 2559 | dependencies = [ 2560 | "indexmap 2.2.1", 2561 | "serde", 2562 | "serde_spanned", 2563 | "toml_datetime", 2564 | "winnow", 2565 | ] 2566 | 2567 | [[package]] 2568 | name = "tower" 2569 | version = "0.4.13" 2570 | source = "registry+https://github.com/rust-lang/crates.io-index" 2571 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2572 | dependencies = [ 2573 | "futures-core", 2574 | "futures-util", 2575 | "pin-project", 2576 | "pin-project-lite", 2577 | "tokio", 2578 | "tower-layer", 2579 | "tower-service", 2580 | "tracing", 2581 | ] 2582 | 2583 | [[package]] 2584 | name = "tower-http" 2585 | version = "0.4.4" 2586 | source = "registry+https://github.com/rust-lang/crates.io-index" 2587 | checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" 2588 | dependencies = [ 2589 | "async-compression", 2590 | "bitflags 2.3.3", 2591 | "bytes", 2592 | "futures-core", 2593 | "futures-util", 2594 | "http 0.2.9", 2595 | "http-body 0.4.5", 2596 | "http-range-header", 2597 | "pin-project-lite", 2598 | "tokio", 2599 | "tokio-util", 2600 | "tower-layer", 2601 | "tower-service", 2602 | "tracing", 2603 | ] 2604 | 2605 | [[package]] 2606 | name = "tower-layer" 2607 | version = "0.3.2" 2608 | source = "registry+https://github.com/rust-lang/crates.io-index" 2609 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2610 | 2611 | [[package]] 2612 | name = "tower-service" 2613 | version = "0.3.2" 2614 | source = "registry+https://github.com/rust-lang/crates.io-index" 2615 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2616 | 2617 | [[package]] 2618 | name = "tracing" 2619 | version = "0.1.37" 2620 | source = "registry+https://github.com/rust-lang/crates.io-index" 2621 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 2622 | dependencies = [ 2623 | "cfg-if", 2624 | "log", 2625 | "pin-project-lite", 2626 | "tracing-attributes", 2627 | "tracing-core", 2628 | ] 2629 | 2630 | [[package]] 2631 | name = "tracing-attributes" 2632 | version = "0.1.26" 2633 | source = "registry+https://github.com/rust-lang/crates.io-index" 2634 | checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" 2635 | dependencies = [ 2636 | "proc-macro2", 2637 | "quote", 2638 | "syn 2.0.48", 2639 | ] 2640 | 2641 | [[package]] 2642 | name = "tracing-core" 2643 | version = "0.1.31" 2644 | source = "registry+https://github.com/rust-lang/crates.io-index" 2645 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 2646 | dependencies = [ 2647 | "once_cell", 2648 | "valuable", 2649 | ] 2650 | 2651 | [[package]] 2652 | name = "tracing-log" 2653 | version = "0.1.3" 2654 | source = "registry+https://github.com/rust-lang/crates.io-index" 2655 | checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" 2656 | dependencies = [ 2657 | "lazy_static", 2658 | "log", 2659 | "tracing-core", 2660 | ] 2661 | 2662 | [[package]] 2663 | name = "tracing-subscriber" 2664 | version = "0.3.17" 2665 | source = "registry+https://github.com/rust-lang/crates.io-index" 2666 | checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" 2667 | dependencies = [ 2668 | "nu-ansi-term", 2669 | "sharded-slab", 2670 | "smallvec", 2671 | "thread_local", 2672 | "tracing-core", 2673 | "tracing-log", 2674 | ] 2675 | 2676 | [[package]] 2677 | name = "trust-dns-proto" 2678 | version = "0.21.2" 2679 | source = "registry+https://github.com/rust-lang/crates.io-index" 2680 | checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" 2681 | dependencies = [ 2682 | "async-trait", 2683 | "cfg-if", 2684 | "data-encoding", 2685 | "enum-as-inner", 2686 | "futures-channel", 2687 | "futures-io", 2688 | "futures-util", 2689 | "idna 0.2.3", 2690 | "ipnet", 2691 | "lazy_static", 2692 | "log", 2693 | "rand", 2694 | "smallvec", 2695 | "thiserror", 2696 | "tinyvec", 2697 | "tokio", 2698 | "url", 2699 | ] 2700 | 2701 | [[package]] 2702 | name = "trust-dns-resolver" 2703 | version = "0.21.2" 2704 | source = "registry+https://github.com/rust-lang/crates.io-index" 2705 | checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" 2706 | dependencies = [ 2707 | "cfg-if", 2708 | "futures-util", 2709 | "ipconfig", 2710 | "lazy_static", 2711 | "log", 2712 | "lru-cache", 2713 | "parking_lot", 2714 | "resolv-conf", 2715 | "smallvec", 2716 | "thiserror", 2717 | "tokio", 2718 | "trust-dns-proto", 2719 | ] 2720 | 2721 | [[package]] 2722 | name = "try-lock" 2723 | version = "0.2.4" 2724 | source = "registry+https://github.com/rust-lang/crates.io-index" 2725 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 2726 | 2727 | [[package]] 2728 | name = "typed-builder" 2729 | version = "0.10.0" 2730 | source = "registry+https://github.com/rust-lang/crates.io-index" 2731 | checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" 2732 | dependencies = [ 2733 | "proc-macro2", 2734 | "quote", 2735 | "syn 1.0.109", 2736 | ] 2737 | 2738 | [[package]] 2739 | name = "typenum" 2740 | version = "1.16.0" 2741 | source = "registry+https://github.com/rust-lang/crates.io-index" 2742 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 2743 | 2744 | [[package]] 2745 | name = "ucd-trie" 2746 | version = "0.1.6" 2747 | source = "registry+https://github.com/rust-lang/crates.io-index" 2748 | checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" 2749 | 2750 | [[package]] 2751 | name = "unicode-bidi" 2752 | version = "0.3.13" 2753 | source = "registry+https://github.com/rust-lang/crates.io-index" 2754 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 2755 | 2756 | [[package]] 2757 | name = "unicode-ident" 2758 | version = "1.0.11" 2759 | source = "registry+https://github.com/rust-lang/crates.io-index" 2760 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 2761 | 2762 | [[package]] 2763 | name = "unicode-normalization" 2764 | version = "0.1.22" 2765 | source = "registry+https://github.com/rust-lang/crates.io-index" 2766 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 2767 | dependencies = [ 2768 | "tinyvec", 2769 | ] 2770 | 2771 | [[package]] 2772 | name = "unicode-segmentation" 2773 | version = "1.10.1" 2774 | source = "registry+https://github.com/rust-lang/crates.io-index" 2775 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 2776 | 2777 | [[package]] 2778 | name = "untrusted" 2779 | version = "0.7.1" 2780 | source = "registry+https://github.com/rust-lang/crates.io-index" 2781 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2782 | 2783 | [[package]] 2784 | name = "untrusted" 2785 | version = "0.9.0" 2786 | source = "registry+https://github.com/rust-lang/crates.io-index" 2787 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2788 | 2789 | [[package]] 2790 | name = "url" 2791 | version = "2.4.0" 2792 | source = "registry+https://github.com/rust-lang/crates.io-index" 2793 | checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" 2794 | dependencies = [ 2795 | "form_urlencoded", 2796 | "idna 0.4.0", 2797 | "percent-encoding", 2798 | ] 2799 | 2800 | [[package]] 2801 | name = "uuid" 2802 | version = "1.4.0" 2803 | source = "registry+https://github.com/rust-lang/crates.io-index" 2804 | checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" 2805 | dependencies = [ 2806 | "getrandom", 2807 | "serde", 2808 | ] 2809 | 2810 | [[package]] 2811 | name = "validator" 2812 | version = "0.16.1" 2813 | source = "registry+https://github.com/rust-lang/crates.io-index" 2814 | checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" 2815 | dependencies = [ 2816 | "idna 0.4.0", 2817 | "lazy_static", 2818 | "regex", 2819 | "serde", 2820 | "serde_derive", 2821 | "serde_json", 2822 | "url", 2823 | "validator_derive", 2824 | ] 2825 | 2826 | [[package]] 2827 | name = "validator_derive" 2828 | version = "0.16.0" 2829 | source = "registry+https://github.com/rust-lang/crates.io-index" 2830 | checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" 2831 | dependencies = [ 2832 | "if_chain", 2833 | "lazy_static", 2834 | "proc-macro-error", 2835 | "proc-macro2", 2836 | "quote", 2837 | "regex", 2838 | "syn 1.0.109", 2839 | "validator_types", 2840 | ] 2841 | 2842 | [[package]] 2843 | name = "validator_types" 2844 | version = "0.16.0" 2845 | source = "registry+https://github.com/rust-lang/crates.io-index" 2846 | checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" 2847 | dependencies = [ 2848 | "proc-macro2", 2849 | "syn 1.0.109", 2850 | ] 2851 | 2852 | [[package]] 2853 | name = "valuable" 2854 | version = "0.1.0" 2855 | source = "registry+https://github.com/rust-lang/crates.io-index" 2856 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2857 | 2858 | [[package]] 2859 | name = "vcpkg" 2860 | version = "0.2.15" 2861 | source = "registry+https://github.com/rust-lang/crates.io-index" 2862 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2863 | 2864 | [[package]] 2865 | name = "version_check" 2866 | version = "0.9.4" 2867 | source = "registry+https://github.com/rust-lang/crates.io-index" 2868 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2869 | 2870 | [[package]] 2871 | name = "want" 2872 | version = "0.3.1" 2873 | source = "registry+https://github.com/rust-lang/crates.io-index" 2874 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2875 | dependencies = [ 2876 | "try-lock", 2877 | ] 2878 | 2879 | [[package]] 2880 | name = "wasi" 2881 | version = "0.11.0+wasi-snapshot-preview1" 2882 | source = "registry+https://github.com/rust-lang/crates.io-index" 2883 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2884 | 2885 | [[package]] 2886 | name = "wasm-bindgen" 2887 | version = "0.2.87" 2888 | source = "registry+https://github.com/rust-lang/crates.io-index" 2889 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 2890 | dependencies = [ 2891 | "cfg-if", 2892 | "wasm-bindgen-macro", 2893 | ] 2894 | 2895 | [[package]] 2896 | name = "wasm-bindgen-backend" 2897 | version = "0.2.87" 2898 | source = "registry+https://github.com/rust-lang/crates.io-index" 2899 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 2900 | dependencies = [ 2901 | "bumpalo", 2902 | "log", 2903 | "once_cell", 2904 | "proc-macro2", 2905 | "quote", 2906 | "syn 2.0.48", 2907 | "wasm-bindgen-shared", 2908 | ] 2909 | 2910 | [[package]] 2911 | name = "wasm-bindgen-futures" 2912 | version = "0.4.37" 2913 | source = "registry+https://github.com/rust-lang/crates.io-index" 2914 | checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" 2915 | dependencies = [ 2916 | "cfg-if", 2917 | "js-sys", 2918 | "wasm-bindgen", 2919 | "web-sys", 2920 | ] 2921 | 2922 | [[package]] 2923 | name = "wasm-bindgen-macro" 2924 | version = "0.2.87" 2925 | source = "registry+https://github.com/rust-lang/crates.io-index" 2926 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 2927 | dependencies = [ 2928 | "quote", 2929 | "wasm-bindgen-macro-support", 2930 | ] 2931 | 2932 | [[package]] 2933 | name = "wasm-bindgen-macro-support" 2934 | version = "0.2.87" 2935 | source = "registry+https://github.com/rust-lang/crates.io-index" 2936 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 2937 | dependencies = [ 2938 | "proc-macro2", 2939 | "quote", 2940 | "syn 2.0.48", 2941 | "wasm-bindgen-backend", 2942 | "wasm-bindgen-shared", 2943 | ] 2944 | 2945 | [[package]] 2946 | name = "wasm-bindgen-shared" 2947 | version = "0.2.87" 2948 | source = "registry+https://github.com/rust-lang/crates.io-index" 2949 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 2950 | 2951 | [[package]] 2952 | name = "web-sys" 2953 | version = "0.3.64" 2954 | source = "registry+https://github.com/rust-lang/crates.io-index" 2955 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 2956 | dependencies = [ 2957 | "js-sys", 2958 | "wasm-bindgen", 2959 | ] 2960 | 2961 | [[package]] 2962 | name = "webpki" 2963 | version = "0.22.0" 2964 | source = "registry+https://github.com/rust-lang/crates.io-index" 2965 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 2966 | dependencies = [ 2967 | "ring 0.16.20", 2968 | "untrusted 0.7.1", 2969 | ] 2970 | 2971 | [[package]] 2972 | name = "webpki-roots" 2973 | version = "0.22.6" 2974 | source = "registry+https://github.com/rust-lang/crates.io-index" 2975 | checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" 2976 | dependencies = [ 2977 | "webpki", 2978 | ] 2979 | 2980 | [[package]] 2981 | name = "widestring" 2982 | version = "1.0.2" 2983 | source = "registry+https://github.com/rust-lang/crates.io-index" 2984 | checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" 2985 | 2986 | [[package]] 2987 | name = "winapi" 2988 | version = "0.3.9" 2989 | source = "registry+https://github.com/rust-lang/crates.io-index" 2990 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2991 | dependencies = [ 2992 | "winapi-i686-pc-windows-gnu", 2993 | "winapi-x86_64-pc-windows-gnu", 2994 | ] 2995 | 2996 | [[package]] 2997 | name = "winapi-i686-pc-windows-gnu" 2998 | version = "0.4.0" 2999 | source = "registry+https://github.com/rust-lang/crates.io-index" 3000 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3001 | 3002 | [[package]] 3003 | name = "winapi-x86_64-pc-windows-gnu" 3004 | version = "0.4.0" 3005 | source = "registry+https://github.com/rust-lang/crates.io-index" 3006 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3007 | 3008 | [[package]] 3009 | name = "windows" 3010 | version = "0.48.0" 3011 | source = "registry+https://github.com/rust-lang/crates.io-index" 3012 | checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" 3013 | dependencies = [ 3014 | "windows-targets 0.48.1", 3015 | ] 3016 | 3017 | [[package]] 3018 | name = "windows-sys" 3019 | version = "0.48.0" 3020 | source = "registry+https://github.com/rust-lang/crates.io-index" 3021 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 3022 | dependencies = [ 3023 | "windows-targets 0.48.1", 3024 | ] 3025 | 3026 | [[package]] 3027 | name = "windows-sys" 3028 | version = "0.52.0" 3029 | source = "registry+https://github.com/rust-lang/crates.io-index" 3030 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 3031 | dependencies = [ 3032 | "windows-targets 0.52.4", 3033 | ] 3034 | 3035 | [[package]] 3036 | name = "windows-targets" 3037 | version = "0.48.1" 3038 | source = "registry+https://github.com/rust-lang/crates.io-index" 3039 | checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" 3040 | dependencies = [ 3041 | "windows_aarch64_gnullvm 0.48.0", 3042 | "windows_aarch64_msvc 0.48.0", 3043 | "windows_i686_gnu 0.48.0", 3044 | "windows_i686_msvc 0.48.0", 3045 | "windows_x86_64_gnu 0.48.0", 3046 | "windows_x86_64_gnullvm 0.48.0", 3047 | "windows_x86_64_msvc 0.48.0", 3048 | ] 3049 | 3050 | [[package]] 3051 | name = "windows-targets" 3052 | version = "0.52.4" 3053 | source = "registry+https://github.com/rust-lang/crates.io-index" 3054 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 3055 | dependencies = [ 3056 | "windows_aarch64_gnullvm 0.52.4", 3057 | "windows_aarch64_msvc 0.52.4", 3058 | "windows_i686_gnu 0.52.4", 3059 | "windows_i686_msvc 0.52.4", 3060 | "windows_x86_64_gnu 0.52.4", 3061 | "windows_x86_64_gnullvm 0.52.4", 3062 | "windows_x86_64_msvc 0.52.4", 3063 | ] 3064 | 3065 | [[package]] 3066 | name = "windows_aarch64_gnullvm" 3067 | version = "0.48.0" 3068 | source = "registry+https://github.com/rust-lang/crates.io-index" 3069 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 3070 | 3071 | [[package]] 3072 | name = "windows_aarch64_gnullvm" 3073 | version = "0.52.4" 3074 | source = "registry+https://github.com/rust-lang/crates.io-index" 3075 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 3076 | 3077 | [[package]] 3078 | name = "windows_aarch64_msvc" 3079 | version = "0.48.0" 3080 | source = "registry+https://github.com/rust-lang/crates.io-index" 3081 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 3082 | 3083 | [[package]] 3084 | name = "windows_aarch64_msvc" 3085 | version = "0.52.4" 3086 | source = "registry+https://github.com/rust-lang/crates.io-index" 3087 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 3088 | 3089 | [[package]] 3090 | name = "windows_i686_gnu" 3091 | version = "0.48.0" 3092 | source = "registry+https://github.com/rust-lang/crates.io-index" 3093 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 3094 | 3095 | [[package]] 3096 | name = "windows_i686_gnu" 3097 | version = "0.52.4" 3098 | source = "registry+https://github.com/rust-lang/crates.io-index" 3099 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 3100 | 3101 | [[package]] 3102 | name = "windows_i686_msvc" 3103 | version = "0.48.0" 3104 | source = "registry+https://github.com/rust-lang/crates.io-index" 3105 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 3106 | 3107 | [[package]] 3108 | name = "windows_i686_msvc" 3109 | version = "0.52.4" 3110 | source = "registry+https://github.com/rust-lang/crates.io-index" 3111 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 3112 | 3113 | [[package]] 3114 | name = "windows_x86_64_gnu" 3115 | version = "0.48.0" 3116 | source = "registry+https://github.com/rust-lang/crates.io-index" 3117 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 3118 | 3119 | [[package]] 3120 | name = "windows_x86_64_gnu" 3121 | version = "0.52.4" 3122 | source = "registry+https://github.com/rust-lang/crates.io-index" 3123 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 3124 | 3125 | [[package]] 3126 | name = "windows_x86_64_gnullvm" 3127 | version = "0.48.0" 3128 | source = "registry+https://github.com/rust-lang/crates.io-index" 3129 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 3130 | 3131 | [[package]] 3132 | name = "windows_x86_64_gnullvm" 3133 | version = "0.52.4" 3134 | source = "registry+https://github.com/rust-lang/crates.io-index" 3135 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 3136 | 3137 | [[package]] 3138 | name = "windows_x86_64_msvc" 3139 | version = "0.48.0" 3140 | source = "registry+https://github.com/rust-lang/crates.io-index" 3141 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 3142 | 3143 | [[package]] 3144 | name = "windows_x86_64_msvc" 3145 | version = "0.52.4" 3146 | source = "registry+https://github.com/rust-lang/crates.io-index" 3147 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 3148 | 3149 | [[package]] 3150 | name = "winnow" 3151 | version = "0.5.36" 3152 | source = "registry+https://github.com/rust-lang/crates.io-index" 3153 | checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" 3154 | dependencies = [ 3155 | "memchr", 3156 | ] 3157 | 3158 | [[package]] 3159 | name = "winreg" 3160 | version = "0.50.0" 3161 | source = "registry+https://github.com/rust-lang/crates.io-index" 3162 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 3163 | dependencies = [ 3164 | "cfg-if", 3165 | "windows-sys 0.48.0", 3166 | ] 3167 | 3168 | [[package]] 3169 | name = "wither" 3170 | version = "0.9.0" 3171 | source = "git+https://github.com/thedodd/wither?rev=52fd503#52fd5037d5aa0dc358def3760cea8ef13a8766e8" 3172 | dependencies = [ 3173 | "async-trait", 3174 | "chrono", 3175 | "futures", 3176 | "log", 3177 | "mongodb", 3178 | "serde", 3179 | "thiserror", 3180 | "wither_derive", 3181 | ] 3182 | 3183 | [[package]] 3184 | name = "wither_derive" 3185 | version = "0.9.0" 3186 | source = "git+https://github.com/thedodd/wither?rev=52fd503#52fd5037d5aa0dc358def3760cea8ef13a8766e8" 3187 | dependencies = [ 3188 | "Inflector", 3189 | "async-trait", 3190 | "darling 0.10.2", 3191 | "proc-macro-error", 3192 | "proc-macro2", 3193 | "quote", 3194 | "serde", 3195 | "syn 1.0.109", 3196 | ] 3197 | 3198 | [[package]] 3199 | name = "wyz" 3200 | version = "0.5.1" 3201 | source = "registry+https://github.com/rust-lang/crates.io-index" 3202 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 3203 | dependencies = [ 3204 | "tap", 3205 | ] 3206 | 3207 | [[package]] 3208 | name = "yaml-rust" 3209 | version = "0.4.5" 3210 | source = "registry+https://github.com/rust-lang/crates.io-index" 3211 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 3212 | dependencies = [ 3213 | "linked-hash-map", 3214 | ] 3215 | 3216 | [[package]] 3217 | name = "yansi" 3218 | version = "0.5.1" 3219 | source = "registry+https://github.com/rust-lang/crates.io-index" 3220 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 3221 | 3222 | [[package]] 3223 | name = "zeroize" 3224 | version = "1.6.0" 3225 | source = "registry+https://github.com/rust-lang/crates.io-index" 3226 | checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" 3227 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustapi" 3 | version = "0.1.0" 4 | authors = ["ndelvalle "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | config = "0.14.0" 9 | serde = { version = "1.0.188", features = ["derive"] } 10 | serde_json = "1.0.113" 11 | serde_derive = "1.0.152" 12 | # Wait for wither to relase a new version. 13 | # https://github.com/thedodd/wither/pull/89#issuecomment-1023644443 14 | wither = { git = "https://github.com/thedodd/wither", rev = "52fd503" } 15 | futures = "0.3.28" 16 | thiserror = "1.0.55" 17 | axum = { version = "0.6.20", features = ["headers"] } 18 | tokio = { version = "1.35.0", features = ["full"] } 19 | tracing = "0.1.37" 20 | tracing-subscriber = "0.3.17" 21 | tower-http = { version = "0.4.4", features = [ 22 | "trace", 23 | "compression-br", 24 | "propagate-header", 25 | "sensitive-headers", 26 | "cors", 27 | ] } 28 | http = "0.2.9" 29 | chrono = "0.4.31" 30 | async-trait = "0.1.79" 31 | # Investigate if wither::bson can be used instead and activate this feature. 32 | bson = { version = "2.7.0", features = ["serde_with", "chrono-0_4"] } 33 | jsonwebtoken = "9.3.0" 34 | once_cell = "1.18.0" 35 | bcrypt = "0.15.0" 36 | validator = { version = "0.16.1", features = ["derive"] } 37 | lazy_static = "1.4.0" 38 | mime = "0.3.17" 39 | bytes = "1.5.0" 40 | 41 | [dev-dependencies] 42 | assert-json-diff = "2.0.2" 43 | reqwest = { version = "0.12.2", features = ["json"] } 44 | pretty_assertions = "1.4.0" 45 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | # Tests depend on the database state. The database is cleanup before each 4 | # test, this is why tests needs to be run sequentially. 5 | 6 | # By default the Rust test harness hides output from test execution to keep 7 | # results readable. The nocapture flag disables that behavior. 8 | 9 | cargo test -- \ 10 | --test-threads=1 \ 11 | --nocapture \ 12 | --color=always 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rustapi 2 | 3 | [![Tests](https://github.com/ndelvalle/rustapi/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/ndelvalle/rustapi/actions/workflows/test.yml) 4 | 5 | RESTful API template built with Rust lang. It uses [MongoDB](https://docs.mongodb.com/) 6 | database and [Axum](https://github.com/tokio-rs/axum) HTTP framework. 7 | 8 | ### Requirements 9 | 10 | - [Rust](https://www.rust-lang.org/tools/install) 11 | - [MongoDB](https://docs.mongodb.com/manual/installation/) 12 | 13 | ### Feature highlights 14 | 15 | * Authentication. Based on [jsonwebtoken](https://github.com/Keats/jsonwebtoken) 16 | * Layered configuration. Based on [config-rs](https://github.com/mehcode/config-rs) 17 | * Logs. Based on [tracing](https://github.com/tokio-rs/tracing) 18 | * Error handling 19 | * Pagination 20 | * E2E Tests 21 | * OpenAPI Specification 22 | * CI based on Github actions 23 | * Dependabot configuration 24 | 25 | ### Project structure 26 | 27 | ```bash 28 | ├── Cargo.lock 29 | ├── Cargo.toml 30 | ├── README.md 31 | ├── config 32 | │   ├── default.json # Default configuration 33 | │   ├── production.json # Production configuration (Overwrites the default) 34 | │   └── test.json # Test configuration (Overwrites the default) 35 | ├── rustfmt.toml 36 | ├── src 37 | │   ├── database.rs 38 | │   ├── errors.rs 39 | │   ├── lib # Helpers not related to the business model 40 | │   │   ├── authenticate_request.rs 41 | │   │   ├── date.rs 42 | │   │   ├── mod.rs 43 | │   │   ├── models.rs # Base Database Model trait 44 | │   │   ├── to_object_id.rs 45 | │   │   └── token.rs 46 | │   ├── logger.rs 47 | │   ├── main.rs 48 | │   ├── models 49 | │   │   ├── cat.rs 50 | │   │   ├── mod.rs 51 | │   │   └── user.rs 52 | │   ├── routes 53 | │   │   ├── cat.rs 54 | │   │   ├── mod.rs 55 | │   │   ├── status.rs 56 | │   │   └── user.rs 57 | │   ├── settings.rs 58 | │   └── tests # E2E Tests 59 | └── test.sh 60 | ``` 61 | 62 | ### Test 63 | To run tests make sure MongoDB is up and running. 64 | ``` 65 | make test 66 | ``` 67 | 68 | ## Contributing 69 | 70 | Contributors are welcome, please fork and send pull requests! If you find a bug 71 | or have any ideas on how to improve this project please submit an issue. 72 | -------------------------------------------------------------------------------- /config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "environment": "development", 3 | 4 | "server": { 5 | "port": 8080 6 | }, 7 | 8 | "database": { 9 | "uri": "mongodb://localhost:27017", 10 | "name": "rustapi" 11 | }, 12 | 13 | "auth": { 14 | "secret": "secret" 15 | }, 16 | 17 | "logger": { 18 | "level": "debug" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/production.json: -------------------------------------------------------------------------------- 1 | { 2 | "environment": "production", 3 | 4 | "logger": { 5 | "level": "info" 6 | } 7 | } -------------------------------------------------------------------------------- /config/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "environment": "test", 3 | 4 | "server": { 5 | "port": 8088 6 | }, 7 | 8 | "database": { 9 | "uri": "mongodb://localhost:27017", 10 | "name": "rustapi-test" 11 | }, 12 | 13 | "logger": { 14 | "level": "error" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | 3 | info: 4 | version: 1.0.0 5 | title: v1 REST API 6 | description: v1 REST API 7 | 8 | servers: 9 | - url: https://api.yoururl.com 10 | 11 | externalDocs: 12 | description: v1 REST API 13 | url: https://github.com/ndelvalle/rustapi 14 | 15 | paths: 16 | "/v1/cats": 17 | # Query cats 18 | get: 19 | summary: Query cats 20 | description: Query cats 21 | operationId: application/query-cats 22 | security: 23 | - bearerAuth: [] 24 | responses: 25 | '200': 26 | description: Response 27 | content: 28 | application/json: 29 | schema: 30 | "$ref": "#/components/schemas/Cat" 31 | '401': 32 | $ref: '#/components/responses/Unauthorized' 33 | 34 | # Create a new cat 35 | post: 36 | summary: Create a new cat 37 | description: Create a new cat 38 | operationId: application/create-cat 39 | requestBody: 40 | required: true 41 | content: 42 | application/json: 43 | schema: 44 | type: object 45 | required: 46 | - name 47 | properties: 48 | name: 49 | type: string 50 | description: The cat name 51 | responses: 52 | '201': 53 | description: Response 54 | content: 55 | application/json: 56 | schema: 57 | "$ref": "#/components/schemas/Cat" 58 | '401': 59 | $ref: '#/components/responses/Unauthorized' 60 | 61 | "/v1/cats/{cat_id}": 62 | # Get cat by ID 63 | get: 64 | summary: Get cat by ID 65 | description: get cat by ID 66 | operationId: application/get-cat-by-id 67 | responses: 68 | '200': 69 | description: Response 70 | content: 71 | application/json: 72 | schema: 73 | "$ref": "#/components/schemas/Cat" 74 | '401': 75 | $ref: '#/components/responses/Unauthorized' 76 | 77 | # Remove cat by ID 78 | delete: 79 | summary: Remove a cat by ID 80 | description: Removes a cat by ID 81 | operationId: application/remove-cat-by-id 82 | responses: 83 | '204': 84 | description: Response 85 | '401': 86 | $ref: '#/components/responses/Unauthorized' 87 | 88 | # Update cat by ID 89 | patch: 90 | summary: Update a cat by ID 91 | description: Update cat by ID 92 | operationId: application/update-cat-by-id 93 | requestBody: 94 | required: true 95 | content: 96 | application/json: 97 | schema: 98 | type: object 99 | required: 100 | - name 101 | properties: 102 | name: 103 | type: string 104 | description: The cat name 105 | responses: 106 | '200': 107 | description: Response 108 | content: 109 | application/json: 110 | schema: 111 | "$ref": "#/components/schemas/Cat" 112 | '401': 113 | $ref: '#/components/responses/Unauthorized' 114 | 115 | components: 116 | schemas: 117 | # Cat schema 118 | Cat: 119 | type: object 120 | required: 121 | - id 122 | - user 123 | - name 124 | - created_at 125 | - updated_at 126 | properties: 127 | id: 128 | type: string 129 | user: 130 | type: string 131 | name: 132 | type: string 133 | created_at: 134 | type: string 135 | updated_at: 136 | type: string 137 | 138 | securitySchemes: 139 | bearerAuth: 140 | type: http 141 | scheme: bearer 142 | bearerFormat: JWT 143 | 144 | responses: 145 | Unauthorized: 146 | description: Authentication information is missing or invalid 147 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # rustfmt configurations from master branch, check rustfmt version 2 | # (cargo fmt --version). 3 | # https://github.com/rust-lang/rustfmt/blob/master/Configurations.md 4 | 5 | edition = "2021" 6 | tab_spaces = 2 -------------------------------------------------------------------------------- /src/app.rs: -------------------------------------------------------------------------------- 1 | use axum::Router; 2 | use http::header; 3 | use tower_http::{ 4 | compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, 5 | sensitive_headers::SetSensitiveHeadersLayer, trace, 6 | }; 7 | 8 | use crate::logger; 9 | use crate::models; 10 | use crate::routes; 11 | 12 | pub async fn create_app() -> Router { 13 | logger::setup(); 14 | 15 | models::sync_indexes() 16 | .await 17 | .expect("Failed to sync database indexes"); 18 | 19 | Router::new() 20 | .merge(routes::status::create_route()) 21 | .merge(routes::user::create_route()) 22 | .merge(Router::new().nest( 23 | "/v1", 24 | // All public v1 routes will be nested here. 25 | Router::new().merge(routes::cat::create_route()), 26 | )) 27 | // High level logging of requests and responses 28 | .layer( 29 | trace::TraceLayer::new_for_http() 30 | .make_span_with(trace::DefaultMakeSpan::new().include_headers(true)) 31 | .on_request(trace::DefaultOnRequest::new().level(tracing::Level::INFO)) 32 | .on_response(trace::DefaultOnResponse::new().level(tracing::Level::INFO)), 33 | ) 34 | // Mark the `Authorization` request header as sensitive so it doesn't 35 | // show in logs. 36 | .layer(SetSensitiveHeadersLayer::new(std::iter::once( 37 | header::AUTHORIZATION, 38 | ))) 39 | // Compress responses 40 | .layer(CompressionLayer::new()) 41 | // Propagate `X-Request-Id`s from requests to responses 42 | .layer(PropagateHeaderLayer::new(header::HeaderName::from_static( 43 | "x-request-id", 44 | ))) 45 | // CORS configuration. This should probably be more restrictive in 46 | // production. 47 | .layer(CorsLayer::permissive()) 48 | } 49 | -------------------------------------------------------------------------------- /src/database.rs: -------------------------------------------------------------------------------- 1 | use mongodb::Database; 2 | use tokio::sync::OnceCell; 3 | use wither::mongodb; 4 | 5 | use crate::settings::SETTINGS; 6 | 7 | static CONNECTION: OnceCell = OnceCell::const_new(); 8 | 9 | pub async fn connection() -> &'static Database { 10 | CONNECTION 11 | .get_or_init(|| async { 12 | let db_uri = SETTINGS.database.uri.as_str(); 13 | let db_name = SETTINGS.database.name.as_str(); 14 | 15 | mongodb::Client::with_uri_str(db_uri) 16 | .await 17 | .expect("Failed to initialize MongoDB connection") 18 | .database(db_name) 19 | }) 20 | .await 21 | } 22 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::response::{IntoResponse, Response}; 3 | use axum::Json; 4 | use bcrypt::BcryptError; 5 | use serde_json::json; 6 | use tokio::task::JoinError; 7 | use wither::bson; 8 | use wither::mongodb::error::Error as MongoError; 9 | use wither::WitherError; 10 | 11 | #[derive(thiserror::Error, Debug)] 12 | #[error("...")] 13 | pub enum Error { 14 | #[error("{0}")] 15 | Wither(#[from] WitherError), 16 | 17 | #[error("{0}")] 18 | Mongo(#[from] MongoError), 19 | 20 | #[error("Error parsing ObjectID {0}")] 21 | ParseObjectID(String), 22 | 23 | #[error("{0}")] 24 | SerializeMongoResponse(#[from] bson::de::Error), 25 | 26 | #[error("{0}")] 27 | Authenticate(#[from] AuthenticateError), 28 | 29 | #[error("{0}")] 30 | BadRequest(#[from] BadRequest), 31 | 32 | #[error("{0}")] 33 | NotFound(#[from] NotFound), 34 | 35 | #[error("{0}")] 36 | RunSyncTask(#[from] JoinError), 37 | 38 | #[error("{0}")] 39 | HashPassword(#[from] BcryptError), 40 | } 41 | 42 | impl Error { 43 | fn get_codes(&self) -> (StatusCode, u16) { 44 | match *self { 45 | // 4XX Errors 46 | Error::ParseObjectID(_) => (StatusCode::BAD_REQUEST, 40001), 47 | Error::BadRequest(_) => (StatusCode::BAD_REQUEST, 40002), 48 | Error::NotFound(_) => (StatusCode::NOT_FOUND, 40003), 49 | Error::Authenticate(AuthenticateError::WrongCredentials) => (StatusCode::UNAUTHORIZED, 40004), 50 | Error::Authenticate(AuthenticateError::InvalidToken) => (StatusCode::UNAUTHORIZED, 40005), 51 | Error::Authenticate(AuthenticateError::Locked) => (StatusCode::LOCKED, 40006), 52 | 53 | // 5XX Errors 54 | Error::Authenticate(AuthenticateError::TokenCreation) => { 55 | (StatusCode::INTERNAL_SERVER_ERROR, 5001) 56 | } 57 | Error::Wither(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5002), 58 | Error::Mongo(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5003), 59 | Error::SerializeMongoResponse(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5004), 60 | Error::RunSyncTask(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5005), 61 | Error::HashPassword(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5006), 62 | } 63 | } 64 | 65 | pub fn bad_request() -> Self { 66 | Error::BadRequest(BadRequest {}) 67 | } 68 | 69 | pub fn not_found() -> Self { 70 | Error::NotFound(NotFound {}) 71 | } 72 | } 73 | 74 | impl IntoResponse for Error { 75 | fn into_response(self) -> Response { 76 | let (status_code, code) = self.get_codes(); 77 | let message = self.to_string(); 78 | let body = Json(json!({ "code": code, "message": message })); 79 | 80 | (status_code, body).into_response() 81 | } 82 | } 83 | 84 | #[derive(thiserror::Error, Debug)] 85 | #[error("...")] 86 | pub enum AuthenticateError { 87 | #[error("Wrong authentication credentials")] 88 | WrongCredentials, 89 | #[error("Failed to create authentication token")] 90 | TokenCreation, 91 | #[error("Invalid authentication credentials")] 92 | InvalidToken, 93 | #[error("User is locked")] 94 | Locked, 95 | } 96 | 97 | #[derive(thiserror::Error, Debug)] 98 | #[error("Bad Request")] 99 | pub struct BadRequest {} 100 | 101 | #[derive(thiserror::Error, Debug)] 102 | #[error("Not found")] 103 | pub struct NotFound {} 104 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use crate::settings::SETTINGS; 4 | 5 | pub fn setup() { 6 | if env::var_os("RUST_LOG").is_none() { 7 | let level = SETTINGS.logger.level.as_str(); 8 | let env = format!("rustapi={level},tower_http={level}"); 9 | 10 | env::set_var("RUST_LOG", env); 11 | } 12 | 13 | tracing_subscriber::fmt::init(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use tracing::info; 3 | 4 | mod app; 5 | mod database; 6 | mod errors; 7 | mod logger; 8 | mod models; 9 | mod routes; 10 | mod settings; 11 | mod utils; 12 | 13 | // There are a couple approaches to take when implementing E2E tests. This 14 | // approach adds tests on /src/tests, this way tests can reference modules 15 | // inside the src folder. Another approach would be to have the tests in a 16 | // /tests folder on the root of the project, to do this and be able to import 17 | // modules from the src folder, modules need to be exported as a lib. 18 | #[cfg(test)] 19 | mod tests; 20 | 21 | use errors::Error; 22 | use settings::SETTINGS; 23 | 24 | #[tokio::main] 25 | async fn main() { 26 | let app = app::create_app().await; 27 | 28 | let port = SETTINGS.server.port; 29 | let address = SocketAddr::from(([127, 0, 0, 1], port)); 30 | 31 | info!("Server listening on {}", &address); 32 | axum::Server::bind(&address) 33 | .serve(app.into_make_service()) 34 | .await 35 | .expect("Failed to start server"); 36 | } 37 | -------------------------------------------------------------------------------- /src/models/cat.rs: -------------------------------------------------------------------------------- 1 | use bson::serde_helpers::bson_datetime_as_rfc3339_string; 2 | use bson::serde_helpers::serialize_object_id_as_hex_string; 3 | use serde::{Deserialize, Serialize}; 4 | use validator::Validate; 5 | use wither::bson::{doc, oid::ObjectId}; 6 | use wither::Model as WitherModel; 7 | 8 | use crate::utils::date; 9 | use crate::utils::date::Date; 10 | use crate::utils::models::ModelExt; 11 | 12 | impl ModelExt for Cat {} 13 | 14 | #[derive(Debug, Clone, Serialize, Deserialize, WitherModel, Validate)] 15 | #[model(index(keys = r#"doc!{ "user": 1, "created_at": 1 }"#))] 16 | pub struct Cat { 17 | #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] 18 | pub id: Option, 19 | pub user: ObjectId, 20 | pub name: String, 21 | pub updated_at: Date, 22 | pub created_at: Date, 23 | } 24 | 25 | impl Cat { 26 | pub fn new(user: ObjectId, name: String) -> Self { 27 | let now = date::now(); 28 | Self { 29 | id: None, 30 | user, 31 | name, 32 | updated_at: now, 33 | created_at: now, 34 | } 35 | } 36 | } 37 | 38 | #[derive(Debug, Serialize, Deserialize)] 39 | pub struct PublicCat { 40 | #[serde(alias = "_id", serialize_with = "serialize_object_id_as_hex_string")] 41 | pub id: ObjectId, 42 | #[serde(serialize_with = "serialize_object_id_as_hex_string")] 43 | pub user: ObjectId, 44 | pub name: String, 45 | #[serde(with = "bson_datetime_as_rfc3339_string")] 46 | pub updated_at: Date, 47 | #[serde(with = "bson_datetime_as_rfc3339_string")] 48 | pub created_at: Date, 49 | } 50 | 51 | impl From for PublicCat { 52 | fn from(cat: Cat) -> Self { 53 | Self { 54 | id: cat.id.unwrap(), 55 | user: cat.user, 56 | name: cat.name.clone(), 57 | updated_at: cat.updated_at, 58 | created_at: cat.created_at, 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cat; 2 | pub mod user; 3 | 4 | use crate::utils::models::ModelExt; 5 | use crate::Error; 6 | 7 | pub async fn sync_indexes() -> Result<(), Error> { 8 | user::User::sync_indexes().await?; 9 | cat::Cat::sync_indexes().await?; 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /src/models/user.rs: -------------------------------------------------------------------------------- 1 | use bson::serde_helpers::bson_datetime_as_rfc3339_string; 2 | use bson::serde_helpers::serialize_object_id_as_hex_string; 3 | use serde::{Deserialize, Serialize}; 4 | use tokio::task; 5 | use validator::Validate; 6 | use wither::bson::{doc, oid::ObjectId}; 7 | use wither::Model as WitherModel; 8 | 9 | use crate::errors::Error; 10 | use crate::utils::date; 11 | use crate::utils::date::Date; 12 | use crate::utils::models::ModelExt; 13 | 14 | impl ModelExt for User {} 15 | 16 | #[derive(Debug, Clone, Serialize, Deserialize, WitherModel, Validate)] 17 | #[model(index(keys = r#"doc!{ "email": 1 }"#, options = r#"doc!{ "unique": true }"#))] 18 | pub struct User { 19 | #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] 20 | pub id: Option, 21 | #[validate(length(min = 1))] 22 | pub name: String, 23 | #[validate(email)] 24 | pub email: String, 25 | pub password: String, 26 | pub updated_at: Date, 27 | pub created_at: Date, 28 | pub locked_at: Option, 29 | } 30 | 31 | impl User { 32 | pub fn new(name: A, email: B, password_hash: C) -> Self 33 | where 34 | A: Into, 35 | B: Into, 36 | C: Into, 37 | { 38 | let now = date::now(); 39 | Self { 40 | id: None, 41 | name: name.into(), 42 | email: email.into(), 43 | password: password_hash.into(), 44 | updated_at: now, 45 | created_at: now, 46 | locked_at: None, 47 | } 48 | } 49 | 50 | pub fn is_password_match(&self, password: &str) -> bool { 51 | bcrypt::verify(password, self.password.as_ref()).unwrap_or(false) 52 | } 53 | } 54 | 55 | #[derive(Debug, Serialize, Deserialize)] 56 | pub struct PublicUser { 57 | #[serde(alias = "_id", serialize_with = "serialize_object_id_as_hex_string")] 58 | pub id: ObjectId, 59 | pub name: String, 60 | pub email: String, 61 | #[serde(with = "bson_datetime_as_rfc3339_string")] 62 | pub updated_at: Date, 63 | #[serde(with = "bson_datetime_as_rfc3339_string")] 64 | pub created_at: Date, 65 | } 66 | 67 | impl From for PublicUser { 68 | fn from(user: User) -> Self { 69 | Self { 70 | id: user.id.unwrap(), 71 | name: user.name.clone(), 72 | email: user.email.clone(), 73 | updated_at: user.updated_at, 74 | created_at: user.created_at, 75 | } 76 | } 77 | } 78 | 79 | pub async fn hash_password

(password: P) -> Result 80 | where 81 | P: AsRef + Send + 'static, 82 | { 83 | // TODO: Hash password with salt. 84 | // https://docs.rs/bcrypt/latest/bcrypt/fn.hash_with_salt.html 85 | #[cfg(not(test))] 86 | let cost = bcrypt::DEFAULT_COST; 87 | #[cfg(test)] 88 | let cost = 4; 89 | task::spawn_blocking(move || bcrypt::hash(password.as_ref(), cost)) 90 | .await 91 | .map_err(Error::RunSyncTask)? 92 | .map_err(Error::HashPassword) 93 | } 94 | -------------------------------------------------------------------------------- /src/routes/cat.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::{ 3 | extract::Path, 4 | routing::{delete, get, post, put}, 5 | Json, Router, 6 | }; 7 | use bson::doc; 8 | use serde::{Deserialize, Serialize}; 9 | use tracing::debug; 10 | use wither::mongodb::options::FindOptions; 11 | 12 | use crate::errors::Error; 13 | use crate::models::cat::{Cat, PublicCat}; 14 | use crate::utils::custom_response::CustomResponseResult as Response; 15 | use crate::utils::custom_response::{CustomResponse, CustomResponseBuilder, ResponsePagination}; 16 | use crate::utils::models::ModelExt; 17 | use crate::utils::pagination::Pagination; 18 | use crate::utils::to_object_id::to_object_id; 19 | use crate::utils::token::TokenUser; 20 | 21 | pub fn create_route() -> Router { 22 | Router::new() 23 | .route("/cats", post(create_cat)) 24 | .route("/cats", get(query_cats)) 25 | .route("/cats/:id", get(get_cat_by_id)) 26 | .route("/cats/:id", delete(remove_cat_by_id)) 27 | .route("/cats/:id", put(update_cat_by_id)) 28 | } 29 | 30 | async fn create_cat(user: TokenUser, Json(payload): Json) -> Response { 31 | let cat = Cat::new(user.id, payload.name); 32 | let cat = Cat::create(cat).await?; 33 | let res = PublicCat::from(cat); 34 | 35 | let res = CustomResponseBuilder::new() 36 | .body(res) 37 | .status_code(StatusCode::CREATED) 38 | .build(); 39 | 40 | Ok(res) 41 | } 42 | 43 | async fn query_cats(user: TokenUser, pagination: Pagination) -> Response> { 44 | let options = FindOptions::builder() 45 | .sort(doc! { "created_at": -1_i32 }) 46 | .skip(pagination.offset) 47 | .limit(pagination.limit as i64) 48 | .build(); 49 | 50 | let (cats, count) = Cat::find_and_count(doc! { "user": &user.id }, options).await?; 51 | let cats = cats.into_iter().map(Into::into).collect::>(); 52 | 53 | let res = CustomResponseBuilder::new() 54 | .body(cats) 55 | .pagination(ResponsePagination { 56 | count, 57 | offset: pagination.offset, 58 | limit: pagination.limit, 59 | }) 60 | .build(); 61 | 62 | debug!("Returning cats"); 63 | Ok(res) 64 | } 65 | 66 | async fn get_cat_by_id(user: TokenUser, Path(id): Path) -> Result, Error> { 67 | let cat_id = to_object_id(id)?; 68 | let cat = Cat::find_one(doc! { "_id": cat_id, "user": &user.id }, None) 69 | .await? 70 | .map(PublicCat::from); 71 | 72 | let cat = match cat { 73 | Some(cat) => cat, 74 | None => { 75 | debug!("Cat not found, returning 404 status code"); 76 | return Err(Error::not_found()); 77 | } 78 | }; 79 | 80 | debug!("Returning cat"); 81 | Ok(Json(cat)) 82 | } 83 | 84 | async fn remove_cat_by_id( 85 | user: TokenUser, 86 | Path(id): Path, 87 | ) -> Result, Error> { 88 | let cat_id = to_object_id(id)?; 89 | let delete_result = Cat::delete_one(doc! { "_id": cat_id, "user": &user.id }).await?; 90 | 91 | if delete_result.deleted_count == 0 { 92 | debug!("Cat not found, returning 404 status code"); 93 | return Err(Error::not_found()); 94 | } 95 | 96 | let res = CustomResponseBuilder::new() 97 | .status_code(StatusCode::NO_CONTENT) 98 | .build(); 99 | 100 | Ok(res) 101 | } 102 | 103 | async fn update_cat_by_id( 104 | user: TokenUser, 105 | Path(id): Path, 106 | Json(payload): Json, 107 | ) -> Result, Error> { 108 | let cat_id = to_object_id(id)?; 109 | let update = bson::to_document(&payload).unwrap(); 110 | 111 | let cat = Cat::find_one_and_update( 112 | doc! { "_id": &cat_id, "user": &user.id }, 113 | doc! { "$set": update }, 114 | ) 115 | .await? 116 | .map(PublicCat::from); 117 | 118 | let cat = match cat { 119 | Some(cat) => cat, 120 | None => { 121 | debug!("Cat not found, returning 404 status code"); 122 | return Err(Error::not_found()); 123 | } 124 | }; 125 | 126 | debug!("Returning cat"); 127 | Ok(Json(cat)) 128 | } 129 | 130 | #[derive(Deserialize)] 131 | struct CreateCat { 132 | name: String, 133 | } 134 | 135 | #[derive(Serialize, Deserialize)] 136 | struct UpdateCat { 137 | name: String, 138 | } 139 | -------------------------------------------------------------------------------- /src/routes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cat; 2 | pub mod status; 3 | pub mod user; 4 | -------------------------------------------------------------------------------- /src/routes/status.rs: -------------------------------------------------------------------------------- 1 | use axum::{routing::get, Json, Router}; 2 | use bson::doc; 3 | use serde::{Deserialize, Serialize}; 4 | use tracing::debug; 5 | 6 | use crate::errors::Error; 7 | 8 | pub fn create_route() -> Router { 9 | Router::new().route("/status", get(get_status)) 10 | } 11 | 12 | async fn get_status() -> Result, Error> { 13 | debug!("Returning status"); 14 | Ok(Json(Status { 15 | status: "ok".to_owned(), 16 | })) 17 | } 18 | 19 | #[derive(Serialize, Deserialize, Debug)] 20 | struct Status { 21 | status: String, 22 | } 23 | -------------------------------------------------------------------------------- /src/routes/user.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::{routing::post, Json, Router}; 3 | use bson::doc; 4 | use serde::{Deserialize, Serialize}; 5 | use tracing::debug; 6 | 7 | use crate::errors::{AuthenticateError, Error}; 8 | use crate::models::user; 9 | use crate::models::user::{PublicUser, User}; 10 | use crate::settings::SETTINGS; 11 | use crate::utils::custom_response::{CustomResponse, CustomResponseBuilder}; 12 | use crate::utils::models::ModelExt; 13 | use crate::utils::token; 14 | 15 | pub fn create_route() -> Router { 16 | Router::new() 17 | .route("/users", post(create_user)) 18 | .route("/users/authenticate", post(authenticate_user)) 19 | } 20 | 21 | async fn create_user(Json(body): Json) -> Result, Error> { 22 | let password_hash = user::hash_password(body.password).await?; 23 | let user = User::new(body.name, body.email, password_hash); 24 | let user = User::create(user).await?; 25 | let res = PublicUser::from(user); 26 | 27 | let res = CustomResponseBuilder::new() 28 | .body(res) 29 | .status_code(StatusCode::CREATED) 30 | .build(); 31 | 32 | Ok(res) 33 | } 34 | 35 | async fn authenticate_user( 36 | Json(body): Json, 37 | ) -> Result, Error> { 38 | let email = &body.email; 39 | let password = &body.password; 40 | 41 | if email.is_empty() { 42 | debug!("Missing email, returning 400 status code"); 43 | return Err(Error::bad_request()); 44 | } 45 | 46 | if password.is_empty() { 47 | debug!("Missing password, returning 400 status code"); 48 | return Err(Error::bad_request()); 49 | } 50 | 51 | let user = User::find_one(doc! { "email": email }, None).await?; 52 | 53 | let user = match user { 54 | Some(user) => user, 55 | None => { 56 | debug!("User not found, returning 401"); 57 | return Err(Error::not_found()); 58 | } 59 | }; 60 | 61 | if !user.is_password_match(password) { 62 | debug!("User password is incorrect, returning 401 status code"); 63 | return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); 64 | } 65 | 66 | if user.locked_at.is_some() { 67 | debug!("User is locked, returning 401"); 68 | return Err(Error::Authenticate(AuthenticateError::Locked)); 69 | } 70 | 71 | let secret = SETTINGS.auth.secret.as_str(); 72 | let token = token::create(user.clone(), secret) 73 | .map_err(|_| Error::Authenticate(AuthenticateError::TokenCreation))?; 74 | 75 | let res = AuthenticateResponse { 76 | access_token: token, 77 | user: PublicUser::from(user), 78 | }; 79 | 80 | Ok(Json(res)) 81 | } 82 | 83 | // TODO: Validate password length 84 | #[derive(Debug, Deserialize)] 85 | struct CreateBody { 86 | name: String, 87 | email: String, 88 | password: String, 89 | } 90 | 91 | #[derive(Debug, Deserialize)] 92 | struct AuthorizeBody { 93 | email: String, 94 | password: String, 95 | } 96 | 97 | #[derive(Debug, Serialize, Deserialize)] 98 | pub struct AuthenticateResponse { 99 | pub access_token: String, 100 | pub user: PublicUser, 101 | } 102 | -------------------------------------------------------------------------------- /src/settings.rs: -------------------------------------------------------------------------------- 1 | use config::{Config, ConfigError, Environment, File}; 2 | use lazy_static::lazy_static; 3 | use serde::Deserialize; 4 | use std::{env, fmt}; 5 | 6 | lazy_static! { 7 | pub static ref SETTINGS: Settings = Settings::new().expect("Failed to setup settings"); 8 | } 9 | 10 | #[derive(Debug, Clone, Deserialize)] 11 | pub struct Server { 12 | pub port: u16, 13 | } 14 | 15 | #[derive(Debug, Clone, Deserialize)] 16 | pub struct Logger { 17 | pub level: String, 18 | } 19 | 20 | #[derive(Debug, Clone, Deserialize)] 21 | pub struct Database { 22 | pub uri: String, 23 | pub name: String, 24 | } 25 | 26 | #[derive(Debug, Clone, Deserialize)] 27 | pub struct Auth { 28 | pub secret: String, 29 | } 30 | 31 | #[derive(Debug, Clone, Deserialize)] 32 | pub struct Settings { 33 | pub environment: String, 34 | pub server: Server, 35 | pub logger: Logger, 36 | pub database: Database, 37 | pub auth: Auth, 38 | } 39 | 40 | impl Settings { 41 | pub fn new() -> Result { 42 | let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); 43 | 44 | let mut builder = Config::builder() 45 | .add_source(File::with_name("config/default")) 46 | .add_source(File::with_name(&format!("config/{run_mode}")).required(false)) 47 | .add_source(File::with_name("config/local").required(false)) 48 | .add_source(Environment::default().separator("__")); 49 | 50 | // Some cloud services like Heroku exposes a randomly assigned port in 51 | // the PORT env var and there is no way to change the env var name. 52 | if let Ok(port) = env::var("PORT") { 53 | builder = builder.set_override("server.port", port)?; 54 | } 55 | 56 | builder 57 | .build()? 58 | // Deserialize (and thus freeze) the entire configuration. 59 | .try_deserialize() 60 | } 61 | } 62 | 63 | impl fmt::Display for Server { 64 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 65 | write!(f, "http://localhost:{}", &self.port) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod routes; 2 | mod setup; 3 | mod utils; 4 | -------------------------------------------------------------------------------- /src/tests/routes/cat.rs: -------------------------------------------------------------------------------- 1 | use reqwest; 2 | use reqwest::StatusCode; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::models::cat::Cat; 6 | use crate::models::cat::PublicCat; 7 | use crate::tests::setup::use_app; 8 | use crate::tests::utils::create_user; 9 | use crate::tests::utils::create_user_token; 10 | use crate::utils::models::ModelExt; 11 | 12 | #[cfg(test)] 13 | use pretty_assertions::assert_eq; 14 | 15 | #[test] 16 | fn post_cat_route() { 17 | #[derive(Debug, Serialize, Deserialize)] 18 | struct Body { 19 | name: String, 20 | } 21 | 22 | let body = Body { 23 | name: "Tigrin".to_owned(), 24 | }; 25 | 26 | use_app(async move { 27 | let user = create_user("nico@test.com").await.unwrap(); 28 | let token = create_user_token(user.clone()).await.unwrap(); 29 | 30 | let client = reqwest::Client::new(); 31 | let res = client 32 | .post("http://localhost:8088/v1/cats") 33 | .header("Authorization", format!("Bearer {}", token)) 34 | .json(&body) 35 | .send() 36 | .await 37 | .unwrap(); 38 | 39 | // Status code: 40 | let status_code = res.status(); 41 | let actual = status_code; 42 | let expected = StatusCode::CREATED; 43 | assert_eq!(actual, expected); 44 | 45 | // Body: 46 | let body = res.json::().await.unwrap(); 47 | assert_eq!(body.name, "Tigrin"); 48 | assert_eq!(body.user, user.id.unwrap(), "Cat should belong to user"); 49 | }); 50 | } 51 | 52 | #[test] 53 | fn get_cats_route() { 54 | use_app(async move { 55 | let user = create_user("nico@test.com").await.unwrap(); 56 | let token = create_user_token(user.clone()).await.unwrap(); 57 | 58 | let tigrin = Cat::new(user.id.unwrap(), "Tigrin".to_owned()); 59 | Cat::create(tigrin).await.unwrap(); 60 | 61 | let cielito = Cat::new(user.id.unwrap(), "Cielito".to_owned()); 62 | Cat::create(cielito).await.unwrap(); 63 | 64 | let client = reqwest::Client::new(); 65 | let res = client 66 | .get("http://localhost:8088/v1/cats") 67 | .header("Authorization", format!("Bearer {}", token)) 68 | .send() 69 | .await 70 | .unwrap(); 71 | 72 | // Status code: 73 | let status_code = res.status(); 74 | let actual = status_code; 75 | let expected = StatusCode::OK; 76 | assert_eq!(actual, expected); 77 | 78 | // Response headers: 79 | let headers = res.headers(); 80 | assert_eq!(headers.get("Content-Type").unwrap(), "application/json"); 81 | // Response pagination headers: 82 | assert_eq!(headers.get("X-Pagination-Count").unwrap(), "2"); 83 | assert_eq!(headers.get("X-Pagination-Offset").unwrap(), "0"); 84 | assert_eq!(headers.get("X-Pagination-Limit").unwrap(), "100"); 85 | 86 | // Body: 87 | let body = res.json::>().await.unwrap(); 88 | assert_eq!(body.len(), 2, "Should return two cats"); 89 | 90 | // First cat (Cielito): 91 | let cat = body.get(0).unwrap(); 92 | assert_eq!(cat.name, "Cielito"); 93 | assert_eq!(cat.user, user.id.unwrap()); 94 | 95 | // Second cat (Tigrin): 96 | let cat = body.get(1).unwrap(); 97 | assert_eq!(cat.name, "Tigrin"); 98 | assert_eq!(cat.user, user.id.unwrap()); 99 | }); 100 | } 101 | 102 | #[test] 103 | fn get_cat_by_id_route() { 104 | use_app(async move { 105 | let user = create_user("nico@test.com").await.unwrap(); 106 | let token = create_user_token(user.clone()).await.unwrap(); 107 | 108 | let cholin = Cat::new(user.id.unwrap(), "Cholin".to_owned()); 109 | let cholin = Cat::create(cholin).await.unwrap(); 110 | 111 | let client = reqwest::Client::new(); 112 | let res = client 113 | .get(format!( 114 | "http://localhost:8088/v1/cats/{}", 115 | cholin.id.unwrap() 116 | )) 117 | .header("Authorization", format!("Bearer {}", token)) 118 | .send() 119 | .await 120 | .unwrap(); 121 | 122 | // Status code: 123 | let status_code = res.status(); 124 | let actual = status_code; 125 | let expected = StatusCode::OK; 126 | assert_eq!(actual, expected); 127 | 128 | // Body: 129 | let body = res.json::().await.unwrap(); 130 | assert_eq!(body.name, "Cholin"); 131 | assert_eq!(body.user, user.id.unwrap()); 132 | }); 133 | } 134 | 135 | #[test] 136 | fn remove_cat_by_id_route() { 137 | use_app(async move { 138 | let user = create_user("nico@test.com").await.unwrap(); 139 | let token = create_user_token(user.clone()).await.unwrap(); 140 | 141 | let tigrin = Cat::new(user.id.unwrap(), "Tigrin".to_owned()); 142 | let tigrin = Cat::create(tigrin).await.unwrap(); 143 | 144 | let client = reqwest::Client::new(); 145 | let res = client 146 | .delete(format!( 147 | "http://localhost:8088/v1/cats/{}", 148 | tigrin.id.unwrap() 149 | )) 150 | .header("Authorization", format!("Bearer {}", token)) 151 | .send() 152 | .await 153 | .unwrap(); 154 | 155 | // Status code: 156 | let status_code = res.status(); 157 | let actual = status_code; 158 | let expected = StatusCode::NO_CONTENT; 159 | assert_eq!(actual, expected); 160 | 161 | // Cat from the database 162 | let cat = Cat::find_by_id(&tigrin.id.unwrap()).await.unwrap(); 163 | assert!(cat.is_none(), "Cat should be removed from the database"); 164 | }); 165 | } 166 | -------------------------------------------------------------------------------- /src/tests/routes/mod.rs: -------------------------------------------------------------------------------- 1 | mod cat; 2 | mod status; 3 | mod user; 4 | -------------------------------------------------------------------------------- /src/tests/routes/status.rs: -------------------------------------------------------------------------------- 1 | use assert_json_diff::assert_json_eq; 2 | use reqwest; 3 | use reqwest::StatusCode; 4 | use serde_json::json; 5 | use serde_json::Value as Json; 6 | 7 | use crate::tests::setup::use_app; 8 | 9 | #[cfg(test)] 10 | use pretty_assertions::assert_eq; 11 | 12 | #[test] 13 | fn get_status_route() { 14 | use_app(async { 15 | let res = reqwest::get("http://localhost:8088/status").await.unwrap(); 16 | let status_code = res.status(); 17 | let body = res.json::().await.unwrap(); 18 | 19 | // Status code: 20 | let actual = status_code; 21 | let expected = StatusCode::OK; 22 | assert_eq!(actual, expected); 23 | 24 | // Body: 25 | let actual = body; 26 | let expected = json!({ "status": "ok" }); 27 | assert_json_eq!(actual, expected); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /src/tests/routes/user.rs: -------------------------------------------------------------------------------- 1 | use reqwest; 2 | use reqwest::StatusCode; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::models::user::PublicUser; 6 | use crate::routes::user::AuthenticateResponse; 7 | use crate::tests::setup::use_app; 8 | use crate::tests::utils::create_user; 9 | 10 | #[cfg(test)] 11 | use pretty_assertions::assert_eq; 12 | 13 | #[test] 14 | fn post_user_route() { 15 | #[derive(Debug, Serialize, Deserialize)] 16 | struct Body { 17 | name: String, 18 | email: String, 19 | password: String, 20 | } 21 | 22 | let body = Body { 23 | name: "Nahuel".to_owned(), 24 | email: "nahuel@gmail.com".to_owned(), 25 | password: "Password1".to_owned(), 26 | }; 27 | 28 | use_app(async move { 29 | let client = reqwest::Client::new(); 30 | let res = client 31 | .post("http://localhost:8088/users") 32 | .json(&body) 33 | .send() 34 | .await 35 | .unwrap(); 36 | 37 | // Status code: 38 | let status_code = res.status(); 39 | let actual = status_code; 40 | let expected = StatusCode::CREATED; 41 | assert_eq!(actual, expected); 42 | 43 | // Body: 44 | let body = res.json::().await.unwrap(); 45 | assert_eq!(body.name, "Nahuel"); 46 | assert_eq!(body.email, "nahuel@gmail.com"); 47 | }); 48 | } 49 | 50 | #[test] 51 | fn authenticate_user_route() { 52 | #[derive(Debug, Serialize, Deserialize)] 53 | struct RequestBody { 54 | email: String, 55 | password: String, 56 | } 57 | 58 | let request_body = RequestBody { 59 | email: "nahuel@gmail.com".to_owned(), 60 | password: "Password1".to_owned(), 61 | }; 62 | 63 | use_app(async move { 64 | create_user("nahuel@gmail.com").await.unwrap(); 65 | 66 | let client = reqwest::Client::new(); 67 | let res = client 68 | .post("http://localhost:8088/users/authenticate") 69 | .json(&request_body) 70 | .send() 71 | .await 72 | .unwrap(); 73 | 74 | // Status code: 75 | let status_code = res.status(); 76 | let actual = status_code; 77 | let expected = StatusCode::OK; 78 | assert_eq!(actual, expected); 79 | 80 | // Body: 81 | let body = res.json::().await.unwrap(); 82 | assert_eq!(body.user.email, "nahuel@gmail.com"); 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /src/tests/setup.rs: -------------------------------------------------------------------------------- 1 | use bson::doc; 2 | use lazy_static::lazy_static; 3 | use std::net::SocketAddr; 4 | use tokio::runtime::Runtime; 5 | use tokio::sync::OnceCell; 6 | 7 | use crate::app::create_app; 8 | use crate::models::cat::Cat; 9 | use crate::models::user::User; 10 | use crate::settings::SETTINGS; 11 | use crate::utils::models::ModelExt; 12 | 13 | static API: OnceCell<()> = OnceCell::const_new(); 14 | 15 | pub async fn start_api_once() { 16 | API 17 | .get_or_init(|| async { 18 | std::env::set_var("RUN_MODE", "test"); 19 | 20 | let app = create_app().await; 21 | let port = SETTINGS.server.port; 22 | let address = SocketAddr::from(([127, 0, 0, 1], port)); 23 | 24 | tokio::spawn(async move { 25 | axum::Server::bind(&address) 26 | .serve(app.into_make_service()) 27 | .await 28 | .expect("Failed to start server"); 29 | }); 30 | }) 31 | .await; 32 | } 33 | 34 | lazy_static! { 35 | static ref RUNTIME: Runtime = Runtime::new().unwrap(); 36 | } 37 | 38 | pub fn use_app(test: F) 39 | where 40 | F: std::future::Future, 41 | { 42 | RUNTIME.block_on(async move { 43 | start_api_once().await; 44 | 45 | Cat::delete_many(doc! {}).await.unwrap(); 46 | User::delete_many(doc! {}).await.unwrap(); 47 | 48 | test.await; 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /src/tests/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Error; 2 | use crate::models::user::hash_password; 3 | use crate::models::user::User; 4 | use crate::settings::SETTINGS; 5 | use crate::utils::models::ModelExt; 6 | use crate::utils::token; 7 | 8 | pub async fn create_user>(email: T) -> Result { 9 | let name = "Nahuel"; 10 | let password = "Password1"; 11 | 12 | let password_hash = hash_password(password).await?; 13 | let user = User::new(name, email.as_ref(), password_hash); 14 | let user = User::create(user).await?; 15 | 16 | Ok(user) 17 | } 18 | 19 | pub async fn create_user_token(user: User) -> Result { 20 | let secret = SETTINGS.auth.secret.as_str(); 21 | let token = token::create(user, secret).unwrap(); 22 | 23 | Ok(token) 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/authenticate_request.rs: -------------------------------------------------------------------------------- 1 | use axum::{ 2 | async_trait, 3 | extract::{FromRequestParts, TypedHeader}, 4 | headers::{authorization::Bearer, Authorization}, 5 | http::request::Parts, 6 | RequestPartsExt, 7 | }; 8 | 9 | use crate::errors::AuthenticateError; 10 | use crate::errors::Error; 11 | use crate::settings::SETTINGS; 12 | use crate::utils::token; 13 | use crate::utils::token::TokenUser; 14 | 15 | #[async_trait] 16 | impl FromRequestParts for TokenUser 17 | where 18 | S: Send + Sync, 19 | { 20 | type Rejection = Error; 21 | 22 | async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { 23 | let TypedHeader(Authorization(bearer)) = parts 24 | .extract::>>() 25 | .await 26 | .map_err(|_| AuthenticateError::InvalidToken)?; 27 | 28 | let secret = SETTINGS.auth.secret.as_str(); 29 | let token_data = 30 | token::decode(bearer.token(), secret).map_err(|_| AuthenticateError::InvalidToken)?; 31 | 32 | Ok(token_data.claims.user) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/custom_response.rs: -------------------------------------------------------------------------------- 1 | use axum::{ 2 | http::header::{self, HeaderValue}, 3 | http::StatusCode, 4 | response::{IntoResponse, IntoResponseParts, Response, ResponseParts}, 5 | }; 6 | use bytes::{BufMut, BytesMut}; 7 | use serde::Serialize; 8 | use tracing::error; 9 | 10 | use crate::errors::Error; 11 | 12 | pub type CustomResponseResult = Result, Error>; 13 | 14 | #[derive(Debug)] 15 | pub struct CustomResponse { 16 | pub body: Option, 17 | pub status_code: StatusCode, 18 | pub pagination: Option, 19 | } 20 | 21 | pub struct CustomResponseBuilder { 22 | pub body: Option, 23 | pub status_code: StatusCode, 24 | pub pagination: Option, 25 | } 26 | 27 | #[derive(Debug)] 28 | pub struct ResponsePagination { 29 | pub count: u64, 30 | pub offset: u64, 31 | pub limit: u32, 32 | } 33 | 34 | impl Default for CustomResponseBuilder 35 | where 36 | T: Serialize, 37 | { 38 | fn default() -> Self { 39 | Self { 40 | body: None, 41 | status_code: StatusCode::OK, 42 | pagination: None, 43 | } 44 | } 45 | } 46 | 47 | impl CustomResponseBuilder 48 | where 49 | T: Serialize, 50 | { 51 | pub fn new() -> Self { 52 | Self::default() 53 | } 54 | 55 | pub fn body(mut self, body: T) -> Self { 56 | self.body = Some(body); 57 | self 58 | } 59 | 60 | pub fn status_code(mut self, status_code: StatusCode) -> Self { 61 | self.status_code = status_code; 62 | self 63 | } 64 | 65 | pub fn pagination(mut self, pagination: ResponsePagination) -> Self { 66 | self.pagination = Some(pagination); 67 | self 68 | } 69 | 70 | pub fn build(self) -> CustomResponse { 71 | CustomResponse { 72 | body: self.body, 73 | status_code: self.status_code, 74 | pagination: self.pagination, 75 | } 76 | } 77 | } 78 | 79 | impl IntoResponse for CustomResponse 80 | where 81 | T: Serialize, 82 | { 83 | fn into_response(self) -> Response { 84 | let body = match self.body { 85 | Some(body) => body, 86 | None => return (self.status_code).into_response(), 87 | }; 88 | 89 | let mut bytes = BytesMut::new().writer(); 90 | if let Err(err) = serde_json::to_writer(&mut bytes, &body) { 91 | error!("Error serializing response body as JSON: {:?}", err); 92 | return (StatusCode::INTERNAL_SERVER_ERROR).into_response(); 93 | } 94 | 95 | let bytes = bytes.into_inner().freeze(); 96 | let headers = [( 97 | header::CONTENT_TYPE, 98 | HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), 99 | )]; 100 | 101 | match self.pagination { 102 | Some(pagination) => (self.status_code, pagination, headers, bytes).into_response(), 103 | None => (self.status_code, headers, bytes).into_response(), 104 | } 105 | } 106 | } 107 | 108 | impl IntoResponseParts for ResponsePagination { 109 | type Error = (StatusCode, String); 110 | 111 | fn into_response_parts(self, mut res: ResponseParts) -> Result { 112 | res 113 | .headers_mut() 114 | .insert("x-pagination-count", self.count.into()); 115 | 116 | res 117 | .headers_mut() 118 | .insert("x-pagination-offset", self.offset.into()); 119 | 120 | res 121 | .headers_mut() 122 | .insert("x-pagination-limit", self.limit.into()); 123 | 124 | Ok(res) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/utils/date.rs: -------------------------------------------------------------------------------- 1 | use chrono::Utc; 2 | 3 | pub type Date = bson::DateTime; 4 | 5 | pub fn now() -> Date { 6 | Utc::now().into() 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod authenticate_request; 2 | pub mod custom_response; 3 | pub mod date; 4 | pub mod models; 5 | pub mod pagination; 6 | pub mod to_object_id; 7 | pub mod token; 8 | -------------------------------------------------------------------------------- /src/utils/models.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use futures::stream::TryStreamExt; 3 | use serde::{de::DeserializeOwned, ser::Serialize}; 4 | use validator::Validate; 5 | use wither::bson::doc; 6 | use wither::bson::from_bson; 7 | use wither::bson::Bson; 8 | use wither::bson::Document; 9 | use wither::bson::{self, oid::ObjectId}; 10 | use wither::mongodb::options::FindOneAndUpdateOptions; 11 | use wither::mongodb::options::FindOneOptions; 12 | use wither::mongodb::options::FindOptions; 13 | use wither::mongodb::options::ReturnDocument; 14 | use wither::mongodb::options::UpdateOptions; 15 | use wither::mongodb::results::DeleteResult; 16 | use wither::mongodb::results::UpdateResult; 17 | use wither::Model as WitherModel; 18 | use wither::ModelCursor; 19 | 20 | use crate::database; 21 | use crate::errors::Error; 22 | 23 | // This is the Model trait. All models that have a MongoDB collection should 24 | // implement this and therefore inherit theses methods. 25 | #[async_trait] 26 | pub trait ModelExt 27 | where 28 | Self: WitherModel + Validate, 29 | { 30 | async fn create(mut model: Self) -> Result { 31 | let connection = database::connection().await; 32 | model.validate().map_err(|_error| Error::bad_request())?; 33 | model.save(connection, None).await.map_err(Error::Wither)?; 34 | 35 | Ok(model) 36 | } 37 | 38 | async fn find_by_id(id: &ObjectId) -> Result, Error> { 39 | let connection = database::connection().await; 40 | ::find_one(connection, doc! { "_id": id }, None) 41 | .await 42 | .map_err(Error::Wither) 43 | } 44 | 45 | async fn find_one(query: Document, options: O) -> Result, Error> 46 | where 47 | O: Into> + Send, 48 | { 49 | let connection = database::connection().await; 50 | ::find_one(connection, query, options) 51 | .await 52 | .map_err(Error::Wither) 53 | } 54 | 55 | async fn find(query: Document, options: O) -> Result, Error> 56 | where 57 | O: Into> + Send, 58 | { 59 | let connection = database::connection().await; 60 | ::find(connection, query, options) 61 | .await 62 | .map_err(Error::Wither)? 63 | .try_collect::>() 64 | .await 65 | .map_err(Error::Wither) 66 | } 67 | 68 | async fn find_and_count(query: Document, options: O) -> Result<(Vec, u64), Error> 69 | where 70 | O: Into> + Send, 71 | { 72 | let connection = database::connection().await; 73 | 74 | let count = Self::collection(connection) 75 | .count_documents(query.clone(), None) 76 | .await 77 | .map_err(Error::Mongo)?; 78 | 79 | let items = ::find(connection, query, options.into()) 80 | .await 81 | .map_err(Error::Wither)? 82 | .try_collect::>() 83 | .await 84 | .map_err(Error::Wither)?; 85 | 86 | Ok((items, count)) 87 | } 88 | 89 | async fn cursor(query: Document, options: O) -> Result, Error> 90 | where 91 | O: Into> + Send, 92 | { 93 | let connection = database::connection().await; 94 | ::find(connection, query, options) 95 | .await 96 | .map_err(Error::Wither) 97 | } 98 | 99 | async fn find_one_and_update(query: Document, update: Document) -> Result, Error> { 100 | let connection = database::connection().await; 101 | let options = FindOneAndUpdateOptions::builder() 102 | .return_document(ReturnDocument::After) 103 | .build(); 104 | 105 | ::find_one_and_update(connection, query, update, options) 106 | .await 107 | .map_err(Error::Wither) 108 | } 109 | 110 | async fn update_one( 111 | query: Document, 112 | update: Document, 113 | options: O, 114 | ) -> Result 115 | where 116 | O: Into> + Send, 117 | { 118 | let connection = database::connection().await; 119 | Self::collection(connection) 120 | .update_one(query, update, options) 121 | .await 122 | .map_err(Error::Mongo) 123 | } 124 | 125 | async fn update_many( 126 | query: Document, 127 | update: Document, 128 | options: O, 129 | ) -> Result 130 | where 131 | O: Into> + Send, 132 | { 133 | let connection = database::connection().await; 134 | Self::collection(connection) 135 | .update_many(query, update, options) 136 | .await 137 | .map_err(Error::Mongo) 138 | } 139 | 140 | async fn delete_many(query: Document) -> Result { 141 | let connection = database::connection().await; 142 | ::delete_many(connection, query, None) 143 | .await 144 | .map_err(Error::Wither) 145 | } 146 | 147 | async fn delete_one(query: Document) -> Result { 148 | let connection = database::connection().await; 149 | Self::collection(connection) 150 | .delete_one(query, None) 151 | .await 152 | .map_err(Error::Mongo) 153 | } 154 | 155 | async fn count(query: Document) -> Result { 156 | let connection = database::connection().await; 157 | Self::collection(connection) 158 | .count_documents(query, None) 159 | .await 160 | .map_err(Error::Mongo) 161 | } 162 | 163 | async fn exists(query: Document) -> Result { 164 | let connection = database::connection().await; 165 | let count = Self::collection(connection) 166 | .count_documents(query, None) 167 | .await 168 | .map_err(Error::Mongo)?; 169 | 170 | Ok(count > 0) 171 | } 172 | 173 | async fn aggregate(pipeline: Vec) -> Result, Error> 174 | where 175 | A: Serialize + DeserializeOwned, 176 | { 177 | let connection = database::connection().await; 178 | 179 | let documents = Self::collection(connection) 180 | .aggregate(pipeline, None) 181 | .await 182 | .map_err(Error::Mongo)? 183 | .try_collect::>() 184 | .await 185 | .map_err(Error::Mongo)?; 186 | 187 | let documents = documents 188 | .into_iter() 189 | .map(|document| from_bson::(Bson::Document(document))) 190 | .collect::, bson::de::Error>>() 191 | .map_err(Error::SerializeMongoResponse)?; 192 | 193 | Ok(documents) 194 | } 195 | 196 | async fn sync_indexes() -> Result<(), Error> { 197 | let connection = database::connection().await; 198 | Self::sync(connection).await.map_err(Error::Wither) 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/utils/pagination.rs: -------------------------------------------------------------------------------- 1 | // Original author: Christian Gill (@gillchristian) 2 | // From: https://gist.github.com/gillchristian/db76e712cc02bff620b86f0cd2bfb691 3 | 4 | use async_trait::async_trait; 5 | use axum::extract::{FromRequestParts, Query}; 6 | use axum::http::{request::Parts, StatusCode}; 7 | use serde::Deserialize; 8 | 9 | #[derive(Debug, Clone, Deserialize)] 10 | struct Limit { 11 | limit: u32, 12 | } 13 | 14 | impl Default for Limit { 15 | fn default() -> Self { 16 | Self { limit: 100 } 17 | } 18 | } 19 | 20 | #[derive(Debug, Clone, Default, Deserialize)] 21 | struct Offset { 22 | offset: u64, 23 | } 24 | 25 | #[derive(Debug, Clone)] 26 | pub struct Pagination { 27 | /// The number of documents to skip before counting. 28 | pub offset: u64, 29 | /// The maximum number of documents to query. 30 | pub limit: u32, 31 | } 32 | 33 | #[async_trait] 34 | impl FromRequestParts for Pagination 35 | where 36 | S: Send + Sync, 37 | { 38 | type Rejection = (StatusCode, &'static str); 39 | 40 | async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { 41 | let Query(Limit { limit }) = Query::::from_request_parts(parts, state) 42 | .await 43 | .unwrap_or_default(); 44 | 45 | let Query(Offset { offset }) = Query::::from_request_parts(parts, state) 46 | .await 47 | .unwrap_or_default(); 48 | 49 | Ok(Self { limit, offset }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/utils/to_object_id.rs: -------------------------------------------------------------------------------- 1 | use bson::oid::ObjectId; 2 | 3 | use crate::errors::Error; 4 | 5 | pub fn to_object_id>(id: S) -> Result { 6 | ObjectId::parse_str(id.as_ref()).map_err(|_| Error::ParseObjectID(id.as_ref().to_string())) 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/token.rs: -------------------------------------------------------------------------------- 1 | use bson::oid::ObjectId; 2 | use jsonwebtoken::{errors::Error, DecodingKey, EncodingKey, Header, TokenData, Validation}; 3 | use once_cell::sync::Lazy; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::models::user::User; 7 | 8 | type TokenResult = Result, Error>; 9 | 10 | static VALIDATION: Lazy = Lazy::new(Validation::default); 11 | static HEADER: Lazy

= Lazy::new(Header::default); 12 | 13 | #[derive(Debug, Serialize, Deserialize)] 14 | pub struct TokenUser { 15 | pub id: ObjectId, 16 | pub name: String, 17 | pub email: String, 18 | } 19 | 20 | impl From for TokenUser { 21 | fn from(user: User) -> Self { 22 | Self { 23 | id: user.id.unwrap(), 24 | name: user.name.clone(), 25 | email: user.email, 26 | } 27 | } 28 | } 29 | 30 | #[derive(Debug, Serialize, Deserialize)] 31 | pub struct Claims { 32 | pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation 33 | pub iat: usize, // Issued at (as UTC timestamp) 34 | pub user: TokenUser, 35 | } 36 | 37 | impl Claims { 38 | pub fn new(user: User) -> Self { 39 | Self { 40 | exp: (chrono::Local::now() + chrono::Duration::days(30)).timestamp() as usize, 41 | iat: chrono::Local::now().timestamp() as usize, 42 | user: TokenUser::from(user), 43 | } 44 | } 45 | } 46 | 47 | pub fn create(user: User, secret: &str) -> Result { 48 | let encoding_key = EncodingKey::from_secret(secret.as_ref()); 49 | let claims = Claims::new(user); 50 | 51 | jsonwebtoken::encode(&HEADER, &claims, &encoding_key) 52 | } 53 | 54 | pub fn decode(token: &str, secret: &str) -> TokenResult { 55 | let decoding_key = DecodingKey::from_secret(secret.as_ref()); 56 | 57 | jsonwebtoken::decode::(token, &decoding_key, &VALIDATION) 58 | } 59 | --------------------------------------------------------------------------------