├── .env ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── migrations └── 000000_init.sql ├── src ├── auth │ ├── auth_service_impl.rs │ ├── mod.rs │ ├── ports.rs │ ├── postgres_credential_repo.rs │ ├── redis_token_repo.rs │ └── rest_auth_controller.rs ├── infrastructure │ ├── mod.rs │ ├── postgresql.rs │ └── redis.rs └── main.rs └── test-stack.yml /.env: -------------------------------------------------------------------------------- 1 | PORT=8080 2 | DB_URL=postgresql://postgres:test@localhost:5431/postgres 3 | REDIS_URL=redis://localhost:6378 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/intellij,rust 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=intellij,rust 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/artifacts 37 | # .idea/compiler.xml 38 | # .idea/jarRepositories.xml 39 | # .idea/modules.xml 40 | # .idea/*.iml 41 | # .idea/modules 42 | # *.iml 43 | # *.ipr 44 | 45 | # CMake 46 | cmake-build-*/ 47 | 48 | # Mongo Explorer plugin 49 | .idea/**/mongoSettings.xml 50 | 51 | # File-based project format 52 | *.iws 53 | 54 | # IntelliJ 55 | out/ 56 | 57 | # mpeltonen/sbt-idea plugin 58 | .idea_modules/ 59 | 60 | # JIRA plugin 61 | atlassian-ide-plugin.xml 62 | 63 | # Cursive Clojure plugin 64 | .idea/replstate.xml 65 | 66 | # Crashlytics plugin (for Android Studio and IntelliJ) 67 | com_crashlytics_export_strings.xml 68 | crashlytics.properties 69 | crashlytics-build.properties 70 | fabric.properties 71 | 72 | # Editor-based Rest Client 73 | .idea/httpRequests 74 | 75 | # Android studio 3.1+ serialized cache file 76 | .idea/caches/build_file_checksums.ser 77 | 78 | ### Intellij Patch ### 79 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 80 | 81 | # *.iml 82 | # modules.xml 83 | # .idea/misc.xml 84 | # *.ipr 85 | 86 | # Sonarlint plugin 87 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 88 | .idea/**/sonarlint/ 89 | 90 | # SonarQube Plugin 91 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 92 | .idea/**/sonarIssues.xml 93 | 94 | # Markdown Navigator plugin 95 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 96 | .idea/**/markdown-navigator.xml 97 | .idea/**/markdown-navigator-enh.xml 98 | .idea/**/markdown-navigator/ 99 | 100 | # Cache file creation bug 101 | # See https://youtrack.jetbrains.com/issue/JBR-2257 102 | .idea/$CACHE_FILE$ 103 | 104 | # CodeStream plugin 105 | # https://plugins.jetbrains.com/plugin/12206-codestream 106 | .idea/codestream.xml 107 | 108 | .idea/ 109 | *.iml 110 | 111 | ### Rust ### 112 | # Generated by Cargo 113 | # will have compiled files and executables 114 | /target/ 115 | 116 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 117 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 118 | # Cargo.lock 119 | 120 | # End of https://www.toptal.com/developers/gitignore/api/intellij,rust -------------------------------------------------------------------------------- /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 = "actix-codec" 7 | version = "0.5.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" 10 | dependencies = [ 11 | "bitflags", 12 | "bytes", 13 | "futures-core", 14 | "futures-sink", 15 | "log", 16 | "memchr", 17 | "pin-project-lite", 18 | "tokio", 19 | "tokio-util 0.7.3", 20 | ] 21 | 22 | [[package]] 23 | name = "actix-http" 24 | version = "3.2.1" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "6f9ffb6db08c1c3a1f4aef540f1a63193adc73c4fbd40b75a95fc8c5258f6e51" 27 | dependencies = [ 28 | "actix-codec", 29 | "actix-rt", 30 | "actix-service", 31 | "actix-utils", 32 | "ahash", 33 | "base64", 34 | "bitflags", 35 | "brotli", 36 | "bytes", 37 | "bytestring", 38 | "derive_more", 39 | "encoding_rs", 40 | "flate2", 41 | "futures-core", 42 | "h2", 43 | "http", 44 | "httparse", 45 | "httpdate", 46 | "itoa 1.0.2", 47 | "language-tags", 48 | "local-channel", 49 | "mime", 50 | "percent-encoding", 51 | "pin-project-lite", 52 | "rand", 53 | "sha1 0.10.1", 54 | "smallvec", 55 | "tracing", 56 | "zstd", 57 | ] 58 | 59 | [[package]] 60 | name = "actix-macros" 61 | version = "0.2.3" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" 64 | dependencies = [ 65 | "quote", 66 | "syn", 67 | ] 68 | 69 | [[package]] 70 | name = "actix-router" 71 | version = "0.5.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" 74 | dependencies = [ 75 | "bytestring", 76 | "firestorm", 77 | "http", 78 | "log", 79 | "regex", 80 | "serde", 81 | ] 82 | 83 | [[package]] 84 | name = "actix-rt" 85 | version = "2.7.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" 88 | dependencies = [ 89 | "futures-core", 90 | "tokio", 91 | ] 92 | 93 | [[package]] 94 | name = "actix-server" 95 | version = "2.1.1" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" 98 | dependencies = [ 99 | "actix-rt", 100 | "actix-service", 101 | "actix-utils", 102 | "futures-core", 103 | "futures-util", 104 | "mio", 105 | "num_cpus", 106 | "socket2", 107 | "tokio", 108 | "tracing", 109 | ] 110 | 111 | [[package]] 112 | name = "actix-service" 113 | version = "2.0.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" 116 | dependencies = [ 117 | "futures-core", 118 | "paste", 119 | "pin-project-lite", 120 | ] 121 | 122 | [[package]] 123 | name = "actix-utils" 124 | version = "3.0.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" 127 | dependencies = [ 128 | "local-waker", 129 | "pin-project-lite", 130 | ] 131 | 132 | [[package]] 133 | name = "actix-web" 134 | version = "4.1.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "a27e8fe9ba4ae613c21f677c2cfaf0696c3744030c6f485b34634e502d6bb379" 137 | dependencies = [ 138 | "actix-codec", 139 | "actix-http", 140 | "actix-macros", 141 | "actix-router", 142 | "actix-rt", 143 | "actix-server", 144 | "actix-service", 145 | "actix-utils", 146 | "actix-web-codegen", 147 | "ahash", 148 | "bytes", 149 | "bytestring", 150 | "cfg-if 1.0.0", 151 | "cookie", 152 | "derive_more", 153 | "encoding_rs", 154 | "futures-core", 155 | "futures-util", 156 | "itoa 1.0.2", 157 | "language-tags", 158 | "log", 159 | "mime", 160 | "once_cell", 161 | "pin-project-lite", 162 | "regex", 163 | "serde", 164 | "serde_json", 165 | "serde_urlencoded", 166 | "smallvec", 167 | "socket2", 168 | "time", 169 | "url", 170 | ] 171 | 172 | [[package]] 173 | name = "actix-web-codegen" 174 | version = "4.0.1" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "5f270541caec49c15673b0af0e9a00143421ad4f118d2df7edcb68b627632f56" 177 | dependencies = [ 178 | "actix-router", 179 | "proc-macro2", 180 | "quote", 181 | "syn", 182 | ] 183 | 184 | [[package]] 185 | name = "adler" 186 | version = "0.2.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 189 | 190 | [[package]] 191 | name = "ahash" 192 | version = "0.7.6" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 195 | dependencies = [ 196 | "getrandom", 197 | "once_cell", 198 | "version_check", 199 | ] 200 | 201 | [[package]] 202 | name = "aho-corasick" 203 | version = "0.7.18" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 206 | dependencies = [ 207 | "memchr", 208 | ] 209 | 210 | [[package]] 211 | name = "alloc-no-stdlib" 212 | version = "2.0.3" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" 215 | 216 | [[package]] 217 | name = "alloc-stdlib" 218 | version = "0.2.1" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" 221 | dependencies = [ 222 | "alloc-no-stdlib", 223 | ] 224 | 225 | [[package]] 226 | name = "async-trait" 227 | version = "0.1.56" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" 230 | dependencies = [ 231 | "proc-macro2", 232 | "quote", 233 | "syn", 234 | ] 235 | 236 | [[package]] 237 | name = "atoi" 238 | version = "0.4.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" 241 | dependencies = [ 242 | "num-traits", 243 | ] 244 | 245 | [[package]] 246 | name = "autocfg" 247 | version = "1.0.1" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 250 | 251 | [[package]] 252 | name = "base64" 253 | version = "0.13.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 256 | 257 | [[package]] 258 | name = "bitflags" 259 | version = "1.3.2" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 262 | 263 | [[package]] 264 | name = "block-buffer" 265 | version = "0.9.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 268 | dependencies = [ 269 | "generic-array", 270 | ] 271 | 272 | [[package]] 273 | name = "block-buffer" 274 | version = "0.10.2" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 277 | dependencies = [ 278 | "generic-array", 279 | ] 280 | 281 | [[package]] 282 | name = "brotli" 283 | version = "3.3.4" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" 286 | dependencies = [ 287 | "alloc-no-stdlib", 288 | "alloc-stdlib", 289 | "brotli-decompressor", 290 | ] 291 | 292 | [[package]] 293 | name = "brotli-decompressor" 294 | version = "2.3.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" 297 | dependencies = [ 298 | "alloc-no-stdlib", 299 | "alloc-stdlib", 300 | ] 301 | 302 | [[package]] 303 | name = "bumpalo" 304 | version = "3.4.0" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" 307 | 308 | [[package]] 309 | name = "byteorder" 310 | version = "1.4.3" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 313 | 314 | [[package]] 315 | name = "bytes" 316 | version = "1.1.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 319 | 320 | [[package]] 321 | name = "bytestring" 322 | version = "1.1.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a" 325 | dependencies = [ 326 | "bytes", 327 | ] 328 | 329 | [[package]] 330 | name = "cc" 331 | version = "1.0.73" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 334 | dependencies = [ 335 | "jobserver", 336 | ] 337 | 338 | [[package]] 339 | name = "cfg-if" 340 | version = "0.1.10" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 343 | 344 | [[package]] 345 | name = "cfg-if" 346 | version = "1.0.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 349 | 350 | [[package]] 351 | name = "cloudabi" 352 | version = "0.1.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" 355 | dependencies = [ 356 | "bitflags", 357 | ] 358 | 359 | [[package]] 360 | name = "combine" 361 | version = "4.6.4" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" 364 | dependencies = [ 365 | "bytes", 366 | "futures-core", 367 | "memchr", 368 | "pin-project-lite", 369 | "tokio", 370 | "tokio-util 0.7.3", 371 | ] 372 | 373 | [[package]] 374 | name = "cookie" 375 | version = "0.16.0" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" 378 | dependencies = [ 379 | "percent-encoding", 380 | "time", 381 | "version_check", 382 | ] 383 | 384 | [[package]] 385 | name = "cpufeatures" 386 | version = "0.2.2" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" 389 | dependencies = [ 390 | "libc", 391 | ] 392 | 393 | [[package]] 394 | name = "cpuid-bool" 395 | version = "0.1.2" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 398 | 399 | [[package]] 400 | name = "crc" 401 | version = "2.1.0" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" 404 | dependencies = [ 405 | "crc-catalog", 406 | ] 407 | 408 | [[package]] 409 | name = "crc-catalog" 410 | version = "1.1.1" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" 413 | 414 | [[package]] 415 | name = "crc32fast" 416 | version = "1.2.1" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 419 | dependencies = [ 420 | "cfg-if 1.0.0", 421 | ] 422 | 423 | [[package]] 424 | name = "crossbeam-channel" 425 | version = "0.5.5" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" 428 | dependencies = [ 429 | "cfg-if 1.0.0", 430 | "crossbeam-utils", 431 | ] 432 | 433 | [[package]] 434 | name = "crossbeam-queue" 435 | version = "0.3.5" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" 438 | dependencies = [ 439 | "cfg-if 1.0.0", 440 | "crossbeam-utils", 441 | ] 442 | 443 | [[package]] 444 | name = "crossbeam-utils" 445 | version = "0.8.10" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" 448 | dependencies = [ 449 | "cfg-if 1.0.0", 450 | "once_cell", 451 | ] 452 | 453 | [[package]] 454 | name = "crypto-common" 455 | version = "0.1.5" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" 458 | dependencies = [ 459 | "generic-array", 460 | "typenum", 461 | ] 462 | 463 | [[package]] 464 | name = "crypto-mac" 465 | version = "0.11.1" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 468 | dependencies = [ 469 | "generic-array", 470 | "subtle", 471 | ] 472 | 473 | [[package]] 474 | name = "derive_more" 475 | version = "0.99.11" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" 478 | dependencies = [ 479 | "proc-macro2", 480 | "quote", 481 | "syn", 482 | ] 483 | 484 | [[package]] 485 | name = "difference" 486 | version = "2.0.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 489 | 490 | [[package]] 491 | name = "digest" 492 | version = "0.9.0" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 495 | dependencies = [ 496 | "generic-array", 497 | ] 498 | 499 | [[package]] 500 | name = "digest" 501 | version = "0.10.3" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 504 | dependencies = [ 505 | "block-buffer 0.10.2", 506 | "crypto-common", 507 | ] 508 | 509 | [[package]] 510 | name = "dirs" 511 | version = "3.0.2" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" 514 | dependencies = [ 515 | "dirs-sys", 516 | ] 517 | 518 | [[package]] 519 | name = "dirs-sys" 520 | version = "0.3.7" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 523 | dependencies = [ 524 | "libc", 525 | "redox_users", 526 | "winapi", 527 | ] 528 | 529 | [[package]] 530 | name = "dotenv" 531 | version = "0.15.0" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 534 | 535 | [[package]] 536 | name = "downcast" 537 | version = "0.10.0" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" 540 | 541 | [[package]] 542 | name = "dtoa" 543 | version = "0.4.6" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" 546 | 547 | [[package]] 548 | name = "either" 549 | version = "1.6.1" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 552 | 553 | [[package]] 554 | name = "encoding_rs" 555 | version = "0.8.24" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" 558 | dependencies = [ 559 | "cfg-if 0.1.10", 560 | ] 561 | 562 | [[package]] 563 | name = "firestorm" 564 | version = "0.5.1" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" 567 | 568 | [[package]] 569 | name = "flate2" 570 | version = "1.0.18" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" 573 | dependencies = [ 574 | "cfg-if 0.1.10", 575 | "crc32fast", 576 | "libc", 577 | "miniz_oxide", 578 | ] 579 | 580 | [[package]] 581 | name = "float-cmp" 582 | version = "0.8.0" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" 585 | dependencies = [ 586 | "num-traits", 587 | ] 588 | 589 | [[package]] 590 | name = "fnv" 591 | version = "1.0.7" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 594 | 595 | [[package]] 596 | name = "form_urlencoded" 597 | version = "1.0.1" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 600 | dependencies = [ 601 | "matches", 602 | "percent-encoding", 603 | ] 604 | 605 | [[package]] 606 | name = "fragile" 607 | version = "1.0.0" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2" 610 | 611 | [[package]] 612 | name = "futures-channel" 613 | version = "0.3.21" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 616 | dependencies = [ 617 | "futures-core", 618 | "futures-sink", 619 | ] 620 | 621 | [[package]] 622 | name = "futures-core" 623 | version = "0.3.21" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 626 | 627 | [[package]] 628 | name = "futures-intrusive" 629 | version = "0.4.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" 632 | dependencies = [ 633 | "futures-core", 634 | "lock_api", 635 | "parking_lot 0.11.0", 636 | ] 637 | 638 | [[package]] 639 | name = "futures-sink" 640 | version = "0.3.21" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 643 | 644 | [[package]] 645 | name = "futures-task" 646 | version = "0.3.21" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 649 | 650 | [[package]] 651 | name = "futures-util" 652 | version = "0.3.21" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 655 | dependencies = [ 656 | "futures-core", 657 | "futures-sink", 658 | "futures-task", 659 | "pin-project-lite", 660 | "pin-utils", 661 | ] 662 | 663 | [[package]] 664 | name = "generic-array" 665 | version = "0.14.4" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 668 | dependencies = [ 669 | "typenum", 670 | "version_check", 671 | ] 672 | 673 | [[package]] 674 | name = "getrandom" 675 | version = "0.2.7" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 678 | dependencies = [ 679 | "cfg-if 1.0.0", 680 | "libc", 681 | "wasi", 682 | ] 683 | 684 | [[package]] 685 | name = "glob" 686 | version = "0.3.0" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 689 | 690 | [[package]] 691 | name = "h2" 692 | version = "0.3.13" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" 695 | dependencies = [ 696 | "bytes", 697 | "fnv", 698 | "futures-core", 699 | "futures-sink", 700 | "futures-util", 701 | "http", 702 | "indexmap", 703 | "slab", 704 | "tokio", 705 | "tokio-util 0.7.3", 706 | "tracing", 707 | ] 708 | 709 | [[package]] 710 | name = "hashbrown" 711 | version = "0.11.2" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 714 | dependencies = [ 715 | "ahash", 716 | ] 717 | 718 | [[package]] 719 | name = "hashbrown" 720 | version = "0.12.2" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" 723 | 724 | [[package]] 725 | name = "hashlink" 726 | version = "0.7.0" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" 729 | dependencies = [ 730 | "hashbrown 0.11.2", 731 | ] 732 | 733 | [[package]] 734 | name = "heck" 735 | version = "0.3.1" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 738 | dependencies = [ 739 | "unicode-segmentation", 740 | ] 741 | 742 | [[package]] 743 | name = "hermit-abi" 744 | version = "0.1.17" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" 747 | dependencies = [ 748 | "libc", 749 | ] 750 | 751 | [[package]] 752 | name = "hex" 753 | version = "0.4.3" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 756 | 757 | [[package]] 758 | name = "hmac" 759 | version = "0.11.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 762 | dependencies = [ 763 | "crypto-mac", 764 | "digest 0.9.0", 765 | ] 766 | 767 | [[package]] 768 | name = "http" 769 | version = "0.2.8" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 772 | dependencies = [ 773 | "bytes", 774 | "fnv", 775 | "itoa 1.0.2", 776 | ] 777 | 778 | [[package]] 779 | name = "httparse" 780 | version = "1.7.1" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" 783 | 784 | [[package]] 785 | name = "httpdate" 786 | version = "1.0.2" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 789 | 790 | [[package]] 791 | name = "idna" 792 | version = "0.2.0" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 795 | dependencies = [ 796 | "matches", 797 | "unicode-bidi", 798 | "unicode-normalization", 799 | ] 800 | 801 | [[package]] 802 | name = "include_dir" 803 | version = "0.7.2" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "482a2e29200b7eed25d7fdbd14423326760b7f6658d21a4cf12d55a50713c69f" 806 | dependencies = [ 807 | "glob", 808 | "include_dir_macros", 809 | ] 810 | 811 | [[package]] 812 | name = "include_dir_macros" 813 | version = "0.7.2" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "5e074c19deab2501407c91ba1860fa3d6820bfde307db6d8cb851b55a10be89b" 816 | dependencies = [ 817 | "proc-macro2", 818 | "quote", 819 | ] 820 | 821 | [[package]] 822 | name = "indexmap" 823 | version = "1.9.1" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 826 | dependencies = [ 827 | "autocfg", 828 | "hashbrown 0.12.2", 829 | ] 830 | 831 | [[package]] 832 | name = "instant" 833 | version = "0.1.8" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" 836 | dependencies = [ 837 | "cfg-if 1.0.0", 838 | ] 839 | 840 | [[package]] 841 | name = "itertools" 842 | version = "0.10.3" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 845 | dependencies = [ 846 | "either", 847 | ] 848 | 849 | [[package]] 850 | name = "itoa" 851 | version = "0.4.6" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 854 | 855 | [[package]] 856 | name = "itoa" 857 | version = "1.0.2" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" 860 | 861 | [[package]] 862 | name = "jobserver" 863 | version = "0.1.24" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 866 | dependencies = [ 867 | "libc", 868 | ] 869 | 870 | [[package]] 871 | name = "js-sys" 872 | version = "0.3.45" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" 875 | dependencies = [ 876 | "wasm-bindgen", 877 | ] 878 | 879 | [[package]] 880 | name = "language-tags" 881 | version = "0.3.2" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" 884 | 885 | [[package]] 886 | name = "lazy_static" 887 | version = "1.4.0" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 890 | 891 | [[package]] 892 | name = "libc" 893 | version = "0.2.126" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 896 | 897 | [[package]] 898 | name = "local-channel" 899 | version = "0.1.3" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" 902 | dependencies = [ 903 | "futures-core", 904 | "futures-sink", 905 | "futures-util", 906 | "local-waker", 907 | ] 908 | 909 | [[package]] 910 | name = "local-waker" 911 | version = "0.1.3" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" 914 | 915 | [[package]] 916 | name = "lock_api" 917 | version = "0.4.6" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 920 | dependencies = [ 921 | "scopeguard", 922 | ] 923 | 924 | [[package]] 925 | name = "log" 926 | version = "0.4.17" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 929 | dependencies = [ 930 | "cfg-if 1.0.0", 931 | ] 932 | 933 | [[package]] 934 | name = "matches" 935 | version = "0.1.8" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 938 | 939 | [[package]] 940 | name = "md-5" 941 | version = "0.9.1" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" 944 | dependencies = [ 945 | "block-buffer 0.9.0", 946 | "digest 0.9.0", 947 | "opaque-debug", 948 | ] 949 | 950 | [[package]] 951 | name = "memchr" 952 | version = "2.5.0" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 955 | 956 | [[package]] 957 | name = "mime" 958 | version = "0.3.16" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 961 | 962 | [[package]] 963 | name = "minimal-lexical" 964 | version = "0.2.1" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 967 | 968 | [[package]] 969 | name = "miniz_oxide" 970 | version = "0.4.3" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" 973 | dependencies = [ 974 | "adler", 975 | "autocfg", 976 | ] 977 | 978 | [[package]] 979 | name = "mio" 980 | version = "0.8.4" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 983 | dependencies = [ 984 | "libc", 985 | "log", 986 | "wasi", 987 | "windows-sys", 988 | ] 989 | 990 | [[package]] 991 | name = "mockall" 992 | version = "0.8.3" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "41cabea45a7fc0e37093f4f30a5e2b62602253f91791c057d5f0470c63260c3d" 995 | dependencies = [ 996 | "cfg-if 0.1.10", 997 | "downcast", 998 | "fragile", 999 | "lazy_static", 1000 | "mockall_derive", 1001 | "predicates", 1002 | "predicates-tree", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "mockall_derive" 1007 | version = "0.8.3" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "7c461918bf7f59eefb1459252756bf2351a995d6bd510d0b2061bd86bcdabfa6" 1010 | dependencies = [ 1011 | "cfg-if 0.1.10", 1012 | "proc-macro2", 1013 | "quote", 1014 | "syn", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "nom" 1019 | version = "7.1.1" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 1022 | dependencies = [ 1023 | "memchr", 1024 | "minimal-lexical", 1025 | ] 1026 | 1027 | [[package]] 1028 | name = "normalize-line-endings" 1029 | version = "0.3.0" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" 1032 | 1033 | [[package]] 1034 | name = "num-traits" 1035 | version = "0.2.14" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1038 | dependencies = [ 1039 | "autocfg", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "num_cpus" 1044 | version = "1.13.0" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1047 | dependencies = [ 1048 | "hermit-abi", 1049 | "libc", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "num_threads" 1054 | version = "0.1.6" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" 1057 | dependencies = [ 1058 | "libc", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "once_cell" 1063 | version = "1.13.0" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 1066 | 1067 | [[package]] 1068 | name = "opaque-debug" 1069 | version = "0.3.0" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1072 | 1073 | [[package]] 1074 | name = "parking_lot" 1075 | version = "0.11.0" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" 1078 | dependencies = [ 1079 | "instant", 1080 | "lock_api", 1081 | "parking_lot_core 0.8.0", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "parking_lot" 1086 | version = "0.12.1" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1089 | dependencies = [ 1090 | "lock_api", 1091 | "parking_lot_core 0.9.3", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "parking_lot_core" 1096 | version = "0.8.0" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" 1099 | dependencies = [ 1100 | "cfg-if 0.1.10", 1101 | "cloudabi", 1102 | "instant", 1103 | "libc", 1104 | "redox_syscall 0.1.57", 1105 | "smallvec", 1106 | "winapi", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "parking_lot_core" 1111 | version = "0.9.3" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 1114 | dependencies = [ 1115 | "cfg-if 1.0.0", 1116 | "libc", 1117 | "redox_syscall 0.2.13", 1118 | "smallvec", 1119 | "windows-sys", 1120 | ] 1121 | 1122 | [[package]] 1123 | name = "paste" 1124 | version = "1.0.7" 1125 | source = "registry+https://github.com/rust-lang/crates.io-index" 1126 | checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" 1127 | 1128 | [[package]] 1129 | name = "percent-encoding" 1130 | version = "2.1.0" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1133 | 1134 | [[package]] 1135 | name = "pin-project-lite" 1136 | version = "0.2.9" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1139 | 1140 | [[package]] 1141 | name = "pin-utils" 1142 | version = "0.1.0" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1145 | 1146 | [[package]] 1147 | name = "ppv-lite86" 1148 | version = "0.2.9" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" 1151 | 1152 | [[package]] 1153 | name = "predicates" 1154 | version = "1.0.5" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a" 1157 | dependencies = [ 1158 | "difference", 1159 | "float-cmp", 1160 | "normalize-line-endings", 1161 | "predicates-core", 1162 | "regex", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "predicates-core" 1167 | version = "1.0.0" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" 1170 | 1171 | [[package]] 1172 | name = "predicates-tree" 1173 | version = "1.0.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" 1176 | dependencies = [ 1177 | "predicates-core", 1178 | "treeline", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "proc-macro2" 1183 | version = "1.0.40" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" 1186 | dependencies = [ 1187 | "unicode-ident", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "quote" 1192 | version = "1.0.20" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" 1195 | dependencies = [ 1196 | "proc-macro2", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "rand" 1201 | version = "0.8.5" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1204 | dependencies = [ 1205 | "libc", 1206 | "rand_chacha", 1207 | "rand_core", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "rand_chacha" 1212 | version = "0.3.1" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1215 | dependencies = [ 1216 | "ppv-lite86", 1217 | "rand_core", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "rand_core" 1222 | version = "0.6.3" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1225 | dependencies = [ 1226 | "getrandom", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "redis" 1231 | version = "0.21.5" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "1a80b5f38d7f5a020856a0e16e40a9cfabf88ae8f0e4c2dcd8a3114c1e470852" 1234 | dependencies = [ 1235 | "async-trait", 1236 | "bytes", 1237 | "combine", 1238 | "dtoa", 1239 | "futures-util", 1240 | "itoa 0.4.6", 1241 | "percent-encoding", 1242 | "pin-project-lite", 1243 | "sha1 0.6.0", 1244 | "tokio", 1245 | "tokio-util 0.6.10", 1246 | "url", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "redox_syscall" 1251 | version = "0.1.57" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1254 | 1255 | [[package]] 1256 | name = "redox_syscall" 1257 | version = "0.2.13" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 1260 | dependencies = [ 1261 | "bitflags", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "redox_users" 1266 | version = "0.4.3" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 1269 | dependencies = [ 1270 | "getrandom", 1271 | "redox_syscall 0.2.13", 1272 | "thiserror", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "regex" 1277 | version = "1.6.0" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 1280 | dependencies = [ 1281 | "aho-corasick", 1282 | "memchr", 1283 | "regex-syntax", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "regex-syntax" 1288 | version = "0.6.27" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 1291 | 1292 | [[package]] 1293 | name = "ring" 1294 | version = "0.16.20" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1297 | dependencies = [ 1298 | "cc", 1299 | "libc", 1300 | "once_cell", 1301 | "spin", 1302 | "untrusted", 1303 | "web-sys", 1304 | "winapi", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "rustls" 1309 | version = "0.19.1" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 1312 | dependencies = [ 1313 | "base64", 1314 | "log", 1315 | "ring", 1316 | "sct", 1317 | "webpki", 1318 | ] 1319 | 1320 | [[package]] 1321 | name = "ryu" 1322 | version = "1.0.5" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1325 | 1326 | [[package]] 1327 | name = "scopeguard" 1328 | version = "1.1.0" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1331 | 1332 | [[package]] 1333 | name = "sct" 1334 | version = "0.6.1" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1337 | dependencies = [ 1338 | "ring", 1339 | "untrusted", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "serde" 1344 | version = "1.0.138" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" 1347 | dependencies = [ 1348 | "serde_derive", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "serde_derive" 1353 | version = "1.0.138" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" 1356 | dependencies = [ 1357 | "proc-macro2", 1358 | "quote", 1359 | "syn", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "serde_json" 1364 | version = "1.0.82" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" 1367 | dependencies = [ 1368 | "itoa 1.0.2", 1369 | "ryu", 1370 | "serde", 1371 | ] 1372 | 1373 | [[package]] 1374 | name = "serde_urlencoded" 1375 | version = "0.7.1" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1378 | dependencies = [ 1379 | "form_urlencoded", 1380 | "itoa 1.0.2", 1381 | "ryu", 1382 | "serde", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "sha-1" 1387 | version = "0.9.1" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770" 1390 | dependencies = [ 1391 | "block-buffer 0.9.0", 1392 | "cfg-if 0.1.10", 1393 | "cpuid-bool", 1394 | "digest 0.9.0", 1395 | "opaque-debug", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "sha1" 1400 | version = "0.6.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" 1403 | 1404 | [[package]] 1405 | name = "sha1" 1406 | version = "0.10.1" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" 1409 | dependencies = [ 1410 | "cfg-if 1.0.0", 1411 | "cpufeatures", 1412 | "digest 0.10.3", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "sha2" 1417 | version = "0.9.9" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1420 | dependencies = [ 1421 | "block-buffer 0.9.0", 1422 | "cfg-if 1.0.0", 1423 | "cpufeatures", 1424 | "digest 0.9.0", 1425 | "opaque-debug", 1426 | ] 1427 | 1428 | [[package]] 1429 | name = "signal-hook-registry" 1430 | version = "1.2.2" 1431 | source = "registry+https://github.com/rust-lang/crates.io-index" 1432 | checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" 1433 | dependencies = [ 1434 | "libc", 1435 | ] 1436 | 1437 | [[package]] 1438 | name = "slab" 1439 | version = "0.4.2" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1442 | 1443 | [[package]] 1444 | name = "smallvec" 1445 | version = "1.9.0" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" 1448 | 1449 | [[package]] 1450 | name = "socket2" 1451 | version = "0.4.4" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 1454 | dependencies = [ 1455 | "libc", 1456 | "winapi", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "spin" 1461 | version = "0.5.2" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1464 | 1465 | [[package]] 1466 | name = "sqlformat" 1467 | version = "0.1.8" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" 1470 | dependencies = [ 1471 | "itertools", 1472 | "nom", 1473 | "unicode_categories", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "sqlx" 1478 | version = "0.5.9" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43" 1481 | dependencies = [ 1482 | "sqlx-core", 1483 | "sqlx-macros", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "sqlx-core" 1488 | version = "0.5.9" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1" 1491 | dependencies = [ 1492 | "ahash", 1493 | "atoi", 1494 | "base64", 1495 | "bitflags", 1496 | "byteorder", 1497 | "bytes", 1498 | "crc", 1499 | "crossbeam-channel", 1500 | "crossbeam-queue", 1501 | "crossbeam-utils", 1502 | "dirs", 1503 | "either", 1504 | "futures-channel", 1505 | "futures-core", 1506 | "futures-intrusive", 1507 | "futures-util", 1508 | "hashlink", 1509 | "hex", 1510 | "hmac", 1511 | "indexmap", 1512 | "itoa 0.4.6", 1513 | "libc", 1514 | "log", 1515 | "md-5", 1516 | "memchr", 1517 | "once_cell", 1518 | "parking_lot 0.11.0", 1519 | "percent-encoding", 1520 | "rand", 1521 | "rustls", 1522 | "serde", 1523 | "serde_json", 1524 | "sha-1", 1525 | "sha2", 1526 | "smallvec", 1527 | "sqlformat", 1528 | "sqlx-rt", 1529 | "stringprep", 1530 | "thiserror", 1531 | "tokio-stream", 1532 | "url", 1533 | "webpki", 1534 | "webpki-roots", 1535 | "whoami", 1536 | ] 1537 | 1538 | [[package]] 1539 | name = "sqlx-macros" 1540 | version = "0.5.9" 1541 | source = "registry+https://github.com/rust-lang/crates.io-index" 1542 | checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" 1543 | dependencies = [ 1544 | "dotenv", 1545 | "either", 1546 | "heck", 1547 | "once_cell", 1548 | "proc-macro2", 1549 | "quote", 1550 | "sha2", 1551 | "sqlx-core", 1552 | "sqlx-rt", 1553 | "syn", 1554 | "url", 1555 | ] 1556 | 1557 | [[package]] 1558 | name = "sqlx-pg-migrate" 1559 | version = "1.2.0" 1560 | source = "registry+https://github.com/rust-lang/crates.io-index" 1561 | checksum = "c953f3c114842c806461afc90a68da2fad7072d302cfcf69bdc31c893f6c899b" 1562 | dependencies = [ 1563 | "include_dir", 1564 | "sqlx", 1565 | "thiserror", 1566 | ] 1567 | 1568 | [[package]] 1569 | name = "sqlx-rt" 1570 | version = "0.5.13" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" 1573 | dependencies = [ 1574 | "once_cell", 1575 | "tokio", 1576 | "tokio-rustls", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "stringprep" 1581 | version = "0.1.2" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" 1584 | dependencies = [ 1585 | "unicode-bidi", 1586 | "unicode-normalization", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "subtle" 1591 | version = "2.4.1" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1594 | 1595 | [[package]] 1596 | name = "syn" 1597 | version = "1.0.98" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 1600 | dependencies = [ 1601 | "proc-macro2", 1602 | "quote", 1603 | "unicode-ident", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "testable-rust-web-project" 1608 | version = "0.1.0" 1609 | dependencies = [ 1610 | "actix-web", 1611 | "async-trait", 1612 | "dotenv", 1613 | "include_dir", 1614 | "mockall", 1615 | "redis", 1616 | "serde", 1617 | "sqlx", 1618 | "sqlx-pg-migrate", 1619 | "tokio", 1620 | "uuid", 1621 | ] 1622 | 1623 | [[package]] 1624 | name = "thiserror" 1625 | version = "1.0.31" 1626 | source = "registry+https://github.com/rust-lang/crates.io-index" 1627 | checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" 1628 | dependencies = [ 1629 | "thiserror-impl", 1630 | ] 1631 | 1632 | [[package]] 1633 | name = "thiserror-impl" 1634 | version = "1.0.31" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" 1637 | dependencies = [ 1638 | "proc-macro2", 1639 | "quote", 1640 | "syn", 1641 | ] 1642 | 1643 | [[package]] 1644 | name = "time" 1645 | version = "0.3.11" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" 1648 | dependencies = [ 1649 | "itoa 1.0.2", 1650 | "libc", 1651 | "num_threads", 1652 | "time-macros", 1653 | ] 1654 | 1655 | [[package]] 1656 | name = "time-macros" 1657 | version = "0.2.4" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" 1660 | 1661 | [[package]] 1662 | name = "tinyvec" 1663 | version = "0.3.4" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" 1666 | 1667 | [[package]] 1668 | name = "tokio" 1669 | version = "1.19.2" 1670 | source = "registry+https://github.com/rust-lang/crates.io-index" 1671 | checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" 1672 | dependencies = [ 1673 | "bytes", 1674 | "libc", 1675 | "memchr", 1676 | "mio", 1677 | "num_cpus", 1678 | "once_cell", 1679 | "parking_lot 0.12.1", 1680 | "pin-project-lite", 1681 | "signal-hook-registry", 1682 | "socket2", 1683 | "tokio-macros", 1684 | "winapi", 1685 | ] 1686 | 1687 | [[package]] 1688 | name = "tokio-macros" 1689 | version = "1.8.0" 1690 | source = "registry+https://github.com/rust-lang/crates.io-index" 1691 | checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" 1692 | dependencies = [ 1693 | "proc-macro2", 1694 | "quote", 1695 | "syn", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "tokio-rustls" 1700 | version = "0.22.0" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 1703 | dependencies = [ 1704 | "rustls", 1705 | "tokio", 1706 | "webpki", 1707 | ] 1708 | 1709 | [[package]] 1710 | name = "tokio-stream" 1711 | version = "0.1.9" 1712 | source = "registry+https://github.com/rust-lang/crates.io-index" 1713 | checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" 1714 | dependencies = [ 1715 | "futures-core", 1716 | "pin-project-lite", 1717 | "tokio", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "tokio-util" 1722 | version = "0.6.10" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" 1725 | dependencies = [ 1726 | "bytes", 1727 | "futures-core", 1728 | "futures-sink", 1729 | "log", 1730 | "pin-project-lite", 1731 | "tokio", 1732 | ] 1733 | 1734 | [[package]] 1735 | name = "tokio-util" 1736 | version = "0.7.3" 1737 | source = "registry+https://github.com/rust-lang/crates.io-index" 1738 | checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" 1739 | dependencies = [ 1740 | "bytes", 1741 | "futures-core", 1742 | "futures-sink", 1743 | "pin-project-lite", 1744 | "tokio", 1745 | "tracing", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "tracing" 1750 | version = "0.1.35" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" 1753 | dependencies = [ 1754 | "cfg-if 1.0.0", 1755 | "log", 1756 | "pin-project-lite", 1757 | "tracing-core", 1758 | ] 1759 | 1760 | [[package]] 1761 | name = "tracing-core" 1762 | version = "0.1.28" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" 1765 | dependencies = [ 1766 | "once_cell", 1767 | ] 1768 | 1769 | [[package]] 1770 | name = "treeline" 1771 | version = "0.1.0" 1772 | source = "registry+https://github.com/rust-lang/crates.io-index" 1773 | checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" 1774 | 1775 | [[package]] 1776 | name = "typenum" 1777 | version = "1.15.0" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1780 | 1781 | [[package]] 1782 | name = "unicode-bidi" 1783 | version = "0.3.4" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1786 | dependencies = [ 1787 | "matches", 1788 | ] 1789 | 1790 | [[package]] 1791 | name = "unicode-ident" 1792 | version = "1.0.1" 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" 1794 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 1795 | 1796 | [[package]] 1797 | name = "unicode-normalization" 1798 | version = "0.1.13" 1799 | source = "registry+https://github.com/rust-lang/crates.io-index" 1800 | checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" 1801 | dependencies = [ 1802 | "tinyvec", 1803 | ] 1804 | 1805 | [[package]] 1806 | name = "unicode-segmentation" 1807 | version = "1.6.0" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 1810 | 1811 | [[package]] 1812 | name = "unicode_categories" 1813 | version = "0.1.1" 1814 | source = "registry+https://github.com/rust-lang/crates.io-index" 1815 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 1816 | 1817 | [[package]] 1818 | name = "untrusted" 1819 | version = "0.7.1" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1822 | 1823 | [[package]] 1824 | name = "url" 1825 | version = "2.2.2" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1828 | dependencies = [ 1829 | "form_urlencoded", 1830 | "idna", 1831 | "matches", 1832 | "percent-encoding", 1833 | ] 1834 | 1835 | [[package]] 1836 | name = "uuid" 1837 | version = "1.1.2" 1838 | source = "registry+https://github.com/rust-lang/crates.io-index" 1839 | checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" 1840 | dependencies = [ 1841 | "getrandom", 1842 | ] 1843 | 1844 | [[package]] 1845 | name = "version_check" 1846 | version = "0.9.2" 1847 | source = "registry+https://github.com/rust-lang/crates.io-index" 1848 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 1849 | 1850 | [[package]] 1851 | name = "wasi" 1852 | version = "0.11.0+wasi-snapshot-preview1" 1853 | source = "registry+https://github.com/rust-lang/crates.io-index" 1854 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1855 | 1856 | [[package]] 1857 | name = "wasm-bindgen" 1858 | version = "0.2.68" 1859 | source = "registry+https://github.com/rust-lang/crates.io-index" 1860 | checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" 1861 | dependencies = [ 1862 | "cfg-if 0.1.10", 1863 | "wasm-bindgen-macro", 1864 | ] 1865 | 1866 | [[package]] 1867 | name = "wasm-bindgen-backend" 1868 | version = "0.2.68" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" 1871 | dependencies = [ 1872 | "bumpalo", 1873 | "lazy_static", 1874 | "log", 1875 | "proc-macro2", 1876 | "quote", 1877 | "syn", 1878 | "wasm-bindgen-shared", 1879 | ] 1880 | 1881 | [[package]] 1882 | name = "wasm-bindgen-macro" 1883 | version = "0.2.68" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" 1886 | dependencies = [ 1887 | "quote", 1888 | "wasm-bindgen-macro-support", 1889 | ] 1890 | 1891 | [[package]] 1892 | name = "wasm-bindgen-macro-support" 1893 | version = "0.2.68" 1894 | source = "registry+https://github.com/rust-lang/crates.io-index" 1895 | checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" 1896 | dependencies = [ 1897 | "proc-macro2", 1898 | "quote", 1899 | "syn", 1900 | "wasm-bindgen-backend", 1901 | "wasm-bindgen-shared", 1902 | ] 1903 | 1904 | [[package]] 1905 | name = "wasm-bindgen-shared" 1906 | version = "0.2.68" 1907 | source = "registry+https://github.com/rust-lang/crates.io-index" 1908 | checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" 1909 | 1910 | [[package]] 1911 | name = "web-sys" 1912 | version = "0.3.45" 1913 | source = "registry+https://github.com/rust-lang/crates.io-index" 1914 | checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" 1915 | dependencies = [ 1916 | "js-sys", 1917 | "wasm-bindgen", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "webpki" 1922 | version = "0.21.4" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 1925 | dependencies = [ 1926 | "ring", 1927 | "untrusted", 1928 | ] 1929 | 1930 | [[package]] 1931 | name = "webpki-roots" 1932 | version = "0.21.1" 1933 | source = "registry+https://github.com/rust-lang/crates.io-index" 1934 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 1935 | dependencies = [ 1936 | "webpki", 1937 | ] 1938 | 1939 | [[package]] 1940 | name = "whoami" 1941 | version = "1.2.1" 1942 | source = "registry+https://github.com/rust-lang/crates.io-index" 1943 | checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" 1944 | dependencies = [ 1945 | "wasm-bindgen", 1946 | "web-sys", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "winapi" 1951 | version = "0.3.9" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1954 | dependencies = [ 1955 | "winapi-i686-pc-windows-gnu", 1956 | "winapi-x86_64-pc-windows-gnu", 1957 | ] 1958 | 1959 | [[package]] 1960 | name = "winapi-i686-pc-windows-gnu" 1961 | version = "0.4.0" 1962 | source = "registry+https://github.com/rust-lang/crates.io-index" 1963 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1964 | 1965 | [[package]] 1966 | name = "winapi-x86_64-pc-windows-gnu" 1967 | version = "0.4.0" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1970 | 1971 | [[package]] 1972 | name = "windows-sys" 1973 | version = "0.36.1" 1974 | source = "registry+https://github.com/rust-lang/crates.io-index" 1975 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1976 | dependencies = [ 1977 | "windows_aarch64_msvc", 1978 | "windows_i686_gnu", 1979 | "windows_i686_msvc", 1980 | "windows_x86_64_gnu", 1981 | "windows_x86_64_msvc", 1982 | ] 1983 | 1984 | [[package]] 1985 | name = "windows_aarch64_msvc" 1986 | version = "0.36.1" 1987 | source = "registry+https://github.com/rust-lang/crates.io-index" 1988 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1989 | 1990 | [[package]] 1991 | name = "windows_i686_gnu" 1992 | version = "0.36.1" 1993 | source = "registry+https://github.com/rust-lang/crates.io-index" 1994 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1995 | 1996 | [[package]] 1997 | name = "windows_i686_msvc" 1998 | version = "0.36.1" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 2001 | 2002 | [[package]] 2003 | name = "windows_x86_64_gnu" 2004 | version = "0.36.1" 2005 | source = "registry+https://github.com/rust-lang/crates.io-index" 2006 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 2007 | 2008 | [[package]] 2009 | name = "windows_x86_64_msvc" 2010 | version = "0.36.1" 2011 | source = "registry+https://github.com/rust-lang/crates.io-index" 2012 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 2013 | 2014 | [[package]] 2015 | name = "zstd" 2016 | version = "0.11.2+zstd.1.5.2" 2017 | source = "registry+https://github.com/rust-lang/crates.io-index" 2018 | checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" 2019 | dependencies = [ 2020 | "zstd-safe", 2021 | ] 2022 | 2023 | [[package]] 2024 | name = "zstd-safe" 2025 | version = "5.0.2+zstd.1.5.2" 2026 | source = "registry+https://github.com/rust-lang/crates.io-index" 2027 | checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" 2028 | dependencies = [ 2029 | "libc", 2030 | "zstd-sys", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "zstd-sys" 2035 | version = "2.0.1+zstd.1.5.2" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" 2038 | dependencies = [ 2039 | "cc", 2040 | "libc", 2041 | ] 2042 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testable-rust-web-project" 3 | version = "0.1.0" 4 | authors = ["ecky"] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | async-trait = "0.1.56" 11 | sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "postgres"] } 12 | sqlx-pg-migrate = "1.2.0" 13 | include_dir = "0.7.2" 14 | redis = { version = "0.21.5", features = ["tokio-comp"] } 15 | uuid = { version = "1.1.2", features = ["v4"] } 16 | actix-web = "4.1.0" 17 | serde = { version = "1.0.138", features = ["derive"] } 18 | dotenv = "0.15" 19 | tokio = { version = "1.19.2", features = ["macros"] } 20 | 21 | [dev-dependencies] 22 | mockall = "0.8.3" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Testable Rust Web Project 2 | 3 | An example project that implements Ports-and-Adapters pattern. This pattern helps with testability of the project. 4 | 5 | Read the accompanying article that explains this repository: [Structuring Rust Project For Testability](https://eckyputrady.medium.com/structuring-rust-project-for-testability-18207b5d0243). 6 | 7 | ## Running The Test 8 | 9 | Setup the infrastructure required for testing via Docker: 10 | 11 | ``` 12 | $ sudo docker stack deploy -c test-stack.yml testable-rust-web-project 13 | ``` 14 | 15 | Run the test: 16 | 17 | ``` 18 | $ cargo test 19 | ``` 20 | 21 | ## Running The Application 22 | 23 | Setup the infrastructure required for running the application via Docker: 24 | 25 | ``` 26 | $ sudo docker stack deploy -c test-stack.yml testable-rust-web-project 27 | ``` 28 | 29 | Run the application: 30 | 31 | ``` 32 | $ cargo run 33 | ``` 34 | 35 | Interact with the application using `curl` or other HTTP testing tools. 36 | -------------------------------------------------------------------------------- /migrations/000000_init.sql: -------------------------------------------------------------------------------- 1 | create extension pgcrypto; 2 | 3 | create table if not exists credentials ( 4 | id bigserial primary key, 5 | username varchar(50) not null unique, 6 | password text not null 7 | ); -------------------------------------------------------------------------------- /src/auth/auth_service_impl.rs: -------------------------------------------------------------------------------- 1 | use super::ports::*; 2 | use async_trait::async_trait; 3 | 4 | pub struct AuthServiceImpl { 5 | pub credential_repo: A, 6 | pub token_repo: B, 7 | } 8 | 9 | #[async_trait] 10 | impl AuthService for AuthServiceImpl 11 | where A: CredentialRepo + Sync + Send, 12 | B: TokenRepo + Sync + Send { 13 | 14 | async fn register(self: &Self, credential: &Credential) -> bool { 15 | self.credential_repo.save_credential(credential).await 16 | } 17 | 18 | async fn login(self: &Self, credential: &Credential) -> Option { 19 | if !self.credential_repo.is_credential_exists(credential).await { 20 | return None; 21 | } 22 | 23 | let token = self.token_repo.generate_token().await; 24 | if !self.token_repo.save_token(&token, &credential.username).await { 25 | return None; 26 | } 27 | 28 | Some(token) 29 | } 30 | 31 | async fn authenticate(self: &Self, token: &Token) -> Option { 32 | self.token_repo.get_username_by_token(token).await 33 | } 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::*; 39 | use mockall::predicate::*; 40 | 41 | #[actix_web::main] 42 | #[test] 43 | async fn test_login_success() { 44 | let credential = Credential { username: "u".to_string(), password: "p".to_string() }; 45 | let token = "token".to_string(); 46 | 47 | let mut credential_repo = MockCredentialRepo::new(); 48 | credential_repo.expect_is_credential_exists() 49 | .with(eq(credential.clone())) 50 | .return_const(true); 51 | 52 | let mut token_repo = MockTokenRepo::new(); 53 | token_repo.expect_generate_token() 54 | .return_const(token.clone()); 55 | token_repo.expect_save_token() 56 | .with(eq(token.clone()), eq(credential.username.clone())) 57 | .return_const(true); 58 | 59 | let sut = AuthServiceImpl { credential_repo, token_repo }; 60 | 61 | let actual = sut.login(&credential).await; 62 | let expected = Some(token.clone()); 63 | assert_eq!(expected, actual); 64 | } 65 | 66 | #[actix_web::main] 67 | #[test] 68 | async fn test_login_failure_unable_to_save_token() { 69 | let credential = Credential { username: "u".to_string(), password: "p".to_string() }; 70 | let token = "token".to_string(); 71 | 72 | let mut credential_repo = MockCredentialRepo::new(); 73 | credential_repo.expect_is_credential_exists() 74 | .with(eq(credential.clone())) 75 | .return_const(true); 76 | 77 | let mut token_repo = MockTokenRepo::new(); 78 | token_repo.expect_generate_token() 79 | .return_const(token.clone()); 80 | token_repo.expect_save_token() 81 | .with(eq(token.clone()), eq(credential.username.clone())) 82 | .return_const(false); 83 | 84 | let sut = AuthServiceImpl { credential_repo, token_repo }; 85 | 86 | let actual = sut.login(&credential).await; 87 | let expected = None; 88 | assert_eq!(expected, actual); 89 | } 90 | 91 | #[actix_web::main] 92 | #[test] 93 | async fn test_login_failure_credential_does_not_exists() { 94 | let credential = Credential { username: "u".to_string(), password: "p".to_string() }; 95 | 96 | let mut credential_repo = MockCredentialRepo::new(); 97 | credential_repo.expect_is_credential_exists() 98 | .with(eq(credential.clone())) 99 | .return_const(false); 100 | 101 | let token_repo = MockTokenRepo::new(); 102 | 103 | let sut = AuthServiceImpl { credential_repo, token_repo }; 104 | 105 | let actual = sut.login(&credential).await; 106 | let expected = None; 107 | assert_eq!(expected, actual); 108 | } 109 | } -------------------------------------------------------------------------------- /src/auth/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ports; 2 | pub mod rest_auth_controller; 3 | pub mod auth_service_impl; 4 | pub mod redis_token_repo; 5 | pub mod postgres_credential_repo; -------------------------------------------------------------------------------- /src/auth/ports.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use serde::{Serialize, Deserialize}; 3 | 4 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] 5 | pub struct Credential { 6 | pub username: String, 7 | pub password: String 8 | } 9 | 10 | pub type Token = String; 11 | 12 | #[cfg_attr(test, mockall::automock)] 13 | #[async_trait] 14 | pub trait AuthService { 15 | async fn register(&self, credential: &Credential) -> bool; 16 | async fn login(&self, credential: &Credential) -> Option; 17 | async fn authenticate(&self, token: &Token) -> Option; 18 | } 19 | 20 | #[cfg_attr(test, mockall::automock)] 21 | #[async_trait] 22 | pub trait CredentialRepo { 23 | async fn save_credential(&self, credential: &Credential) -> bool; 24 | async fn is_credential_exists(&self, credential: &Credential) -> bool; 25 | } 26 | 27 | #[cfg_attr(test, mockall::automock)] 28 | #[async_trait] 29 | pub trait TokenRepo { 30 | async fn generate_token(&self) -> Token; 31 | async fn save_token(&self, token: &Token, username: &String) -> bool; 32 | async fn get_username_by_token(&self, token: &Token) -> Option; 33 | } -------------------------------------------------------------------------------- /src/auth/postgres_credential_repo.rs: -------------------------------------------------------------------------------- 1 | use super::ports::*; 2 | use sqlx::PgPool; 3 | use async_trait::async_trait; 4 | use std::sync::Arc; 5 | 6 | pub struct PostgresCredentialRepoImpl { 7 | pub pg_pool: Arc 8 | } 9 | 10 | #[async_trait] 11 | impl CredentialRepo for PostgresCredentialRepoImpl { 12 | async fn save_credential(self: &Self, credential: &Credential) -> bool { 13 | sqlx::query("insert into credentials (username, password) values ($1, crypt($2, gen_salt('bf')))") 14 | .bind(&credential.username) 15 | .bind(&credential.password) 16 | .execute(&*self.pg_pool) 17 | .await 18 | .map(|row| row.rows_affected() > 0) 19 | .unwrap_or(false) 20 | } 21 | 22 | async fn is_credential_exists(self: &Self, credential: &Credential) -> bool { 23 | let (found,): (bool,) = sqlx::query_as("select true from credentials where username = $1 and password = crypt($2, password)") 24 | .bind(&credential.username) 25 | .bind(&credential.password) 26 | .fetch_one(&*self.pg_pool) 27 | .await 28 | .unwrap_or((false,)); 29 | found 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | use std::sync::Arc; 37 | use sqlx::postgres::PgPoolOptions; 38 | 39 | #[tokio::test] 40 | async fn test_save_and_check() { 41 | let pg_pool = PgPoolOptions::new() 42 | .connect("postgresql://postgres:test@localhost:5431") 43 | .await 44 | .expect("Unable to connect to DB"); 45 | sqlx::query("drop database if exists test_credential_repo").execute(&pg_pool).await.unwrap(); 46 | sqlx::query("create database test_credential_repo").execute(&pg_pool).await.unwrap(); 47 | let pg_pool = crate::infrastructure::postgresql::configure_with_db_url("postgresql://postgres:test@localhost:5431/test_credential_repo").await; 48 | 49 | let sut = PostgresCredentialRepoImpl { pg_pool: Arc::new(pg_pool) }; 50 | 51 | let credential = Credential { username: "u".to_string(), password: "p".to_string() }; 52 | 53 | assert_eq!(false, sut.is_credential_exists(&credential).await); 54 | 55 | assert_eq!(true, sut.save_credential(&credential).await); 56 | assert_eq!(true, sut.is_credential_exists(&credential).await); 57 | } 58 | } -------------------------------------------------------------------------------- /src/auth/redis_token_repo.rs: -------------------------------------------------------------------------------- 1 | use super::ports::*; 2 | use async_trait::async_trait; 3 | use uuid::Uuid; 4 | use redis::AsyncCommands; 5 | use std::sync::Arc; 6 | 7 | pub struct RedisTokenRepoImpl { 8 | pub redis_client: Arc 9 | } 10 | 11 | #[async_trait] 12 | impl TokenRepo for RedisTokenRepoImpl { 13 | 14 | async fn generate_token(self: &Self) -> Token { 15 | Uuid::new_v4().to_string() 16 | } 17 | 18 | async fn save_token(self: &Self, token: &Token, username: &String) -> bool { 19 | let redis_client = &*self.redis_client; 20 | if let Ok(mut conn) = redis_client.get_async_connection().await { 21 | let key = format!("token:{}", token); 22 | conn.set(key, username) 23 | .await 24 | .map(|_: String| true) 25 | .unwrap_or(false) 26 | } else { 27 | false 28 | } 29 | } 30 | 31 | async fn get_username_by_token(self: &Self, token: &Token) -> Option { 32 | let redis_client = &*self.redis_client; 33 | if let Ok(mut conn) = redis_client.get_async_connection().await { 34 | let key = format!("token:{}", token); 35 | conn.get(key).await.ok() 36 | } else { 37 | None 38 | } 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use super::*; 45 | use std::sync::Arc; 46 | 47 | #[actix_web::main] 48 | #[test] 49 | async fn test_save_and_check() { 50 | let redis_client = redis::Client::open("redis://localhost:6378").unwrap(); 51 | let sut = RedisTokenRepoImpl { redis_client: Arc::new(redis_client) }; 52 | 53 | let token = sut.generate_token().await; 54 | let username = "username".to_string(); 55 | assert_eq!(None, sut.get_username_by_token(&token).await); 56 | assert_eq!(true, sut.save_token(&token, &username).await); 57 | assert_eq!(Some(username), sut.get_username_by_token(&token).await); 58 | } 59 | } -------------------------------------------------------------------------------- /src/auth/rest_auth_controller.rs: -------------------------------------------------------------------------------- 1 | use super::ports::*; 2 | use actix_web::{web, Responder}; 3 | use actix_web::web::Json; 4 | 5 | pub fn configure(service: web::Data, cfg: &mut web::ServiceConfig) { 6 | cfg.app_data(service); 7 | cfg.route("/register", web::post().to(register::)); 8 | cfg.route("/login", web::post().to(login::)); 9 | cfg.route("/authenticate", web::post().to(authenticate::)); 10 | } 11 | 12 | async fn register(service: web::Data, body: Json) -> impl Responder { 13 | Json(service.register(&body).await) 14 | } 15 | 16 | async fn login(service: web::Data, body: Json) -> impl Responder { 17 | Json(service.login(&body).await) 18 | } 19 | 20 | async fn authenticate(service: web::Data, body: Json) -> impl Responder { 21 | Json(service.authenticate(&body).await) 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | use actix_web::{test, web, App}; 28 | use mockall::predicate::*; 29 | 30 | #[tokio::test] 31 | async fn test_authenticate_wrong() { 32 | let mut auth_service = MockAuthService::new(); 33 | auth_service.expect_authenticate().return_const(None); 34 | let auth_service = web::Data::new(auth_service); 35 | 36 | let mut sut = test::init_service(App::new().configure(|cfg| configure(auth_service, cfg))).await; 37 | 38 | let req = test::TestRequest::post() 39 | .uri("/authenticate") 40 | .set_json(&"test") 41 | .to_request(); 42 | let resp = test::call_service(&mut sut, req).await; 43 | let actual_body: Option = test::read_body_json(resp).await; 44 | assert_eq!(actual_body, None); 45 | } 46 | 47 | #[tokio::test] 48 | async fn test_authenticate_correct() { 49 | let mut auth_service = MockAuthService::new(); 50 | auth_service.expect_authenticate() 51 | .with(eq("test".to_string())) 52 | .return_const(Some("username".to_string())); 53 | let auth_service = web::Data::new(auth_service); 54 | 55 | let mut sut = test::init_service(App::new().configure(|cfg| configure(auth_service, cfg))).await; 56 | 57 | let req = test::TestRequest::post() 58 | .uri("/authenticate") 59 | .set_json(&"test") 60 | .to_request(); 61 | let resp = test::call_service(&mut sut, req).await; 62 | let actual_body: Option = test::read_body_json(resp).await; 63 | assert_eq!(actual_body, Some("username".to_string())); 64 | } 65 | } -------------------------------------------------------------------------------- /src/infrastructure/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod redis; 2 | pub mod postgresql; -------------------------------------------------------------------------------- /src/infrastructure/postgresql.rs: -------------------------------------------------------------------------------- 1 | use sqlx_pg_migrate::migrate; 2 | use include_dir::{include_dir, Dir}; 3 | use sqlx::postgres::{PgPool, PgPoolOptions}; 4 | use std::env; 5 | 6 | static MIGRATIONS: Dir = include_dir!("migrations"); 7 | 8 | pub async fn configure() -> PgPool { 9 | let db_url = env::var("DB_URL").expect("DB_URL env var needs to be set"); 10 | configure_with_db_url(&db_url).await 11 | } 12 | 13 | pub async fn configure_with_db_url(db_url: &str) -> PgPool { 14 | migrate(&db_url, &MIGRATIONS).await.expect("Unable to migrate DB"); 15 | PgPoolOptions::new() 16 | .max_connections(5) 17 | .connect(&db_url) 18 | .await 19 | .expect("Unable to connect to Postgresql") 20 | } -------------------------------------------------------------------------------- /src/infrastructure/redis.rs: -------------------------------------------------------------------------------- 1 | pub use redis::Client; 2 | 3 | pub async fn configure() -> redis::Client { 4 | let redis_url = std::env::var("REDIS_URL").expect("REDIS_URL env var needs to be set"); 5 | redis::Client::open(redis_url).expect("Unable to connect to Redis") 6 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod auth; 2 | mod infrastructure; 3 | 4 | use actix_web::{HttpServer, App, web}; 5 | use std::sync::Arc; 6 | use sqlx::PgPool; 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | if let Err(e) = dotenv::dotenv() { 11 | print!("Not applying .env : {:?}", e); 12 | } 13 | 14 | let pg_pool = Arc::new(infrastructure::postgresql::configure().await); 15 | let redis_client = Arc::new(infrastructure::redis::configure().await); 16 | 17 | let port = std::env::var("PORT").expect("PORT env var must be set"); 18 | let address = format!("0.0.0.0:{}", port); 19 | println!("Binding server to {} ...", address); 20 | HttpServer::new(move || App::new().configure(|cfg| configure_features(redis_client.clone(), pg_pool.clone(), cfg))) 21 | .bind(address) 22 | .expect("Unable to bind server") 23 | .run() 24 | .await 25 | .expect("Failed to start web server") 26 | } 27 | 28 | fn configure_features(redis_client: Arc, pg_pool: Arc, cfg: &mut web::ServiceConfig) { 29 | configure_auth(redis_client.clone(), pg_pool.clone(), cfg); 30 | } 31 | 32 | fn configure_auth(redis_client: Arc, pg_pool: Arc, cfg: &mut web::ServiceConfig) { 33 | use crate::auth::auth_service_impl::AuthServiceImpl; 34 | use crate::auth::postgres_credential_repo::PostgresCredentialRepoImpl; 35 | use crate::auth::redis_token_repo::RedisTokenRepoImpl; 36 | use crate::auth::rest_auth_controller; 37 | 38 | let service = AuthServiceImpl { 39 | credential_repo: PostgresCredentialRepoImpl { 40 | pg_pool: pg_pool.clone() 41 | }, 42 | token_repo: RedisTokenRepoImpl { 43 | redis_client: redis_client.clone() 44 | } 45 | }; 46 | rest_auth_controller::configure(web::Data::new(service), cfg); 47 | } 48 | -------------------------------------------------------------------------------- /test-stack.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | 5 | postgres: 6 | image: "postgres:13.0" 7 | ports: 8 | - 5431:5432 9 | environment: 10 | POSTGRES_PASSWORD: test 11 | 12 | redis: 13 | image: "redis:6.0.9" 14 | ports: 15 | - 6378:6379 --------------------------------------------------------------------------------